mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	kube-apiserver: add a bootstrap token authenticator for TLS bootstrapping
This commit is contained in:
		@@ -20,6 +20,7 @@ go_library(
 | 
				
			|||||||
        "//pkg/apis/batch:go_default_library",
 | 
					        "//pkg/apis/batch:go_default_library",
 | 
				
			||||||
        "//pkg/capabilities:go_default_library",
 | 
					        "//pkg/capabilities:go_default_library",
 | 
				
			||||||
        "//pkg/client/clientset_generated/internalclientset:go_default_library",
 | 
					        "//pkg/client/clientset_generated/internalclientset:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/client/informers/informers_generated/internalversion:go_default_library",
 | 
				
			||||||
        "//pkg/cloudprovider:go_default_library",
 | 
					        "//pkg/cloudprovider:go_default_library",
 | 
				
			||||||
        "//pkg/cloudprovider/providers:go_default_library",
 | 
					        "//pkg/cloudprovider/providers:go_default_library",
 | 
				
			||||||
        "//pkg/controller/informers:go_default_library",
 | 
					        "//pkg/controller/informers:go_default_library",
 | 
				
			||||||
@@ -51,10 +52,12 @@ go_library(
 | 
				
			|||||||
        "//plugin/pkg/admission/securitycontext/scdeny:go_default_library",
 | 
					        "//plugin/pkg/admission/securitycontext/scdeny:go_default_library",
 | 
				
			||||||
        "//plugin/pkg/admission/serviceaccount:go_default_library",
 | 
					        "//plugin/pkg/admission/serviceaccount:go_default_library",
 | 
				
			||||||
        "//plugin/pkg/admission/storageclass/default:go_default_library",
 | 
					        "//plugin/pkg/admission/storageclass/default:go_default_library",
 | 
				
			||||||
 | 
					        "//plugin/pkg/auth/authenticator/token/bootstrap:go_default_library",
 | 
				
			||||||
        "//vendor:github.com/go-openapi/spec",
 | 
					        "//vendor:github.com/go-openapi/spec",
 | 
				
			||||||
        "//vendor:github.com/golang/glog",
 | 
					        "//vendor:github.com/golang/glog",
 | 
				
			||||||
        "//vendor:github.com/spf13/cobra",
 | 
					        "//vendor:github.com/spf13/cobra",
 | 
				
			||||||
        "//vendor:github.com/spf13/pflag",
 | 
					        "//vendor:github.com/spf13/pflag",
 | 
				
			||||||
 | 
					        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/openapi",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/openapi",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/util/errors",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/util/errors",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,7 @@ import (
 | 
				
			|||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
	"github.com/spf13/pflag"
 | 
						"github.com/spf13/pflag"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/openapi"
 | 
						"k8s.io/apimachinery/pkg/openapi"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
						utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
				
			||||||
@@ -50,6 +51,7 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/apis/batch"
 | 
						"k8s.io/kubernetes/pkg/apis/batch"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/capabilities"
 | 
						"k8s.io/kubernetes/pkg/capabilities"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
 | 
						"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/cloudprovider"
 | 
						"k8s.io/kubernetes/pkg/cloudprovider"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/controller/informers"
 | 
						"k8s.io/kubernetes/pkg/controller/informers"
 | 
				
			||||||
	serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
 | 
						serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
 | 
				
			||||||
@@ -61,6 +63,7 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/master/tunneler"
 | 
						"k8s.io/kubernetes/pkg/master/tunneler"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/registry/cachesize"
 | 
						"k8s.io/kubernetes/pkg/registry/cachesize"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/version"
 | 
						"k8s.io/kubernetes/pkg/version"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewAPIServerCommand creates a *cobra.Command object with default parameters
 | 
					// NewAPIServerCommand creates a *cobra.Command object with default parameters
 | 
				
			||||||
@@ -253,11 +256,6 @@ func Run(s *options.ServerRunOptions) error {
 | 
				
			|||||||
		authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets")))
 | 
							authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets")))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apiAuthenticator, securityDefinitions, err := authenticatorConfig.New()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("invalid Authentication Config: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	client, err := internalclientset.NewForConfig(genericConfig.LoopbackClientConfig)
 | 
						client, err := internalclientset.NewForConfig(genericConfig.LoopbackClientConfig)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		kubeAPIVersions := os.Getenv("KUBE_API_VERSIONS")
 | 
							kubeAPIVersions := os.Getenv("KUBE_API_VERSIONS")
 | 
				
			||||||
@@ -267,10 +265,29 @@ func Run(s *options.ServerRunOptions) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API
 | 
							// KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API
 | 
				
			||||||
		// groups. This leads to a nil client above and undefined behaviour further down.
 | 
							// groups. This leads to a nil client above and undefined behaviour further down.
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
		// TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set
 | 
							// TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set
 | 
				
			||||||
		glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions)
 | 
							glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: Internal informers should switch to using 'pkg/client/informers/informers_generated',
 | 
				
			||||||
 | 
						// the second informer created here. Refactor clients which take the former to accept the latter.
 | 
				
			||||||
	sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
 | 
						sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
 | 
				
			||||||
 | 
						internalSharedInformers := internalversion.NewSharedInformerFactory(client, 10*time.Minute)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if client == nil {
 | 
				
			||||||
 | 
							// TODO: Remove check once client can never be nil.
 | 
				
			||||||
 | 
							glog.Errorf("Failed to setup bootstrap token authenticator because the loopback clientset was not setup properly.")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							authenticatorConfig.BootstrapTokenAuthenticator = bootstrap.NewTokenAuthenticator(
 | 
				
			||||||
 | 
								internalSharedInformers.Core().InternalVersion().Secrets().Lister().Secrets(v1.NamespaceSystem),
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apiAuthenticator, securityDefinitions, err := authenticatorConfig.New()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("invalid authentication config: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
 | 
						authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
 | 
				
			||||||
	apiAuthorizer, err := authorizationConfig.New()
 | 
						apiAuthorizer, err := authorizationConfig.New()
 | 
				
			||||||
@@ -350,6 +367,7 @@ func Run(s *options.ServerRunOptions) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sharedInformers.Start(wait.NeverStop)
 | 
						sharedInformers.Start(wait.NeverStop)
 | 
				
			||||||
 | 
						internalSharedInformers.Start(wait.NeverStop)
 | 
				
			||||||
	m.GenericAPIServer.PrepareRun().Run(wait.NeverStop)
 | 
						m.GenericAPIServer.PrepareRun().Run(wait.NeverStop)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -267,6 +267,7 @@ plugin/pkg/admission/resourcequota/apis/resourcequota/install
 | 
				
			|||||||
plugin/pkg/admission/resourcequota/apis/resourcequota/validation
 | 
					plugin/pkg/admission/resourcequota/apis/resourcequota/validation
 | 
				
			||||||
plugin/pkg/admission/securitycontext/scdeny
 | 
					plugin/pkg/admission/securitycontext/scdeny
 | 
				
			||||||
plugin/pkg/auth
 | 
					plugin/pkg/auth
 | 
				
			||||||
 | 
					plugin/pkg/auth/authenticator/token/bootstrap
 | 
				
			||||||
plugin/pkg/auth/authorizer
 | 
					plugin/pkg/auth/authorizer
 | 
				
			||||||
plugin/pkg/auth/authorizer/rbac/bootstrappolicy
 | 
					plugin/pkg/auth/authorizer/rbac/bootstrappolicy
 | 
				
			||||||
staging/src/k8s.io/apimachinery/pkg/api/equality
 | 
					staging/src/k8s.io/apimachinery/pkg/api/equality
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -204,6 +204,7 @@ executor-suicide-timeout
 | 
				
			|||||||
exit-on-lock-contention
 | 
					exit-on-lock-contention
 | 
				
			||||||
experimental-allowed-unsafe-sysctls
 | 
					experimental-allowed-unsafe-sysctls
 | 
				
			||||||
experimental-bootstrap-kubeconfig
 | 
					experimental-bootstrap-kubeconfig
 | 
				
			||||||
 | 
					experimental-bootstrap-token-auth
 | 
				
			||||||
experimental-keystone-url
 | 
					experimental-keystone-url
 | 
				
			||||||
experimental-keystone-ca-file
 | 
					experimental-keystone-ca-file
 | 
				
			||||||
experimental-mounter-path
 | 
					experimental-mounter-path
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,12 +33,12 @@ const (
 | 
				
			|||||||
	SecretTypeBootstrapToken v1.SecretType = "bootstrap.kubernetes.io/token"
 | 
						SecretTypeBootstrapToken v1.SecretType = "bootstrap.kubernetes.io/token"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// BootstrapTokenIDKey is the id of this token. This can be transmitted in the
 | 
						// BootstrapTokenIDKey is the id of this token. This can be transmitted in the
 | 
				
			||||||
	// clear and encoded in the name of the secret. It should be a random 6
 | 
						// clear and encoded in the name of the secret. It must be a random 6 character
 | 
				
			||||||
	// character string. Required
 | 
						// string that matches the regexp `^([a-z0-9]{6})$`. Required.
 | 
				
			||||||
	BootstrapTokenIDKey = "token-id"
 | 
						BootstrapTokenIDKey = "token-id"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// BootstrapTokenSecretKey is the actual secret. Typically this is a random 16
 | 
						// BootstrapTokenSecretKey is the actual secret. It must be a random 16 character
 | 
				
			||||||
	// character string. Required.
 | 
						// string that matches the regexp `^([a-z0-9]{16})$`. Required.
 | 
				
			||||||
	BootstrapTokenSecretKey = "token-secret"
 | 
						BootstrapTokenSecretKey = "token-secret"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// BootstrapTokenExpirationKey is when this token should be expired and no
 | 
						// BootstrapTokenExpirationKey is when this token should be expired and no
 | 
				
			||||||
@@ -52,6 +52,13 @@ const (
 | 
				
			|||||||
	// other value is assumed to be false. Optional.
 | 
						// other value is assumed to be false. Optional.
 | 
				
			||||||
	BootstrapTokenUsageSigningKey = "usage-bootstrap-signing"
 | 
						BootstrapTokenUsageSigningKey = "usage-bootstrap-signing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// BootstrapTokenUsageAuthentication signals that this token should be used
 | 
				
			||||||
 | 
						// as a bearer token to authenticate against the Kubernetes API. The bearer
 | 
				
			||||||
 | 
						// token takes the form "<token-id>.<token-secret>" and authenticates as the
 | 
				
			||||||
 | 
						// user "system:bootstrap:<token-id>" in the group "system:bootstrappers".
 | 
				
			||||||
 | 
						// Value must be "true". Any other value is assumed to be false. Optional.
 | 
				
			||||||
 | 
						BootstrapTokenUsageAuthentication = "usage-bootstrap-authentication"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ConfigMapClusterInfo defines the name for the ConfigMap where the information how to connect and trust the cluster exist
 | 
						// ConfigMapClusterInfo defines the name for the ConfigMap where the information how to connect and trust the cluster exist
 | 
				
			||||||
	ConfigMapClusterInfo = "cluster-info"
 | 
						ConfigMapClusterInfo = "cluster-info"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,4 +67,11 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// JWSSignatureKeyPrefix defines what key prefix the JWS-signed tokens have
 | 
						// JWSSignatureKeyPrefix defines what key prefix the JWS-signed tokens have
 | 
				
			||||||
	JWSSignatureKeyPrefix = "jws-kubeconfig-"
 | 
						JWSSignatureKeyPrefix = "jws-kubeconfig-"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// BootstrapUserPrefix is the username prefix bootstrapping bearer tokens
 | 
				
			||||||
 | 
						// authenticate as. The full username given is "system:bootstrap:<token-id>".
 | 
				
			||||||
 | 
						BootstrapUserPrefix = "system:bootstrap:"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// BootstrapGroup is the group bootstrapping bearer tokens authenticate in.
 | 
				
			||||||
 | 
						BootstrapGroup = "system:bootstrappers"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,6 +49,7 @@ type AuthenticatorConfig struct {
 | 
				
			|||||||
	Anonymous                   bool
 | 
						Anonymous                   bool
 | 
				
			||||||
	AnyToken                    bool
 | 
						AnyToken                    bool
 | 
				
			||||||
	BasicAuthFile               string
 | 
						BasicAuthFile               string
 | 
				
			||||||
 | 
						BootstrapToken              bool
 | 
				
			||||||
	ClientCAFile                string
 | 
						ClientCAFile                string
 | 
				
			||||||
	TokenAuthFile               string
 | 
						TokenAuthFile               string
 | 
				
			||||||
	OIDCIssuerURL               string
 | 
						OIDCIssuerURL               string
 | 
				
			||||||
@@ -67,6 +68,7 @@ type AuthenticatorConfig struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// TODO, this is the only non-serializable part of the entire config.  Factor it out into a clientconfig
 | 
						// TODO, this is the only non-serializable part of the entire config.  Factor it out into a clientconfig
 | 
				
			||||||
	ServiceAccountTokenGetter   serviceaccount.ServiceAccountTokenGetter
 | 
						ServiceAccountTokenGetter   serviceaccount.ServiceAccountTokenGetter
 | 
				
			||||||
 | 
						BootstrapTokenAuthenticator authenticator.Token
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// New returns an authenticator.Request or an error that supports the standard
 | 
					// New returns an authenticator.Request or an error that supports the standard
 | 
				
			||||||
@@ -136,6 +138,13 @@ func (config AuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDe
 | 
				
			|||||||
		authenticators = append(authenticators, serviceAccountAuth)
 | 
							authenticators = append(authenticators, serviceAccountAuth)
 | 
				
			||||||
		hasTokenAuth = true
 | 
							hasTokenAuth = true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if config.BootstrapToken {
 | 
				
			||||||
 | 
							if config.BootstrapTokenAuthenticator != nil {
 | 
				
			||||||
 | 
								// TODO: This can sometimes be nil because of
 | 
				
			||||||
 | 
								authenticators = append(authenticators, bearertoken.New(config.BootstrapTokenAuthenticator))
 | 
				
			||||||
 | 
								hasTokenAuth = true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	// NOTE(ericchiang): Keep the OpenID Connect after Service Accounts.
 | 
						// NOTE(ericchiang): Keep the OpenID Connect after Service Accounts.
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	// Because both plugins verify JWTs whichever comes first in the union experiences
 | 
						// Because both plugins verify JWTs whichever comes first in the union experiences
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@ import (
 | 
				
			|||||||
type BuiltInAuthenticationOptions struct {
 | 
					type BuiltInAuthenticationOptions struct {
 | 
				
			||||||
	Anonymous       *AnonymousAuthenticationOptions
 | 
						Anonymous       *AnonymousAuthenticationOptions
 | 
				
			||||||
	AnyToken        *AnyTokenAuthenticationOptions
 | 
						AnyToken        *AnyTokenAuthenticationOptions
 | 
				
			||||||
 | 
						BootstrapToken  *BootstrapTokenAuthenticationOptions
 | 
				
			||||||
	ClientCert      *genericoptions.ClientCertAuthenticationOptions
 | 
						ClientCert      *genericoptions.ClientCertAuthenticationOptions
 | 
				
			||||||
	Keystone        *KeystoneAuthenticationOptions
 | 
						Keystone        *KeystoneAuthenticationOptions
 | 
				
			||||||
	OIDC            *OIDCAuthenticationOptions
 | 
						OIDC            *OIDCAuthenticationOptions
 | 
				
			||||||
@@ -51,6 +52,10 @@ type AnonymousAuthenticationOptions struct {
 | 
				
			|||||||
	Allow bool
 | 
						Allow bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type BootstrapTokenAuthenticationOptions struct {
 | 
				
			||||||
 | 
						Allow bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type KeystoneAuthenticationOptions struct {
 | 
					type KeystoneAuthenticationOptions struct {
 | 
				
			||||||
	URL    string
 | 
						URL    string
 | 
				
			||||||
	CAFile string
 | 
						CAFile string
 | 
				
			||||||
@@ -90,6 +95,7 @@ func (s *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions {
 | 
				
			|||||||
	return s.
 | 
						return s.
 | 
				
			||||||
		WithAnyonymous().
 | 
							WithAnyonymous().
 | 
				
			||||||
		WithAnyToken().
 | 
							WithAnyToken().
 | 
				
			||||||
 | 
							WithBootstrapToken().
 | 
				
			||||||
		WithClientCert().
 | 
							WithClientCert().
 | 
				
			||||||
		WithKeystone().
 | 
							WithKeystone().
 | 
				
			||||||
		WithOIDC().
 | 
							WithOIDC().
 | 
				
			||||||
@@ -110,6 +116,11 @@ func (s *BuiltInAuthenticationOptions) WithAnyToken() *BuiltInAuthenticationOpti
 | 
				
			|||||||
	return s
 | 
						return s
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *BuiltInAuthenticationOptions) WithBootstrapToken() *BuiltInAuthenticationOptions {
 | 
				
			||||||
 | 
						s.BootstrapToken = &BootstrapTokenAuthenticationOptions{}
 | 
				
			||||||
 | 
						return s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *BuiltInAuthenticationOptions) WithClientCert() *BuiltInAuthenticationOptions {
 | 
					func (s *BuiltInAuthenticationOptions) WithClientCert() *BuiltInAuthenticationOptions {
 | 
				
			||||||
	s.ClientCert = &genericoptions.ClientCertAuthenticationOptions{}
 | 
						s.ClientCert = &genericoptions.ClientCertAuthenticationOptions{}
 | 
				
			||||||
	return s
 | 
						return s
 | 
				
			||||||
@@ -172,6 +183,12 @@ func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if s.BootstrapToken != nil {
 | 
				
			||||||
 | 
							fs.BoolVar(&s.BootstrapToken.Allow, "experimental-bootstrap-token-auth", s.BootstrapToken.Allow, ""+
 | 
				
			||||||
 | 
								"Enable to allow secrets of type 'bootstrap.kubernetes.io/token' in the 'kube-system' "+
 | 
				
			||||||
 | 
								"namespace to be used for TLS bootstrapping authentication.")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if s.ClientCert != nil {
 | 
						if s.ClientCert != nil {
 | 
				
			||||||
		s.ClientCert.AddFlags(fs)
 | 
							s.ClientCert.AddFlags(fs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -255,6 +272,10 @@ func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() authenticator.Au
 | 
				
			|||||||
		ret.AnyToken = s.AnyToken.Allow
 | 
							ret.AnyToken = s.AnyToken.Allow
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if s.BootstrapToken != nil {
 | 
				
			||||||
 | 
							ret.BootstrapToken = s.BootstrapToken.Allow
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if s.ClientCert != nil {
 | 
						if s.ClientCert != nil {
 | 
				
			||||||
		ret.ClientCAFile = s.ClientCert.ClientCA
 | 
							ret.ClientCAFile = s.ClientCert.ClientCA
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ filegroup(
 | 
				
			|||||||
    name = "all-srcs",
 | 
					    name = "all-srcs",
 | 
				
			||||||
    srcs = [
 | 
					    srcs = [
 | 
				
			||||||
        ":package-srcs",
 | 
					        ":package-srcs",
 | 
				
			||||||
 | 
					        "//plugin/pkg/auth/authenticator/token/bootstrap:all-srcs",
 | 
				
			||||||
        "//plugin/pkg/auth/authorizer:all-srcs",
 | 
					        "//plugin/pkg/auth/authorizer:all-srcs",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    tags = ["automanaged"],
 | 
					    tags = ["automanaged"],
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										52
									
								
								plugin/pkg/auth/authenticator/token/bootstrap/BUILD
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								plugin/pkg/auth/authenticator/token/bootstrap/BUILD
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					package(default_visibility = ["//visibility:public"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					licenses(["notice"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					load(
 | 
				
			||||||
 | 
					    "@io_bazel_rules_go//go:def.bzl",
 | 
				
			||||||
 | 
					    "go_library",
 | 
				
			||||||
 | 
					    "go_test",
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					go_test(
 | 
				
			||||||
 | 
					    name = "go_default_test",
 | 
				
			||||||
 | 
					    srcs = ["bootstrap_test.go"],
 | 
				
			||||||
 | 
					    library = ":go_default_library",
 | 
				
			||||||
 | 
					    tags = ["automanaged"],
 | 
				
			||||||
 | 
					    deps = [
 | 
				
			||||||
 | 
					        "//pkg/api:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/bootstrap/api:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor:k8s.io/apimachinery/pkg/api/errors",
 | 
				
			||||||
 | 
					        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
				
			||||||
 | 
					        "//vendor:k8s.io/apimachinery/pkg/labels",
 | 
				
			||||||
 | 
					        "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
 | 
				
			||||||
 | 
					        "//vendor:k8s.io/apiserver/pkg/authentication/user",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					go_library(
 | 
				
			||||||
 | 
					    name = "go_default_library",
 | 
				
			||||||
 | 
					    srcs = ["bootstrap.go"],
 | 
				
			||||||
 | 
					    tags = ["automanaged"],
 | 
				
			||||||
 | 
					    deps = [
 | 
				
			||||||
 | 
					        "//pkg/api:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/bootstrap/api:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/client/listers/core/internalversion:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor:github.com/golang/glog",
 | 
				
			||||||
 | 
					        "//vendor:k8s.io/apimachinery/pkg/api/errors",
 | 
				
			||||||
 | 
					        "//vendor:k8s.io/apiserver/pkg/authentication/user",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					filegroup(
 | 
				
			||||||
 | 
					    name = "package-srcs",
 | 
				
			||||||
 | 
					    srcs = glob(["**"]),
 | 
				
			||||||
 | 
					    tags = ["automanaged"],
 | 
				
			||||||
 | 
					    visibility = ["//visibility:private"],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					filegroup(
 | 
				
			||||||
 | 
					    name = "all-srcs",
 | 
				
			||||||
 | 
					    srcs = [":package-srcs"],
 | 
				
			||||||
 | 
					    tags = ["automanaged"],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										168
									
								
								plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2017 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 bootstrap provides a token authenticator for TLS bootstrap secrets.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					package bootstrap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/golang/glog"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/authentication/user"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/client/listers/core/internalversion"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: A few methods in this package is copied from other sources. Either
 | 
				
			||||||
 | 
					// because the existing functionality isn't exported or because it is in a
 | 
				
			||||||
 | 
					// package that shouldn't be directly imported by this packages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewTokenAuthenticator initializes a bootstrap token authenticator.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Lister is expected to be for the "kube-system" namespace.
 | 
				
			||||||
 | 
					func NewTokenAuthenticator(lister internalversion.SecretNamespaceLister) *TokenAuthenticator {
 | 
				
			||||||
 | 
						return &TokenAuthenticator{lister}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TokenAuthenticator authenticates bootstrap tokens from secrets in the API server.
 | 
				
			||||||
 | 
					type TokenAuthenticator struct {
 | 
				
			||||||
 | 
						lister internalversion.SecretNamespaceLister
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AuthenticateToken tries to match the provided token to a bootstrap token secret
 | 
				
			||||||
 | 
					// in a given namespace. If found, it authenticates the token in the
 | 
				
			||||||
 | 
					// "system:bootstrappers" group and with the "system:bootstrap:(token-id)" username.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// All secrets must be of type "bootstrap.kubernetes.io/token". An example secret:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     apiVersion: v1
 | 
				
			||||||
 | 
					//     kind: Secret
 | 
				
			||||||
 | 
					//     metadata:
 | 
				
			||||||
 | 
					//       # Name MUST be of form "bootstrap-token-( token id )".
 | 
				
			||||||
 | 
					//       name: bootstrap-token-( token id )
 | 
				
			||||||
 | 
					//       namespace: kube-system
 | 
				
			||||||
 | 
					//     # Only secrets of this type will be evaluated.
 | 
				
			||||||
 | 
					//     type: bootstrap.kubernetes.io/token
 | 
				
			||||||
 | 
					//     data:
 | 
				
			||||||
 | 
					//       token-secret: ( private part of token )
 | 
				
			||||||
 | 
					//       token-id: ( token id )
 | 
				
			||||||
 | 
					//       # Required key usage.
 | 
				
			||||||
 | 
					//       usage-bootstrap-authentication: true
 | 
				
			||||||
 | 
					//       # May also contain an expiry.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Tokens are expected to be of the form:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     ( token-id ).( token-secret )
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func (t *TokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, error) {
 | 
				
			||||||
 | 
						tokenID, tokenSecret, err := parseToken(token)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// Token isn't of the correct form, ignore it.
 | 
				
			||||||
 | 
							return nil, false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						secretName := bootstrapapi.BootstrapTokenSecretPrefix + tokenID
 | 
				
			||||||
 | 
						secret, err := t.lister.Get(secretName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if errors.IsNotFound(err) {
 | 
				
			||||||
 | 
								return nil, false, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil, false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if string(secret.Type) != string(bootstrapapi.SecretTypeBootstrapToken) || secret.Data == nil {
 | 
				
			||||||
 | 
							return nil, false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ts := getSecretString(secret, bootstrapapi.BootstrapTokenSecretKey)
 | 
				
			||||||
 | 
						if ts != tokenSecret {
 | 
				
			||||||
 | 
							return nil, false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						id := getSecretString(secret, bootstrapapi.BootstrapTokenIDKey)
 | 
				
			||||||
 | 
						if id != tokenID {
 | 
				
			||||||
 | 
							return nil, false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if isSecretExpired(secret) {
 | 
				
			||||||
 | 
							return nil, false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if getSecretString(secret, bootstrapapi.BootstrapTokenUsageAuthentication) != "true" {
 | 
				
			||||||
 | 
							glog.V(3).Infof("Bearer token matching bootstrap Secret %s/%s not marked %s=true.",
 | 
				
			||||||
 | 
								secret.Namespace, secret.Name, bootstrapapi.BootstrapTokenUsageAuthentication)
 | 
				
			||||||
 | 
							return nil, false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &user.DefaultInfo{
 | 
				
			||||||
 | 
							Name:   bootstrapapi.BootstrapUserPrefix + string(id),
 | 
				
			||||||
 | 
							Groups: []string{bootstrapapi.BootstrapGroup},
 | 
				
			||||||
 | 
						}, true, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copied from k8s.io/kubernetes/pkg/bootstrap/api
 | 
				
			||||||
 | 
					func getSecretString(secret *api.Secret, key string) string {
 | 
				
			||||||
 | 
						if secret.Data == nil {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if val, ok := secret.Data[key]; ok {
 | 
				
			||||||
 | 
							return string(val)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copied from k8s.io/kubernetes/pkg/bootstrap/api
 | 
				
			||||||
 | 
					func isSecretExpired(secret *api.Secret) bool {
 | 
				
			||||||
 | 
						expiration := getSecretString(secret, bootstrapapi.BootstrapTokenExpirationKey)
 | 
				
			||||||
 | 
						if len(expiration) > 0 {
 | 
				
			||||||
 | 
							expTime, err2 := time.Parse(time.RFC3339, expiration)
 | 
				
			||||||
 | 
							if err2 != nil {
 | 
				
			||||||
 | 
								glog.V(3).Infof("Unparseable expiration time (%s) in %s/%s Secret: %v. Treating as expired.",
 | 
				
			||||||
 | 
									expiration, secret.Namespace, secret.Name, err2)
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if time.Now().After(expTime) {
 | 
				
			||||||
 | 
								glog.V(3).Infof("Expired bootstrap token in %s/%s Secret: %v",
 | 
				
			||||||
 | 
									secret.Namespace, secret.Name, expiration)
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copied from kubernetes/cmd/kubeadm/app/util/token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						tokenRegexpString = "^([a-z0-9]{6})\\.([a-z0-9]{16})$"
 | 
				
			||||||
 | 
						tokenRegexp       = regexp.MustCompile(tokenRegexpString)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// parseToken tries and parse a valid token from a string.
 | 
				
			||||||
 | 
					// A token ID and token secret are returned in case of success, an error otherwise.
 | 
				
			||||||
 | 
					func parseToken(s string) (string, string, error) {
 | 
				
			||||||
 | 
						split := tokenRegexp.FindStringSubmatch(s)
 | 
				
			||||||
 | 
						if len(split) != 3 {
 | 
				
			||||||
 | 
							return "", "", fmt.Errorf("token [%q] was not of form [%q]", s, tokenRegexpString)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return split[1], split[2], nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										228
									
								
								plugin/pkg/auth/authenticator/token/bootstrap/bootstrap_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								plugin/pkg/auth/authenticator/token/bootstrap/bootstrap_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2017 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 bootstrap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/labels"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/authentication/user"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type lister struct {
 | 
				
			||||||
 | 
						secrets []*api.Secret
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l *lister) List(selector labels.Selector) (ret []*api.Secret, err error) {
 | 
				
			||||||
 | 
						return l.secrets, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l *lister) Get(name string) (*api.Secret, error) {
 | 
				
			||||||
 | 
						for _, s := range l.secrets {
 | 
				
			||||||
 | 
							if s.Name == name {
 | 
				
			||||||
 | 
								return s, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, errors.NewNotFound(schema.GroupResource{}, name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						tokenID     = "foobar"           // 6 letters
 | 
				
			||||||
 | 
						tokenSecret = "circumnavigation" // 16 letters
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTokenAuthenticator(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							secrets []*api.Secret
 | 
				
			||||||
 | 
							token   string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wantNotFound bool
 | 
				
			||||||
 | 
							wantUser     *user.DefaultInfo
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "valid token",
 | 
				
			||||||
 | 
								secrets: []*api.Secret{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
											Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Data: map[string][]byte{
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenIDKey:               []byte(tokenID),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenSecretKey:           []byte(tokenSecret),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Type: "bootstrap.kubernetes.io/token",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								token: tokenID + "." + tokenSecret,
 | 
				
			||||||
 | 
								wantUser: &user.DefaultInfo{
 | 
				
			||||||
 | 
									Name:   "system:bootstrap:" + tokenID,
 | 
				
			||||||
 | 
									Groups: []string{"system:bootstrappers"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "invalid secret name",
 | 
				
			||||||
 | 
								secrets: []*api.Secret{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
											Name: "bad-name",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Data: map[string][]byte{
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenIDKey:               []byte(tokenID),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenSecretKey:           []byte(tokenSecret),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Type: "bootstrap.kubernetes.io/token",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								token:        tokenID + "." + tokenSecret,
 | 
				
			||||||
 | 
								wantNotFound: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "no usage",
 | 
				
			||||||
 | 
								secrets: []*api.Secret{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
											Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Data: map[string][]byte{
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenIDKey:     []byte(tokenID),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Type: "bootstrap.kubernetes.io/token",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								token:        tokenID + "." + tokenSecret,
 | 
				
			||||||
 | 
								wantNotFound: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "wrong token",
 | 
				
			||||||
 | 
								secrets: []*api.Secret{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
											Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Data: map[string][]byte{
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenIDKey:               []byte(tokenID),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenSecretKey:           []byte(tokenSecret),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Type: "bootstrap.kubernetes.io/token",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								token:        "barfoo" + "." + tokenSecret,
 | 
				
			||||||
 | 
								wantNotFound: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "expired token",
 | 
				
			||||||
 | 
								secrets: []*api.Secret{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
											Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Data: map[string][]byte{
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenIDKey:               []byte(tokenID),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenSecretKey:           []byte(tokenSecret),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenExpirationKey:       []byte("2009-11-10T23:00:00Z"),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Type: "bootstrap.kubernetes.io/token",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								token:        tokenID + "." + tokenSecret,
 | 
				
			||||||
 | 
								wantNotFound: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "not expired token",
 | 
				
			||||||
 | 
								secrets: []*api.Secret{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
											Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Data: map[string][]byte{
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenIDKey:               []byte(tokenID),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenSecretKey:           []byte(tokenSecret),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenExpirationKey:       []byte("2109-11-10T23:00:00Z"),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Type: "bootstrap.kubernetes.io/token",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								token: tokenID + "." + tokenSecret,
 | 
				
			||||||
 | 
								wantUser: &user.DefaultInfo{
 | 
				
			||||||
 | 
									Name:   "system:bootstrap:" + tokenID,
 | 
				
			||||||
 | 
									Groups: []string{"system:bootstrappers"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "token id wrong length",
 | 
				
			||||||
 | 
								secrets: []*api.Secret{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
											Name: bootstrapapi.BootstrapTokenSecretPrefix + "foo",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Data: map[string][]byte{
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenIDKey:               []byte("foo"),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenSecretKey:           []byte(tokenSecret),
 | 
				
			||||||
 | 
											bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Type: "bootstrap.kubernetes.io/token",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								// Token ID must be 6 characters.
 | 
				
			||||||
 | 
								token:        "foo" + "." + tokenSecret,
 | 
				
			||||||
 | 
								wantNotFound: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							func() {
 | 
				
			||||||
 | 
								a := NewTokenAuthenticator(&lister{test.secrets})
 | 
				
			||||||
 | 
								u, found, err := a.AuthenticateToken(test.token)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									t.Errorf("test %q returned an error: %v", test.name, err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if !found {
 | 
				
			||||||
 | 
									if !test.wantNotFound {
 | 
				
			||||||
 | 
										t.Errorf("test %q expected to get user", test.name)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if test.wantNotFound {
 | 
				
			||||||
 | 
									t.Errorf("test %q expected to not get a user", test.name)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								gotUser := u.(*user.DefaultInfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if !reflect.DeepEqual(gotUser, test.wantUser) {
 | 
				
			||||||
 | 
									t.Errorf("test %q want user=%#v, got=%#v", test.name, test.wantUser, gotUser)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user