diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 87eba74b8be..eb30d96f067 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -463,27 +463,35 @@ func BuildGenericConfig(s *options.ServerRunOptions, proxyTransport *http.Transp genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName) } - webhookAuthResolver := func(delegate webhookconfig.AuthenticationInfoResolver) webhookconfig.AuthenticationInfoResolver { - return webhookconfig.AuthenticationInfoResolverFunc(func(server string) (*rest.Config, error) { - if server == "kubernetes.default.svc" { - return genericConfig.LoopbackClientConfig, nil - } - ret, err := delegate.ClientConfigFor(server) - if err != nil { - return nil, err - } - if proxyTransport != nil && proxyTransport.Dial != nil { - ret.Dial = proxyTransport.Dial - } - return ret, err - }) + webhookAuthResolverWrapper := func(delegate webhookconfig.AuthenticationInfoResolver) webhookconfig.AuthenticationInfoResolver { + return &webhookconfig.AuthenticationInfoResolverDelegator{ + ClientConfigForFunc: func(server string) (*rest.Config, error) { + if server == "kubernetes.default.svc" { + return genericConfig.LoopbackClientConfig, nil + } + return delegate.ClientConfigFor(server) + }, + ClientConfigForServiceFunc: func(serviceName, serviceNamespace string) (*rest.Config, error) { + if serviceName == "kubernetes" && serviceNamespace == "default" { + return genericConfig.LoopbackClientConfig, nil + } + ret, err := delegate.ClientConfigForService(serviceName, serviceNamespace) + if err != nil { + return nil, err + } + if proxyTransport != nil && proxyTransport.Dial != nil { + ret.Dial = proxyTransport.Dial + } + return ret, err + }, + } } pluginInitializers, err := BuildAdmissionPluginInitializers( s, client, sharedInformers, serviceResolver, - webhookAuthResolver, + webhookAuthResolverWrapper, ) if err != nil { return nil, nil, nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err) diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/authentication.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/authentication.go index dd956f140a7..9b70c976e25 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/authentication.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/authentication.go @@ -31,17 +31,28 @@ import ( // rest.Config generated by the resolver. type AuthenticationInfoResolverWrapper func(AuthenticationInfoResolver) AuthenticationInfoResolver -// AuthenticationInfoResolver builds rest.Config base on the server name. +// AuthenticationInfoResolver builds rest.Config base on the server or service +// name and service namespace. type AuthenticationInfoResolver interface { + // ClientConfigFor builds rest.Config based on the server. ClientConfigFor(server string) (*rest.Config, error) + // ClientConfigForService builds rest.Config based on the serviceName and + // serviceNamespace. + ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) } -// AuthenticationInfoResolverFunc implements AuthenticationInfoResolver. -type AuthenticationInfoResolverFunc func(server string) (*rest.Config, error) +// AuthenticationInfoResolverDelegator implements AuthenticationInfoResolver. +type AuthenticationInfoResolverDelegator struct { + ClientConfigForFunc func(server string) (*rest.Config, error) + ClientConfigForServiceFunc func(serviceName, serviceNamespace string) (*rest.Config, error) +} -//ClientConfigFor implements AuthenticationInfoResolver. -func (a AuthenticationInfoResolverFunc) ClientConfigFor(server string) (*rest.Config, error) { - return a(server) +func (a *AuthenticationInfoResolverDelegator) ClientConfigFor(server string) (*rest.Config, error) { + return a.ClientConfigForFunc(server) +} + +func (a *AuthenticationInfoResolverDelegator) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) { + return a.ClientConfigForServiceFunc(serviceName, serviceNamespace) } type defaultAuthenticationInfoResolver struct { @@ -68,13 +79,21 @@ func NewDefaultAuthenticationInfoResolver(kubeconfigFile string) (Authentication } func (c *defaultAuthenticationInfoResolver) ClientConfigFor(server string) (*rest.Config, error) { + return c.clientConfig(server) +} + +func (c *defaultAuthenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) { + return c.clientConfig(serviceName + "." + serviceNamespace + ".svc") +} + +func (c *defaultAuthenticationInfoResolver) clientConfig(target string) (*rest.Config, error) { // exact match - if authConfig, ok := c.kubeconfig.AuthInfos[server]; ok { + if authConfig, ok := c.kubeconfig.AuthInfos[target]; ok { return restConfigFromKubeconfig(authConfig) } // star prefixed match - serverSteps := strings.Split(server, ".") + serverSteps := strings.Split(target, ".") for i := 1; i < len(serverSteps); i++ { nickName := "*." + strings.Join(serverSteps[i:], ".") if authConfig, ok := c.kubeconfig.AuthInfos[nickName]; ok { @@ -83,7 +102,7 @@ func (c *defaultAuthenticationInfoResolver) ClientConfigFor(server string) (*res } // if we're trying to hit the kube-apiserver and there wasn't an explicit config, use the in-cluster config - if server == "kubernetes.default.svc" { + if target == "kubernetes.default.svc" { // if we can find an in-cluster-config use that. If we can't, fall through. inClusterConfig, err := rest.InClusterConfig() if err == nil { diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/client.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/client.go index 28fac414e17..808ef944ffe 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/client.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/client.go @@ -122,12 +122,12 @@ func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error } if svc := h.ClientConfig.Service; svc != nil { - serverName := svc.Name + "." + svc.Namespace + ".svc" - restConfig, err := cm.authInfoResolver.ClientConfigFor(serverName) + restConfig, err := cm.authInfoResolver.ClientConfigForService(svc.Name, svc.Namespace) if err != nil { return nil, err } cfg := rest.CopyConfig(restConfig) + serverName := svc.Name + "." + svc.Namespace + ".svc" host := serverName + ":443" cfg.Host = "https://" + host if svc.Path != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/admission_test.go index da9c79a3b9d..9f92fad1126 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/admission_test.go @@ -636,6 +636,11 @@ func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string) (*rest.C return c.restConfig, nil } +func (c *fakeAuthenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) { + atomic.AddInt32(c.cachedCount, 1) + return c.restConfig, nil +} + func newMatchEverythingRules() []registrationv1beta1.RuleWithOperations { return []registrationv1beta1.RuleWithOperations{{ Operations: []registrationv1beta1.OperationType{registrationv1beta1.OperationAll}, diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/admission_test.go index 15271f040b4..9a190f41239 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/admission_test.go @@ -661,6 +661,11 @@ func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string) (*rest.C return c.restConfig, nil } +func (c *fakeAuthenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) { + atomic.AddInt32(c.cachedCount, 1) + return c.restConfig, nil +} + func newMatchEverythingRules() []registrationv1beta1.RuleWithOperations { return []registrationv1beta1.RuleWithOperations{{ Operations: []registrationv1beta1.OperationType{registrationv1beta1.OperationAll},