diff options
Diffstat (limited to 'vendor/k8s.io/kubernetes/pkg/serviceaccount')
-rw-r--r-- | vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go | 186 | ||||
-rw-r--r-- | vendor/k8s.io/kubernetes/pkg/serviceaccount/jwt.go | 212 | ||||
-rw-r--r-- | vendor/k8s.io/kubernetes/pkg/serviceaccount/legacy.go | 135 | ||||
-rw-r--r-- | vendor/k8s.io/kubernetes/pkg/serviceaccount/util.go | 74 |
4 files changed, 0 insertions, 607 deletions
diff --git a/vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go b/vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go deleted file mode 100644 index c3ed29c4c..000000000 --- a/vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package serviceaccount - -import ( - "errors" - "fmt" - "time" - - "github.com/golang/glog" - apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount" - "k8s.io/kubernetes/pkg/apis/core" - - "gopkg.in/square/go-jose.v2/jwt" -) - -// time.Now stubbed out to allow testing -var now = time.Now - -type privateClaims struct { - Kubernetes kubernetes `json:"kubernetes.io,omitempty"` -} - -type kubernetes struct { - Namespace string `json:"namespace,omitempty"` - Svcacct ref `json:"serviceaccount,omitempty"` - Pod *ref `json:"pod,omitempty"` - Secret *ref `json:"secret,omitempty"` -} - -type ref struct { - Name string `json:"name,omitempty"` - UID string `json:"uid,omitempty"` -} - -func Claims(sa core.ServiceAccount, pod *core.Pod, secret *core.Secret, expirationSeconds int64, audience []string) (*jwt.Claims, interface{}) { - now := now() - sc := &jwt.Claims{ - Subject: apiserverserviceaccount.MakeUsername(sa.Namespace, sa.Name), - Audience: jwt.Audience(audience), - IssuedAt: jwt.NewNumericDate(now), - NotBefore: jwt.NewNumericDate(now), - Expiry: jwt.NewNumericDate(now.Add(time.Duration(expirationSeconds) * time.Second)), - } - pc := &privateClaims{ - Kubernetes: kubernetes{ - Namespace: sa.Namespace, - Svcacct: ref{ - Name: sa.Name, - UID: string(sa.UID), - }, - }, - } - switch { - case pod != nil: - pc.Kubernetes.Pod = &ref{ - Name: pod.Name, - UID: string(pod.UID), - } - case secret != nil: - pc.Kubernetes.Secret = &ref{ - Name: secret.Name, - UID: string(secret.UID), - } - } - return sc, pc -} - -func NewValidator(audiences []string, getter ServiceAccountTokenGetter) Validator { - return &validator{ - auds: audiences, - getter: getter, - } -} - -type validator struct { - auds []string - getter ServiceAccountTokenGetter -} - -var _ = Validator(&validator{}) - -func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{}) (string, string, string, error) { - private, ok := privateObj.(*privateClaims) - if !ok { - glog.Errorf("jwt validator expected private claim of type *privateClaims but got: %T", privateObj) - return "", "", "", errors.New("Token could not be validated.") - } - err := public.Validate(jwt.Expected{ - Time: now(), - }) - switch { - case err == nil: - case err == jwt.ErrExpired: - return "", "", "", errors.New("Token has expired.") - default: - glog.Errorf("unexpected validation error: %T", err) - return "", "", "", errors.New("Token could not be validated.") - } - - var audValid bool - - for _, aud := range v.auds { - audValid = public.Audience.Contains(aud) - if audValid { - break - } - } - - if !audValid { - return "", "", "", errors.New("Token is invalid for this audience.") - } - - namespace := private.Kubernetes.Namespace - saref := private.Kubernetes.Svcacct - podref := private.Kubernetes.Pod - secref := private.Kubernetes.Secret - // Make sure service account still exists (name and UID) - serviceAccount, err := v.getter.GetServiceAccount(namespace, saref.Name) - if err != nil { - glog.V(4).Infof("Could not retrieve service account %s/%s: %v", namespace, saref.Name, err) - return "", "", "", err - } - if serviceAccount.DeletionTimestamp != nil { - glog.V(4).Infof("Service account has been deleted %s/%s", namespace, saref.Name) - return "", "", "", fmt.Errorf("ServiceAccount %s/%s has been deleted", namespace, saref.Name) - } - if string(serviceAccount.UID) != saref.UID { - glog.V(4).Infof("Service account UID no longer matches %s/%s: %q != %q", namespace, saref.Name, string(serviceAccount.UID), saref.UID) - return "", "", "", fmt.Errorf("ServiceAccount UID (%s) does not match claim (%s)", serviceAccount.UID, saref.UID) - } - - if secref != nil { - // Make sure token hasn't been invalidated by deletion of the secret - secret, err := v.getter.GetSecret(namespace, secref.Name) - if err != nil { - glog.V(4).Infof("Could not retrieve bound secret %s/%s for service account %s/%s: %v", namespace, secref.Name, namespace, saref.Name, err) - return "", "", "", errors.New("Token has been invalidated") - } - if secret.DeletionTimestamp != nil { - glog.V(4).Infof("Bound secret is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, secref.Name, namespace, saref.Name) - return "", "", "", errors.New("Token has been invalidated") - } - if string(secref.UID) != secref.UID { - glog.V(4).Infof("Secret UID no longer matches %s/%s: %q != %q", namespace, secref.Name, string(serviceAccount.UID), secref.UID) - return "", "", "", fmt.Errorf("Secret UID (%s) does not match claim (%s)", secret.UID, secref.UID) - } - } - - if podref != nil { - // Make sure token hasn't been invalidated by deletion of the pod - pod, err := v.getter.GetPod(namespace, podref.Name) - if err != nil { - glog.V(4).Infof("Could not retrieve bound secret %s/%s for service account %s/%s: %v", namespace, podref.Name, namespace, saref.Name, err) - return "", "", "", errors.New("Token has been invalidated") - } - if pod.DeletionTimestamp != nil { - glog.V(4).Infof("Bound pod is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, podref.Name, namespace, saref.Name) - return "", "", "", errors.New("Token has been invalidated") - } - if string(podref.UID) != podref.UID { - glog.V(4).Infof("Pod UID no longer matches %s/%s: %q != %q", namespace, podref.Name, string(serviceAccount.UID), podref.UID) - return "", "", "", fmt.Errorf("Pod UID (%s) does not match claim (%s)", pod.UID, podref.UID) - } - } - - return private.Kubernetes.Namespace, private.Kubernetes.Svcacct.Name, private.Kubernetes.Svcacct.UID, nil -} - -func (v *validator) NewPrivateClaims() interface{} { - return &privateClaims{} -} diff --git a/vendor/k8s.io/kubernetes/pkg/serviceaccount/jwt.go b/vendor/k8s.io/kubernetes/pkg/serviceaccount/jwt.go deleted file mode 100644 index 01c369a31..000000000 --- a/vendor/k8s.io/kubernetes/pkg/serviceaccount/jwt.go +++ /dev/null @@ -1,212 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package serviceaccount - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rsa" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "strings" - - "k8s.io/api/core/v1" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - - jose "gopkg.in/square/go-jose.v2" - "gopkg.in/square/go-jose.v2/jwt" -) - -// ServiceAccountTokenGetter defines functions to retrieve a named service account and secret -type ServiceAccountTokenGetter interface { - GetServiceAccount(namespace, name string) (*v1.ServiceAccount, error) - GetPod(namespace, name string) (*v1.Pod, error) - GetSecret(namespace, name string) (*v1.Secret, error) -} - -type TokenGenerator interface { - // GenerateToken generates a token which will identify the given - // ServiceAccount. privateClaims is an interface that will be - // serialized into the JWT payload JSON encoding at the root level of - // the payload object. Public claims take precedent over private - // claims i.e. if both claims and privateClaims have an "exp" field, - // the value in claims will be used. - GenerateToken(claims *jwt.Claims, privateClaims interface{}) (string, error) -} - -// JWTTokenGenerator returns a TokenGenerator that generates signed JWT tokens, using the given privateKey. -// privateKey is a PEM-encoded byte array of a private RSA key. -// JWTTokenAuthenticator() -func JWTTokenGenerator(iss string, privateKey interface{}) TokenGenerator { - return &jwtTokenGenerator{ - iss: iss, - privateKey: privateKey, - } -} - -type jwtTokenGenerator struct { - iss string - privateKey interface{} -} - -func (j *jwtTokenGenerator) GenerateToken(claims *jwt.Claims, privateClaims interface{}) (string, error) { - var alg jose.SignatureAlgorithm - switch privateKey := j.privateKey.(type) { - case *rsa.PrivateKey: - alg = jose.RS256 - case *ecdsa.PrivateKey: - switch privateKey.Curve { - case elliptic.P256(): - alg = jose.ES256 - case elliptic.P384(): - alg = jose.ES384 - case elliptic.P521(): - alg = jose.ES512 - default: - return "", fmt.Errorf("unknown private key curve, must be 256, 384, or 521") - } - default: - return "", fmt.Errorf("unknown private key type %T, must be *rsa.PrivateKey or *ecdsa.PrivateKey", j.privateKey) - } - - signer, err := jose.NewSigner( - jose.SigningKey{ - Algorithm: alg, - Key: j.privateKey, - }, - nil, - ) - if err != nil { - return "", err - } - - // claims are applied in reverse precedence - return jwt.Signed(signer). - Claims(privateClaims). - Claims(claims). - Claims(&jwt.Claims{ - Issuer: j.iss, - }). - CompactSerialize() -} - -// JWTTokenAuthenticator authenticates tokens as JWT tokens produced by JWTTokenGenerator -// Token signatures are verified using each of the given public keys until one works (allowing key rotation) -// If lookup is true, the service account and secret referenced as claims inside the token are retrieved and verified with the provided ServiceAccountTokenGetter -func JWTTokenAuthenticator(iss string, keys []interface{}, validator Validator) authenticator.Token { - return &jwtTokenAuthenticator{ - iss: iss, - keys: keys, - validator: validator, - } -} - -type jwtTokenAuthenticator struct { - iss string - keys []interface{} - validator Validator -} - -// Validator is called by the JWT token authentictaor to apply domain specific -// validation to a token and extract user information. -type Validator interface { - // Validate validates a token and returns user information or an error. - // Validator can assume that the issuer and signature of a token are already - // verified when this function is called. - Validate(tokenData string, public *jwt.Claims, private interface{}) (namespace, name, uid string, err error) - // NewPrivateClaims returns a struct that the authenticator should - // deserialize the JWT payload into. The authenticator may then pass this - // struct back to the Validator as the 'private' argument to a Validate() - // call. This struct should contain fields for any private claims that the - // Validator requires to validate the JWT. - NewPrivateClaims() interface{} -} - -var errMismatchedSigningMethod = errors.New("invalid signing method") - -func (j *jwtTokenAuthenticator) AuthenticateToken(tokenData string) (user.Info, bool, error) { - if !j.hasCorrectIssuer(tokenData) { - return nil, false, nil - } - - tok, err := jwt.ParseSigned(tokenData) - if err != nil { - return nil, false, nil - } - - public := &jwt.Claims{} - private := j.validator.NewPrivateClaims() - - var ( - found bool - errlist []error - ) - for _, key := range j.keys { - if err := tok.Claims(key, public, private); err != nil { - errlist = append(errlist, err) - continue - } - found = true - break - } - - if !found { - return nil, false, utilerrors.NewAggregate(errlist) - } - - // If we get here, we have a token with a recognized signature and - // issuer string. - ns, name, uid, err := j.validator.Validate(tokenData, public, private) - if err != nil { - return nil, false, err - } - - return UserInfo(ns, name, uid), true, nil -} - -// hasCorrectIssuer returns true if tokenData is a valid JWT in compact -// serialization format and the "iss" claim matches the iss field of this token -// authenticator, and otherwise returns false. -// -// Note: go-jose currently does not allow access to unverified JWS payloads. -// See https://github.com/square/go-jose/issues/169 -func (j *jwtTokenAuthenticator) hasCorrectIssuer(tokenData string) bool { - parts := strings.Split(tokenData, ".") - if len(parts) != 3 { - return false - } - payload, err := base64.RawURLEncoding.DecodeString(parts[1]) - if err != nil { - return false - } - claims := struct { - // WARNING: this JWT is not verified. Do not trust these claims. - Issuer string `json:"iss"` - }{} - if err := json.Unmarshal(payload, &claims); err != nil { - return false - } - if claims.Issuer != j.iss { - return false - } - return true - -} diff --git a/vendor/k8s.io/kubernetes/pkg/serviceaccount/legacy.go b/vendor/k8s.io/kubernetes/pkg/serviceaccount/legacy.go deleted file mode 100644 index 5055db7cb..000000000 --- a/vendor/k8s.io/kubernetes/pkg/serviceaccount/legacy.go +++ /dev/null @@ -1,135 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package serviceaccount - -import ( - "bytes" - "errors" - "fmt" - - "k8s.io/api/core/v1" - apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount" - - "github.com/golang/glog" - "gopkg.in/square/go-jose.v2/jwt" -) - -func LegacyClaims(serviceAccount v1.ServiceAccount, secret v1.Secret) (*jwt.Claims, interface{}) { - return &jwt.Claims{ - Subject: apiserverserviceaccount.MakeUsername(serviceAccount.Namespace, serviceAccount.Name), - }, &legacyPrivateClaims{ - Namespace: serviceAccount.Namespace, - ServiceAccountName: serviceAccount.Name, - ServiceAccountUID: string(serviceAccount.UID), - SecretName: secret.Name, - } -} - -const LegacyIssuer = "kubernetes/serviceaccount" - -type legacyPrivateClaims struct { - ServiceAccountName string `json:"kubernetes.io/serviceaccount/service-account.name"` - ServiceAccountUID string `json:"kubernetes.io/serviceaccount/service-account.uid"` - SecretName string `json:"kubernetes.io/serviceaccount/secret.name"` - Namespace string `json:"kubernetes.io/serviceaccount/namespace"` -} - -func NewLegacyValidator(lookup bool, getter ServiceAccountTokenGetter) Validator { - return &legacyValidator{ - lookup: lookup, - getter: getter, - } -} - -type legacyValidator struct { - lookup bool - getter ServiceAccountTokenGetter -} - -var _ = Validator(&legacyValidator{}) - -func (v *legacyValidator) Validate(tokenData string, public *jwt.Claims, privateObj interface{}) (string, string, string, error) { - private, ok := privateObj.(*legacyPrivateClaims) - if !ok { - glog.Errorf("jwt validator expected private claim of type *legacyPrivateClaims but got: %T", privateObj) - return "", "", "", errors.New("Token could not be validated.") - } - - // Make sure the claims we need exist - if len(public.Subject) == 0 { - return "", "", "", errors.New("sub claim is missing") - } - namespace := private.Namespace - if len(namespace) == 0 { - return "", "", "", errors.New("namespace claim is missing") - } - secretName := private.SecretName - if len(secretName) == 0 { - return "", "", "", errors.New("secretName claim is missing") - } - serviceAccountName := private.ServiceAccountName - if len(serviceAccountName) == 0 { - return "", "", "", errors.New("serviceAccountName claim is missing") - } - serviceAccountUID := private.ServiceAccountUID - if len(serviceAccountUID) == 0 { - return "", "", "", errors.New("serviceAccountUID claim is missing") - } - - subjectNamespace, subjectName, err := apiserverserviceaccount.SplitUsername(public.Subject) - if err != nil || subjectNamespace != namespace || subjectName != serviceAccountName { - return "", "", "", errors.New("sub claim is invalid") - } - - if v.lookup { - // Make sure token hasn't been invalidated by deletion of the secret - secret, err := v.getter.GetSecret(namespace, secretName) - if err != nil { - glog.V(4).Infof("Could not retrieve token %s/%s for service account %s/%s: %v", namespace, secretName, namespace, serviceAccountName, err) - return "", "", "", errors.New("Token has been invalidated") - } - if secret.DeletionTimestamp != nil { - glog.V(4).Infof("Token is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, secretName, namespace, serviceAccountName) - return "", "", "", errors.New("Token has been invalidated") - } - if bytes.Compare(secret.Data[v1.ServiceAccountTokenKey], []byte(tokenData)) != 0 { - glog.V(4).Infof("Token contents no longer matches %s/%s for service account %s/%s", namespace, secretName, namespace, serviceAccountName) - return "", "", "", errors.New("Token does not match server's copy") - } - - // Make sure service account still exists (name and UID) - serviceAccount, err := v.getter.GetServiceAccount(namespace, serviceAccountName) - if err != nil { - glog.V(4).Infof("Could not retrieve service account %s/%s: %v", namespace, serviceAccountName, err) - return "", "", "", err - } - if serviceAccount.DeletionTimestamp != nil { - glog.V(4).Infof("Service account has been deleted %s/%s", namespace, serviceAccountName) - return "", "", "", fmt.Errorf("ServiceAccount %s/%s has been deleted", namespace, serviceAccountName) - } - if string(serviceAccount.UID) != serviceAccountUID { - glog.V(4).Infof("Service account UID no longer matches %s/%s: %q != %q", namespace, serviceAccountName, string(serviceAccount.UID), serviceAccountUID) - return "", "", "", fmt.Errorf("ServiceAccount UID (%s) does not match claim (%s)", serviceAccount.UID, serviceAccountUID) - } - } - - return private.Namespace, private.ServiceAccountName, private.ServiceAccountUID, nil -} - -func (v *legacyValidator) NewPrivateClaims() interface{} { - return &legacyPrivateClaims{} -} diff --git a/vendor/k8s.io/kubernetes/pkg/serviceaccount/util.go b/vendor/k8s.io/kubernetes/pkg/serviceaccount/util.go deleted file mode 100644 index 0503c1513..000000000 --- a/vendor/k8s.io/kubernetes/pkg/serviceaccount/util.go +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package serviceaccount - -import ( - "k8s.io/api/core/v1" - apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount" - "k8s.io/apiserver/pkg/authentication/user" - api "k8s.io/kubernetes/pkg/apis/core" -) - -// UserInfo returns a user.Info interface for the given namespace, service account name and UID -func UserInfo(namespace, name, uid string) user.Info { - return &user.DefaultInfo{ - Name: apiserverserviceaccount.MakeUsername(namespace, name), - UID: uid, - Groups: apiserverserviceaccount.MakeGroupNames(namespace), - } -} - -// IsServiceAccountToken returns true if the secret is a valid api token for the service account -func IsServiceAccountToken(secret *v1.Secret, sa *v1.ServiceAccount) bool { - if secret.Type != v1.SecretTypeServiceAccountToken { - return false - } - - name := secret.Annotations[v1.ServiceAccountNameKey] - uid := secret.Annotations[v1.ServiceAccountUIDKey] - if name != sa.Name { - // Name must match - return false - } - if len(uid) > 0 && uid != string(sa.UID) { - // If UID is specified, it must match - return false - } - - return true -} - -// TODO: remove the duplicate code -// InternalIsServiceAccountToken returns true if the secret is a valid api token for the service account -func InternalIsServiceAccountToken(secret *api.Secret, sa *api.ServiceAccount) bool { - if secret.Type != api.SecretTypeServiceAccountToken { - return false - } - - name := secret.Annotations[api.ServiceAccountNameKey] - uid := secret.Annotations[api.ServiceAccountUIDKey] - if name != sa.Name { - // Name must match - return false - } - if len(uid) > 0 && uid != string(sa.UID) { - // If UID is specified, it must match - return false - } - - return true -} |