From 798d3edabf6c6745ded1f99a9fad3257092e531e Mon Sep 17 00:00:00 2001 From: deads2k Date: Wed, 7 Dec 2016 09:19:13 -0500 Subject: [PATCH] add authentication/authorization to kubernetes-discovery --- .../pkg/cmd/server/start.go | 20 ++++++++-- hack/local-up-cluster.sh | 21 ++++++++-- pkg/genericapiserver/config.go | 40 +++++++++++++++++++ pkg/genericapiserver/options/authorization.go | 13 +++++- 4 files changed, 84 insertions(+), 10 deletions(-) diff --git a/cmd/kubernetes-discovery/pkg/cmd/server/start.go b/cmd/kubernetes-discovery/pkg/cmd/server/start.go index 009dd16d6dd..894512551de 100644 --- a/cmd/kubernetes-discovery/pkg/cmd/server/start.go +++ b/cmd/kubernetes-discovery/pkg/cmd/server/start.go @@ -40,8 +40,10 @@ import ( const defaultEtcdPathPrefix = "/registry/kubernetes.io/kubernetes-discovery" type DiscoveryServerOptions struct { - Etcd *genericoptions.EtcdOptions - SecureServing *genericoptions.SecureServingOptions + Etcd *genericoptions.EtcdOptions + SecureServing *genericoptions.SecureServingOptions + Authentication *genericoptions.DelegatingAuthenticationOptions + Authorization *genericoptions.DelegatingAuthorizationOptions StdOut io.Writer StdErr io.Writer @@ -50,8 +52,10 @@ type DiscoveryServerOptions struct { // NewCommandStartMaster provides a CLI handler for 'start master' command func NewCommandStartDiscoveryServer(out, err io.Writer) *cobra.Command { o := &DiscoveryServerOptions{ - Etcd: genericoptions.NewEtcdOptions(), - SecureServing: genericoptions.NewSecureServingOptions(), + Etcd: genericoptions.NewEtcdOptions(), + SecureServing: genericoptions.NewSecureServingOptions(), + Authentication: genericoptions.NewDelegatingAuthenticationOptions(), + Authorization: genericoptions.NewDelegatingAuthorizationOptions(), StdOut: out, StdErr: err, @@ -73,6 +77,8 @@ func NewCommandStartDiscoveryServer(out, err io.Writer) *cobra.Command { flags := cmd.Flags() o.Etcd.AddFlags(flags) o.SecureServing.AddFlags(flags) + o.Authentication.AddFlags(flags) + o.Authorization.AddFlags(flags) return cmd } @@ -100,6 +106,12 @@ func (o DiscoveryServerOptions) RunDiscoveryServer() error { if _, err := genericAPIServerConfig.ApplySecureServingOptions(o.SecureServing); err != nil { return err } + if _, err := genericAPIServerConfig.ApplyDelegatingAuthenticationOptions(o.Authentication); err != nil { + return err + } + if _, err := genericAPIServerConfig.ApplyDelegatingAuthorizationOptions(o.Authorization); err != nil { + return err + } var err error privilegedLoopbackToken := uuid.NewRandom().String() diff --git a/hack/local-up-cluster.sh b/hack/local-up-cluster.sh index 1e6c686342f..0d475207022 100755 --- a/hack/local-up-cluster.sh +++ b/hack/local-up-cluster.sh @@ -444,7 +444,7 @@ EOF create_client_certkey client-ca kube-proxy system:kube-proxy system:nodes create_client_certkey client-ca controller system:controller system:masters create_client_certkey client-ca scheduler system:scheduler system:masters - create_client_certkey client-ca admin system:admin system:cluster-admins + create_client_certkey client-ca admin system:admin system:masters # Create auth proxy client ca sudo /bin/bash -e <"${APISERVER_LOG}" 2>&1 & APISERVER_PID=$! @@ -486,6 +486,7 @@ EOF kube::util::wait_for_url "https://${API_HOST}:${API_SECURE_PORT}/version" "apiserver: " 1 ${WAIT_FOR_URL_API_SERVER} || exit 1 # Create kubeconfigs for all components, using client certs + write_client_kubeconfig admin write_client_kubeconfig kubelet write_client_kubeconfig kube-proxy write_client_kubeconfig controller @@ -509,11 +510,23 @@ EOF # start_discovery relies on certificates created by start_apiserver function start_discovery { # TODO generate serving certificates - + create_client_certkey client-ca discovery-auth system:discovery-auth + write_client_kubeconfig discovery-auth + + # grant permission to run delegated authentication and authorization checks + kubectl create clusterrolebinding discovery:system:auth-delegator --clusterrole=system:auth-delegator --user=system:discovery-auth + DISCOVERY_SERVER_LOG=/tmp/kubernetes-discovery.log ${CONTROLPLANE_SUDO} "${GO_OUT}/kubernetes-discovery" \ --cert-dir="${CERT_DIR}" \ --client-ca-file="${CERT_DIR}/client-ca-bundle.crt" \ + --authentication-kubeconfig="${CERT_DIR}/discovery-auth.kubeconfig" \ + --authorization-kubeconfig="${CERT_DIR}/discovery-auth.kubeconfig" \ + --requestheader-username-headers=X-Remote-User \ + --requestheader-group-headers=X-Remote-Group \ + --requestheader-extra-headers-prefix=X-Remote-Extra- \ + --requestheader-client-ca-file="${CERT_DIR}/auth-proxy-client-ca.crt" \ + --requestheader-allowed-names=system:auth-proxy \ --bind-address="${API_BIND_ADDR}" \ --secure-port="${DISCOVERY_SECURE_PORT}" \ --tls-ca-file="${ROOT_CA_FILE}" \ @@ -800,7 +813,7 @@ if [[ "${START_MODE}" != "kubeletonly" ]]; then start_etcd set_service_accounts start_apiserver - # start_discovery + start_discovery start_controller_manager start_kubeproxy start_kubedns diff --git a/pkg/genericapiserver/config.go b/pkg/genericapiserver/config.go index 38c7d6b5b4e..bee7be97db2 100644 --- a/pkg/genericapiserver/config.go +++ b/pkg/genericapiserver/config.go @@ -343,6 +343,46 @@ func (c *Config) ApplyAuthenticationOptions(o *options.BuiltInAuthenticationOpti return c, nil } +func (c *Config) ApplyDelegatingAuthenticationOptions(o *options.DelegatingAuthenticationOptions) (*Config, error) { + if o == nil { + return c, nil + } + + cfg, err := o.ToAuthenticationConfig() + if err != nil { + return nil, err + } + authenticator, securityDefinitions, err := cfg.New() + if err != nil { + return nil, err + } + + c.Authenticator = authenticator + c.OpenAPIConfig.SecurityDefinitions = securityDefinitions + c.SupportsBasicAuth = false + + return c, nil +} + +func (c *Config) ApplyDelegatingAuthorizationOptions(o *options.DelegatingAuthorizationOptions) (*Config, error) { + if o == nil { + return c, nil + } + + cfg, err := o.ToAuthorizationConfig() + if err != nil { + return nil, err + } + authorizer, err := cfg.New() + if err != nil { + return nil, err + } + + c.Authorizer = authorizer + + return c, nil +} + // ApplyOptions applies the run options to the method receiver and returns self func (c *Config) ApplyOptions(options *options.ServerRunOptions) *Config { if len(options.AuditLogPath) != 0 { diff --git a/pkg/genericapiserver/options/authorization.go b/pkg/genericapiserver/options/authorization.go index f43d30b9692..b99eec87fcd 100644 --- a/pkg/genericapiserver/options/authorization.go +++ b/pkg/genericapiserver/options/authorization.go @@ -111,8 +111,9 @@ type DelegatingAuthorizationOptions struct { func NewDelegatingAuthorizationOptions() *DelegatingAuthorizationOptions { return &DelegatingAuthorizationOptions{ - AllowCacheTTL: 5 * time.Minute, - DenyCacheTTL: 30 * time.Second, + // very low for responsiveness, but high enough to handle storms + AllowCacheTTL: 10 * time.Second, + DenyCacheTTL: 10 * time.Second, } } @@ -125,6 +126,14 @@ func (s *DelegatingAuthorizationOptions) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.RemoteKubeConfigFile, "authorization-kubeconfig", s.RemoteKubeConfigFile, ""+ "kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+ " subjectaccessreviews.authorization.k8s.io.") + + fs.DurationVar(&s.AllowCacheTTL, "authorization-webhook-cache-authorized-ttl", + s.AllowCacheTTL, + "The duration to cache 'authorized' responses from the webhook authorizer.") + + fs.DurationVar(&s.DenyCacheTTL, + "authorization-webhook-cache-unauthorized-ttl", s.DenyCacheTTL, + "The duration to cache 'unauthorized' responses from the webhook authorizer.") } func (s *DelegatingAuthorizationOptions) ToAuthorizationConfig() (authorizer.DelegatingAuthorizerConfig, error) {