From 0458fac8c0788de022acf9308721413257392bf9 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Mon, 7 Aug 2017 11:55:35 -0400 Subject: [PATCH] Simplify bearer token auth chain, cache successful authentications --- .../app/options/options_test.go | 4 ++- pkg/kubeapiserver/authenticator/BUILD | 2 ++ pkg/kubeapiserver/authenticator/config.go | 31 ++++++++++++------- pkg/kubeapiserver/options/authentication.go | 22 +++++++++++-- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/cmd/kube-apiserver/app/options/options_test.go b/cmd/kube-apiserver/app/options/options_test.go index a7c9274303a..b96a878ec27 100644 --- a/cmd/kube-apiserver/app/options/options_test.go +++ b/cmd/kube-apiserver/app/options/options_test.go @@ -166,7 +166,9 @@ func TestAddFlagsFlag(t *testing.T) { ServiceAccounts: &kubeoptions.ServiceAccountAuthenticationOptions{ Lookup: true, }, - TokenFile: &kubeoptions.TokenFileAuthenticationOptions{}, + TokenFile: &kubeoptions.TokenFileAuthenticationOptions{}, + TokenSuccessCacheTTL: 10 * time.Second, + TokenFailureCacheTTL: 0, }, Authorization: &kubeoptions.BuiltInAuthorizationOptions{ Mode: "AlwaysDeny", diff --git a/pkg/kubeapiserver/authenticator/BUILD b/pkg/kubeapiserver/authenticator/BUILD index 5375c49a7a1..218dd289d4c 100644 --- a/pkg/kubeapiserver/authenticator/BUILD +++ b/pkg/kubeapiserver/authenticator/BUILD @@ -23,7 +23,9 @@ go_library( "//vendor/k8s.io/apiserver/pkg/authentication/request/union:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/request/websocket:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/request/x509:go_default_library", + "//vendor/k8s.io/apiserver/pkg/authentication/token/cache:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/token/tokenfile:go_default_library", + "//vendor/k8s.io/apiserver/pkg/authentication/token/union:go_default_library", "//vendor/k8s.io/apiserver/plugin/pkg/authenticator/password/keystone:go_default_library", "//vendor/k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile:go_default_library", "//vendor/k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth:go_default_library", diff --git a/pkg/kubeapiserver/authenticator/config.go b/pkg/kubeapiserver/authenticator/config.go index 418b616855c..72261cfdac4 100644 --- a/pkg/kubeapiserver/authenticator/config.go +++ b/pkg/kubeapiserver/authenticator/config.go @@ -30,7 +30,9 @@ import ( "k8s.io/apiserver/pkg/authentication/request/union" "k8s.io/apiserver/pkg/authentication/request/websocket" "k8s.io/apiserver/pkg/authentication/request/x509" + tokencache "k8s.io/apiserver/pkg/authentication/token/cache" "k8s.io/apiserver/pkg/authentication/token/tokenfile" + tokenunion "k8s.io/apiserver/pkg/authentication/token/union" "k8s.io/apiserver/plugin/pkg/authenticator/password/keystone" "k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile" "k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth" @@ -62,6 +64,9 @@ type AuthenticatorConfig struct { WebhookTokenAuthnConfigFile string WebhookTokenAuthnCacheTTL time.Duration + TokenSuccessCacheTTL time.Duration + TokenFailureCacheTTL time.Duration + RequestHeaderConfig *authenticatorfactory.RequestHeaderConfig // TODO, this is the only non-serializable part of the entire config. Factor it out into a clientconfig @@ -73,9 +78,9 @@ type AuthenticatorConfig struct { // Kubernetes authentication mechanisms. func (config AuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDefinitions, error) { var authenticators []authenticator.Request + var tokenAuthenticators []authenticator.Token securityDefinitions := spec.SecurityDefinitions{} hasBasicAuth := false - hasTokenAuth := false // front-proxy, BasicAuth methods, local first, then remote // Add the front proxy authenticator if requested @@ -125,22 +130,19 @@ func (config AuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDe if err != nil { return nil, nil, err } - authenticators = append(authenticators, bearertoken.New(tokenAuth), websocket.NewProtocolAuthenticator(tokenAuth)) - hasTokenAuth = true + tokenAuthenticators = append(tokenAuthenticators, tokenAuth) } if len(config.ServiceAccountKeyFiles) > 0 { serviceAccountAuth, err := newServiceAccountAuthenticator(config.ServiceAccountKeyFiles, config.ServiceAccountLookup, config.ServiceAccountTokenGetter) if err != nil { return nil, nil, err } - authenticators = append(authenticators, bearertoken.New(serviceAccountAuth), websocket.NewProtocolAuthenticator(serviceAccountAuth)) - hasTokenAuth = true + tokenAuthenticators = append(tokenAuthenticators, serviceAccountAuth) } if config.BootstrapToken { if config.BootstrapTokenAuthenticator != nil { // TODO: This can sometimes be nil because of - authenticators = append(authenticators, bearertoken.New(config.BootstrapTokenAuthenticator), websocket.NewProtocolAuthenticator(config.BootstrapTokenAuthenticator)) - hasTokenAuth = true + tokenAuthenticators = append(tokenAuthenticators, config.BootstrapTokenAuthenticator) } } // NOTE(ericchiang): Keep the OpenID Connect after Service Accounts. @@ -154,16 +156,14 @@ func (config AuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDe if err != nil { return nil, nil, err } - authenticators = append(authenticators, bearertoken.New(oidcAuth), websocket.NewProtocolAuthenticator(oidcAuth)) - hasTokenAuth = true + tokenAuthenticators = append(tokenAuthenticators, oidcAuth) } if len(config.WebhookTokenAuthnConfigFile) > 0 { webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnCacheTTL) if err != nil { return nil, nil, err } - authenticators = append(authenticators, bearertoken.New(webhookTokenAuth), websocket.NewProtocolAuthenticator(webhookTokenAuth)) - hasTokenAuth = true + tokenAuthenticators = append(tokenAuthenticators, webhookTokenAuth) } if hasBasicAuth { @@ -175,7 +175,14 @@ func (config AuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDe } } - if hasTokenAuth { + if len(tokenAuthenticators) > 0 { + // Union the token authenticators + tokenAuth := tokenunion.New(tokenAuthenticators...) + // Optionally cache authentication results + if config.TokenSuccessCacheTTL > 0 || config.TokenFailureCacheTTL > 0 { + tokenAuth = tokencache.New(tokenAuth, config.TokenSuccessCacheTTL, config.TokenFailureCacheTTL) + } + authenticators = append(authenticators, bearertoken.New(tokenAuth), websocket.NewProtocolAuthenticator(tokenAuth)) securityDefinitions["BearerToken"] = &spec.SecurityScheme{ SecuritySchemeProps: spec.SecuritySchemeProps{ Type: "apiKey", diff --git a/pkg/kubeapiserver/options/authentication.go b/pkg/kubeapiserver/options/authentication.go index 89a5219d6af..cc21d4cacb2 100644 --- a/pkg/kubeapiserver/options/authentication.go +++ b/pkg/kubeapiserver/options/authentication.go @@ -41,6 +41,9 @@ type BuiltInAuthenticationOptions struct { ServiceAccounts *ServiceAccountAuthenticationOptions TokenFile *TokenFileAuthenticationOptions WebHook *WebHookAuthenticationOptions + + TokenSuccessCacheTTL time.Duration + TokenFailureCacheTTL time.Duration } type AnonymousAuthenticationOptions struct { @@ -83,7 +86,10 @@ type WebHookAuthenticationOptions struct { } func NewBuiltInAuthenticationOptions() *BuiltInAuthenticationOptions { - return &BuiltInAuthenticationOptions{} + return &BuiltInAuthenticationOptions{ + TokenSuccessCacheTTL: 10 * time.Second, + TokenFailureCacheTTL: 0 * time.Second, + } } func (s *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions { @@ -250,7 +256,10 @@ func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { } func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() authenticator.AuthenticatorConfig { - ret := authenticator.AuthenticatorConfig{} + ret := authenticator.AuthenticatorConfig{ + TokenSuccessCacheTTL: s.TokenSuccessCacheTTL, + TokenFailureCacheTTL: s.TokenFailureCacheTTL, + } if s.Anonymous != nil { ret.Anonymous = s.Anonymous.Allow @@ -297,6 +306,15 @@ func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() authenticator.Au if s.WebHook != nil { ret.WebhookTokenAuthnConfigFile = s.WebHook.ConfigFile ret.WebhookTokenAuthnCacheTTL = s.WebHook.CacheTTL + + if len(s.WebHook.ConfigFile) > 0 && s.WebHook.CacheTTL > 0 { + if s.TokenSuccessCacheTTL > 0 && s.WebHook.CacheTTL < s.TokenSuccessCacheTTL { + glog.Warningf("the webhook cache ttl of %s is shorter than the overall cache ttl of %s for successful token authentication attempts.", s.WebHook.CacheTTL, s.TokenSuccessCacheTTL) + } + if s.TokenFailureCacheTTL > 0 && s.WebHook.CacheTTL < s.TokenFailureCacheTTL { + glog.Warningf("the webhook cache ttl of %s is shorter than the overall cache ttl of %s for failed token authentication attempts.", s.WebHook.CacheTTL, s.TokenFailureCacheTTL) + } + } } return ret