From dc0a736d1ea924dfa35ece64cb59d551c2a0b51f Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Wed, 4 Jul 2018 17:08:23 +0200 Subject: [PATCH] apiserver: make loopback logic in SecureServingOptions reusable --- cmd/kube-apiserver/app/server.go | 2 +- .../src/k8s.io/apiserver/pkg/server/config.go | 42 +++++++++++-------- .../pkg/server/options/recommended.go | 2 +- .../pkg/server/options/serving_test.go | 2 +- .../server/options/serving_with_loopback.go | 19 +++++---- 5 files changed, 37 insertions(+), 30 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index b44e1abad1a..033dda2d29f 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -433,7 +433,7 @@ func BuildGenericConfig( if insecureServingInfo, lastErr = s.InsecureServing.ApplyTo(genericConfig); lastErr != nil { return } - if lastErr = s.SecureServing.ApplyTo(genericConfig); lastErr != nil { + if lastErr = s.SecureServing.ApplyTo(&genericConfig.SecureServing, &genericConfig.LoopbackClientConfig); lastErr != nil { return } if lastErr = s.Authentication.ApplyTo(genericConfig); lastErr != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/server/config.go b/staging/src/k8s.io/apiserver/pkg/server/config.go index 43fb57cd468..45d53184440 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -410,24 +410,7 @@ func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedCo c.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: c.ExternalAddress} } - // If the loopbackclientconfig is specified AND it has a token for use against the API server - // wrap the authenticator and authorizer in loopback authentication logic - if c.Authentication.Authenticator != nil && c.Authorization.Authorizer != nil && c.LoopbackClientConfig != nil && len(c.LoopbackClientConfig.BearerToken) > 0 { - privilegedLoopbackToken := c.LoopbackClientConfig.BearerToken - var uid = uuid.NewRandom().String() - tokens := make(map[string]*user.DefaultInfo) - tokens[privilegedLoopbackToken] = &user.DefaultInfo{ - Name: user.APIServerUser, - UID: uid, - Groups: []string{user.SystemPrivilegedGroup}, - } - - tokenAuthenticator := authenticatorfactory.NewFromTokens(tokens) - c.Authentication.Authenticator = authenticatorunion.New(tokenAuthenticator, c.Authentication.Authenticator) - - tokenAuthorizer := authorizerfactory.NewPrivilegedGroups(user.SystemPrivilegedGroup) - c.Authorization.Authorizer = authorizerunion.New(tokenAuthorizer, c.Authorization.Authorizer) - } + AuthorizeClientBearerToken(c.LoopbackClientConfig, &c.Authentication, &c.Authorization) if c.RequestInfoResolver == nil { c.RequestInfoResolver = NewRequestInfoResolver(c) @@ -632,3 +615,26 @@ func (s *SecureServingInfo) HostPort() (string, int, error) { } return host, port, nil } + +// AuthorizeClientBearerToken wraps the authenticator and authorizer in loopback authentication logic +// if the loopback client config is specified AND it has a bearer token. +func AuthorizeClientBearerToken(loopback *restclient.Config, authn *AuthenticationInfo, authz *AuthorizationInfo) { + if loopback == nil || authn == nil || authz == nil || authn.Authenticator == nil && authz.Authorizer == nil || len(loopback.BearerToken) == 0 { + return + } + + privilegedLoopbackToken := loopback.BearerToken + var uid = uuid.NewRandom().String() + tokens := make(map[string]*user.DefaultInfo) + tokens[privilegedLoopbackToken] = &user.DefaultInfo{ + Name: user.APIServerUser, + UID: uid, + Groups: []string{user.SystemPrivilegedGroup}, + } + + tokenAuthenticator := authenticatorfactory.NewFromTokens(tokens) + authn.Authenticator = authenticatorunion.New(tokenAuthenticator, authn.Authenticator) + + tokenAuthorizer := authorizerfactory.NewPrivilegedGroups(user.SystemPrivilegedGroup) + authz.Authorizer = authorizerunion.New(tokenAuthorizer, authz.Authorizer) +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go b/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go index ebd750c2b21..d792d875159 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go @@ -83,7 +83,7 @@ func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig, scheme *r if err := o.Etcd.ApplyTo(&config.Config); err != nil { return err } - if err := o.SecureServing.ApplyTo(&config.Config); err != nil { + if err := o.SecureServing.ApplyTo(&config.Config.SecureServing, &config.Config.LoopbackClientConfig); err != nil { return err } if err := o.Authentication.ApplyTo(&config.Config.Authentication, config.SecureServing, config.OpenAPIConfig); err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go b/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go index 9edfe42692b..939566a027a 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go @@ -485,7 +485,7 @@ func TestServerRunWithSNI(t *testing.T) { // get port secureOptions.BindPort = ln.Addr().(*net.TCPAddr).Port config.LoopbackClientConfig = &restclient.Config{} - if err := secureOptions.ApplyTo(&config); err != nil { + if err := secureOptions.ApplyTo(&config.SecureServing, &config.LoopbackClientConfig); err != nil { t.Fatalf("failed applying the SecureServingOptions: %v", err) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go b/staging/src/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go index dd6e0e1a7f5..df4750d9ac0 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go @@ -23,6 +23,7 @@ import ( "github.com/pborman/uuid" "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/rest" certutil "k8s.io/client-go/util/cert" ) @@ -35,16 +36,16 @@ func WithLoopback(o *SecureServingOptions) *SecureServingOptionsWithLoopback { } // ApplyTo fills up serving information in the server configuration. -func (s *SecureServingOptionsWithLoopback) ApplyTo(c *server.Config) error { - if s == nil || s.SecureServingOptions == nil { +func (s *SecureServingOptionsWithLoopback) ApplyTo(secureServingInfo **server.SecureServingInfo, loopbackClientConfig **rest.Config) error { + if s == nil || s.SecureServingOptions == nil || secureServingInfo == nil { return nil } - if err := s.SecureServingOptions.ApplyTo(&c.SecureServing); err != nil { + if err := s.SecureServingOptions.ApplyTo(secureServingInfo); err != nil { return err } - if c.SecureServing == nil { + if *secureServingInfo == nil || loopbackClientConfig == nil { return nil } @@ -59,18 +60,18 @@ func (s *SecureServingOptionsWithLoopback) ApplyTo(c *server.Config) error { return fmt.Errorf("failed to generate self-signed certificate for loopback connection: %v", err) } - secureLoopbackClientConfig, err := c.SecureServing.NewLoopbackClientConfig(uuid.NewRandom().String(), certPem) + secureLoopbackClientConfig, err := (*secureServingInfo).NewLoopbackClientConfig(uuid.NewRandom().String(), certPem) switch { // if we failed and there's no fallback loopback client config, we need to fail - case err != nil && c.LoopbackClientConfig == nil: + case err != nil && secureLoopbackClientConfig == nil: return err // if we failed, but we already have a fallback loopback client config (usually insecure), allow it - case err != nil && c.LoopbackClientConfig != nil: + case err != nil && secureLoopbackClientConfig != nil: default: - c.LoopbackClientConfig = secureLoopbackClientConfig - c.SecureServing.SNICerts[server.LoopbackClientServerNameOverride] = &tlsCert + *loopbackClientConfig = secureLoopbackClientConfig + (*secureServingInfo).SNICerts[server.LoopbackClientServerNameOverride] = &tlsCert } return nil