func newWebhookTokenAuthenticator(webhookConfigFile string, ttl time.Duration) (authenticator.Request, error) { webhookTokenAuthenticator, err := webhook.New(webhookConfigFile, ttl) if err != nil { return nil, err } return bearertoken.New(webhookTokenAuthenticator), nil }
// newAuthenticatorFromOIDCIssuerURL returns an authenticator.Request or an error. func newAuthenticatorFromOIDCIssuerURL(issuerURL, clientID, caFile, usernameClaim, groupsClaim string) (authenticator.Request, error) { tokenAuthenticator, err := oidc.New(issuerURL, clientID, caFile, usernameClaim, groupsClaim) if err != nil { return nil, err } return bearertoken.New(tokenAuthenticator), nil }
// newAuthenticatorFromTokenFile returns an authenticator.Request or an error func newAuthenticatorFromTokenFile(tokenAuthFile string) (authenticator.Request, error) { tokenAuthenticator, err := tokenfile.NewCSV(tokenAuthFile) if err != nil { return nil, err } return bearertoken.New(tokenAuthenticator), nil }
// newServiceAccountAuthenticator returns an authenticator.Request or an error func newServiceAccountAuthenticator(keyfile string, lookup bool, serviceAccountGetter serviceaccount.ServiceAccountTokenGetter) (authenticator.Request, error) { publicKey, err := serviceaccount.ReadPublicKey(keyfile) if err != nil { return nil, err } tokenAuthenticator := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{publicKey}, lookup, serviceAccountGetter) return bearertoken.New(tokenAuthenticator), nil }
func newFakeAuthenticator() authenticator.Request { return bearertoken.New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) { if token == "" { return nil, false, errors.New("no bearer token found") } // Set the bearer token as the user name. return &user.DefaultInfo{Name: token, UID: token}, true, nil })) }
// newServiceAccountAuthenticator returns an authenticator.Request or an error func newServiceAccountAuthenticator(keyfiles []string, lookup bool, serviceAccountGetter serviceaccount.ServiceAccountTokenGetter) (authenticator.Request, error) { allPublicKeys := []interface{}{} for _, keyfile := range keyfiles { publicKeys, err := serviceaccount.ReadPublicKeys(keyfile) if err != nil { return nil, err } allPublicKeys = append(allPublicKeys, publicKeys...) } tokenAuthenticator := serviceaccount.JWTTokenAuthenticator(allPublicKeys, lookup, serviceAccountGetter) return bearertoken.New(tokenAuthenticator), nil }
// newAuthenticatorFromOIDCIssuerURL returns an authenticator.Request or an error. func newAuthenticatorFromOIDCIssuerURL(issuerURL, clientID, caFile, usernameClaim, groupsClaim string) (authenticator.Request, error) { tokenAuthenticator, err := oidc.New(oidc.OIDCOptions{ IssuerURL: issuerURL, ClientID: clientID, CAFile: caFile, UsernameClaim: usernameClaim, GroupsClaim: groupsClaim, }) if err != nil { return nil, err } return bearertoken.New(tokenAuthenticator), nil }
// newServiceAccountAuthenticator returns an authenticator.Request or an error func newServiceAccountAuthenticator(keyfile string, lookup bool, storage storage.Interface) (authenticator.Request, error) { publicKey, err := serviceaccount.ReadPublicKey(keyfile) if err != nil { return nil, err } var serviceAccountGetter serviceaccount.ServiceAccountTokenGetter if lookup { // If we need to look up service accounts and tokens, // go directly to etcd to avoid recursive auth insanity serviceAccountGetter = serviceaccount.NewGetterFromStorageInterface(storage) } tokenAuthenticator := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{publicKey}, lookup, serviceAccountGetter) return bearertoken.New(tokenAuthenticator), nil }
func buildAuthn(client authenticationclient.TokenReviewInterface, authn componentconfig.KubeletAuthentication) (authenticator.Request, error) { authenticators := []authenticator.Request{} // x509 client cert auth if len(authn.X509.ClientCAFile) > 0 { clientCAs, err := cert.NewPool(authn.X509.ClientCAFile) if err != nil { return nil, fmt.Errorf("unable to load client CA file %s: %v", authn.X509.ClientCAFile, err) } verifyOpts := x509.DefaultVerifyOptions() verifyOpts.Roots = clientCAs authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion)) } // bearer token auth that uses authentication.k8s.io TokenReview to determine userinfo if authn.Webhook.Enabled { if client == nil { return nil, errors.New("no client provided, cannot use webhook authentication") } tokenAuth, err := webhooktoken.NewFromInterface(client, authn.Webhook.CacheTTL.Duration) if err != nil { return nil, err } authenticators = append(authenticators, bearertoken.New(tokenAuth)) } if len(authenticators) == 0 { if authn.Anonymous.Enabled { return anonymous.NewAuthenticator(), nil } return nil, errors.New("No authentication method configured") } authenticator := group.NewGroupAdder(unionauth.New(authenticators...), []string{"system:authenticated"}) if authn.Anonymous.Enabled { authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator()) } return authenticator, nil }
func getTestWebhookTokenAuth(serverURL string) (authenticator.Request, error) { kubecfgFile, err := ioutil.TempFile("", "webhook-kubecfg") if err != nil { return nil, err } defer os.Remove(kubecfgFile.Name()) config := v1.Config{ Clusters: []v1.NamedCluster{ { Cluster: v1.Cluster{Server: serverURL}, }, }, } if err := json.NewEncoder(kubecfgFile).Encode(config); err != nil { return nil, err } webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), 2*time.Minute) if err != nil { return nil, err } return bearertoken.New(webhookTokenAuth), nil }
// newAuthenticatorFromToken returns an authenticator.Request or an error func NewAuthenticatorFromTokens(tokens map[string]*user.DefaultInfo) authenticator.Request { return bearertoken.New(tokenfile.New(tokens)) }
// startServiceAccountTestServer returns a started server // It is the responsibility of the caller to ensure the returned stopFunc is called func startServiceAccountTestServer(t *testing.T) (*client.Client, client.Config, func()) { deleteAllEtcdKeys() // Etcd etcdStorage, err := framework.NewEtcdStorage() if err != nil { t.Fatalf("unexpected error: %v", err) } expEtcdStorage, err := framework.NewExtensionsEtcdStorage(nil) if err != nil { t.Fatalf("unexpected error: %v", err) } storageDestinations := master.NewStorageDestinations() storageDestinations.AddAPIGroup("", etcdStorage) storageDestinations.AddAPIGroup("extensions", expEtcdStorage) storageVersions := make(map[string]string) storageVersions[""] = testapi.Default.Version() storageVersions["extensions"] = testapi.Extensions.GroupAndVersion() // Listener var m *master.Master apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) // Anonymous client config clientConfig := client.Config{Host: apiServer.URL, Version: testapi.Default.Version()} // Root client rootClient := client.NewOrDie(&client.Config{Host: apiServer.URL, Version: testapi.Default.Version(), BearerToken: rootToken}) // Set up two authenticators: // 1. A token authenticator that maps the rootToken to the "root" user // 2. A ServiceAccountToken authenticator that validates ServiceAccount tokens rootTokenAuth := authenticator.TokenFunc(func(token string) (user.Info, bool, error) { if token == rootToken { return &user.DefaultInfo{rootUserName, "", "", "", []string{}, ""}, true, nil } return nil, false, nil }) serviceAccountKey, err := rsa.GenerateKey(rand.Reader, 2048) serviceAccountTokenGetter := serviceaccount.NewGetterFromClient(rootClient) serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{&serviceAccountKey.PublicKey}, true, serviceAccountTokenGetter) authenticator := union.New( bearertoken.New(rootTokenAuth), bearertoken.New(serviceAccountTokenAuth), ) // Set up a stub authorizer: // 1. The "root" user is allowed to do anything // 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace // 3. ServiceAccounts named "rw" are allowed any operation in their namespace authorizer := authorizer.AuthorizerFunc(func(attrs authorizer.Attributes) (string, error) { username := attrs.GetUserName() ns := attrs.GetNamespace() // If the user is "root"... if username == rootUserName { // allow them to do anything return "", nil } // If the user is a service account... if serviceAccountNamespace, serviceAccountName, err := serviceaccount.SplitUsername(username); err == nil { // Limit them to their own namespace if serviceAccountNamespace == ns { switch serviceAccountName { case readOnlyServiceAccountName: if attrs.IsReadOnly() { return "", nil } case readWriteServiceAccountName: return "", nil } } } return "", fmt.Errorf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()) }) // Set up admission plugin to auto-assign serviceaccounts to pods serviceAccountAdmission := serviceaccountadmission.NewServiceAccount(rootClient) // Create a master and install handlers into mux. m = master.New(&master.Config{ StorageDestinations: storageDestinations, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", Authenticator: authenticator, Authorizer: authorizer, AdmissionControl: serviceAccountAdmission, StorageVersions: storageVersions, }) // Start the service account and service account token controllers tokenController := serviceaccount.NewTokensController(rootClient, serviceaccount.TokensControllerOptions{TokenGenerator: serviceaccount.JWTTokenGenerator(serviceAccountKey)}) tokenController.Run() serviceAccountController := serviceaccount.NewServiceAccountsController(rootClient, serviceaccount.DefaultServiceAccountsControllerOptions()) serviceAccountController.Run() // Start the admission plugin reflectors serviceAccountAdmission.Run() stop := func() { tokenController.Stop() serviceAccountController.Stop() serviceAccountAdmission.Stop() apiServer.Close() } return rootClient, clientConfig, stop }
// startServiceAccountTestServer returns a started server // It is the responsibility of the caller to ensure the returned stopFunc is called func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclient.Config, func()) { // Listener h := &framework.MasterHolder{Initialized: make(chan struct{})} apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { <-h.Initialized h.M.GenericAPIServer.Handler.ServeHTTP(w, req) })) // Anonymous client config clientConfig := restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(v1.GroupName).GroupVersion}} // Root client // TODO: remove rootClient after we refactor pkg/admission to use the clientset. rootClientset := clientset.NewForConfigOrDie(&restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(v1.GroupName).GroupVersion}, BearerToken: rootToken}) internalRootClientset := internalclientset.NewForConfigOrDie(&restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(v1.GroupName).GroupVersion}, BearerToken: rootToken}) // Set up two authenticators: // 1. A token authenticator that maps the rootToken to the "root" user // 2. A ServiceAccountToken authenticator that validates ServiceAccount tokens rootTokenAuth := authenticator.TokenFunc(func(token string) (user.Info, bool, error) { if token == rootToken { return &user.DefaultInfo{Name: rootUserName}, true, nil } return nil, false, nil }) serviceAccountKey, _ := rsa.GenerateKey(rand.Reader, 2048) serviceAccountTokenGetter := serviceaccountcontroller.NewGetterFromClient(rootClientset) serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator([]interface{}{&serviceAccountKey.PublicKey}, true, serviceAccountTokenGetter) authenticator := union.New( bearertoken.New(rootTokenAuth), bearertoken.New(serviceAccountTokenAuth), ) // Set up a stub authorizer: // 1. The "root" user is allowed to do anything // 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace // 3. ServiceAccounts named "rw" are allowed any operation in their namespace authorizer := authorizer.AuthorizerFunc(func(attrs authorizer.Attributes) (bool, string, error) { username := "" if user := attrs.GetUser(); user != nil { username = user.GetName() } ns := attrs.GetNamespace() // If the user is "root"... if username == rootUserName { // allow them to do anything return true, "", nil } // If the user is a service account... if serviceAccountNamespace, serviceAccountName, err := serviceaccount.SplitUsername(username); err == nil { // Limit them to their own namespace if serviceAccountNamespace == ns { switch serviceAccountName { case readOnlyServiceAccountName: if attrs.IsReadOnly() { return true, "", nil } case readWriteServiceAccountName: return true, "", nil } } } return false, fmt.Sprintf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()), nil }) // Set up admission plugin to auto-assign serviceaccounts to pods serviceAccountAdmission := serviceaccountadmission.NewServiceAccount(internalRootClientset) masterConfig := framework.NewMasterConfig() masterConfig.GenericConfig.EnableIndex = true masterConfig.GenericConfig.Authenticator = authenticator masterConfig.GenericConfig.Authorizer = authorizer masterConfig.GenericConfig.AdmissionControl = serviceAccountAdmission framework.RunAMasterUsingServer(masterConfig, apiServer, h) // Start the service account and service account token controllers stopCh := make(chan struct{}) tokenController := serviceaccountcontroller.NewTokensController(rootClientset, serviceaccountcontroller.TokensControllerOptions{TokenGenerator: serviceaccount.JWTTokenGenerator(serviceAccountKey)}) go tokenController.Run(1, stopCh) informers := informers.NewSharedInformerFactory(rootClientset, nil, controller.NoResyncPeriodFunc()) serviceAccountController := serviceaccountcontroller.NewServiceAccountsController(informers.ServiceAccounts(), informers.Namespaces(), rootClientset, serviceaccountcontroller.DefaultServiceAccountsControllerOptions()) informers.Start(stopCh) go serviceAccountController.Run(5, stopCh) // Start the admission plugin reflectors serviceAccountAdmission.Run() stop := func() { close(stopCh) serviceAccountAdmission.Stop() apiServer.Close() } return rootClientset, clientConfig, stop }
// New returns an authenticator.Request or an error that supports the standard // Kubernetes authentication mechanisms. func New(config AuthenticatorConfig) (authenticator.Request, *spec.SecurityDefinitions, error) { var authenticators []authenticator.Request securityDefinitions := spec.SecurityDefinitions{} hasBasicAuth := false hasTokenAuth := false // front-proxy, BasicAuth methods, local first, then remote // Add the front proxy authenticator if requested if config.RequestHeaderConfig != nil { requestHeaderAuthenticator, err := headerrequest.NewSecure( config.RequestHeaderConfig.ClientCA, config.RequestHeaderConfig.AllowedClientNames, config.RequestHeaderConfig.UsernameHeaders, ) if err != nil { return nil, nil, err } authenticators = append(authenticators, requestHeaderAuthenticator) } if len(config.BasicAuthFile) > 0 { basicAuth, err := newAuthenticatorFromBasicAuthFile(config.BasicAuthFile) if err != nil { return nil, nil, err } authenticators = append(authenticators, basicAuth) hasBasicAuth = true } if len(config.KeystoneURL) > 0 { keystoneAuth, err := newAuthenticatorFromKeystoneURL(config.KeystoneURL) if err != nil { return nil, nil, err } authenticators = append(authenticators, keystoneAuth) hasBasicAuth = true } // X509 methods if len(config.ClientCAFile) > 0 { certAuth, err := newAuthenticatorFromClientCAFile(config.ClientCAFile) if err != nil { return nil, nil, err } authenticators = append(authenticators, certAuth) } // Bearer token methods, local first, then remote if len(config.TokenAuthFile) > 0 { tokenAuth, err := newAuthenticatorFromTokenFile(config.TokenAuthFile) if err != nil { return nil, nil, err } authenticators = append(authenticators, tokenAuth) hasTokenAuth = true } if len(config.ServiceAccountKeyFiles) > 0 { serviceAccountAuth, err := newServiceAccountAuthenticator(config.ServiceAccountKeyFiles, config.ServiceAccountLookup, config.ServiceAccountTokenGetter) if err != nil { return nil, nil, err } authenticators = append(authenticators, serviceAccountAuth) hasTokenAuth = true } // NOTE(ericchiang): Keep the OpenID Connect after Service Accounts. // // Because both plugins verify JWTs whichever comes first in the union experiences // cache misses for all requests using the other. While the service account plugin // simply returns an error, the OpenID Connect plugin may query the provider to // update the keys, causing performance hits. if len(config.OIDCIssuerURL) > 0 && len(config.OIDCClientID) > 0 { oidcAuth, err := newAuthenticatorFromOIDCIssuerURL(config.OIDCIssuerURL, config.OIDCClientID, config.OIDCCAFile, config.OIDCUsernameClaim, config.OIDCGroupsClaim) if err != nil { return nil, nil, err } authenticators = append(authenticators, oidcAuth) hasTokenAuth = true } if len(config.WebhookTokenAuthnConfigFile) > 0 { webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnCacheTTL) if err != nil { return nil, nil, err } authenticators = append(authenticators, webhookTokenAuth) hasTokenAuth = true } // always add anytoken last, so that every other token authenticator gets to try first if config.AnyToken { authenticators = append(authenticators, bearertoken.New(anytoken.AnyTokenAuthenticator{})) hasTokenAuth = true } if hasBasicAuth { securityDefinitions["HTTPBasic"] = &spec.SecurityScheme{ SecuritySchemeProps: spec.SecuritySchemeProps{ Type: "basic", Description: "HTTP Basic authentication", }, } } if hasTokenAuth { securityDefinitions["BearerToken"] = &spec.SecurityScheme{ SecuritySchemeProps: spec.SecuritySchemeProps{ Type: "apiKey", Name: "authorization", In: "header", Description: "Bearer Token authentication", }, } } if len(authenticators) == 0 { if config.Anonymous { return anonymous.NewAuthenticator(), &securityDefinitions, nil } } switch len(authenticators) { case 0: return nil, &securityDefinitions, nil } authenticator := union.New(authenticators...) authenticator = group.NewGroupAdder(authenticator, []string{user.AllAuthenticated}) if config.Anonymous { // If the authenticator chain returns an error, return an error (don't consider a bad bearer token anonymous). authenticator = union.NewFailOnError(authenticator, anonymous.NewAuthenticator()) } return authenticator, &securityDefinitions, nil }
// New returns an authenticator.Request or an error that supports the standard // Kubernetes authentication mechanisms. func New(config AuthenticatorConfig) (authenticator.Request, error) { var authenticators []authenticator.Request // BasicAuth methods, local first, then remote if len(config.BasicAuthFile) > 0 { basicAuth, err := newAuthenticatorFromBasicAuthFile(config.BasicAuthFile) if err != nil { return nil, err } authenticators = append(authenticators, basicAuth) } if len(config.KeystoneURL) > 0 { keystoneAuth, err := newAuthenticatorFromKeystoneURL(config.KeystoneURL) if err != nil { return nil, err } authenticators = append(authenticators, keystoneAuth) } // X509 methods if len(config.ClientCAFile) > 0 { certAuth, err := newAuthenticatorFromClientCAFile(config.ClientCAFile) if err != nil { return nil, err } authenticators = append(authenticators, certAuth) } // Bearer token methods, local first, then remote if len(config.TokenAuthFile) > 0 { tokenAuth, err := newAuthenticatorFromTokenFile(config.TokenAuthFile) if err != nil { return nil, err } authenticators = append(authenticators, tokenAuth) } if len(config.ServiceAccountKeyFile) > 0 { serviceAccountAuth, err := newServiceAccountAuthenticator(config.ServiceAccountKeyFile, config.ServiceAccountLookup, config.ServiceAccountTokenGetter) if err != nil { return nil, err } authenticators = append(authenticators, serviceAccountAuth) } // NOTE(ericchiang): Keep the OpenID Connect after Service Accounts. // // Because both plugins verify JWTs whichever comes first in the union experiences // cache misses for all requests using the other. While the service account plugin // simply returns an error, the OpenID Connect plugin may query the provider to // update the keys, causing performance hits. if len(config.OIDCIssuerURL) > 0 && len(config.OIDCClientID) > 0 { oidcAuth, err := newAuthenticatorFromOIDCIssuerURL(config.OIDCIssuerURL, config.OIDCClientID, config.OIDCCAFile, config.OIDCUsernameClaim, config.OIDCGroupsClaim) if err != nil { return nil, err } authenticators = append(authenticators, oidcAuth) } if len(config.WebhookTokenAuthnConfigFile) > 0 { webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnCacheTTL) if err != nil { return nil, err } authenticators = append(authenticators, webhookTokenAuth) } // always add anytoken last, so that every other token authenticator gets to try first if config.AnyToken { authenticators = append(authenticators, bearertoken.New(anytoken.AnyTokenAuthenticator{})) } if len(authenticators) == 0 { if config.Anonymous { return anonymous.NewAuthenticator(), nil } } switch len(authenticators) { case 0: return nil, nil } authenticator := union.New(authenticators...) authenticator = group.NewGroupAdder(authenticator, []string{user.AllAuthenticated}) if config.Anonymous { // If the authenticator chain returns an error, return an error (don't consider a bad bearer token anonymous). authenticator = union.NewFailOnError(authenticator, anonymous.NewAuthenticator()) } return authenticator, nil }
func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDefinitions, error) { authenticators := []authenticator.Request{} securityDefinitions := spec.SecurityDefinitions{} // front-proxy first, then remote // Add the front proxy authenticator if requested if c.RequestHeaderConfig != nil { requestHeaderAuthenticator, err := headerrequest.NewSecure( c.RequestHeaderConfig.ClientCA, c.RequestHeaderConfig.AllowedClientNames, c.RequestHeaderConfig.UsernameHeaders, c.RequestHeaderConfig.GroupHeaders, c.RequestHeaderConfig.ExtraHeaderPrefixes, ) if err != nil { return nil, nil, err } authenticators = append(authenticators, requestHeaderAuthenticator) } // x509 client cert auth if len(c.ClientCAFile) > 0 { clientCAs, err := cert.NewPool(c.ClientCAFile) if err != nil { return nil, nil, fmt.Errorf("unable to load client CA file %s: %v", c.ClientCAFile, err) } verifyOpts := x509.DefaultVerifyOptions() verifyOpts.Roots = clientCAs authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion)) } if c.TokenAccessReviewClient != nil { tokenAuth, err := webhooktoken.NewFromInterface(c.TokenAccessReviewClient, c.CacheTTL) if err != nil { return nil, nil, err } authenticators = append(authenticators, bearertoken.New(tokenAuth)) securityDefinitions["BearerToken"] = &spec.SecurityScheme{ SecuritySchemeProps: spec.SecuritySchemeProps{ Type: "apiKey", Name: "authorization", In: "header", Description: "Bearer Token authentication", }, } } if len(authenticators) == 0 { if c.Anonymous { return anonymous.NewAuthenticator(), &securityDefinitions, nil } return nil, nil, errors.New("No authentication method configured") } authenticator := group.NewGroupAdder(unionauth.New(authenticators...), []string{user.AllAuthenticated}) if c.Anonymous { authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator()) } return authenticator, &securityDefinitions, nil }
func getTestTokenAuth() authenticator.Request { tokenAuthenticator := tokentest.New() tokenAuthenticator.Tokens[AliceToken] = &user.DefaultInfo{Name: "alice", UID: "1"} tokenAuthenticator.Tokens[BobToken] = &user.DefaultInfo{Name: "bob", UID: "2"} return bearertoken.New(tokenAuthenticator) }
func newFakeAuthenticator() authenticator.Request { return bearertoken.New(anytoken.AnyTokenAuthenticator{}) }
// startServiceAccountTestServer returns a started server // It is the responsibility of the caller to ensure the returned stopFunc is called func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclient.Config, func()) { deleteAllEtcdKeys() // Listener var m *master.Master apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) // Anonymous client config clientConfig := restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}} // Root client // TODO: remove rootClient after we refactor pkg/admission to use the clientset. rootClientset := clientset.NewForConfigOrDie(&restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}, BearerToken: rootToken}) // Set up two authenticators: // 1. A token authenticator that maps the rootToken to the "root" user // 2. A ServiceAccountToken authenticator that validates ServiceAccount tokens rootTokenAuth := authenticator.TokenFunc(func(token string) (user.Info, bool, error) { if token == rootToken { return &user.DefaultInfo{rootUserName, "", []string{}}, true, nil } return nil, false, nil }) serviceAccountKey, _ := rsa.GenerateKey(rand.Reader, 2048) serviceAccountTokenGetter := serviceaccountcontroller.NewGetterFromClient(rootClientset) serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{&serviceAccountKey.PublicKey}, true, serviceAccountTokenGetter) authenticator := union.New( bearertoken.New(rootTokenAuth), bearertoken.New(serviceAccountTokenAuth), ) // Set up a stub authorizer: // 1. The "root" user is allowed to do anything // 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace // 3. ServiceAccounts named "rw" are allowed any operation in their namespace authorizer := authorizer.AuthorizerFunc(func(attrs authorizer.Attributes) error { username := attrs.GetUserName() ns := attrs.GetNamespace() // If the user is "root"... if username == rootUserName { // allow them to do anything return nil } // If the user is a service account... if serviceAccountNamespace, serviceAccountName, err := serviceaccount.SplitUsername(username); err == nil { // Limit them to their own namespace if serviceAccountNamespace == ns { switch serviceAccountName { case readOnlyServiceAccountName: if attrs.IsReadOnly() { return nil } case readWriteServiceAccountName: return nil } } } return fmt.Errorf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()) }) // Set up admission plugin to auto-assign serviceaccounts to pods serviceAccountAdmission := serviceaccountadmission.NewServiceAccount(rootClientset) masterConfig := framework.NewMasterConfig() masterConfig.EnableIndex = true masterConfig.Authenticator = authenticator masterConfig.Authorizer = authorizer masterConfig.AdmissionControl = serviceAccountAdmission // Create a master and install handlers into mux. m, err := master.New(masterConfig) if err != nil { t.Fatalf("Error in bringing up the master: %v", err) } // Start the service account and service account token controllers tokenController := serviceaccountcontroller.NewTokensController(rootClientset, serviceaccountcontroller.TokensControllerOptions{TokenGenerator: serviceaccount.JWTTokenGenerator(serviceAccountKey)}) tokenController.Run() serviceAccountController := serviceaccountcontroller.NewServiceAccountsController(rootClientset, serviceaccountcontroller.DefaultServiceAccountsControllerOptions()) serviceAccountController.Run() // Start the admission plugin reflectors serviceAccountAdmission.Run() stop := func() { tokenController.Stop() serviceAccountController.Stop() serviceAccountAdmission.Stop() // TODO: Uncomment when fix #19254 // apiServer.Close() } return rootClientset, clientConfig, stop }
func getTestTokenAuth() authenticator.Request { tokenAuthenticator := tokentest.New() tokenAuthenticator.Tokens[AliceToken] = &user.DefaultInfo{Name: "alice", UID: "1"} tokenAuthenticator.Tokens[BobToken] = &user.DefaultInfo{Name: "bob", UID: "2"} return group.NewGroupAdder(bearertoken.New(tokenAuthenticator), []string{user.AllAuthenticated}) }