From bbb47768d7034d53818328a5fd28ad2cdb40b91b Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Mon, 21 Dec 2020 09:47:18 +0200 Subject: [PATCH] Setup impersonation for GC and health checks Signed-off-by: Stefan Prodan --- .github/workflows/e2e.yaml | 2 + config/rbac/role.yaml | 9 +++++ controllers/kustomization_controller.go | 1 + controllers/kustomization_impersonation.go | 44 +++++++++++++++++++--- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index f3ede26c..4d3e60b4 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -80,6 +80,8 @@ jobs: run: | kubectl -n impersonation apply -f ./config/testdata/impersonation kubectl -n impersonation wait kustomizations/podinfo --for=condition=ready --timeout=4m + kubectl -n impersonation delete kustomizations/podinfo + until kubectl -n impersonation get deploy/podinfo 2>&1 | grep NotFound ; do sleep 2; done - name: Run image overide tests run: | kubectl -n override-test apply -f ./config/testdata/overrides diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 2323bde3..8084ff74 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -13,6 +13,15 @@ rules: verbs: - create - patch +- apiGroups: + - "" + resources: + - secrets + - serviceaccounts + verbs: + - get + - list + - watch - apiGroups: - kustomize.toolkit.fluxcd.io resources: diff --git a/controllers/kustomization_controller.go b/controllers/kustomization_controller.go index 4327c7ee..eae1846b 100644 --- a/controllers/kustomization_controller.go +++ b/controllers/kustomization_controller.go @@ -65,6 +65,7 @@ import ( // +kubebuilder:rbac:groups=kustomize.toolkit.fluxcd.io,resources=kustomizations/finalizers,verbs=get;create;update;patch;delete // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=buckets;gitrepositories,verbs=get;list;watch // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=buckets/status;gitrepositories/status,verbs=get +// +kubebuilder:rbac:groups="",resources=secrets;serviceaccounts,verbs=get;list;watch // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch // KustomizationReconciler reconciles a Kustomization object diff --git a/controllers/kustomization_impersonation.go b/controllers/kustomization_impersonation.go index 00b826b5..63fc2018 100644 --- a/controllers/kustomization_impersonation.go +++ b/controllers/kustomization_impersonation.go @@ -28,6 +28,7 @@ import ( "sigs.k8s.io/cli-utils/pkg/kstatus/polling" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/client/config" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1" ) @@ -92,12 +93,49 @@ func (ki *KustomizeImpersonation) GetServiceAccountToken(ctx context.Context) (s return token, nil } +// GetClient creates a controller-runtime client for talking to a Kubernetes API server. +// If KubeConfig is set, will use the kubeconfig bytes from the Kubernetes secret. +// If ServiceAccountName is set, will use the cluster provided kubeconfig impersonating the SA. +// If --kubeconfig is set, will use the kubeconfig file at that location. +// Otherwise will assume running in cluster and use the cluster provided kubeconfig. func (ki *KustomizeImpersonation) GetClient(ctx context.Context) (client.Client, *polling.StatusPoller, error) { if ki.kustomization.Spec.KubeConfig == nil { - // TODO: implement impersonation overrides for in-cluster + if ki.kustomization.Spec.ServiceAccountName != "" { + return ki.clientForServiceAccount(ctx) + } + return ki.Client, ki.statusPoller, nil } + return ki.clientForKubeConfig(ctx) +} + +func (ki *KustomizeImpersonation) clientForServiceAccount(ctx context.Context) (client.Client, *polling.StatusPoller, error) { + token, err := ki.GetServiceAccountToken(ctx) + if err != nil { + return nil, nil, err + } + restConfig, err := config.GetConfig() + if err != nil { + return nil, nil, err + } + restConfig.BearerToken = token + + restMapper, err := apiutil.NewDynamicRESTMapper(restConfig) + if err != nil { + return nil, nil, err + } + + client, err := client.New(restConfig, client.Options{Mapper: restMapper}) + if err != nil { + return nil, nil, err + } + statusPoller := polling.NewStatusPoller(client, restMapper) + return client, statusPoller, err + +} + +func (ki *KustomizeImpersonation) clientForKubeConfig(ctx context.Context) (client.Client, *polling.StatusPoller, error) { kubeConfigBytes, err := ki.getKubeConfig(ctx) if err != nil { return nil, nil, err @@ -108,15 +146,11 @@ func (ki *KustomizeImpersonation) GetClient(ctx context.Context) (client.Client, return nil, nil, err } - // TODO: implement impersonation overrides on the target cluster restConfig - restMapper, err := apiutil.NewDynamicRESTMapper(restConfig) if err != nil { return nil, nil, err } - // this client does not have a cache like the normal controller-runtime default client - // this is intentional but one could be added client, err := client.New(restConfig, client.Options{Mapper: restMapper}) if err != nil { return nil, nil, err