From 5870e00392da27d19b64873ef8476dea2b93ab2d Mon Sep 17 00:00:00 2001 From: savitaashture Date: Mon, 20 Sep 2021 11:01:36 +0530 Subject: [PATCH] Option to disable the default creation of RBAC resources --- .../operator/v1alpha1/tektonconfig_types.go | 3 + .../openshift/tektonconfig/extension.go | 11 +- pkg/reconciler/openshift/tektonconfig/rbac.go | 219 ++++++++++++++++-- 3 files changed, 208 insertions(+), 25 deletions(-) diff --git a/pkg/apis/operator/v1alpha1/tektonconfig_types.go b/pkg/apis/operator/v1alpha1/tektonconfig_types.go index ba7dac5db5..79240344d2 100644 --- a/pkg/apis/operator/v1alpha1/tektonconfig_types.go +++ b/pkg/apis/operator/v1alpha1/tektonconfig_types.go @@ -89,6 +89,9 @@ type TektonConfigSpec struct { // Dashboard holds the customizable options for dashboards component // +optional Dashboard Dashboard `json:"dashboard,omitempty"` + // DisableRbacClusterWide holds the option to disable/enable creation of RBAC resources + // +optional + DisableRbacClusterWide bool `json:"disable-rbac-clusterwide,omitempty"` } // TektonConfigStatus defines the observed state of TektonConfig diff --git a/pkg/reconciler/openshift/tektonconfig/extension.go b/pkg/reconciler/openshift/tektonconfig/extension.go index d6491c3b20..ddddd2dbe2 100644 --- a/pkg/reconciler/openshift/tektonconfig/extension.go +++ b/pkg/reconciler/openshift/tektonconfig/extension.go @@ -86,11 +86,12 @@ func (oe openshiftExtension) PreReconcile(ctx context.Context, tc v1alpha1.Tekto } r := rbac{ - kubeClientSet: oe.kubeClientSet, - operatorClientSet: oe.operatorClientSet, - manifest: oe.manifest, - ownerRef: configOwnerRef(tc), - version: os.Getenv(versionKey), + kubeClientSet: oe.kubeClientSet, + operatorClientSet: oe.operatorClientSet, + manifest: oe.manifest, + ownerRef: configOwnerRef(tc), + version: os.Getenv(versionKey), + disableRbacClusterWide: config.Spec.DisableRbacClusterWide, } return r.createResources(ctx) } diff --git a/pkg/reconciler/openshift/tektonconfig/rbac.go b/pkg/reconciler/openshift/tektonconfig/rbac.go index 1d36831e8c..5ff440fad5 100644 --- a/pkg/reconciler/openshift/tektonconfig/rbac.go +++ b/pkg/reconciler/openshift/tektonconfig/rbac.go @@ -42,23 +42,25 @@ const ( trustedCABundleConfigMap = "config-trusted-cabundle" clusterInterceptors = "openshift-pipelines-clusterinterceptors" namespaceVersionLabel = "openshift-pipelines.tekton.dev/namespace-reconcile-version" + disableRbacInjection = "openshift-pipelines.tekton.dev/disable-rbac-injection" ) // Namespace Regex to ignore the namespace for creating rbac resources. var nsRegex = regexp.MustCompile(common.NamespaceIgnorePattern) type rbac struct { - kubeClientSet kubernetes.Interface - operatorClientSet clientset.Interface - manifest mf.Manifest - ownerRef metav1.OwnerReference - version string + kubeClientSet kubernetes.Interface + operatorClientSet clientset.Interface + manifest mf.Manifest + ownerRef metav1.OwnerReference + version string + disableRbacClusterWide bool } func (r *rbac) cleanUp(ctx context.Context) error { // fetch the list of all namespaces which have label - // `openshift-pipelines.tekton.dev/namespace-ready: ` + // `openshift-pipelines.tekton.dev/namespace-reconcile-version: ` namespaces, err := r.kubeClientSet.CoreV1().Namespaces().List(ctx, metav1.ListOptions{ LabelSelector: fmt.Sprintf("%s = %s", namespaceVersionLabel, r.version), }) @@ -81,25 +83,69 @@ func (r *rbac) createResources(ctx context.Context) error { logger := logging.FromContext(ctx) - // fetch the list of all namespaces which doesn't have label - // `openshift-pipelines.tekton.dev/namespace-ready: ` - namespaces, err := r.kubeClientSet.CoreV1().Namespaces().List(ctx, metav1.ListOptions{ - LabelSelector: fmt.Sprintf("%s != %s", namespaceVersionLabel, r.version), - }) + // list of namespaces rbac resources need to be created + var rbacNamespaces []corev1.Namespace + // list of namespaces rbac resources need not to be created + var nonRbacNamespaces []corev1.Namespace + + // list all namespaces + allNamespaces, err := r.kubeClientSet.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) if err != nil { return err } - // list of namespaces rbac resources need to be created - var rbacNamespaces []corev1.Namespace - - // filter namespaces: - // ignore ns with name passing regex `^(openshift|kube)-` - for _, n := range namespaces.Items { + for _, n := range allNamespaces.Items { if ignore := nsRegex.MatchString(n.GetName()); ignore { continue } - rbacNamespaces = append(rbacNamespaces, n) + v, ok := n.GetLabels()[disableRbacInjection] + if ok { + if v == "true" { + nonRbacNamespaces = append(nonRbacNamespaces, n) + } else { + rbacNamespaces = append(rbacNamespaces, n) + } + continue + } + if r.disableRbacClusterWide { + nonRbacNamespaces = append(nonRbacNamespaces, n) + } else { + rbacNamespaces = append(rbacNamespaces, n) + } + continue + } + + for _, n := range nonRbacNamespaces { + + logger.Infow("Remove CA bundle configmap in ", "Namespace if any", n.GetName()) + if err := r.deleteCABundles(ctx, &n); err != nil { + return err + } + + logger.Infow("Remove Default SA in ", "Namespace", n.GetName()) + if err := r.removeSA(ctx, &n); err != nil { + return err + } + + if err := r.removePipelinesSCCRoleBinding(ctx, &n); err != nil { + return err + } + + if err := r.removeRoleBindings(ctx, &n); err != nil { + return err + } + + // Add `openshift-pipelines.tekton.dev/namespace-reconcile-version` label to namespace + // so that rbac won't loop on it again + nsLabels := n.GetLabels() + if len(nsLabels) == 0 { + nsLabels = map[string]string{} + } + nsLabels[namespaceVersionLabel] = r.version + n.SetLabels(nsLabels) + if _, err := r.kubeClientSet.CoreV1().Namespaces().Update(ctx, &n, metav1.UpdateOptions{}); err != nil { + return err + } } if len(rbacNamespaces) == 0 { @@ -138,7 +184,7 @@ func (r *rbac) createResources(ctx context.Context) error { return err } - // Add `openshift-pipelines.tekton.dev/namespace-ready` label to namespace + // Add `openshift-pipelines.tekton.dev/namespace-reconcile-version` label to namespace // so that rbac won't loop on it again nsLabels := n.GetLabels() if len(nsLabels) == 0 { @@ -154,6 +200,37 @@ func (r *rbac) createResources(ctx context.Context) error { return nil } +func (r *rbac) deleteCABundles(ctx context.Context, ns *corev1.Namespace) error { + logger := logging.FromContext(ctx) + cfgInterface := r.kubeClientSet.CoreV1().ConfigMaps(ns.Name) + + // Delete trusted CA bundle + logger.Infof("finding configmap: %s/%s", ns.Name, trustedCABundleConfigMap) + if _, err := cfgInterface.Get(ctx, trustedCABundleConfigMap, metav1.GetOptions{}); err != nil { + if errors.IsNotFound(err) { + logger.Infof("configmap %s in %s namespace does not exist", trustedCABundleConfigMap, ns.Name) + return nil + } else { + return err + } + } + if err := cfgInterface.Delete(ctx, trustedCABundleConfigMap, metav1.DeleteOptions{}); err != nil { + return err + } + + // Delete service CA bundle + logger.Infof("finding configmap: %s/%s", ns.Name, serviceCABundleConfigMap) + if _, err := cfgInterface.Get(ctx, serviceCABundleConfigMap, metav1.GetOptions{}); err != nil { + if errors.IsNotFound(err) { + logger.Infof("configmap %s in %s namespace does not exist", serviceCABundleConfigMap, ns.Name) + return nil + } else { + return err + } + } + return cfgInterface.Delete(ctx, serviceCABundleConfigMap, metav1.DeleteOptions{}) +} + func (r *rbac) ensureCABundles(ctx context.Context, ns *corev1.Namespace) error { logger := logging.FromContext(ctx) cfgInterface := r.kubeClientSet.CoreV1().ConfigMaps(ns.Name) @@ -245,6 +322,28 @@ func createServiceCABundleConfigMap(ctx context.Context, cfgInterface v1.ConfigM return nil } +func (r *rbac) removeSA(ctx context.Context, ns *corev1.Namespace) error { + logger := logging.FromContext(ctx) + logger.Infof("finding sa: %s/%s", ns.Name, "pipeline") + saInterface := r.kubeClientSet.CoreV1().ServiceAccounts(ns.Name) + + serviceAccount, err := saInterface.Get(ctx, pipelineSA, metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + logger.Infof("serviceaccount %s in %s namespace does not exist", pipelineSA, ns.Name) + return nil + } else { + return err + } + } + + if err := r.removeSAFromClusterRoleBindings(ctx, serviceAccount); err != nil { + return err + } + + return saInterface.Delete(ctx, pipelineSA, metav1.DeleteOptions{}) +} + func (r *rbac) ensureSA(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { logger := logging.FromContext(ctx) logger.Infof("finding sa: %s/%s", ns.Name, "pipeline") @@ -325,6 +424,24 @@ func (r *rbac) ensurePipelinesSCClusterRole(ctx context.Context) error { return err } +func (r *rbac) removePipelinesSCCRoleBinding(ctx context.Context, ns *corev1.Namespace) error { + logger := logging.FromContext(ctx) + rbacClient := r.kubeClientSet.RbacV1() + + logger.Info("finding role-binding", pipelinesSCCRoleBinding) + if _, rbErr := rbacClient.RoleBindings(ns.Name).Get(ctx, pipelinesSCCRoleBinding, metav1.GetOptions{}); rbErr != nil { + if errors.IsNotFound(rbErr) { + logger.Infof("rolebinding %s in %s namespace does not exist", pipelinesSCCRoleBinding, ns.Name) + return nil + } else { + logger.Error(rbErr, "rbac get error", pipelinesSCCRoleBinding) + return rbErr + } + } + + return rbacClient.RoleBindings(ns.Name).Delete(ctx, pipelinesSCCRoleBinding, metav1.DeleteOptions{}) +} + func (r *rbac) ensurePipelinesSCCRoleBinding(ctx context.Context, sa *corev1.ServiceAccount) error { logger := logging.FromContext(ctx) rbacClient := r.kubeClientSet.RbacV1() @@ -386,7 +503,7 @@ func (r *rbac) updateRoleBinding(ctx context.Context, rb *rbacv1.RoleBinding, sa rb.SetOwnerReferences(ownerRef) if hasSubject && (len(ownerRef) != 0) { - logger.Info("rolebinding is up to date", "action", "none") + logger.Info("rolebinding is up to date ", "action ", "none") return nil } @@ -411,6 +528,25 @@ func hasSubject(subjects []rbacv1.Subject, x rbacv1.Subject) bool { return false } +func (r *rbac) removeRoleBindings(ctx context.Context, ns *corev1.Namespace) error { + logger := logging.FromContext(ctx) + + logger.Info("finding role-binding edit") + rbacClient := r.kubeClientSet.RbacV1() + + if _, err := rbacClient.RoleBindings(ns.Name).Get(ctx, "edit", metav1.GetOptions{}); err != nil { + if errors.IsNotFound(err) { + logger.Infof("rolebinding edit in %s namespace does not exist", ns.Name) + return nil + } else { + logger.Error(err, "rbac get error") + return err + } + } + + return rbacClient.RoleBindings(ns.Name).Delete(ctx, "edit", metav1.DeleteOptions{}) +} + func (r *rbac) ensureRoleBindings(ctx context.Context, sa *corev1.ServiceAccount) error { logger := logging.FromContext(ctx) @@ -460,6 +596,23 @@ func (r *rbac) createRoleBinding(ctx context.Context, sa *corev1.ServiceAccount) return nil } +func (r *rbac) removeSAFromClusterRoleBindings(ctx context.Context, sa *corev1.ServiceAccount) error { + logger := logging.FromContext(ctx) + + rbacClient := r.kubeClientSet.RbacV1() + + logger.Info("finding cluster-role-binding ", clusterInterceptors) + + viewCRB, err := rbacClient.ClusterRoleBindings().Get(ctx, clusterInterceptors, metav1.GetOptions{}) + + if err == nil { + logger.Infof("found clusterrolebinding %s", viewCRB.Name) + return r.updateClusterRoleBindingToRemoveSubjects(ctx, viewCRB, sa) + } + + return err +} + func (r *rbac) ensureClusterRoleBindings(ctx context.Context, sa *corev1.ServiceAccount) error { logger := logging.FromContext(ctx) @@ -485,6 +638,32 @@ func (r *rbac) ensureClusterRoleBindings(ctx context.Context, sa *corev1.Service return err } +func (r *rbac) updateClusterRoleBindingToRemoveSubjects(ctx context.Context, rb *rbacv1.ClusterRoleBinding, sa *corev1.ServiceAccount) error { + logger := logging.FromContext(ctx) + + subject := rbacv1.Subject{Kind: rbacv1.ServiceAccountKind, Name: sa.Name, Namespace: sa.Namespace} + + hasSubject := hasSubject(rb.Subjects, subject) + if hasSubject { + for i, v := range rb.Subjects { + if v == subject { + rb.Subjects = append(rb.Subjects[:i], rb.Subjects[i+1:]...) + break + } + } + } + + logger.Info("update existing clusterrolebinding ", clusterInterceptors) + rbacClient := r.kubeClientSet.RbacV1() + + if _, err := rbacClient.ClusterRoleBindings().Update(ctx, rb, metav1.UpdateOptions{}); err != nil { + logger.Error(err, "failed to update "+clusterInterceptors+" crb") + return err + } + logger.Info("successfully removed subject from ", clusterInterceptors) + return nil +} + func (r *rbac) updateClusterRoleBinding(ctx context.Context, rb *rbacv1.ClusterRoleBinding, sa *corev1.ServiceAccount) error { logger := logging.FromContext(ctx)