From 05fbc22064b0502e3f66a60c82a34302850dcb41 Mon Sep 17 00:00:00 2001 From: Yang Guo Date: Thu, 25 Jan 2018 21:31:02 -0800 Subject: [PATCH] Split ClientConfigFor() --- cmd/kube-apiserver/app/server.go | 40 +++++++++------- .../plugin/webhook/config/authentication.go | 46 ++++++++++++------- .../webhook/config/authentication_test.go | 2 +- .../admission/plugin/webhook/config/client.go | 6 +-- .../plugin/webhook/mutating/admission_test.go | 7 ++- .../webhook/validating/admission_test.go | 7 ++- 6 files changed, 69 insertions(+), 39 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index f2f18749694..81482f3f4eb 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -459,29 +459,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, directRouting bool) (*rest.Config, error) { - if server == "kubernetes.default.svc" { - return genericConfig.LoopbackClientConfig, nil - } - ret, err := delegate.ClientConfigFor(server, directRouting) - if err != nil { - return nil, err - } - if !directRouting && proxyTransport != nil && proxyTransport.Dial != nil { - // Use the SSH tunnels iff the webhook server is not directly - // routable from apiserver's network environment. - 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 64aabb735eb..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,22 +31,28 @@ import ( // rest.Config generated by the resolver. type AuthenticationInfoResolverWrapper func(AuthenticationInfoResolver) AuthenticationInfoResolver -// AuthenticationInfoResolver builds rest.Config base on the server name and -// the directRouting flag indicating whether the webhook server is routable -// directly from apiserver's network environment. -// -// TODO(yguo0905): Remove the directRouting flag once the SSH tunnels that is -// used for the communication from master to nodes get removed. +// AuthenticationInfoResolver builds rest.Config base on the server or service +// name and service namespace. type AuthenticationInfoResolver interface { - ClientConfigFor(server string, directRouting bool) (*rest.Config, error) + // 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, directRouting bool) (*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, directRouting bool) (*rest.Config, error) { - return a(server, directRouting) +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 { @@ -72,14 +78,22 @@ func NewDefaultAuthenticationInfoResolver(kubeconfigFile string) (Authentication return &defaultAuthenticationInfoResolver{kubeconfig: clientConfig}, nil } -func (c *defaultAuthenticationInfoResolver) ClientConfigFor(server string, directRouting bool) (*rest.Config, error) { +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 { @@ -88,7 +102,7 @@ func (c *defaultAuthenticationInfoResolver) ClientConfigFor(server string, direc } // 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/authentication_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/authentication_test.go index b20ef2ed6bf..cd63bd94bbd 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/authentication_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/authentication_test.go @@ -114,7 +114,7 @@ func TestAuthenticationDetection(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { resolver := defaultAuthenticationInfoResolver{kubeconfig: tc.kubeconfig} - actual, err := resolver.ClientConfigFor(tc.serverName, false) + actual, err := resolver.ClientConfigFor(tc.serverName) if err != nil { t.Fatal(err) } 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 d03dc92cfda..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, false) + 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 { @@ -162,7 +162,7 @@ func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error return nil, &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Unparsable URL: %v", err)} } - restConfig, err := cm.authInfoResolver.ClientConfigFor(u.Host, true) + restConfig, err := cm.authInfoResolver.ClientConfigFor(u.Host) if err != nil { return nil, err } 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 8c9952d7ea3..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 @@ -631,7 +631,12 @@ type fakeAuthenticationInfoResolver struct { cachedCount *int32 } -func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string, directRouting bool) (*rest.Config, error) { +func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string) (*rest.Config, error) { + atomic.AddInt32(c.cachedCount, 1) + return c.restConfig, nil +} + +func (c *fakeAuthenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) { atomic.AddInt32(c.cachedCount, 1) return c.restConfig, nil } 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 81df9a3a9a4..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 @@ -656,7 +656,12 @@ type fakeAuthenticationInfoResolver struct { cachedCount *int32 } -func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string, directRouting bool) (*rest.Config, error) { +func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string) (*rest.Config, error) { + atomic.AddInt32(c.cachedCount, 1) + return c.restConfig, nil +} + +func (c *fakeAuthenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) { atomic.AddInt32(c.cachedCount, 1) return c.restConfig, nil }