Skip to content

Commit

Permalink
Option to disable the default creation of RBAC resources
Browse files Browse the repository at this point in the history
  • Loading branch information
savitaashture committed Sep 20, 2021
1 parent 0467af4 commit 5870e00
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 25 deletions.
3 changes: 3 additions & 0 deletions pkg/apis/operator/v1alpha1/tektonconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions pkg/reconciler/openshift/tektonconfig/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
219 changes: 199 additions & 20 deletions pkg/reconciler/openshift/tektonconfig/rbac.go
Original file line number Diff line number Diff line change
Expand Up @@ -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: <release-version>`
// `openshift-pipelines.tekton.dev/namespace-reconcile-version: <release-version>`
namespaces, err := r.kubeClientSet.CoreV1().Namespaces().List(ctx, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s = %s", namespaceVersionLabel, r.version),
})
Expand All @@ -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: <release-version>`
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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
}

Expand All @@ -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)

Expand Down Expand Up @@ -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)

Expand All @@ -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)

Expand Down

0 comments on commit 5870e00

Please sign in to comment.