diff --git a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml index 294df9282..fbad7849d 100644 --- a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml +++ b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml @@ -169,7 +169,7 @@ metadata: categories: Monitoring console.openshift.io/plugins: '["netobserv-plugin"]' containerImage: quay.io/netobserv/network-observability-operator:1.0.1 - createdAt: "2023-01-30T08:10:44Z" + createdAt: "2023-02-06T08:00:22Z" description: Network flows collector and monitoring solution operators.operatorframework.io/builder: operator-sdk-v1.25.3 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -292,6 +292,12 @@ spec: - get - list - watch + - apiGroups: + - authentication + resources: + - tokenreviews + verbs: + - create - apiGroups: - autoscaling resources: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 045114750..a492d12d4 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -35,6 +35,12 @@ rules: - get - list - watch +- apiGroups: + - authentication + resources: + - tokenreviews + verbs: + - create - apiGroups: - autoscaling resources: diff --git a/controllers/consoleplugin/consoleplugin_objects.go b/controllers/consoleplugin/consoleplugin_objects.go index dbe22b46b..4d0bd6e72 100644 --- a/controllers/consoleplugin/consoleplugin_objects.go +++ b/controllers/consoleplugin/consoleplugin_objects.go @@ -12,6 +12,7 @@ import ( appsv1 "k8s.io/api/apps/v1" ascv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" flowsv1alpha1 "github.com/netobserv/network-observability-operator/api/v1alpha1" @@ -297,18 +298,6 @@ func (b *builder) service(old *corev1.Service) *corev1.Service { return newService } -func buildServiceAccount(ns string) *corev1.ServiceAccount { - return &corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: constants.PluginName, - Namespace: ns, - Labels: map[string]string{ - "app": constants.PluginName, - }, - }, - } -} - // returns a configmap with a digest of its configuration contents, which will be used to // detect any configuration change func (b *builder) configMap() (*corev1.ConfigMap, string) { @@ -337,3 +326,52 @@ func (b *builder) configMap() (*corev1.ConfigMap, string) { digest := strconv.FormatUint(hasher.Sum64(), 36) return &configMap, digest } + +func (b *builder) serviceAccount() *corev1.ServiceAccount { + return &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.PluginName, + Namespace: b.namespace, + Labels: map[string]string{ + "app": constants.PluginName, + }, + }, + } +} + +// The operator needs to have at least the same permissions as flowlogs-pipeline in order to grant them +//+kubebuilder:rbac:groups=authentication,resources=tokenreviews,verbs=create + +func buildClusterRole() *rbacv1.ClusterRole { + return &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.PluginName, + }, + Rules: []rbacv1.PolicyRule{{ + APIGroups: []string{"authentication"}, + Verbs: []string{"create"}, + Resources: []string{"tokenreviews"}, + }}, + } +} + +func (b *builder) clusterRoleBinding() *rbacv1.ClusterRoleBinding { + return &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.PluginName, + Labels: map[string]string{ + "app": constants.PluginName, + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: constants.PluginName, + }, + Subjects: []rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: constants.PluginName, + Namespace: b.namespace, + }}, + } +} diff --git a/controllers/consoleplugin/consoleplugin_reconciler.go b/controllers/consoleplugin/consoleplugin_reconciler.go index ec1cf7239..d855a42fe 100644 --- a/controllers/consoleplugin/consoleplugin_reconciler.go +++ b/controllers/consoleplugin/consoleplugin_reconciler.go @@ -66,14 +66,16 @@ func NewReconciler(cl reconcilers.ClientHelper, ns, prevNS, imageName string, av // InitStaticResources inits some "static" / one-shot resources, usually not subject to reconciliation func (r *CPReconciler) InitStaticResources(ctx context.Context) error { - return r.CreateOwned(ctx, buildServiceAccount(r.nobjMngr.Namespace)) + cr := buildClusterRole() + return r.ReconcileClusterRole(ctx, cr) } // PrepareNamespaceChange cleans up old namespace and restore the relevant "static" resources func (r *CPReconciler) PrepareNamespaceChange(ctx context.Context) error { // Switching namespace => delete everything in the previous namespace r.nobjMngr.CleanupPreviousNamespace(ctx) - return r.CreateOwned(ctx, buildServiceAccount(r.nobjMngr.Namespace)) + cr := buildClusterRole() + return r.ReconcileClusterRole(ctx, cr) } // Reconcile is the reconciler entry point to reconcile the current plugin state with the desired configuration @@ -92,6 +94,10 @@ func (r *CPReconciler) Reconcile(ctx context.Context, desired *flowsv1alpha1.Flo // Create object builder builder := newBuilder(ns, r.image, &desired.Spec.ConsolePlugin, &desired.Spec.Loki, r.CertWatcher) + if err := r.reconcilePermissions(ctx, &builder); err != nil { + return err + } + if err = r.reconcilePlugin(ctx, builder, &desired.Spec, ns); err != nil { return err } @@ -136,6 +142,18 @@ func (r *CPReconciler) checkAutoPatch(ctx context.Context, desired *flowsv1alpha return nil } +func (r *CPReconciler) reconcilePermissions(ctx context.Context, builder *builder) error { + if !r.nobjMngr.Exists(r.owned.serviceAccount) { + return r.CreateOwned(ctx, builder.serviceAccount()) + } // update not needed for now + + desired := builder.clusterRoleBinding() + if err := r.ReconcileClusterRoleBinding(ctx, desired); err != nil { + return err + } + return nil +} + func (r *CPReconciler) reconcilePlugin(ctx context.Context, builder builder, desired *flowsv1alpha1.FlowCollectorSpec, ns string) error { // Console plugin is cluster-scope (it's not deployed in our namespace) however it must still be updated if our namespace changes oldPlg := osv1alpha1.ConsolePlugin{}