From ab9a842f3c7f6d7b20a07a87332e555aa73c2389 Mon Sep 17 00:00:00 2001 From: deads2k Date: Thu, 10 Nov 2016 14:42:00 -0500 Subject: [PATCH] add loopback auth defaulting to generic apiserver --- cmd/kube-apiserver/app/BUILD | 3 --- cmd/kube-apiserver/app/server.go | 27 ++----------------- federation/cmd/federation-apiserver/app/BUILD | 3 --- .../cmd/federation-apiserver/app/server.go | 27 ++----------------- pkg/genericapiserver/BUILD | 6 +++++ pkg/genericapiserver/authorizer/delegating.go | 2 +- pkg/genericapiserver/config.go | 27 ++++++++++++++++++- .../options/authentication.go | 10 ++++--- pkg/genericapiserver/options/authorization.go | 19 ++++++++----- 9 files changed, 56 insertions(+), 68 deletions(-) diff --git a/cmd/kube-apiserver/app/BUILD b/cmd/kube-apiserver/app/BUILD index 322419ed9a1..b17e4ec7f4e 100644 --- a/cmd/kube-apiserver/app/BUILD +++ b/cmd/kube-apiserver/app/BUILD @@ -26,8 +26,6 @@ go_library( "//pkg/apis/extensions:go_default_library", "//pkg/apiserver:go_default_library", "//pkg/apiserver/authenticator:go_default_library", - "//pkg/auth/authorizer/union:go_default_library", - "//pkg/auth/user:go_default_library", "//pkg/capabilities:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/cloudprovider:go_default_library", @@ -64,7 +62,6 @@ go_library( "//plugin/pkg/admission/securitycontext/scdeny:go_default_library", "//plugin/pkg/admission/serviceaccount:go_default_library", "//plugin/pkg/admission/storageclass/default:go_default_library", - "//plugin/pkg/auth/authenticator/request/union:go_default_library", "//vendor:github.com/golang/glog", "//vendor:github.com/pborman/uuid", "//vendor:github.com/spf13/cobra", diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index d0d014625b7..e2b233e5137 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -41,8 +41,6 @@ import ( "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apiserver" "k8s.io/kubernetes/pkg/apiserver/authenticator" - authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union" - "k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/cloudprovider" @@ -59,7 +57,6 @@ import ( utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/version" - authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union" ) // NewAPIServerCommand creates a *cobra.Command object with default parameters @@ -94,8 +91,7 @@ func Run(s *options.ServerRunOptions) error { ApplySecureServingOptions(s.SecureServing). ApplyInsecureServingOptions(s.InsecureServing). ApplyAuthenticationOptions(s.Authentication). - ApplyRBACSuperUser(s.Authorization.RBACSuperUser). - Complete() // set default values based on the known values + ApplyRBACSuperUser(s.Authorization.RBACSuperUser) serviceIPRange, apiServerServiceIP, err := genericapiserver.DefaultServiceIPRange(s.GenericServerRunOptions.ServiceClusterIPRange) if err != nil { @@ -253,26 +249,7 @@ func Run(s *options.ServerRunOptions) error { } admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") - - // TODO(dims): We probably need to add an option "EnableLoopbackToken" - if apiAuthenticator != nil { - 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 := authenticator.NewAuthenticatorFromTokens(tokens) - apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator) - - tokenAuthorizer := authorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup) - apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer) - } - pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) - admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) if err != nil { glog.Fatalf("Failed to initialize plugins: %v", err) @@ -297,7 +274,7 @@ func Run(s *options.ServerRunOptions) error { genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions config := &master.Config{ - GenericConfig: genericConfig.Config, + GenericConfig: genericConfig, StorageFactory: storageFactory, EnableWatchCache: s.GenericServerRunOptions.EnableWatchCache, diff --git a/federation/cmd/federation-apiserver/app/BUILD b/federation/cmd/federation-apiserver/app/BUILD index 3194543485b..46fa167c6f1 100644 --- a/federation/cmd/federation-apiserver/app/BUILD +++ b/federation/cmd/federation-apiserver/app/BUILD @@ -36,8 +36,6 @@ go_library( "//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions/install:go_default_library", "//pkg/apiserver/authenticator:go_default_library", - "//pkg/auth/authorizer/union:go_default_library", - "//pkg/auth/user:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/cloudprovider/providers:go_default_library", "//pkg/controller/informers:go_default_library", @@ -66,7 +64,6 @@ go_library( "//plugin/pkg/admission/deny:go_default_library", "//plugin/pkg/admission/gc:go_default_library", "//plugin/pkg/admission/namespace/lifecycle:go_default_library", - "//plugin/pkg/auth/authenticator/request/union:go_default_library", "//vendor:github.com/golang/glog", "//vendor:github.com/pborman/uuid", "//vendor:github.com/spf13/cobra", diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 5663528f251..0c4d118268f 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -32,8 +32,6 @@ import ( "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apiserver/authenticator" - authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union" - "k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/controller/informers" "k8s.io/kubernetes/pkg/generated/openapi" @@ -48,7 +46,6 @@ import ( utilerrors "k8s.io/kubernetes/pkg/util/errors" "k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/version" - authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union" ) // NewAPIServerCommand creates a *cobra.Command object with default parameters @@ -82,8 +79,7 @@ func Run(s *options.ServerRunOptions) error { ApplySecureServingOptions(s.SecureServing). ApplyInsecureServingOptions(s.InsecureServing). ApplyAuthenticationOptions(s.Authentication). - ApplyRBACSuperUser(s.Authorization.RBACSuperUser). - Complete() // set default values based on the known values + ApplyRBACSuperUser(s.Authorization.RBACSuperUser) if err := genericConfig.MaybeGenerateServingCerts(); err != nil { glog.Fatalf("Failed to generate service certificate: %v", err) @@ -151,26 +147,7 @@ func Run(s *options.ServerRunOptions) error { } admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") - - // TODO(dims): We probably need to add an option "EnableLoopbackToken" - if apiAuthenticator != nil { - 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 := authenticator.NewAuthenticatorFromTokens(tokens) - apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator) - - tokenAuthorizer := authorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup) - apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer) - } - pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) - admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) if err != nil { glog.Fatalf("Failed to initialize plugins: %v", err) @@ -193,7 +170,7 @@ func Run(s *options.ServerRunOptions) error { cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) } - m, err := genericConfig.New() + m, err := genericConfig.Complete().New() if err != nil { return err } diff --git a/pkg/genericapiserver/BUILD b/pkg/genericapiserver/BUILD index ccc566ad104..4cd42b49129 100644 --- a/pkg/genericapiserver/BUILD +++ b/pkg/genericapiserver/BUILD @@ -38,14 +38,18 @@ go_library( "//pkg/apimachinery:go_default_library", "//pkg/apimachinery/registered:go_default_library", "//pkg/apiserver:go_default_library", + "//pkg/apiserver/authenticator:go_default_library", "//pkg/apiserver/filters:go_default_library", "//pkg/apiserver/openapi:go_default_library", "//pkg/apiserver/request:go_default_library", "//pkg/auth/authenticator:go_default_library", "//pkg/auth/authorizer:go_default_library", + "//pkg/auth/authorizer/union:go_default_library", "//pkg/auth/handlers:go_default_library", + "//pkg/auth/user:go_default_library", "//pkg/client/restclient:go_default_library", "//pkg/cloudprovider:go_default_library", + "//pkg/genericapiserver/authorizer:go_default_library", "//pkg/genericapiserver/filters:go_default_library", "//pkg/genericapiserver/mux:go_default_library", "//pkg/genericapiserver/openapi/common:go_default_library", @@ -70,10 +74,12 @@ go_library( "//pkg/util/validation:go_default_library", "//pkg/util/wait:go_default_library", "//pkg/version:go_default_library", + "//plugin/pkg/auth/authenticator/request/union:go_default_library", "//vendor:github.com/coreos/go-systemd/daemon", "//vendor:github.com/emicklei/go-restful", "//vendor:github.com/go-openapi/spec", "//vendor:github.com/golang/glog", + "//vendor:github.com/pborman/uuid", "//vendor:github.com/pkg/errors", "//vendor:github.com/prometheus/client_golang/prometheus", "//vendor:gopkg.in/natefinch/lumberjack.v2", diff --git a/pkg/genericapiserver/authorizer/delegating.go b/pkg/genericapiserver/authorizer/delegating.go index 311b6131be8..ff7992b502f 100644 --- a/pkg/genericapiserver/authorizer/delegating.go +++ b/pkg/genericapiserver/authorizer/delegating.go @@ -25,7 +25,7 @@ import ( ) // DelegatingAuthorizerConfig is the minimal configuration needed to create an authenticator -// built to delegate authentication to a kube API server +// built to delegate authorization to a kube API server type DelegatingAuthorizerConfig struct { SubjectAccessReviewClient authorizationclient.SubjectAccessReviewInterface diff --git a/pkg/genericapiserver/config.go b/pkg/genericapiserver/config.go index 866f3963ff4..e19f8419a0b 100644 --- a/pkg/genericapiserver/config.go +++ b/pkg/genericapiserver/config.go @@ -32,20 +32,25 @@ import ( "github.com/go-openapi/spec" "github.com/golang/glog" + "github.com/pborman/uuid" "gopkg.in/natefinch/lumberjack.v2" "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/v1" + apiserverauthenticator "k8s.io/kubernetes/pkg/apiserver/authenticator" apiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters" apiserveropenapi "k8s.io/kubernetes/pkg/apiserver/openapi" "k8s.io/kubernetes/pkg/apiserver/request" "k8s.io/kubernetes/pkg/auth/authenticator" "k8s.io/kubernetes/pkg/auth/authorizer" + authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union" authhandlers "k8s.io/kubernetes/pkg/auth/handlers" + "k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/cloudprovider" + apiserverauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer" genericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters" "k8s.io/kubernetes/pkg/genericapiserver/mux" "k8s.io/kubernetes/pkg/genericapiserver/openapi/common" @@ -56,6 +61,7 @@ import ( certutil "k8s.io/kubernetes/pkg/util/cert" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/version" + authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union" ) const ( @@ -360,6 +366,25 @@ func (c *Config) Complete() completedConfig { c.DiscoveryAddresses = DefaultDiscoveryAddresses{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.Authenticator != nil && c.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 := apiserverauthenticator.NewAuthenticatorFromTokens(tokens) + c.Authenticator = authenticatorunion.New(tokenAuthenticator, c.Authenticator) + + tokenAuthorizer := apiserverauthorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup) + c.Authorizer = authorizerunion.New(tokenAuthorizer, c.Authorizer) + } + return completedConfig{c} } @@ -428,7 +453,7 @@ func (c completedConfig) New() (*GenericAPIServer, error) { } // MaybeGenerateServingCerts generates serving certificates if requested and needed. -func (c completedConfig) MaybeGenerateServingCerts(alternateIPs ...net.IP) error { +func (c *Config) MaybeGenerateServingCerts(alternateIPs ...net.IP) error { // It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless // alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME") if c.SecureServingInfo != nil && c.SecureServingInfo.ServerCert.Generate && !certutil.CanReadCertOrKey(c.SecureServingInfo.ServerCert.CertFile, c.SecureServingInfo.ServerCert.KeyFile) { diff --git a/pkg/genericapiserver/options/authentication.go b/pkg/genericapiserver/options/authentication.go index 83dda7cc506..ecf09887626 100644 --- a/pkg/genericapiserver/options/authentication.go +++ b/pkg/genericapiserver/options/authentication.go @@ -313,7 +313,7 @@ func (s *RequestHeaderAuthenticationOptions) AuthenticationRequestHeaderConfig() // the root kube API server type DelegatingAuthenticationOptions struct { // RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the - // TokenAcessReview.authentication.k8s.io endpoint for checking tokens. + // TokenAccessReview.authentication.k8s.io endpoint for checking tokens. RemoteKubeConfigFile string // CacheTTL is the length of time that a token authentication answer will be cached. @@ -334,7 +334,7 @@ func (s *DelegatingAuthenticationOptions) Validate() []error { func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.RemoteKubeConfigFile, "authentication-kubeconfig", s.RemoteKubeConfigFile, ""+ "kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+ - " tokenaccessreviews.authencation.k8s.io.") + " tokenaccessreviews.authentication.k8s.io.") } func (s *DelegatingAuthenticationOptions) ToAuthenticationConfig(clientCAFile string) (authenticator.DelegatingAuthenticatorConfig, error) { @@ -357,14 +357,16 @@ func (s *DelegatingAuthenticationOptions) newTokenAccessReview() (authentication return nil, nil } - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - loadingRules.ExplicitPath = s.RemoteKubeConfigFile + loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile} loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) clientConfig, err := loader.ClientConfig() if err != nil { return nil, err } + // set high qps/burst limits since this will effectively limit API server responsiveness + clientConfig.QPS = 200 + clientConfig.Burst = 400 client, err := authenticationclient.NewForConfig(clientConfig) if err != nil { diff --git a/pkg/genericapiserver/options/authorization.go b/pkg/genericapiserver/options/authorization.go index c864394c351..869e511b5c4 100644 --- a/pkg/genericapiserver/options/authorization.go +++ b/pkg/genericapiserver/options/authorization.go @@ -79,8 +79,13 @@ func (s *BuiltInAuthorizationOptions) AddFlags(fs *pflag.FlagSet) { } func (s *BuiltInAuthorizationOptions) ToAuthorizationConfig(informerFactory informers.SharedInformerFactory) authorizer.AuthorizationConfig { + modes := []string{} + if len(s.Mode) > 0 { + modes = strings.Split(s.Mode, ",") + } + return authorizer.AuthorizationConfig{ - AuthorizationModes: strings.Split(s.Mode, ","), + AuthorizationModes: modes, PolicyFile: s.PolicyFile, WebhookConfigFile: s.WebhookConfigFile, WebhookCacheAuthorizedTTL: s.WebhookCacheAuthorizedTTL, @@ -94,7 +99,7 @@ func (s *BuiltInAuthorizationOptions) ToAuthorizationConfig(informerFactory info // the root kube API server type DelegatingAuthorizationOptions struct { // RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the - // TokenAcessReview.authentication.k8s.io endpoint for checking tokens. + // SubjectAccessReview.authorization.k8s.io endpoint for checking tokens. RemoteKubeConfigFile string // AllowCacheTTL is the length of time that a successful authorization response will be cached @@ -124,13 +129,13 @@ func (s *DelegatingAuthorizationOptions) AddFlags(fs *pflag.FlagSet) { } func (s *DelegatingAuthorizationOptions) ToAuthorizationConfig() (authorizer.DelegatingAuthorizerConfig, error) { - tokenClient, err := s.newSubjectAccessReview() + sarClient, err := s.newSubjectAccessReview() if err != nil { return authorizer.DelegatingAuthorizerConfig{}, err } ret := authorizer.DelegatingAuthorizerConfig{ - SubjectAccessReviewClient: tokenClient, + SubjectAccessReviewClient: sarClient, AllowCacheTTL: s.AllowCacheTTL, DenyCacheTTL: s.DenyCacheTTL, } @@ -142,14 +147,16 @@ func (s *DelegatingAuthorizationOptions) newSubjectAccessReview() (authorization return nil, nil } - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - loadingRules.ExplicitPath = s.RemoteKubeConfigFile + loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile} loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) clientConfig, err := loader.ClientConfig() if err != nil { return nil, err } + // set high qps/burst limits since this will effectively limit API server responsiveness + clientConfig.QPS = 200 + clientConfig.Burst = 400 client, err := authorizationclient.NewForConfig(clientConfig) if err != nil {