Skip to content

Commit af9d8f7

Browse files
authored
Bind NSS roles' permission to the operator which contains wildcard in apiGroups or Resources (#280)
* Bind NSS roles' permission to the operator which contains wildcard in apiGroups or Resources Signed-off-by: Daniel Fan <[email protected]> * Remove logic of creating RBAC for NSS itself Signed-off-by: Daniel Fan <[email protected]> * fix lint error by removing unused code Signed-off-by: Daniel Fan <[email protected]> --------- Signed-off-by: Daniel Fan <[email protected]>
1 parent a89a569 commit af9d8f7

File tree

1 file changed

+68
-101
lines changed

1 file changed

+68
-101
lines changed

controllers/namespacescope_controller.go

Lines changed: 68 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,13 @@ func (r *NamespaceScopeReconciler) Reconcile(ctx context.Context, req ctrl.Reque
153153
return ctrl.Result{}, err
154154
}
155155

156-
reg, _ := regexp.Compile(`^nss-managed-role-from.*`)
156+
reg, err := regexp.Compile(`^nss-(managed|runtime)-role-from.*`)
157+
if err != nil {
158+
klog.Errorf("Failed to compile regular expression: %v", err)
159+
return ctrl.Result{}, err
160+
}
157161
for _, namespaceMember := range instance.Spec.NamespaceMembers {
158-
if rolesList, _ := r.GetRolesFromNamespace(ctx, namespaceMember); len(rolesList) != 0 {
162+
if rolesList, _ := r.GetRolesFromNamespace(ctx, instance, namespaceMember); len(rolesList) != 0 {
159163
var summarizedRules []rbacv1.PolicyRule
160164
for _, role := range rolesList {
161165
if !reg.MatchString(role.Name) {
@@ -283,9 +287,6 @@ func (r *NamespaceScopeReconciler) PushRbacToNamespace(ctx context.Context, inst
283287
if toNs == operatorNs {
284288
continue
285289
}
286-
if err := r.generateRBACForNSS(ctx, instance, fromNs, toNs); err != nil {
287-
return err
288-
}
289290
if err := r.generateRBACToNamespace(ctx, instance, saNames, fromNs, toNs); err != nil {
290291
return err
291292
}
@@ -401,26 +402,6 @@ func (r *NamespaceScopeReconciler) DeleteAllRbac(ctx context.Context, instance *
401402
return nil
402403
}
403404

404-
func (r *NamespaceScopeReconciler) generateRBACForNSS(ctx context.Context, instance *operatorv1.NamespaceScope, fromNs, toNs string) error {
405-
labels := map[string]string{
406-
"namespace-scope-configmap": instance.Namespace + "-" + instance.Spec.ConfigmapName,
407-
}
408-
if err := r.createRoleForNSS(ctx, labels, fromNs, toNs); err != nil {
409-
if errors.IsForbidden(err) {
410-
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "Forbidden", "cannot create resource roles in API group rbac.authorization.k8s.io in the namespace %s. Please authorize service account ibm-namespace-scope-operator namespace admin permission of %s namespace", toNs, toNs)
411-
}
412-
return err
413-
}
414-
if err := r.createRoleBindingForNSS(ctx, labels, fromNs, toNs); err != nil {
415-
if errors.IsForbidden(err) {
416-
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "Forbidden", "cannot create resource rolebindings in API group rbac.authorization.k8s.io in the namespace %s. Please authorize service account ibm-namespace-scope-operator namespace admin permission of %s namespace", toNs, toNs)
417-
}
418-
return err
419-
}
420-
421-
return nil
422-
}
423-
424405
func (r *NamespaceScopeReconciler) generateRuntimeRoleForNSS(ctx context.Context, instance *operatorv1.NamespaceScope, summarizedRules []rbacv1.PolicyRule, fromNs, toNs string) error {
425406
if err := r.createRuntimeRoleForNSS(ctx, summarizedRules, fromNs, toNs); err != nil {
426407
if errors.IsAlreadyExists(err) {
@@ -479,69 +460,6 @@ func (r *NamespaceScopeReconciler) updateRuntimeRoleForNSS(ctx context.Context,
479460
return nil
480461
}
481462

482-
func (r *NamespaceScopeReconciler) createRoleForNSS(ctx context.Context, labels map[string]string, fromNs, toNs string) error {
483-
name := constant.NamespaceScopeManagedPrefix + fromNs
484-
namespace := toNs
485-
role := &rbacv1.Role{
486-
ObjectMeta: metav1.ObjectMeta{
487-
Name: name,
488-
Namespace: namespace,
489-
Labels: labels,
490-
},
491-
Rules: []rbacv1.PolicyRule{
492-
{
493-
Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch", "deletecollection"},
494-
APIGroups: []string{"*"},
495-
Resources: []string{"*"},
496-
},
497-
},
498-
}
499-
if err := r.Create(ctx, role); err != nil {
500-
if errors.IsAlreadyExists(err) {
501-
return nil
502-
}
503-
klog.Errorf("Failed to create role %s/%s: %v", namespace, name, err)
504-
return err
505-
}
506-
klog.Infof("Created role %s/%s", namespace, name)
507-
return nil
508-
}
509-
510-
func (r *NamespaceScopeReconciler) createRoleBindingForNSS(ctx context.Context, labels map[string]string, fromNs, toNs string) error {
511-
name := constant.NamespaceScopeManagedPrefix + fromNs
512-
namespace := toNs
513-
subjects := []rbacv1.Subject{}
514-
subject := rbacv1.Subject{
515-
Kind: "ServiceAccount",
516-
Name: constant.NamespaceScopeServiceAccount,
517-
Namespace: fromNs,
518-
}
519-
subjects = append(subjects, subject)
520-
roleBinding := &rbacv1.RoleBinding{
521-
ObjectMeta: metav1.ObjectMeta{
522-
Name: name,
523-
Namespace: namespace,
524-
Labels: labels,
525-
},
526-
Subjects: subjects,
527-
RoleRef: rbacv1.RoleRef{
528-
Kind: "Role",
529-
Name: constant.NamespaceScopeManagedPrefix + fromNs,
530-
APIGroup: "rbac.authorization.k8s.io",
531-
},
532-
}
533-
534-
if err := r.Create(ctx, roleBinding); err != nil {
535-
if errors.IsAlreadyExists(err) {
536-
return nil
537-
}
538-
klog.Errorf("Failed to create rolebinding %s/%s: %v", namespace, name, err)
539-
return err
540-
}
541-
klog.Infof("Created rolebinding %s/%s", namespace, name)
542-
return nil
543-
}
544-
545463
func (r *NamespaceScopeReconciler) generateRBACToNamespace(ctx context.Context, instance *operatorv1.NamespaceScope, saNames []string, fromNs, toNs string) error {
546464
labels := map[string]string{
547465
"namespace-scope-configmap": instance.Namespace + "-" + instance.Spec.ConfigmapName,
@@ -571,7 +489,7 @@ func (r *NamespaceScopeReconciler) generateRBACToNamespace(ctx context.Context,
571489
return nil
572490
}
573491

574-
func (r *NamespaceScopeReconciler) GetRolesFromNamespace(ctx context.Context, namespace string) ([]rbacv1.Role, error) {
492+
func (r *NamespaceScopeReconciler) GetRolesFromNamespace(ctx context.Context, instance *operatorv1.NamespaceScope, namespace string) ([]rbacv1.Role, error) {
575493
rolesList := &rbacv1.RoleList{}
576494

577495
opts := []client.ListOption{
@@ -588,7 +506,7 @@ func (r *NamespaceScopeReconciler) GetRolesFromNamespace(ctx context.Context, na
588506

589507
roles := []rbacv1.Role{}
590508
for _, role := range rolesList.Items {
591-
if _, ok := role.Labels[constant.NamespaceScopeConfigmapLabelKey]; ok {
509+
if value, ok := role.Labels[constant.NamespaceScopeConfigmapLabelKey]; ok && value == instance.Namespace+"-"+instance.Spec.ConfigmapName {
592510
roles = append(roles, role)
593511
}
594512
}
@@ -657,6 +575,17 @@ func (r *NamespaceScopeReconciler) GetRolesFromServiceAccount(ctx context.Contex
657575
}
658576

659577
func (r *NamespaceScopeReconciler) CreateRole(ctx context.Context, roleNames []string, labels map[string]string, saName, fromNs, toNs string) error {
578+
// Get the permissions that NamespaceScope Operator has from the toNs
579+
nssManagedRole := &rbacv1.Role{}
580+
if err := r.Reader.Get(ctx, types.NamespacedName{Name: constant.NamespaceScopeManagedPrefix + fromNs, Namespace: toNs}, nssManagedRole); err != nil {
581+
if errors.IsNotFound(err) {
582+
klog.Errorf("Role %s not found in namespace %s: %v", constant.NamespaceScopeManagedPrefix+fromNs, toNs, err)
583+
return err
584+
}
585+
klog.Errorf("Failed to get role %s in namespace %s: %v", constant.NamespaceScopeManagedPrefix+fromNs, toNs, err)
586+
return err
587+
}
588+
660589
for _, roleName := range roleNames {
661590
originalRole := &rbacv1.Role{}
662591
if err := r.Reader.Get(ctx, types.NamespacedName{Name: roleName, Namespace: fromNs}, originalRole); err != nil {
@@ -670,7 +599,7 @@ func (r *NamespaceScopeReconciler) CreateRole(ctx context.Context, roleNames []s
670599
hashedServiceAccount := sha256.Sum256([]byte(roleName + saName + fromNs))
671600
name := strings.Split(roleName, ".")[0] + "-" + hex.EncodeToString(hashedServiceAccount[:7])
672601
namespace := toNs
673-
rules := rulesFilter(originalRole.Rules)
602+
rules := rulesFilter(roleName, fromNs, toNs, originalRole.Rules, nssManagedRole.Rules)
674603
role := &rbacv1.Role{
675604
ObjectMeta: metav1.ObjectMeta{
676605
Name: name,
@@ -938,19 +867,48 @@ func (r *NamespaceScopeReconciler) checkGetNSAuth(ctx context.Context) bool {
938867
return sar.Status.Allowed
939868
}
940869

941-
func rulesFilter(orgRule []rbacv1.PolicyRule) []rbacv1.PolicyRule {
870+
func rulesFilter(roleName, fromNs, toNs string, orgRule, nssManagedRule []rbacv1.PolicyRule) []rbacv1.PolicyRule {
942871
verbMap := make(map[string]struct{})
943872
verbs := []string{"create", "delete", "get", "list", "patch", "update", "watch", "deletecollection"}
944873
for _, v := range verbs {
945874
verbMap[v] = struct{}{}
946875
}
876+
needRuleAppending := false
877+
for i := 0; i < len(orgRule); {
878+
// filter out the wildcard in APIGroups
879+
for j := 0; j < len(orgRule[i].APIGroups); {
880+
if orgRule[i].APIGroups[j] == "*" {
881+
orgRule[i].APIGroups = append(orgRule[i].APIGroups[:j], orgRule[i].APIGroups[j+1:]...)
882+
klog.Warningf("Role %s in namespace %s has wildcard * in APIGroups, which is removed from its copied Role in namespace %s", roleName, fromNs, toNs)
883+
needRuleAppending = true
884+
continue
885+
}
886+
j++
887+
}
888+
if len(orgRule[i].APIGroups) == 0 {
889+
orgRule = append(orgRule[:i], orgRule[i+1:]...)
890+
continue
891+
}
892+
// filter out the wildcard in Resources
893+
for j := 0; j < len(orgRule[i].Resources); {
894+
if orgRule[i].Resources[j] == "*" {
895+
orgRule[i].Resources = append(orgRule[i].Resources[:j], orgRule[i].Resources[j+1:]...)
896+
klog.Warningf("Role %s in namespace %s has wildcard * in Resources, which is removed from its copied Role in namespace %s", roleName, fromNs, toNs)
897+
needRuleAppending = true
898+
continue
899+
}
900+
j++
901+
}
902+
if len(orgRule[i].Resources) == 0 {
903+
orgRule = append(orgRule[:i], orgRule[i+1:]...)
904+
continue
905+
}
947906

948-
for i := 0; i < len(orgRule); i++ {
949-
j := 0
950-
for j < len(orgRule[i].Verbs) {
907+
for j := 0; j < len(orgRule[i].Verbs); {
951908
if orgRule[i].Verbs[j] == "*" {
952909
orgRule[i].Verbs = append(orgRule[i].Verbs[:j], orgRule[i].Verbs[j+1:]...)
953910
orgRule[i].Verbs = append(orgRule[i].Verbs, verbs...)
911+
klog.Warningf("Role %s in namespace %s has wildcard * in Verbs, which is replaced with all verbs in its copied Role in namespace %s", roleName, fromNs, toNs)
954912
continue
955913
}
956914
if _, ok := verbMap[orgRule[i].Verbs[j]]; !ok {
@@ -959,10 +917,19 @@ func rulesFilter(orgRule []rbacv1.PolicyRule) []rbacv1.PolicyRule {
959917
}
960918
j++
961919
}
920+
962921
if len(orgRule[i].Verbs) == 0 {
963922
orgRule = append(orgRule[:i], orgRule[i+1:]...)
923+
continue
964924
}
925+
i++
965926
}
927+
928+
if needRuleAppending {
929+
orgRule = append(orgRule, nssManagedRule...)
930+
klog.Infof("Role %s has been appended with role %s in namespace %s", roleName, constant.NamespaceScopeManagedPrefix+fromNs, toNs)
931+
}
932+
966933
return orgRule
967934
}
968935

@@ -1065,7 +1032,7 @@ func (r *NamespaceScopeReconciler) CSVReconcile(ctx context.Context, req ctrl.Re
10651032
_, patchWebhook := csv.Annotations[constant.WebhookMark]
10661033
if patchWebhook {
10671034
klog.Infof("Patching webhookconfiguration for CSV %s", csv.Name)
1068-
if err := r.patchWebhook(ctx, instance, &csv, managedWebhookList, patchedWebhookList, validatedMembers); err != nil {
1035+
if err := r.patchWebhook(ctx, instance, &csv, &managedWebhookList, &patchedWebhookList, validatedMembers); err != nil {
10691036
return ctrl.Result{}, err
10701037
}
10711038
}
@@ -1166,7 +1133,7 @@ func (r *NamespaceScopeReconciler) CheckListDifference(ctx context.Context, inst
11661133
}
11671134

11681135
func (r *NamespaceScopeReconciler) patchWebhook(ctx context.Context, instance *operatorv1.NamespaceScope, csv *olmv1alpha1.ClusterServiceVersion,
1169-
managedWebhookList []string, patchedWebhookList []string, validatedMembers []string) error {
1136+
managedWebhookList *[]string, patchedWebhookList *[]string, validatedMembers []string) error {
11701137
// get webhooklists
11711138
mWebhookList, vWebhookList, err := r.getWebhooks(ctx, csv.Name, instance.Namespace)
11721139
if err != nil {
@@ -1175,19 +1142,19 @@ func (r *NamespaceScopeReconciler) patchWebhook(ctx context.Context, instance *o
11751142
// add them to the list
11761143
for _, mwbh := range mWebhookList.Items {
11771144
webhook := mwbh
1178-
managedWebhookList = append(managedWebhookList, mwbh.GetName())
1145+
*managedWebhookList = append(*managedWebhookList, mwbh.GetName())
11791146
if err := r.patchMutatingWebhook(ctx, &webhook, validatedMembers, csv.Name, csv.Namespace); err != nil {
11801147
return err
11811148
}
1182-
patchedWebhookList = append(patchedWebhookList, mwbh.GetName())
1149+
*patchedWebhookList = append(*patchedWebhookList, mwbh.GetName())
11831150
}
11841151
for _, vwbh := range vWebhookList.Items {
11851152
webhook := vwbh
1186-
managedWebhookList = append(managedWebhookList, vwbh.GetName())
1153+
*managedWebhookList = append(*managedWebhookList, vwbh.GetName())
11871154
if err := r.patchValidatingWebhook(ctx, &webhook, validatedMembers, csv.Name, csv.Namespace); err != nil {
11881155
return err
11891156
}
1190-
patchedWebhookList = append(patchedWebhookList, vwbh.GetName())
1157+
*patchedWebhookList = append(*patchedWebhookList, vwbh.GetName())
11911158
}
11921159
return nil
11931160
}

0 commit comments

Comments
 (0)