From f3a7f057c423caf77b0c5315d7728727c4b35bde Mon Sep 17 00:00:00 2001 From: Lukasz Szaszkiewicz Date: Tue, 28 Apr 2020 15:35:17 +0200 Subject: [PATCH] expose RunOnce method on RequestHeaderAuthRequest controller --- .../headerrequest/requestheader_controller.go | 47 +++++++++---------- .../requestheader_controller_test.go | 3 +- .../pkg/server/options/authentication.go | 5 ++ .../authentication_dynamic_request_header.go | 27 +++++++++-- 4 files changed, 52 insertions(+), 30 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller.go b/staging/src/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller.go index 889a552f1a8..9e8bc8b21d9 100644 --- a/staging/src/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller.go +++ b/staging/src/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller.go @@ -69,6 +69,7 @@ type RequestHeaderAuthRequestController struct { configmapName string configmapNamespace string + client kubernetes.Interface configmapLister corev1listers.ConfigMapNamespaceLister configmapInformer cache.SharedIndexInformer configmapInformerSynced cache.InformerSynced @@ -89,10 +90,12 @@ func NewRequestHeaderAuthRequestController( cmName string, cmNamespace string, client kubernetes.Interface, - usernameHeadersKey, groupHeadersKey, extraHeaderPrefixesKey, allowedClientNamesKey string) (*RequestHeaderAuthRequestController, error) { + usernameHeadersKey, groupHeadersKey, extraHeaderPrefixesKey, allowedClientNamesKey string) *RequestHeaderAuthRequestController { c := &RequestHeaderAuthRequestController{ name: "RequestHeaderAuthRequestController", + client: client, + configmapName: cmName, configmapNamespace: cmNamespace, @@ -104,11 +107,6 @@ func NewRequestHeaderAuthRequestController( queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "RequestHeaderAuthRequestController"), } - // use the live client to prime the controller - if err := c.syncOnce(client); err != nil { - return nil, err - } - // we construct our own informer because we need such a small subset of the information available. Just one namespace. c.configmapInformer = coreinformers.NewFilteredConfigMapInformer(client, c.configmapNamespace, 12*time.Hour, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, func(listOptions *metav1.ListOptions) { listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", c.configmapName).String() @@ -144,7 +142,7 @@ func NewRequestHeaderAuthRequestController( c.configmapLister = corev1listers.NewConfigMapLister(c.configmapInformer.GetIndexer()).ConfigMaps(c.configmapNamespace) c.configmapInformerSynced = c.configmapInformer.HasSynced - return c, nil + return c } func (c *RequestHeaderAuthRequestController) UsernameHeaders() []string { @@ -184,6 +182,24 @@ func (c *RequestHeaderAuthRequestController) Run(workers int, stopCh <-chan stru <-stopCh } +// // RunOnce runs a single sync loop +func (c *RequestHeaderAuthRequestController) RunOnce() error { + configMap, err := c.client.CoreV1().ConfigMaps(c.configmapNamespace).Get(context.TODO(), c.configmapName, metav1.GetOptions{}) + switch { + case errors.IsNotFound(err): + // ignore, authConfigMap is nil now + return nil + case errors.IsForbidden(err): + klog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+ + "'kubectl create rolebinding -n %s ROLEBINDING_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'", + c.configmapName, c.configmapNamespace, c.configmapNamespace, authenticationRoleName) + return err + case err != nil: + return err + } + return c.syncConfigMap(configMap) +} + func (c *RequestHeaderAuthRequestController) runWorker() { for c.processNextWorkItem() { } @@ -208,23 +224,6 @@ func (c *RequestHeaderAuthRequestController) processNextWorkItem() bool { return true } -func (c *RequestHeaderAuthRequestController) syncOnce(client kubernetes.Interface) error { - configMap, err := client.CoreV1().ConfigMaps(c.configmapNamespace).Get(context.TODO(), c.configmapName, metav1.GetOptions{}) - switch { - case errors.IsNotFound(err): - // ignore, authConfigMap is nil now - return nil - case errors.IsForbidden(err): - klog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+ - "'kubectl create rolebinding -n %s ROLEBINDING_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'", - c.configmapName, c.configmapNamespace, c.configmapNamespace, authenticationRoleName) - return err - case err != nil: - return err - } - return c.syncConfigMap(configMap) -} - // sync reads the config and propagates the changes to exportedRequestHeaderBundle // which is exposed by the set of methods that are used to fill RequestHeaderConfig struct func (c *RequestHeaderAuthRequestController) sync() error { diff --git a/staging/src/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller_test.go b/staging/src/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller_test.go index 07c299398f6..2577d2635b2 100644 --- a/staging/src/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller_test.go +++ b/staging/src/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller_test.go @@ -218,9 +218,10 @@ func TestRequestHeaderAuthRequestControllerSyncOnce(t *testing.T) { // test data target := newDefaultTarget() fakeKubeClient := fake.NewSimpleClientset(scenario.cm) + target.client = fakeKubeClient // act - err := target.syncOnce(fakeKubeClient) + err := target.RunOnce() if err != nil && !scenario.expectErr { t.Errorf("got unexpected error %v", err) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go b/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go index 86ef6feccd7..e2e2d33451b 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go @@ -335,6 +335,11 @@ func (s *DelegatingAuthenticationOptions) createRequestHeaderConfig(client kuber return nil, fmt.Errorf("unable to create request header authentication config: %v", err) } + // look up authentication configuration in the cluster and in case of an err defer to authentication-tolerate-lookup-failure flag + if err := dynamicRequestHeaderProvider.RunOnce(); err != nil { + return nil, err + } + return &authenticatorfactory.RequestHeaderConfig{ CAContentProvider: dynamicRequestHeaderProvider, UsernameHeaders: headerrequest.StringSliceProvider(headerrequest.StringSliceProviderFunc(dynamicRequestHeaderProvider.UsernameHeaders)), diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/authentication_dynamic_request_header.go b/staging/src/k8s.io/apiserver/pkg/server/options/authentication_dynamic_request_header.go index 9f11f728dec..5c558b06d68 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/authentication_dynamic_request_header.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/authentication_dynamic_request_header.go @@ -1,8 +1,25 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package options import ( "fmt" + "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apiserver/pkg/authentication/request/headerrequest" "k8s.io/apiserver/pkg/server/dynamiccertificates" "k8s.io/client-go/kubernetes" @@ -33,7 +50,7 @@ func newDynamicRequestHeaderController(client kubernetes.Interface) (*DynamicReq return nil, fmt.Errorf("unable to create DynamicCAFromConfigMap controller: %v", err) } - requestHeaderAuthRequestController, err := headerrequest.NewRequestHeaderAuthRequestController( + requestHeaderAuthRequestController := headerrequest.NewRequestHeaderAuthRequestController( authenticationConfigMapName, authenticationConfigMapNamespace, client, @@ -42,9 +59,6 @@ func newDynamicRequestHeaderController(client kubernetes.Interface) (*DynamicReq "requestheader-extra-headers-prefix", "requestheader-allowed-names", ) - if err != nil { - return nil, fmt.Errorf("unable to create RequestHeaderAuthRequest controller: %v", err) - } return &DynamicRequestHeaderController{ ConfigMapCAController: requestHeaderCAController, RequestHeaderAuthRequestController: requestHeaderAuthRequestController, @@ -52,7 +66,10 @@ func newDynamicRequestHeaderController(client kubernetes.Interface) (*DynamicReq } func (c *DynamicRequestHeaderController) RunOnce() error { - return c.ConfigMapCAController.RunOnce() + errs := []error{} + errs = append(errs, c.ConfigMapCAController.RunOnce()) + errs = append(errs, c.RequestHeaderAuthRequestController.RunOnce()) + return errors.NewAggregate(errs) } func (c *DynamicRequestHeaderController) Run(workers int, stopCh <-chan struct{}) {