diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 8b1b56fc85..35bee71a65 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -32,7 +32,6 @@ import ( "github.com/spf13/cobra" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilerrors "k8s.io/apimachinery/pkg/util/errors" utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/sets" @@ -69,12 +68,12 @@ import ( "k8s.io/kubernetes/pkg/registry/cachesize" rbacrest "k8s.io/kubernetes/pkg/registry/rbac/rest" "k8s.io/kubernetes/pkg/serviceaccount" + utilflag "k8s.io/kubernetes/pkg/util/flag" _ "k8s.io/kubernetes/pkg/util/reflector/prometheus" // for reflector metric registration _ "k8s.io/kubernetes/pkg/util/workqueue/prometheus" // for workqueue metric registration "k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/pkg/version/verflag" - "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap" ) const etcdRetryLimit = 60 @@ -455,9 +454,6 @@ func BuildAuthenticator(s *options.ServerRunOptions, extclient clientgoclientset versionedInformer.Core().V1().Pods().Lister(), ) } - authenticatorConfig.BootstrapTokenAuthenticator = bootstrap.NewTokenAuthenticator( - versionedInformer.Core().V1().Secrets().Lister().Secrets(v1.NamespaceSystem), - ) return authenticatorConfig.New() } diff --git a/pkg/kubeapiserver/authenticator/config.go b/pkg/kubeapiserver/authenticator/config.go index 472ae4cd36..3a4d1b6d29 100644 --- a/pkg/kubeapiserver/authenticator/config.go +++ b/pkg/kubeapiserver/authenticator/config.go @@ -49,7 +49,6 @@ import ( type Config struct { Anonymous bool BasicAuthFile string - BootstrapToken bool ClientCAFile string TokenAuthFile string OIDCIssuerURL string @@ -75,7 +74,6 @@ type Config struct { // TODO, this is the only non-serializable part of the entire config. Factor it out into a clientconfig ServiceAccountTokenGetter serviceaccount.ServiceAccountTokenGetter - BootstrapTokenAuthenticator authenticator.Token } // New returns an authenticator.Request or an error that supports the standard @@ -140,12 +138,6 @@ func (config Config) New() (authenticator.Request, error) { } tokenAuthenticators = append(tokenAuthenticators, serviceAccountAuth) } - if config.BootstrapToken { - if config.BootstrapTokenAuthenticator != nil { - // TODO: This can sometimes be nil because of - tokenAuthenticators = append(tokenAuthenticators, authenticator.WrapAudienceAgnosticToken(config.APIAudiences, config.BootstrapTokenAuthenticator)) - } - } // NOTE(ericchiang): Keep the OpenID Connect after Service Accounts. // // Because both plugins verify JWTs whichever comes first in the union experiences diff --git a/pkg/kubeapiserver/options/authentication.go b/pkg/kubeapiserver/options/authentication.go index deafb231f3..b1f5c9030c 100644 --- a/pkg/kubeapiserver/options/authentication.go +++ b/pkg/kubeapiserver/options/authentication.go @@ -37,7 +37,6 @@ import ( type BuiltInAuthenticationOptions struct { APIAudiences []string Anonymous *AnonymousAuthenticationOptions - BootstrapToken *BootstrapTokenAuthenticationOptions ClientCert *genericoptions.ClientCertAuthenticationOptions OIDC *OIDCAuthenticationOptions PasswordFile *PasswordFileAuthenticationOptions @@ -54,10 +53,6 @@ type AnonymousAuthenticationOptions struct { Allow bool } -type BootstrapTokenAuthenticationOptions struct { - Enable bool -} - type OIDCAuthenticationOptions struct { CAFile string ClientID string @@ -100,7 +95,6 @@ func NewBuiltInAuthenticationOptions() *BuiltInAuthenticationOptions { func (s *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions { return s. WithAnonymous(). - WithBootstrapToken(). WithClientCert(). WithOIDC(). WithPasswordFile(). @@ -115,11 +109,6 @@ func (s *BuiltInAuthenticationOptions) WithAnonymous() *BuiltInAuthenticationOpt return s } -func (s *BuiltInAuthenticationOptions) WithBootstrapToken() *BuiltInAuthenticationOptions { - s.BootstrapToken = &BootstrapTokenAuthenticationOptions{} - return s -} - func (s *BuiltInAuthenticationOptions) WithClientCert() *BuiltInAuthenticationOptions { s.ClientCert = &genericoptions.ClientCertAuthenticationOptions{} return s @@ -188,12 +177,6 @@ func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { "Anonymous requests have a username of system:anonymous, and a group name of system:unauthenticated.") } - if s.BootstrapToken != nil { - fs.BoolVar(&s.BootstrapToken.Enable, "enable-bootstrap-token-auth", s.BootstrapToken.Enable, ""+ - "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 { s.ClientCert.AddFlags(fs) } @@ -302,10 +285,6 @@ func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() kubeauthenticato ret.Anonymous = s.Anonymous.Allow } - if s.BootstrapToken != nil { - ret.BootstrapToken = s.BootstrapToken.Enable - } - if s.ClientCert != nil { ret.ClientCAFile = s.ClientCert.ClientCA } diff --git a/plugin/pkg/auth/authenticator/token/bootstrap/BUILD b/plugin/pkg/auth/authenticator/token/bootstrap/BUILD deleted file mode 100644 index 4432fe3faa..0000000000 --- a/plugin/pkg/auth/authenticator/token/bootstrap/BUILD +++ /dev/null @@ -1,52 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_test( - name = "go_default_test", - srcs = ["bootstrap_test.go"], - embed = [":go_default_library"], - deps = [ - "//staging/src/k8s.io/api/core/v1:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", - "//staging/src/k8s.io/cluster-bootstrap/token/api:go_default_library", - ], -) - -go_library( - name = "go_default_library", - srcs = ["bootstrap.go"], - importpath = "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap", - deps = [ - "//staging/src/k8s.io/api/core/v1:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", - "//staging/src/k8s.io/client-go/listers/core/v1:go_default_library", - "//staging/src/k8s.io/cluster-bootstrap/token/api:go_default_library", - "//staging/src/k8s.io/cluster-bootstrap/token/util:go_default_library", - "//vendor/k8s.io/klog:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go b/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go deleted file mode 100644 index 4459615665..0000000000 --- a/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go +++ /dev/null @@ -1,228 +0,0 @@ -/* -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 ( - "context" - "crypto/subtle" - "fmt" - "regexp" - "strings" - "time" - - "k8s.io/klog" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - corev1listers "k8s.io/client-go/listers/core/v1" - bootstrapapi "k8s.io/cluster-bootstrap/token/api" - bootstraputil "k8s.io/cluster-bootstrap/token/util" -) - -// 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 corev1listers.SecretNamespaceLister) *TokenAuthenticator { - return &TokenAuthenticator{lister} -} - -// TokenAuthenticator authenticates bootstrap tokens from secrets in the API server. -type TokenAuthenticator struct { - lister corev1listers.SecretNamespaceLister -} - -// tokenErrorf prints a error message for a secret that has matched a bearer -// token but fails to meet some other criteria. -// -// tokenErrorf(secret, "has invalid value for key %s", key) -// -func tokenErrorf(s *corev1.Secret, format string, i ...interface{}) { - format = fmt.Sprintf("Bootstrap secret %s/%s matching bearer token ", s.Namespace, s.Name) + format - klog.V(3).Infof(format, i...) -} - -// 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 -// auth-extra-groups: "system:bootstrappers:custom-group1,system:bootstrappers:custom-group2" -// # May also contain an expiry. -// -// Tokens are expected to be of the form: -// -// ( token-id ).( token-secret ) -// -func (t *TokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, 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) { - klog.V(3).Infof("No secret of name %s to match bootstrap bearer token", secretName) - return nil, false, nil - } - return nil, false, err - } - - if secret.DeletionTimestamp != nil { - tokenErrorf(secret, "is deleted and awaiting removal") - return nil, false, nil - } - - if string(secret.Type) != string(bootstrapapi.SecretTypeBootstrapToken) || secret.Data == nil { - tokenErrorf(secret, "has invalid type, expected %s.", bootstrapapi.SecretTypeBootstrapToken) - return nil, false, nil - } - - ts := getSecretString(secret, bootstrapapi.BootstrapTokenSecretKey) - if subtle.ConstantTimeCompare([]byte(ts), []byte(tokenSecret)) != 1 { - tokenErrorf(secret, "has invalid value for key %s, expected %s.", bootstrapapi.BootstrapTokenSecretKey, tokenSecret) - return nil, false, nil - } - - id := getSecretString(secret, bootstrapapi.BootstrapTokenIDKey) - if id != tokenID { - tokenErrorf(secret, "has invalid value for key %s, expected %s.", bootstrapapi.BootstrapTokenIDKey, tokenID) - return nil, false, nil - } - - if isSecretExpired(secret) { - // logging done in isSecretExpired method. - return nil, false, nil - } - - if getSecretString(secret, bootstrapapi.BootstrapTokenUsageAuthentication) != "true" { - tokenErrorf(secret, "not marked %s=true.", bootstrapapi.BootstrapTokenUsageAuthentication) - return nil, false, nil - } - - groups, err := getGroups(secret) - if err != nil { - tokenErrorf(secret, "has invalid value for key %s: %v.", bootstrapapi.BootstrapTokenExtraGroupsKey, err) - return nil, false, nil - } - - return &authenticator.Response{ - User: &user.DefaultInfo{ - Name: bootstrapapi.BootstrapUserPrefix + string(id), - Groups: groups, - }, - }, true, nil -} - -// Copied from k8s.io/cluster-bootstrap/token/api -func getSecretString(secret *corev1.Secret, key string) string { - data, ok := secret.Data[key] - if !ok { - return "" - } - - return string(data) -} - -// Copied from k8s.io/cluster-bootstrap/token/api -func isSecretExpired(secret *corev1.Secret) bool { - expiration := getSecretString(secret, bootstrapapi.BootstrapTokenExpirationKey) - if len(expiration) > 0 { - expTime, err2 := time.Parse(time.RFC3339, expiration) - if err2 != nil { - klog.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) { - klog.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 defines id.secret regular expression pattern - tokenRegexpString = "^([a-z0-9]{6})\\.([a-z0-9]{16})$" - // tokenRegexp is a compiled regular expression of TokenRegexpString - 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 -} - -// getGroups loads and validates the bootstrapapi.BootstrapTokenExtraGroupsKey -// key from the bootstrap token secret, returning a list of group names or an -// error if any of the group names are invalid. -func getGroups(secret *corev1.Secret) ([]string, error) { - // always include the default group - groups := sets.NewString(bootstrapapi.BootstrapDefaultGroup) - - // grab any extra groups and if there are none, return just the default - extraGroupsString := getSecretString(secret, bootstrapapi.BootstrapTokenExtraGroupsKey) - if extraGroupsString == "" { - return groups.List(), nil - } - - // validate the names of the extra groups - for _, group := range strings.Split(extraGroupsString, ",") { - if err := bootstraputil.ValidateBootstrapGroupName(group); err != nil { - return nil, err - } - groups.Insert(group) - } - - // return the result as a deduplicated, sorted list - return groups.List(), nil -} diff --git a/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap_test.go b/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap_test.go deleted file mode 100644 index 0613e1587a..0000000000 --- a/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap_test.go +++ /dev/null @@ -1,359 +0,0 @@ -/* -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 ( - "context" - "reflect" - "testing" - - corev1 "k8s.io/api/core/v1" - "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" - bootstrapapi "k8s.io/cluster-bootstrap/token/api" -) - -type lister struct { - secrets []*corev1.Secret -} - -func (l *lister) List(selector labels.Selector) (ret []*corev1.Secret, err error) { - return l.secrets, nil -} - -func (l *lister) Get(name string) (*corev1.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) { - now := metav1.Now() - - tests := []struct { - name string - - secrets []*corev1.Secret - token string - - wantNotFound bool - wantUser *user.DefaultInfo - }{ - { - name: "valid token", - secrets: []*corev1.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: "valid token with extra group", - secrets: []*corev1.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.BootstrapTokenExtraGroupsKey: []byte("system:bootstrappers:foo"), - }, - Type: "bootstrap.kubernetes.io/token", - }, - }, - token: tokenID + "." + tokenSecret, - wantUser: &user.DefaultInfo{ - Name: "system:bootstrap:" + tokenID, - Groups: []string{"system:bootstrappers", "system:bootstrappers:foo"}, - }, - }, - { - name: "invalid group", - secrets: []*corev1.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.BootstrapTokenExtraGroupsKey: []byte("foo"), - }, - Type: "bootstrap.kubernetes.io/token", - }, - }, - token: tokenID + "." + tokenSecret, - wantNotFound: true, - }, - { - name: "invalid secret name", - secrets: []*corev1.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: []*corev1.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: []*corev1.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: "deleted token", - secrets: []*corev1.Secret{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID, - DeletionTimestamp: &now, - }, - 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: "expired token", - secrets: []*corev1.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: []*corev1.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: []*corev1.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}) - resp, found, err := a.AuthenticateToken(context.Background(), 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 := resp.User.(*user.DefaultInfo) - if !reflect.DeepEqual(gotUser, test.wantUser) { - t.Errorf("test %q want user=%#v, got=%#v", test.name, test.wantUser, gotUser) - } - }() - } -} - -func TestGetGroups(t *testing.T) { - tests := []struct { - name string - secret *corev1.Secret - expectResult []string - expectError bool - }{ - { - name: "not set", - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, - Data: map[string][]byte{}, - }, - expectResult: []string{"system:bootstrappers"}, - }, - { - name: "set to empty value", - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, - Data: map[string][]byte{ - bootstrapapi.BootstrapTokenExtraGroupsKey: []byte(""), - }, - }, - expectResult: []string{"system:bootstrappers"}, - }, - { - name: "invalid prefix", - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, - Data: map[string][]byte{ - bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("foo"), - }, - }, - expectError: true, - }, - { - name: "valid", - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, - Data: map[string][]byte{ - bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("system:bootstrappers:foo,system:bootstrappers:bar,system:bootstrappers:bar"), - }, - }, - // expect the results in deduplicated, sorted order - expectResult: []string{ - "system:bootstrappers", - "system:bootstrappers:bar", - "system:bootstrappers:foo", - }, - }, - } - for _, test := range tests { - result, err := getGroups(test.secret) - if test.expectError { - if err == nil { - t.Errorf("test %q expected an error, but didn't get one (result: %#v)", test.name, result) - } - continue - } - if err != nil { - t.Errorf("test %q return an unexpected error: %v", test.name, err) - continue - } - if !reflect.DeepEqual(result, test.expectResult) { - t.Errorf("test %q expected %#v, got %#v", test.name, test.expectResult, result) - } - } -}