Skip to content

Commit 3005ddf

Browse files
committed
EPMDEDP-17305: fix: Reduce the operator's RBAC to the permissions it uses
Every grant is backed by a call site. 1. The chart ships no cluster-scoped RBAC. The ServiceAccount holds one namespaced Role and one RoleBinding. 2. Verbs are explicit per resource: secrets get;list;watch;update;delete; configmaps, quicklinks and triggertemplates get; ingresses, httproutes and routes get;create; cdpipelines and stages get;list; pipelineruns list;watch;create; eventlisteners get;create;patch; leases create;get;update; /status get;patch;update; /finalizers update. 3. The cache holds only Secrets labelled app.edp.epam.com/integration-secret, the one type a controller watches. Everything else is read live through client.Cache.DisableFor, so no informer starts and no list/watch is needed. DefaultTransform strips managedFields. 4. The kubebuilder markers are the single source of truth. controller-gen emits a namespaced Role only; both chart Roles mirror config/rbac/role.yaml and differ solely by the platform split. 5. The kustomize path mirrors the chart: manager-role bound by a RoleBinding, carrying leader-election leases and events, plus metrics-auth for the metrics endpoint that config/default enables. Signed-off-by: Sergiy Kulanov <sergiy_kulanov@epam.com>
1 parent 498d381 commit 3005ddf

19 files changed

Lines changed: 222 additions & 355 deletions

cmd/main.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ import (
1616
routeApi "github.com/openshift/api/route/v1"
1717
tektonpipelineApi "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
1818
tektonTriggersApi "github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1"
19+
corev1 "k8s.io/api/core/v1"
1920
networkingV1 "k8s.io/api/networking/v1"
2021
k8sruntime "k8s.io/apimachinery/pkg/runtime"
2122
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2223
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
2324
ctrl "sigs.k8s.io/controller-runtime"
2425
"sigs.k8s.io/controller-runtime/pkg/cache"
2526
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
27+
"sigs.k8s.io/controller-runtime/pkg/client"
2628
"sigs.k8s.io/controller-runtime/pkg/healthz"
2729
"sigs.k8s.io/controller-runtime/pkg/log/zap"
2830
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
@@ -67,6 +69,27 @@ const (
6769
branchStaleCheckDefaultInterval = time.Hour * 24
6870
)
6971

72+
// uncachedTypes are read live. No informer is started for them, so the Role needs only
73+
// the verbs each call site uses. Secret is listed here as well: its informer, scoped
74+
// below, exists for watching alone.
75+
//
76+
// client.MatchingFields is served by the cache only. Never field-index a type listed
77+
// here (pkg/codebase/index.go), and never list an indexed type here.
78+
var uncachedTypes = []client.Object{
79+
&corev1.Secret{},
80+
&corev1.ConfigMap{},
81+
&codebaseApiV1.QuickLink{},
82+
&cdPipeApi.CDPipeline{},
83+
&cdPipeApi.Stage{},
84+
&tektonTriggersApi.TriggerTemplate{},
85+
&networkingV1.Ingress{},
86+
&gatewayv1.HTTPRoute{},
87+
&routeApi.Route{},
88+
}
89+
90+
// Leader election lock. resourcelock.LeasesLock calls Get/Create/Update.
91+
// +kubebuilder:rbac:groups=coordination.k8s.io,namespace=placeholder,resources=leases,verbs=get;create;update
92+
7093
func main() {
7194
var (
7295
metricsAddr string
@@ -224,6 +247,13 @@ func main() {
224247
os.Exit(1)
225248
}
226249

250+
secretCacheSelector := integrationsecret.CacheSelector()
251+
252+
setupLog.Info("Restricting the cache",
253+
"namespace", ns,
254+
"secretLabelSelector", secretCacheSelector.String(),
255+
)
256+
227257
cfg := ctrl.GetConfigOrDie()
228258

229259
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
@@ -235,6 +265,15 @@ func main() {
235265
LeaderElectionID: codebaseOperatorLock,
236266
Cache: cache.Options{
237267
DefaultNamespaces: map[string]cache.Config{ns: {}},
268+
DefaultTransform: cache.TransformStripManagedFields(),
269+
ByObject: map[client.Object]cache.ByObject{
270+
// Only the IntegrationSecret controller watches Secrets. The informer holds
271+
// no other Secret in the namespace.
272+
&corev1.Secret{}: {Label: secretCacheSelector},
273+
},
274+
},
275+
Client: client.Options{
276+
Cache: &client.CacheOptions{DisableFor: uncachedTypes},
238277
},
239278
})
240279
if err != nil {

config/rbac/kustomization.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ resources:
55
# runtime. Be sure to update RoleBinding and ClusterRoleBinding
66
# subjects if changing service account names.
77
- service_account.yaml
8+
# manager-role covers every operator permission, leader-election leases and events
9+
# included. Generated from the kubebuilder markers by `make manifests`.
810
- role.yaml
911
- role_binding.yaml
10-
- leader_election_role.yaml
11-
- leader_election_role_binding.yaml
1212
# The following RBAC configurations are used to protect
1313
# the metrics endpoint with authn/authz. These configurations
1414
# ensure that only authorized users and service accounts

config/rbac/leader_election_role.yaml

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

config/rbac/leader_election_role_binding.yaml

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

config/rbac/role.yaml

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,92 @@
11
---
22
apiVersion: rbac.authorization.k8s.io/v1
3-
kind: ClusterRole
3+
kind: Role
44
metadata:
55
name: manager-role
6+
namespace: placeholder
67
rules:
78
- apiGroups:
8-
- v2.edp.epam.com
9+
- ""
910
resources:
10-
- jiraissuemetadatas
11-
- jiraservers
11+
- configmaps
1212
verbs:
13-
- create
14-
- delete
1513
- get
16-
- list
17-
- patch
18-
- update
19-
- watch
20-
- apiGroups:
21-
- v2.edp.epam.com
22-
resources:
23-
- jiraissuemetadatas/finalizers
24-
- jiraservers/finalizers
25-
verbs:
26-
- update
2714
- apiGroups:
28-
- v2.edp.epam.com
15+
- ""
2916
resources:
30-
- jiraissuemetadatas/status
31-
- jiraservers/status
17+
- events
3218
verbs:
33-
- get
19+
- create
3420
- patch
35-
- update
36-
---
37-
apiVersion: rbac.authorization.k8s.io/v1
38-
kind: Role
39-
metadata:
40-
name: manager-role
41-
namespace: placeholder
42-
rules:
4321
- apiGroups:
4422
- ""
4523
resources:
4624
- secrets
4725
verbs:
26+
- delete
4827
- get
4928
- list
50-
- patch
5129
- update
5230
- watch
31+
- apiGroups:
32+
- coordination.k8s.io
33+
resources:
34+
- leases
35+
verbs:
36+
- create
37+
- get
38+
- update
5339
- apiGroups:
5440
- gateway.networking.k8s.io
5541
resources:
5642
- httproutes
5743
verbs:
5844
- create
5945
- get
60-
- list
61-
- watch
6246
- apiGroups:
6347
- networking.k8s.io
6448
resources:
6549
- ingresses
6650
verbs:
6751
- create
6852
- get
69-
- list
70-
- watch
7153
- apiGroups:
7254
- route.openshift.io
7355
resources:
7456
- routes
7557
verbs:
7658
- create
7759
- get
78-
- list
79-
- watch
8060
- apiGroups:
8161
- tekton.dev
8262
resources:
8363
- pipelineruns
8464
verbs:
8565
- create
86-
- get
8766
- list
88-
- patch
89-
- update
9067
- watch
68+
- apiGroups:
69+
- triggers.tekton.dev
70+
resources:
71+
- eventlisteners
72+
verbs:
73+
- create
74+
- get
75+
- patch
9176
- apiGroups:
9277
- triggers.tekton.dev
9378
resources:
9479
- triggertemplates
9580
verbs:
9681
- get
82+
- apiGroups:
83+
- v2.edp.epam.com
84+
resources:
85+
- cdpipelines
86+
- stages
87+
verbs:
88+
- get
9789
- list
98-
- watch
9990
- apiGroups:
10091
- v2.edp.epam.com
10192
resources:
@@ -104,6 +95,8 @@ rules:
10495
- codebaseimagestreams
10596
- codebases
10697
- gitservers
98+
- jiraissuemetadatas
99+
- jiraservers
107100
verbs:
108101
- create
109102
- delete
@@ -120,6 +113,8 @@ rules:
120113
- codebaseimagestreams/finalizers
121114
- codebases/finalizers
122115
- gitservers/finalizers
116+
- jiraissuemetadatas/finalizers
117+
- jiraservers/finalizers
123118
verbs:
124119
- update
125120
- apiGroups:
@@ -130,7 +125,15 @@ rules:
130125
- codebaseimagestreams/status
131126
- codebases/status
132127
- gitservers/status
128+
- jiraissuemetadatas/status
129+
- jiraservers/status
133130
verbs:
134131
- get
135132
- patch
136133
- update
134+
- apiGroups:
135+
- v2.edp.epam.com
136+
resources:
137+
- quicklinks
138+
verbs:
139+
- get

config/rbac/role_binding.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
# Every kubebuilder marker carries namespace=placeholder, so controller-gen emits a
2+
# namespaced Role. Bind it with a RoleBinding.
13
apiVersion: rbac.authorization.k8s.io/v1
2-
kind: ClusterRoleBinding
4+
kind: RoleBinding
35
metadata:
46
labels:
5-
app.kubernetes.io/name: clusterrolebinding
7+
app.kubernetes.io/name: rolebinding
68
app.kubernetes.io/instance: manager-rolebinding
79
app.kubernetes.io/component: rbac
810
app.kubernetes.io/created-by: edp-codebase-operator
@@ -11,7 +13,7 @@ metadata:
1113
name: manager-rolebinding
1214
roleRef:
1315
apiGroup: rbac.authorization.k8s.io
14-
kind: ClusterRole
16+
kind: Role
1517
name: manager-role
1618
subjects:
1719
- kind: ServiceAccount

controllers/cdstagedeploy/cdstagedeploy_controller.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,10 @@ func (r *ReconcileCDStageDeploy) SetupWithManager(mgr ctrl.Manager) error {
8080
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=cdstagedeployments,verbs=get;list;watch;create;update;patch;delete
8181
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=cdstagedeployments/status,verbs=get;update;patch
8282
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=cdstagedeployments/finalizers,verbs=update
83-
// +kubebuilder:rbac:groups=triggers.tekton.dev,namespace=placeholder,resources=triggertemplates,verbs=get;list;watch;
84-
// +kubebuilder:rbac:groups=tekton.dev,namespace=placeholder,resources=pipelineruns,verbs=get;list;watch;create;update;patch
83+
// +kubebuilder:rbac:groups=triggers.tekton.dev,namespace=placeholder,resources=triggertemplates,verbs=get
84+
// Cached List, hence list+watch.
85+
// +kubebuilder:rbac:groups=tekton.dev,namespace=placeholder,resources=pipelineruns,verbs=list;watch;create
86+
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=cdpipelines;stages,verbs=get;list
8587

8688
// Reconcile reads that state of the cluster for a CDStageDeploy object and makes changes based on the state.
8789
func (r *ReconcileCDStageDeploy) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {

controllers/codebase/codebase_controller.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,13 @@ func (r *ReconcileCodebase) SetupWithManager(mgr ctrl.Manager) error {
9191
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebases,verbs=get;list;watch;create;update;patch;delete
9292
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebases/status,verbs=get;update;patch
9393
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebases/finalizers,verbs=update
94-
// +kubebuilder:rbac:groups=route.openshift.io,namespace=placeholder,resources=routes,verbs=get;list;watch
94+
// +kubebuilder:rbac:groups=route.openshift.io,namespace=placeholder,resources=routes,verbs=get
95+
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=quicklinks,verbs=get
96+
// +kubebuilder:rbac:groups="",namespace=placeholder,resources=configmaps,verbs=get
97+
// update: webhook secret written into the GitServer Secret.
98+
// delete: clone credentials, when Codebase.spec.cloneRepositoryCredentials
99+
// .clearSecretAfterUse is set.
100+
// +kubebuilder:rbac:groups="",namespace=placeholder,resources=secrets,verbs=get;update;delete
95101

96102
// Reconcile reads that state of the cluster for a Codebase object and makes changes based on the state.
97103
func (r *ReconcileCodebase) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {

controllers/codebasebranch/codebasebranch_controller.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ func (r *ReconcileCodebaseBranch) SetupWithManager(mgr ctrl.Manager, maxConcurre
9999
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebasebranches,verbs=get;list;watch;create;update;patch;delete
100100
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebasebranches/status,verbs=get;update;patch
101101
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebasebranches/finalizers,verbs=update
102+
// +kubebuilder:rbac:groups="",namespace=placeholder,resources=secrets,verbs=get
103+
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=cdpipelines;stages,verbs=get;list
104+
// +kubebuilder:rbac:groups="",namespace=placeholder,resources=events,verbs=create;patch
102105

103106
// Reconcile reads that state of the cluster for a CodebaseBranch object and makes changes based on the state.
104107
func (r *ReconcileCodebaseBranch) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {

controllers/codebaseimagestream/codebaseimagestream_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func (r *ReconcileCodebaseImageStream) SetupWithManager(mgr ctrl.Manager) error
7474
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebaseimagestreams,verbs=get;list;watch;create;update;patch;delete
7575
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebaseimagestreams/status,verbs=get;update;patch
7676
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=codebaseimagestreams/finalizers,verbs=update
77+
// +kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=cdpipelines;stages,verbs=get;list
7778

7879
// Reconcile reads that state of the cluster for a CodebaseImageStream object and makes changes based on the state.
7980
func (r *ReconcileCodebaseImageStream) Reconcile(

0 commit comments

Comments
 (0)