Skip to content

Commit eb04829

Browse files
committed
Fix RBAC issue and create deploy-role on a per namespace basis
1 parent fbd2458 commit eb04829

5 files changed

Lines changed: 76 additions & 50 deletions

File tree

config/rbac/deploy_function_clusterrole.yaml

Lines changed: 0 additions & 21 deletions
This file was deleted.

config/rbac/deploy_function_clusterrole_binding.yaml

Lines changed: 0 additions & 13 deletions
This file was deleted.

config/rbac/kustomization.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,3 @@ resources:
2626
- function_editor_role.yaml
2727
- function_viewer_role.yaml
2828

29-
- deploy_function_clusterrole.yaml
30-
- deploy_function_clusterrole_binding.yaml
31-

config/rbac/role.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ rules:
8484
- rbac.authorization.k8s.io
8585
resources:
8686
- rolebindings
87+
- roles
8788
verbs:
8889
- create
8990
- delete
@@ -95,6 +96,7 @@ rules:
9596
- apiGroups:
9697
- serving.knative.dev
9798
resources:
99+
- routes
98100
- services
99101
verbs:
100102
- create

internal/controller/function_controller.go

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ import (
4444
apierrors "k8s.io/apimachinery/pkg/api/errors"
4545
)
4646

47+
const (
48+
deployFunctionRoleName = "func-operator-deploy-function"
49+
)
50+
4751
// FunctionReconciler reconciles a Function object
4852
type FunctionReconciler struct {
4953
client.Client
@@ -58,11 +62,11 @@ type FunctionReconciler struct {
5862
// +kubebuilder:rbac:groups=functions.dev,resources=functions/finalizers,verbs=update
5963
// +kubebuilder:rbac:groups="",resources=secrets;services;persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete
6064
// +kubebuilder:rbac:groups="apps",resources=deployments,verbs=get;list;watch;create;update;patch;delete
61-
// +kubebuilder:rbac:groups="serving.knative.dev",resources=services,verbs=get;list;watch;create;update;patch;delete
65+
// +kubebuilder:rbac:groups="serving.knative.dev",resources=services;routes,verbs=get;list;watch;create;update;patch;delete
6266
// +kubebuilder:rbac:groups="eventing.knative.dev",resources=triggers,verbs=get;list;watch;create;update;patch;delete
6367
// +kubebuilder:rbac:groups=tekton.dev,resources=pipelines;pipelineruns,verbs=get;list;watch;create;update;patch;delete
6468
// +kubebuilder:rbac:groups=tekton.dev,resources=taskruns,verbs=get;list;watch
65-
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete
69+
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings;roles,verbs=get;list;watch;create;update;patch;delete
6670
// +kubebuilder:rbac:groups=http.keda.sh,resources=httpscaledobjects,verbs=get;list;watch;create;update;patch;delete
6771

6872
// Reconcile a Function with status update
@@ -213,9 +217,67 @@ func (r *FunctionReconciler) updateFunctionStatus(function *v1alpha1.Function, m
213217
}
214218

215219
func (r *FunctionReconciler) setupPipelineRBAC(ctx context.Context, function *v1alpha1.Function) error {
220+
if err := r.ensureDeployFunctionRole(ctx, function.Namespace); err != nil {
221+
return fmt.Errorf("failed to ensure deploy-function role: %w", err)
222+
}
223+
224+
if err := r.ensureDeployFunctionRoleBinding(ctx, function); err != nil {
225+
return fmt.Errorf("failed to ensure deploy-function role binding: %w", err)
226+
}
227+
228+
return nil
229+
}
230+
231+
// ensureDeployFunctionRole ensures the deploy-function Role exists in the namespace and is up-to-date.
232+
// This is a namespace-scoped Role so multiple operator instances won't conflict.
233+
func (r *FunctionReconciler) ensureDeployFunctionRole(ctx context.Context, namespace string) error {
234+
logger := log.FromContext(ctx)
235+
236+
expectedRole := &rbacv1.Role{
237+
ObjectMeta: metav1.ObjectMeta{
238+
Name: deployFunctionRoleName,
239+
Namespace: namespace,
240+
},
241+
Rules: []rbacv1.PolicyRule{
242+
{
243+
APIGroups: []string{"serving.knative.dev"},
244+
Resources: []string{"services", "routes"},
245+
Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"},
246+
},
247+
},
248+
}
249+
250+
foundRole := &rbacv1.Role{}
251+
err := r.Get(ctx, types.NamespacedName{Name: expectedRole.Name, Namespace: expectedRole.Namespace}, foundRole)
252+
if err != nil {
253+
if apierrors.IsNotFound(err) {
254+
if err := r.Create(ctx, expectedRole); err != nil {
255+
return fmt.Errorf("failed to create role: %w", err)
256+
}
257+
logger.Info("Created deploy-function role")
258+
return nil
259+
}
260+
return fmt.Errorf("failed to get role: %w", err)
261+
}
262+
263+
// Role exists - update if needed
264+
if !equality.Semantic.DeepEqual(expectedRole.Rules, foundRole.Rules) {
265+
foundRole.Rules = expectedRole.Rules
266+
if err := r.Update(ctx, foundRole); err != nil {
267+
return fmt.Errorf("failed to update role: %w", err)
268+
}
269+
logger.Info("Updated deploy-function role")
270+
} else {
271+
logger.Info("Deploy-function role already up to date")
272+
}
273+
274+
return nil
275+
}
276+
277+
// ensureDeployFunctionRoleBinding ensures the RoleBinding for the deploy-function role exists and is up-to-date.
278+
func (r *FunctionReconciler) ensureDeployFunctionRoleBinding(ctx context.Context, function *v1alpha1.Function) error {
216279
logger := log.FromContext(ctx)
217280

218-
logger.Info("Create rolebinding for deploy-function role")
219281
expectedRoleBinding := &rbacv1.RoleBinding{
220282
ObjectMeta: metav1.ObjectMeta{
221283
Name: "deploy-function-default",
@@ -236,40 +298,39 @@ func (r *FunctionReconciler) setupPipelineRBAC(ctx context.Context, function *v1
236298
Namespace: function.Namespace,
237299
}},
238300
RoleRef: rbacv1.RoleRef{
239-
Kind: "ClusterRole",
240-
Name: "func-operator-deploy-function",
241301
APIGroup: "rbac.authorization.k8s.io",
302+
Kind: "Role",
303+
Name: deployFunctionRoleName,
242304
},
243305
}
306+
244307
foundRoleBinding := &rbacv1.RoleBinding{}
245308
err := r.Get(ctx, types.NamespacedName{Name: expectedRoleBinding.Name, Namespace: expectedRoleBinding.Namespace}, foundRoleBinding)
246309
if err != nil {
247310
if apierrors.IsNotFound(err) {
248311
if err := r.Create(ctx, expectedRoleBinding); err != nil {
249-
return fmt.Errorf("failed to create role binding for deploy-function role: %w", err)
312+
return fmt.Errorf("failed to create role binding: %w", err)
250313
}
251-
logger.Info("Created role binding for deploy-function role")
314+
logger.Info("Created deploy-function role binding")
252315
return nil
253316
}
254-
return fmt.Errorf("failed to check if deploy-function role binding already exists: %w", err)
317+
return fmt.Errorf("failed to get role binding: %w", err)
255318
}
256319

257320
// Update if needed
258321
if !equality.Semantic.DeepDerivative(expectedRoleBinding, foundRoleBinding) {
259-
// Copy expected values into found object
260322
foundRoleBinding.Subjects = expectedRoleBinding.Subjects
261323
foundRoleBinding.RoleRef = expectedRoleBinding.RoleRef
262324
foundRoleBinding.OwnerReferences = expectedRoleBinding.OwnerReferences
263325

264326
if err := r.Update(ctx, foundRoleBinding); err != nil {
265-
return fmt.Errorf("failed to update deploy-function role binding: %w", err)
327+
return fmt.Errorf("failed to update role binding: %w", err)
266328
}
267-
268329
logger.Info("Updated deploy-function role binding")
269-
return nil
330+
} else {
331+
logger.Info("Deploy-function role binding already up to date")
270332
}
271333

272-
logger.Info("Role binding already exists and is up to date. No need to update")
273334
return nil
274335
}
275336

0 commit comments

Comments
 (0)