Skip to content

Commit 576c89d

Browse files
authored
only copy specific role (#40)
* only copy specific role * Add ServiceAccountMembers
1 parent 73b0dc9 commit 576c89d

File tree

5 files changed

+207
-73
lines changed

5 files changed

+207
-73
lines changed

api/v1/namespacescope_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ type NamespaceScopeSpec struct {
3131
// Namespaces that are part of this scope
3232
NamespaceMembers []string `json:"namespaceMembers,omitempty"`
3333

34+
// ServiceAccountMembers are extra service accounts will be bond the roles from other namespaces
35+
ServiceAccountMembers []string `json:"serviceAccountMembers,omitempty"`
36+
3437
// ConfigMap name that will contain the list of namespaces to be watched
3538
ConfigmapName string `json:"configmapName,omitempty"`
3639

api/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/operator.ibm.com_namespacescopes.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ spec:
6060
description: Restart pods with the following labels when the namspace
6161
list changes
6262
type: object
63+
serviceAccountMembers:
64+
description: ServiceAccountMembers are extra service accounts will be
65+
bond the roles from other namespaces
66+
items:
67+
type: string
68+
type: array
6369
type: object
6470
status:
6571
description: NamespaceScopeStatus defines the observed state of NamespaceScope

controllers/constant/constants.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
package constant
1818

1919
const (
20-
NamespaceScopeManagedPrefix = "nss-managed-role-from-"
21-
NamespaceScopeConfigmapName = "namespace-scope"
22-
NamespaceScopeFinalizer = "finalizer.nss.operator.ibm.com"
23-
NamespaceScopeLabel = "managedby-namespace-scope"
24-
DefaultRestartLabelsKey = "intent"
25-
DefaultRestartLabelsValue = "projected"
20+
NamespaceScopeManagedPrefix = "nss-managed-role-from-"
21+
NamespaceScopeConfigmapName = "namespace-scope"
22+
NamespaceScopeFinalizer = "finalizer.nss.operator.ibm.com"
23+
NamespaceScopeLabel = "managedby-namespace-scope"
24+
DefaultRestartLabelsKey = "intent"
25+
DefaultRestartLabelsValue = "projected"
26+
NamespaceScopeServiceAccount = "ibm-namespace-scope-operator"
2627
)

controllers/namespacescope_controller.go

Lines changed: 186 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,10 @@ func (r *NamespaceScopeReconciler) UpdateConfigMap(instance *operatorv1.Namespac
207207

208208
func (r *NamespaceScopeReconciler) PushRbacToNamespace(instance *operatorv1.NamespaceScope) error {
209209
fromNs := instance.Namespace
210-
saNames, err := r.GetServiceAccountFromNamespace(instance.Spec.RestartLabels, fromNs)
210+
saNames, err := r.GetServiceAccountFromNamespace(instance, fromNs)
211211
if err != nil {
212212
return err
213213
}
214-
labels := map[string]string{
215-
"namespace-scope-configmap": instance.Namespace + "-" + instance.Spec.ConfigmapName,
216-
}
217214

218215
operatorNs, err := util.GetOperatorNamespace()
219216
if err != nil {
@@ -225,17 +222,10 @@ func (r *NamespaceScopeReconciler) PushRbacToNamespace(instance *operatorv1.Name
225222
if toNs == operatorNs {
226223
continue
227224
}
228-
229-
if err := r.CreateRole(labels, toNs); err != nil {
230-
if errors.IsForbidden(err) {
231-
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "Forbidden", "cannot create resource roles in API group rbac.authorization.k8s.io in the namespace %s", toNs)
232-
}
225+
if err := r.generateRBACForNSS(instance, fromNs, toNs); err != nil {
233226
return err
234227
}
235-
if err := r.CreateUpdateRoleBinding(labels, saNames, fromNs, toNs); err != nil {
236-
if errors.IsForbidden(err) {
237-
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "Forbidden", "cannot create resource rolebindings in API group rbac.authorization.k8s.io in the namespace %s", toNs)
238-
}
228+
if err := r.generateRBACToNamespace(instance, saNames, fromNs, toNs); err != nil {
239229
return err
240230
}
241231
}
@@ -333,32 +323,26 @@ func (r *NamespaceScopeReconciler) DeleteAllRbac(instance *operatorv1.NamespaceS
333323
return nil
334324
}
335325

336-
func (r *NamespaceScopeReconciler) GetServiceAccountFromNamespace(labels map[string]string, namespace string) ([]string, error) {
337-
pods := &corev1.PodList{}
338-
opts := []client.ListOption{
339-
client.MatchingLabels(labels),
340-
client.InNamespace(namespace),
326+
func (r *NamespaceScopeReconciler) generateRBACForNSS(instance *operatorv1.NamespaceScope, fromNs, toNs string) error {
327+
labels := map[string]string{
328+
"namespace-scope-configmap": instance.Namespace + "-" + instance.Spec.ConfigmapName,
341329
}
342-
343-
if err := r.List(ctx, pods, opts...); err != nil {
344-
klog.Errorf("Cannot list pods with labels %v in namespace %s: %v", labels, namespace, err)
345-
return nil, err
330+
if err := r.createRoleForNSS(labels, toNs); err != nil {
331+
if errors.IsForbidden(err) {
332+
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "Forbidden", "cannot create resource roles in API group rbac.authorization.k8s.io in the namespace %s", toNs)
333+
}
334+
return err
346335
}
347-
348-
// By default, set ibm-namespace-scope-operator service account
349-
var saNames = []string{"ibm-namespace-scope-operator"}
350-
351-
for _, pod := range pods.Items {
352-
if len(pod.Spec.ServiceAccountName) != 0 {
353-
saNames = append(saNames, pod.Spec.ServiceAccountName)
336+
if err := r.createRoleBindingForNSS(labels, fromNs, toNs); err != nil {
337+
if errors.IsForbidden(err) {
338+
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "Forbidden", "cannot create resource rolebindings in API group rbac.authorization.k8s.io in the namespace %s", toNs)
354339
}
340+
return err
355341
}
356-
saNames = util.ToStringSlice(util.MakeSet(saNames))
357-
358-
return saNames, nil
342+
return nil
359343
}
360344

361-
func (r *NamespaceScopeReconciler) CreateRole(labels map[string]string, toNs string) error {
345+
func (r *NamespaceScopeReconciler) createRoleForNSS(labels map[string]string, toNs string) error {
362346
name := constant.NamespaceScopeManagedPrefix + labels["namespace-scope-configmap"]
363347
namespace := toNs
364348
role := &rbacv1.Role{
@@ -386,31 +370,16 @@ func (r *NamespaceScopeReconciler) CreateRole(labels map[string]string, toNs str
386370
return nil
387371
}
388372

389-
func (r *NamespaceScopeReconciler) DeleteRole(labels map[string]string, toNs string) error {
390-
opts := []client.DeleteAllOfOption{
391-
client.MatchingLabels(labels),
392-
client.InNamespace(toNs),
393-
}
394-
if err := r.DeleteAllOf(ctx, &rbacv1.Role{}, opts...); err != nil {
395-
klog.Errorf("Failed to delete role with labels %v in namespace %s: %v", labels, toNs, err)
396-
return err
397-
}
398-
klog.Infof("Deleted role with labels %v in namespace %s", labels, toNs)
399-
return nil
400-
}
401-
402-
func (r *NamespaceScopeReconciler) CreateUpdateRoleBinding(labels map[string]string, saNames []string, fromNs, toNs string) error {
373+
func (r *NamespaceScopeReconciler) createRoleBindingForNSS(labels map[string]string, fromNs, toNs string) error {
403374
name := constant.NamespaceScopeManagedPrefix + labels["namespace-scope-configmap"]
404375
namespace := toNs
405376
subjects := []rbacv1.Subject{}
406-
for _, saName := range saNames {
407-
subject := rbacv1.Subject{
408-
Kind: "ServiceAccount",
409-
Name: saName,
410-
Namespace: fromNs,
411-
}
412-
subjects = append(subjects, subject)
377+
subject := rbacv1.Subject{
378+
Kind: "ServiceAccount",
379+
Name: constant.NamespaceScopeServiceAccount,
380+
Namespace: fromNs,
413381
}
382+
subjects = append(subjects, subject)
414383
roleBinding := &rbacv1.RoleBinding{
415384
ObjectMeta: metav1.ObjectMeta{
416385
Name: name,
@@ -427,9 +396,6 @@ func (r *NamespaceScopeReconciler) CreateUpdateRoleBinding(labels map[string]str
427396

428397
if err := r.Create(ctx, roleBinding); err != nil {
429398
if errors.IsAlreadyExists(err) {
430-
if err := r.UpdateRoleBinding(roleBinding); err != nil {
431-
return err
432-
}
433399
return nil
434400
}
435401
klog.Errorf("Failed to create rolebinding %s/%s: %v", namespace, name, err)
@@ -439,19 +405,172 @@ func (r *NamespaceScopeReconciler) CreateUpdateRoleBinding(labels map[string]str
439405
return nil
440406
}
441407

442-
func (r *NamespaceScopeReconciler) UpdateRoleBinding(newRoleBinding *rbacv1.RoleBinding) error {
443-
currentRoleBinding := &rbacv1.RoleBinding{}
444-
currentRoleBindingKey := types.NamespacedName{Name: newRoleBinding.Name, Namespace: newRoleBinding.Namespace}
445-
if err := r.Get(ctx, currentRoleBindingKey, currentRoleBinding); err != nil {
446-
klog.Errorf("Cannot get rolebinding %s: %v", currentRoleBindingKey.String(), err)
408+
func (r *NamespaceScopeReconciler) generateRBACToNamespace(instance *operatorv1.NamespaceScope, saNames []string, fromNs, toNs string) error {
409+
labels := map[string]string{
410+
"namespace-scope-configmap": instance.Namespace + "-" + instance.Spec.ConfigmapName,
411+
}
412+
for _, sa := range saNames {
413+
roleList, err := r.GetRolesFromServiceAccount(sa, fromNs)
414+
if err != nil {
415+
return err
416+
}
417+
418+
if err := r.CreateRole(roleList, labels, fromNs, toNs); err != nil {
419+
if errors.IsForbidden(err) {
420+
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "Forbidden", "cannot create resource roles in API group rbac.authorization.k8s.io in the namespace %s", toNs)
421+
}
422+
return err
423+
}
424+
if err := r.CreateRoleBinding(roleList, labels, sa, fromNs, toNs); err != nil {
425+
if errors.IsForbidden(err) {
426+
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "Forbidden", "cannot create resource rolebindings in API group rbac.authorization.k8s.io in the namespace %s", toNs)
427+
}
428+
return err
429+
}
430+
}
431+
return nil
432+
}
433+
434+
func (r *NamespaceScopeReconciler) GetServiceAccountFromNamespace(instance *operatorv1.NamespaceScope, namespace string) ([]string, error) {
435+
labels := instance.Spec.RestartLabels
436+
pods := &corev1.PodList{}
437+
opts := []client.ListOption{
438+
client.MatchingLabels(labels),
439+
client.InNamespace(namespace),
440+
}
441+
442+
if err := r.List(ctx, pods, opts...); err != nil {
443+
klog.Errorf("Cannot list pods with labels %v in namespace %s: %v", labels, namespace, err)
444+
return nil, err
445+
}
446+
447+
// By default, set ibm-namespace-scope-operator service account
448+
var saNames = []string{"ibm-namespace-scope-operator"}
449+
450+
for _, pod := range pods.Items {
451+
if len(pod.Spec.ServiceAccountName) != 0 {
452+
saNames = append(saNames, pod.Spec.ServiceAccountName)
453+
}
454+
}
455+
456+
if len(instance.Spec.ServiceAccountMembers) != 0 {
457+
for _, sa := range instance.Spec.ServiceAccountMembers {
458+
serviceaccount := &corev1.ServiceAccount{}
459+
if err := r.Get(ctx, types.NamespacedName{Namespace: namespace, Name: sa}, serviceaccount); err != nil {
460+
klog.Errorf("Failed to get service account %s in namespace %s", sa, namespace)
461+
continue
462+
}
463+
saNames = append(saNames, sa)
464+
}
465+
}
466+
467+
saNames = util.ToStringSlice(util.MakeSet(saNames))
468+
469+
return saNames, nil
470+
}
471+
472+
func (r *NamespaceScopeReconciler) GetRolesFromServiceAccount(sa string, namespace string) ([]string, error) {
473+
roleBindings := &rbacv1.RoleBindingList{}
474+
opts := []client.ListOption{
475+
client.InNamespace(namespace),
476+
}
477+
478+
if err := r.List(ctx, roleBindings, opts...); err != nil {
479+
klog.Errorf("Cannot list rolebindings with in namespace %s: %v", namespace, err)
480+
return nil, err
481+
}
482+
483+
var roleNameList []string
484+
for _, roleBinding := range roleBindings.Items {
485+
for _, subject := range roleBinding.Subjects {
486+
if subject.Name == sa && subject.Kind == "ServiceAccount" {
487+
roleNameList = append(roleNameList, roleBinding.RoleRef.Name)
488+
}
489+
}
490+
}
491+
492+
return util.ToStringSlice(util.MakeSet(roleNameList)), nil
493+
}
494+
495+
func (r *NamespaceScopeReconciler) CreateRole(roleNames []string, labels map[string]string, fromNs string, toNs string) error {
496+
for _, roleName := range roleNames {
497+
originalRole := &rbacv1.Role{}
498+
if err := r.Get(ctx, types.NamespacedName{Name: roleName, Namespace: fromNs}, originalRole); err != nil {
499+
klog.Errorf("Failed to get role %s in namespace %s: %v", roleName, fromNs, err)
500+
return err
501+
}
502+
name := strings.Split(roleName, ".")[0] + "-" + labels["namespace-scope-configmap"]
503+
namespace := toNs
504+
role := &rbacv1.Role{
505+
ObjectMeta: metav1.ObjectMeta{
506+
Name: name,
507+
Namespace: namespace,
508+
Labels: labels,
509+
},
510+
Rules: originalRole.Rules,
511+
}
512+
if err := r.Create(ctx, role); err != nil {
513+
if errors.IsAlreadyExists(err) {
514+
if err := r.Update(ctx, role); err != nil {
515+
klog.Errorf("Failed to update role %s/%s: %v", namespace, name, err)
516+
return err
517+
}
518+
return nil
519+
}
520+
klog.Errorf("Failed to create role %s/%s: %v", namespace, name, err)
521+
return err
522+
}
523+
klog.Infof("Created role %s/%s", namespace, name)
524+
}
525+
return nil
526+
}
527+
528+
func (r *NamespaceScopeReconciler) DeleteRole(labels map[string]string, toNs string) error {
529+
opts := []client.DeleteAllOfOption{
530+
client.MatchingLabels(labels),
531+
client.InNamespace(toNs),
447532
}
448-
if len(newRoleBinding.Subjects) != len(currentRoleBinding.Subjects) {
449-
if err := r.Update(ctx, newRoleBinding); err != nil {
450-
klog.Errorf("Failed to update rolebinding %s: %v", currentRoleBindingKey.String(), err)
533+
if err := r.DeleteAllOf(ctx, &rbacv1.Role{}, opts...); err != nil {
534+
klog.Errorf("Failed to delete role with labels %v in namespace %s: %v", labels, toNs, err)
535+
return err
536+
}
537+
klog.Infof("Deleted role with labels %v in namespace %s", labels, toNs)
538+
return nil
539+
}
540+
541+
func (r *NamespaceScopeReconciler) CreateRoleBinding(roleNames []string, labels map[string]string, saName, fromNs, toNs string) error {
542+
for _, roleName := range roleNames {
543+
name := strings.Split(roleName, ".")[0] + "-" + labels["namespace-scope-configmap"]
544+
namespace := toNs
545+
subjects := []rbacv1.Subject{}
546+
subject := rbacv1.Subject{
547+
Kind: "ServiceAccount",
548+
Name: saName,
549+
Namespace: fromNs,
550+
}
551+
subjects = append(subjects, subject)
552+
roleBinding := &rbacv1.RoleBinding{
553+
ObjectMeta: metav1.ObjectMeta{
554+
Name: name,
555+
Namespace: namespace,
556+
Labels: labels,
557+
},
558+
Subjects: subjects,
559+
RoleRef: rbacv1.RoleRef{
560+
Kind: "Role",
561+
Name: name,
562+
APIGroup: "rbac.authorization.k8s.io",
563+
},
564+
}
565+
566+
if err := r.Create(ctx, roleBinding); err != nil {
567+
if errors.IsAlreadyExists(err) {
568+
return nil
569+
}
570+
klog.Errorf("Failed to create rolebinding %s/%s: %v", namespace, name, err)
451571
return err
452572
}
453-
klog.Infof("Updated rolebinding %s", currentRoleBindingKey.String())
454-
return nil
573+
klog.Infof("Created rolebinding %s/%s", namespace, name)
455574
}
456575
return nil
457576
}

0 commit comments

Comments
 (0)