From ff53cc2f381745163d5b439cce703443e4f10aaf Mon Sep 17 00:00:00 2001 From: Massimiliano Giovagnoli Date: Sat, 13 Aug 2022 16:02:29 +0200 Subject: [PATCH] feat(controllers/tenant): ensure per-tenant owners roles add gitops ready cluster roles per tenant owners. Signed-off-by: Massimiliano Giovagnoli --- controllers/tenant/manager.go | 8 ++++ controllers/tenant/roles.go | 69 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 controllers/tenant/roles.go diff --git a/controllers/tenant/manager.go b/controllers/tenant/manager.go index fe42c948..d125713c 100644 --- a/controllers/tenant/manager.go +++ b/controllers/tenant/manager.go @@ -105,6 +105,14 @@ func (r Manager) Reconcile(ctx context.Context, request ctrl.Request) (result ct return } + // Ensuring Roles resources + r.Log.Info("Ensuring Roles for Owners and Tenant") + + if err = r.syncRoles(ctx, instance); err != nil { + r.Log.Error(err, "Cannot sync Roles items") + + return + } // Ensuring RoleBinding resources r.Log.Info("Ensuring RoleBindings for Owners and Tenant") diff --git a/controllers/tenant/roles.go b/controllers/tenant/roles.go new file mode 100644 index 00000000..c62e7b46 --- /dev/null +++ b/controllers/tenant/roles.go @@ -0,0 +1,69 @@ +package tenant + +import ( + "context" + + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" +) + +const ( + ImpersonatorRoleName = "capsule-tenant-impersonator" +) + +// Sync the Tenant Owner specific cluster-roles. +// When the Tenant is configured GitOpsReady additional (Cluster)Roles are created, then bound. +func (r *Manager) syncRoles(ctx context.Context, tenant *capsulev1beta1.Tenant) (err error) { + + // If the Tenant will be reconciled the GitOps-way, + // Tenant Owners might be machine GitOps reconciler identities. + if tenant.Spec.GitOpsReady { + for _, owner := range tenant.Spec.Owners { + if err = r.ensureOwnerRole(ctx, tenant, &owner, ImpersonatorRoleName); err != nil { + r.Log.Error(err, "Reconciliation for ClusterRole failed", "ClusterRole", ImpersonatorRoleName) + return err + } + } + } + + return +} + +func (r *Manager) ensureOwnerRole(ctx context.Context, tenant *capsulev1beta1.Tenant, owner *capsulev1beta1.OwnerSpec, roleName string) (err error) { + switch roleName { + case ImpersonatorRoleName: + clusterRole := &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: roleName + "-" + tenant.Name + "-" + owner.Name, + }, + } + + resource := "users" + if owner.Kind == capsulev1beta1.GroupOwner { + resource = "groups" + } + + resourceName := owner.Name + if owner.Kind == capsulev1beta1.ServiceAccountOwner { + resourceName = "system:serviceaccount:" + tenant.Namespace + ":" + owner.Name + } + + _, err = controllerutil.CreateOrUpdate(ctx, r.Client, clusterRole, func() error { + clusterRole.Rules = []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{resource}, + Verbs: []string{"impersonate"}, + ResourceNames: []string{resourceName}, + }, + } + + return nil + }) + } + + return +}