Bumping k8s dependencies to 1.13

This commit is contained in:
Cheng Xing
2018-11-16 14:08:25 -08:00
parent 305407125c
commit b4c0b68ec7
8002 changed files with 884099 additions and 276228 deletions

View File

@@ -17,28 +17,14 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/serviceaccount",
deps = [
"//pkg/apis/core:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/gopkg.in/square/go-jose.v2:go_default_library",
"//vendor/gopkg.in/square/go-jose.v2/jwt:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
],
)
go_test(
name = "go_default_xtest",
srcs = ["jwt_test.go"],
deps = [
":go_default_library",
"//pkg/controller/serviceaccount:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/util/cert:go_default_library",
],
)
@@ -59,13 +45,18 @@ go_test(
name = "go_default_test",
srcs = [
"claims_test.go",
"jwt_test.go",
"util_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/controller/serviceaccount:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
"//vendor/gopkg.in/square/go-jose.v2/jwt:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)

View File

@@ -94,11 +94,11 @@ type validator struct {
var _ = Validator(&validator{})
func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{}) (string, string, string, error) {
func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{}) (*ServiceAccountInfo, 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.")
return nil, errors.New("Token could not be validated.")
}
err := public.Validate(jwt.Expected{
Time: now(),
@@ -106,10 +106,10 @@ func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{
switch {
case err == nil:
case err == jwt.ErrExpired:
return "", "", "", errors.New("Token has expired.")
return nil, errors.New("Token has expired.")
default:
glog.Errorf("unexpected validation error: %T", err)
return "", "", "", errors.New("Token could not be validated.")
return nil, errors.New("Token could not be validated.")
}
var audValid bool
@@ -122,7 +122,7 @@ func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{
}
if !audValid {
return "", "", "", errors.New("Token is invalid for this audience.")
return nil, errors.New("Token is invalid for this audience.")
}
namespace := private.Kubernetes.Namespace
@@ -133,15 +133,15 @@ func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{
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
return nil, 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)
return nil, 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)
return nil, fmt.Errorf("ServiceAccount UID (%s) does not match claim (%s)", serviceAccount.UID, saref.UID)
}
if secref != nil {
@@ -149,36 +149,45 @@ func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{
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")
return nil, 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")
return nil, errors.New("Token has been invalidated")
}
if secref.UID != string(secret.UID) {
glog.V(4).Infof("Secret UID no longer matches %s/%s: %q != %q", namespace, secref.Name, string(secret.UID), secref.UID)
return "", "", "", fmt.Errorf("Secret UID (%s) does not match claim (%s)", 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 {
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")
glog.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 {
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")
return nil, errors.New("Token has been invalidated")
}
if podref.UID != string(pod.UID) {
glog.V(4).Infof("Pod UID no longer matches %s/%s: %q != %q", namespace, podref.Name, string(pod.UID), podref.UID)
return "", "", "", fmt.Errorf("Pod UID (%s) does not match claim (%s)", 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 private.Kubernetes.Namespace, private.Kubernetes.Svcacct.Name, private.Kubernetes.Svcacct.UID, nil
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{} {

View File

@@ -54,25 +54,13 @@ type TokenGenerator interface {
// 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) {
func JWTTokenGenerator(iss string, privateKey interface{}) (TokenGenerator, error) {
var alg jose.SignatureAlgorithm
switch privateKey := j.privateKey.(type) {
switch pk := privateKey.(type) {
case *rsa.PrivateKey:
alg = jose.RS256
case *ecdsa.PrivateKey:
switch privateKey.Curve {
switch pk.Curve {
case elliptic.P256():
alg = jose.ES256
case elliptic.P384():
@@ -80,25 +68,38 @@ func (j *jwtTokenGenerator) GenerateToken(claims *jwt.Claims, privateClaims inte
case elliptic.P521():
alg = jose.ES512
default:
return "", fmt.Errorf("unknown private key curve, must be 256, 384, or 521")
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 "", fmt.Errorf("unknown private key type %T, must be *rsa.PrivateKey or *ecdsa.PrivateKey", j.privateKey)
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: j.privateKey,
Key: privateKey,
},
nil,
)
if err != nil {
return "", err
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(signer).
return jwt.Signed(j.signer).
Claims(privateClaims).
Claims(claims).
Claims(&jwt.Claims{
@@ -130,7 +131,7 @@ 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)
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()
@@ -171,12 +172,12 @@ func (j *jwtTokenAuthenticator) AuthenticateToken(tokenData string) (user.Info,
// 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)
sa, err := j.validator.Validate(tokenData, public, private)
if err != nil {
return nil, false, err
}
return UserInfo(ns, name, uid), true, nil
return sa.UserInfo(), true, nil
}
// hasCorrectIssuer returns true if tokenData is a valid JWT in compact

View File

@@ -127,7 +127,10 @@ func TestTokenGenerateAndValidate(t *testing.T) {
}
// Generate the RSA token
rsaGenerator := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(rsaPrivateKey))
rsaGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(rsaPrivateKey))
if err != nil {
t.Fatalf("error making generator: %v", err)
}
rsaToken, err := rsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret))
if err != nil {
t.Fatalf("error generating token: %v", err)
@@ -140,7 +143,10 @@ func TestTokenGenerateAndValidate(t *testing.T) {
}
// Generate the ECDSA token
ecdsaGenerator := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(ecdsaPrivateKey))
ecdsaGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(ecdsaPrivateKey))
if err != nil {
t.Fatalf("error making generator: %v", err)
}
ecdsaToken, err := ecdsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *ecdsaSecret))
if err != nil {
t.Fatalf("error generating token: %v", err)
@@ -153,7 +159,10 @@ func TestTokenGenerateAndValidate(t *testing.T) {
}
// Generate signer with same keys as RSA signer but different issuer
badIssuerGenerator := serviceaccount.JWTTokenGenerator("foo", getPrivateKey(rsaPrivateKey))
badIssuerGenerator, err := serviceaccount.JWTTokenGenerator("foo", getPrivateKey(rsaPrivateKey))
if err != nil {
t.Fatalf("error making generator: %v", err)
}
badIssuerToken, err := badIssuerGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret))
if err != nil {
t.Fatalf("error generating token: %v", err)

View File

@@ -62,37 +62,37 @@ type legacyValidator struct {
var _ = Validator(&legacyValidator{})
func (v *legacyValidator) Validate(tokenData string, public *jwt.Claims, privateObj interface{}) (string, string, string, error) {
func (v *legacyValidator) Validate(tokenData string, public *jwt.Claims, privateObj interface{}) (*ServiceAccountInfo, 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.")
return nil, 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")
return nil, errors.New("sub claim is missing")
}
namespace := private.Namespace
if len(namespace) == 0 {
return "", "", "", errors.New("namespace claim is missing")
return nil, errors.New("namespace claim is missing")
}
secretName := private.SecretName
if len(secretName) == 0 {
return "", "", "", errors.New("secretName claim is missing")
return nil, errors.New("secretName claim is missing")
}
serviceAccountName := private.ServiceAccountName
if len(serviceAccountName) == 0 {
return "", "", "", errors.New("serviceAccountName claim is missing")
return nil, errors.New("serviceAccountName claim is missing")
}
serviceAccountUID := private.ServiceAccountUID
if len(serviceAccountUID) == 0 {
return "", "", "", errors.New("serviceAccountUID claim is missing")
return nil, 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")
return nil, errors.New("sub claim is invalid")
}
if v.lookup {
@@ -100,34 +100,38 @@ func (v *legacyValidator) Validate(tokenData string, public *jwt.Claims, private
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")
return nil, 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")
return nil, 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")
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 {
glog.V(4).Infof("Could not retrieve service account %s/%s: %v", namespace, serviceAccountName, err)
return "", "", "", err
return nil, 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)
return nil, 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 nil, fmt.Errorf("ServiceAccount UID (%s) does not match claim (%s)", serviceAccount.UID, serviceAccountUID)
}
}
return private.Namespace, private.ServiceAccountName, private.ServiceAccountUID, nil
return &ServiceAccountInfo{
Namespace: private.Namespace,
Name: private.ServiceAccountName,
UID: private.ServiceAccountUID,
}, nil
}
func (v *legacyValidator) NewPrivateClaims() interface{} {

View File

@@ -20,16 +20,44 @@ 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"
)
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 &user.DefaultInfo{
Name: apiserverserviceaccount.MakeUsername(namespace, name),
UID: uid,
Groups: apiserverserviceaccount.MakeGroupNames(namespace),
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
@@ -51,24 +79,3 @@ func IsServiceAccountToken(secret *v1.Secret, sa *v1.ServiceAccount) bool {
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
}