add controllers
change kiali mux to go-restful add knative
This commit is contained in:
180
vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go
generated
vendored
Normal file
180
vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
"k8s.io/klog"
|
||||
|
||||
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
// 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(getter ServiceAccountTokenGetter) Validator {
|
||||
return &validator{
|
||||
getter: getter,
|
||||
}
|
||||
}
|
||||
|
||||
type validator struct {
|
||||
getter ServiceAccountTokenGetter
|
||||
}
|
||||
|
||||
var _ = Validator(&validator{})
|
||||
|
||||
func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{}) (*ServiceAccountInfo, error) {
|
||||
private, ok := privateObj.(*privateClaims)
|
||||
if !ok {
|
||||
klog.Errorf("jwt validator expected private claim of type *privateClaims but got: %T", privateObj)
|
||||
return nil, errors.New("Token could not be validated.")
|
||||
}
|
||||
err := public.Validate(jwt.Expected{
|
||||
Time: now(),
|
||||
})
|
||||
switch {
|
||||
case err == nil:
|
||||
case err == jwt.ErrExpired:
|
||||
return nil, errors.New("Token has expired.")
|
||||
default:
|
||||
klog.Errorf("unexpected validation error: %T", err)
|
||||
return nil, errors.New("Token could not be validated.")
|
||||
}
|
||||
|
||||
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 {
|
||||
klog.V(4).Infof("Could not retrieve service account %s/%s: %v", namespace, saref.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
if serviceAccount.DeletionTimestamp != nil {
|
||||
klog.V(4).Infof("Service account has been deleted %s/%s", namespace, saref.Name)
|
||||
return nil, fmt.Errorf("ServiceAccount %s/%s has been deleted", namespace, saref.Name)
|
||||
}
|
||||
if string(serviceAccount.UID) != saref.UID {
|
||||
klog.V(4).Infof("Service account UID no longer matches %s/%s: %q != %q", namespace, saref.Name, string(serviceAccount.UID), saref.UID)
|
||||
return nil, 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 {
|
||||
klog.V(4).Infof("Could not retrieve bound secret %s/%s for service account %s/%s: %v", namespace, secref.Name, namespace, saref.Name, err)
|
||||
return nil, errors.New("Token has been invalidated")
|
||||
}
|
||||
if secret.DeletionTimestamp != nil {
|
||||
klog.V(4).Infof("Bound secret is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, secref.Name, namespace, saref.Name)
|
||||
return nil, errors.New("Token has been invalidated")
|
||||
}
|
||||
if secref.UID != string(secret.UID) {
|
||||
klog.V(4).Infof("Secret UID no longer matches %s/%s: %q != %q", namespace, secref.Name, string(secret.UID), secref.UID)
|
||||
return nil, fmt.Errorf("Secret UID (%s) does not match claim (%s)", secret.UID, secref.UID)
|
||||
}
|
||||
}
|
||||
|
||||
var podName, podUID string
|
||||
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 {
|
||||
klog.V(4).Infof("Could not retrieve bound pod %s/%s for service account %s/%s: %v", namespace, podref.Name, namespace, saref.Name, err)
|
||||
return nil, errors.New("Token has been invalidated")
|
||||
}
|
||||
if pod.DeletionTimestamp != nil {
|
||||
klog.V(4).Infof("Bound pod is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, podref.Name, namespace, saref.Name)
|
||||
return nil, errors.New("Token has been invalidated")
|
||||
}
|
||||
if podref.UID != string(pod.UID) {
|
||||
klog.V(4).Infof("Pod UID no longer matches %s/%s: %q != %q", namespace, podref.Name, string(pod.UID), podref.UID)
|
||||
return nil, fmt.Errorf("Pod UID (%s) does not match claim (%s)", pod.UID, podref.UID)
|
||||
}
|
||||
podName = podref.Name
|
||||
podUID = podref.UID
|
||||
}
|
||||
|
||||
return &ServiceAccountInfo{
|
||||
Namespace: private.Kubernetes.Namespace,
|
||||
Name: private.Kubernetes.Svcacct.Name,
|
||||
UID: private.Kubernetes.Svcacct.UID,
|
||||
PodName: podName,
|
||||
PodUID: podUID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *validator) NewPrivateClaims() interface{} {
|
||||
return &privateClaims{}
|
||||
}
|
||||
232
vendor/k8s.io/kubernetes/pkg/serviceaccount/jwt.go
generated
vendored
Normal file
232
vendor/k8s.io/kubernetes/pkg/serviceaccount/jwt.go
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
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 (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
jose "gopkg.in/square/go-jose.v2"
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
)
|
||||
|
||||
// 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, error) {
|
||||
var alg jose.SignatureAlgorithm
|
||||
switch pk := privateKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
alg = jose.RS256
|
||||
case *ecdsa.PrivateKey:
|
||||
switch pk.Curve {
|
||||
case elliptic.P256():
|
||||
alg = jose.ES256
|
||||
case elliptic.P384():
|
||||
alg = jose.ES384
|
||||
case elliptic.P521():
|
||||
alg = jose.ES512
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown private key curve, must be 256, 384, or 521")
|
||||
}
|
||||
case jose.OpaqueSigner:
|
||||
alg = jose.SignatureAlgorithm(pk.Public().Algorithm)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown private key type %T, must be *rsa.PrivateKey, *ecdsa.PrivateKey, or jose.OpaqueSigner", privateKey)
|
||||
}
|
||||
|
||||
signer, err := jose.NewSigner(
|
||||
jose.SigningKey{
|
||||
Algorithm: alg,
|
||||
Key: privateKey,
|
||||
},
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &jwtTokenGenerator{
|
||||
iss: iss,
|
||||
signer: signer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type jwtTokenGenerator struct {
|
||||
iss string
|
||||
signer jose.Signer
|
||||
}
|
||||
|
||||
func (j *jwtTokenGenerator) GenerateToken(claims *jwt.Claims, privateClaims interface{}) (string, error) {
|
||||
// claims are applied in reverse precedence
|
||||
return jwt.Signed(j.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{}, implicitAuds authenticator.Audiences, validator Validator) authenticator.Token {
|
||||
return &jwtTokenAuthenticator{
|
||||
iss: iss,
|
||||
keys: keys,
|
||||
implicitAuds: implicitAuds,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
type jwtTokenAuthenticator struct {
|
||||
iss string
|
||||
keys []interface{}
|
||||
validator Validator
|
||||
implicitAuds authenticator.Audiences
|
||||
}
|
||||
|
||||
// Validator is called by the JWT token authenticator 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{}) (*ServiceAccountInfo, 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{}
|
||||
}
|
||||
|
||||
func (j *jwtTokenAuthenticator) AuthenticateToken(ctx context.Context, tokenData string) (*authenticator.Response, 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)
|
||||
}
|
||||
|
||||
tokenAudiences := authenticator.Audiences(public.Audience)
|
||||
if len(tokenAudiences) == 0 {
|
||||
// only apiserver audiences are allowed for legacy tokens
|
||||
tokenAudiences = j.implicitAuds
|
||||
}
|
||||
|
||||
requestedAudiences, ok := authenticator.AudiencesFrom(ctx)
|
||||
if !ok {
|
||||
// default to apiserver audiences
|
||||
requestedAudiences = j.implicitAuds
|
||||
}
|
||||
|
||||
auds := authenticator.Audiences(tokenAudiences).Intersect(requestedAudiences)
|
||||
if len(auds) == 0 && len(j.implicitAuds) != 0 {
|
||||
return nil, false, fmt.Errorf("token audiences %q is invalid for the target audiences %q", tokenAudiences, requestedAudiences)
|
||||
}
|
||||
|
||||
// If we get here, we have a token with a recognized signature and
|
||||
// issuer string.
|
||||
sa, err := j.validator.Validate(tokenData, public, private)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return &authenticator.Response{
|
||||
User: sa.UserInfo(),
|
||||
Audiences: auds,
|
||||
}, 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
|
||||
|
||||
}
|
||||
139
vendor/k8s.io/kubernetes/pkg/serviceaccount/legacy.go
generated
vendored
Normal file
139
vendor/k8s.io/kubernetes/pkg/serviceaccount/legacy.go
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||
)
|
||||
|
||||
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{}) (*ServiceAccountInfo, error) {
|
||||
private, ok := privateObj.(*legacyPrivateClaims)
|
||||
if !ok {
|
||||
klog.Errorf("jwt validator expected private claim of type *legacyPrivateClaims but got: %T", privateObj)
|
||||
return nil, errors.New("Token could not be validated.")
|
||||
}
|
||||
|
||||
// Make sure the claims we need exist
|
||||
if len(public.Subject) == 0 {
|
||||
return nil, errors.New("sub claim is missing")
|
||||
}
|
||||
namespace := private.Namespace
|
||||
if len(namespace) == 0 {
|
||||
return nil, errors.New("namespace claim is missing")
|
||||
}
|
||||
secretName := private.SecretName
|
||||
if len(secretName) == 0 {
|
||||
return nil, errors.New("secretName claim is missing")
|
||||
}
|
||||
serviceAccountName := private.ServiceAccountName
|
||||
if len(serviceAccountName) == 0 {
|
||||
return nil, errors.New("serviceAccountName claim is missing")
|
||||
}
|
||||
serviceAccountUID := private.ServiceAccountUID
|
||||
if len(serviceAccountUID) == 0 {
|
||||
return nil, errors.New("serviceAccountUID claim is missing")
|
||||
}
|
||||
|
||||
subjectNamespace, subjectName, err := apiserverserviceaccount.SplitUsername(public.Subject)
|
||||
if err != nil || subjectNamespace != namespace || subjectName != serviceAccountName {
|
||||
return nil, 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 {
|
||||
klog.V(4).Infof("Could not retrieve token %s/%s for service account %s/%s: %v", namespace, secretName, namespace, serviceAccountName, err)
|
||||
return nil, errors.New("Token has been invalidated")
|
||||
}
|
||||
if secret.DeletionTimestamp != nil {
|
||||
klog.V(4).Infof("Token is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, secretName, namespace, serviceAccountName)
|
||||
return nil, errors.New("Token has been invalidated")
|
||||
}
|
||||
if bytes.Compare(secret.Data[v1.ServiceAccountTokenKey], []byte(tokenData)) != 0 {
|
||||
klog.V(4).Infof("Token contents no longer matches %s/%s for service account %s/%s", namespace, secretName, namespace, serviceAccountName)
|
||||
return nil, 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 {
|
||||
klog.V(4).Infof("Could not retrieve service account %s/%s: %v", namespace, serviceAccountName, err)
|
||||
return nil, err
|
||||
}
|
||||
if serviceAccount.DeletionTimestamp != nil {
|
||||
klog.V(4).Infof("Service account has been deleted %s/%s", namespace, serviceAccountName)
|
||||
return nil, fmt.Errorf("ServiceAccount %s/%s has been deleted", namespace, serviceAccountName)
|
||||
}
|
||||
if string(serviceAccount.UID) != serviceAccountUID {
|
||||
klog.V(4).Infof("Service account UID no longer matches %s/%s: %q != %q", namespace, serviceAccountName, string(serviceAccount.UID), serviceAccountUID)
|
||||
return nil, fmt.Errorf("ServiceAccount UID (%s) does not match claim (%s)", serviceAccount.UID, serviceAccountUID)
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceAccountInfo{
|
||||
Namespace: private.Namespace,
|
||||
Name: private.ServiceAccountName,
|
||||
UID: private.ServiceAccountUID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *legacyValidator) NewPrivateClaims() interface{} {
|
||||
return &legacyPrivateClaims{}
|
||||
}
|
||||
81
vendor/k8s.io/kubernetes/pkg/serviceaccount/util.go
generated
vendored
Normal file
81
vendor/k8s.io/kubernetes/pkg/serviceaccount/util.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
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"
|
||||
)
|
||||
|
||||
const (
|
||||
// PodNameKey is the key used in a user's "extra" to specify the pod name of
|
||||
// the authenticating request.
|
||||
PodNameKey = "authentication.kubernetes.io/pod-name"
|
||||
// PodUIDKey is the key used in a user's "extra" to specify the pod UID of
|
||||
// the authenticating request.
|
||||
PodUIDKey = "authentication.kubernetes.io/pod-uid"
|
||||
)
|
||||
|
||||
// UserInfo returns a user.Info interface for the given namespace, service account name and UID
|
||||
func UserInfo(namespace, name, uid string) user.Info {
|
||||
return (&ServiceAccountInfo{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
UID: uid,
|
||||
}).UserInfo()
|
||||
}
|
||||
|
||||
type ServiceAccountInfo struct {
|
||||
Name, Namespace, UID string
|
||||
PodName, PodUID string
|
||||
}
|
||||
|
||||
func (sa *ServiceAccountInfo) UserInfo() user.Info {
|
||||
info := &user.DefaultInfo{
|
||||
Name: apiserverserviceaccount.MakeUsername(sa.Namespace, sa.Name),
|
||||
UID: sa.UID,
|
||||
Groups: apiserverserviceaccount.MakeGroupNames(sa.Namespace),
|
||||
}
|
||||
if sa.PodName != "" && sa.PodUID != "" {
|
||||
info.Extra = map[string][]string{
|
||||
PodNameKey: {sa.PodName},
|
||||
PodUIDKey: {sa.PodUID},
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
Reference in New Issue
Block a user