Skip to content

Commit 616d538

Browse files
committed
Automate helm ClusterRole RBAC sync from kubebuilder
1 parent ed454f5 commit 616d538

File tree

4 files changed

+272
-57
lines changed

4 files changed

+272
-57
lines changed

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ deploy: manifests
8181
manifests: controller-gen kustomize
8282
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=controller-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
8383
yq eval '.metadata.name = "webhook"' -i config/webhook/manifests.yaml
84+
hack/sync-rbac-to-helm.sh
8485

8586
crds: manifests
8687
$(MOVE_GATEWAY_CRDS)
@@ -204,7 +205,7 @@ lint:
204205
echo "TODO"
205206

206207
.PHONY: quick-ci
207-
quick-ci: verify-versions verify-generate verify-crds
208+
quick-ci: verify-versions verify-generate verify-crds verify-rbac-sync
208209
echo "Done!"
209210

210211
.PHONY: verify-generate
@@ -215,6 +216,10 @@ verify-generate:
215216
verify-crds:
216217
hack/verify-crds.sh
217218

219+
.PHONY: verify-rbac-sync
220+
verify-rbac-sync:
221+
hack/verify-rbac-sync.sh
222+
218223
.PHONY: verify-versions
219224
verify-versions:
220225
hack/verify-versions.sh

hack/sync-rbac-to-helm.sh

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright 2025 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# This script syncs RBAC rules from the kubebuilder-generated role.yaml
18+
# into the helm chart's rbac.yaml template, keeping helm-specific sections
19+
# (leader election, bindings, conditionals) intact.
20+
21+
set -o errexit
22+
set -o nounset
23+
set -o pipefail
24+
25+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26+
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
27+
28+
KUBEBUILDER_ROLE="${ROOT_DIR}/config/rbac/role.yaml"
29+
HELM_RBAC="${ROOT_DIR}/helm/aws-load-balancer-controller/templates/rbac.yaml"
30+
31+
if [ ! -f "${KUBEBUILDER_ROLE}" ]; then
32+
echo "Error: kubebuilder role not found at ${KUBEBUILDER_ROLE}"
33+
echo "Run 'make manifests' first."
34+
exit 1
35+
fi
36+
37+
if [ ! -f "${HELM_RBAC}" ]; then
38+
echo "Error: helm rbac template not found at ${HELM_RBAC}"
39+
exit 1
40+
fi
41+
42+
# Extract rules from kubebuilder role.yaml and convert to helm flow style
43+
# We use yq to read the rules and output them in the compact format used by the helm chart
44+
generate_helm_clusterrole_rules() {
45+
# Read rules from kubebuilder role.yaml using yq
46+
# Convert each rule to the flow-style format used in the helm chart
47+
yq eval -o=json '.rules' "${KUBEBUILDER_ROLE}" | python3 -c '
48+
import json
49+
import sys
50+
51+
rules = json.load(sys.stdin)
52+
53+
def format_list(items):
54+
"""Format a list as YAML flow sequence: [item1, item2]"""
55+
return "[" + ", ".join(str(i) for i in items) + "]"
56+
57+
for rule in rules:
58+
api_groups = rule.get("apiGroups", [])
59+
resources = rule.get("resources", [])
60+
verbs = rule.get("verbs", [])
61+
resource_names = rule.get("resourceNames", None)
62+
63+
# Quote empty string api group
64+
formatted_groups = []
65+
for g in api_groups:
66+
if g == "":
67+
formatted_groups.append("\"\"")
68+
else:
69+
formatted_groups.append("\"" + g + "\"")
70+
71+
print("- apiGroups: [{}]".format(", ".join(formatted_groups)))
72+
print(" resources: {}".format(format_list(resources)))
73+
if resource_names:
74+
print(" resourceNames: {}".format(format_list(resource_names)))
75+
print(" verbs: {}".format(format_list(verbs)))
76+
'
77+
}
78+
79+
# Build the new helm rbac.yaml
80+
# We preserve the leader election Role, RoleBinding, and ClusterRoleBinding
81+
# from the existing template, and only replace the ClusterRole rules.
82+
83+
GENERATED_RULES=$(generate_helm_clusterrole_rules)
84+
85+
cat > "${HELM_RBAC}" << 'HELM_HEADER'
86+
{{- if .Values.rbac.create }}
87+
apiVersion: rbac.authorization.k8s.io/v1
88+
kind: Role
89+
metadata:
90+
name: {{ template "aws-load-balancer-controller.fullname" . }}-leader-election-role
91+
namespace: {{ .Release.Namespace }}
92+
labels:
93+
{{- include "aws-load-balancer-controller.labels" . | nindent 4 }}
94+
rules:
95+
- apiGroups: [""]
96+
resources: [configmaps]
97+
verbs: [create]
98+
- apiGroups: [""]
99+
resources: [configmaps]
100+
resourceNames: [aws-load-balancer-controller-leader]
101+
verbs: [get, patch, update]
102+
- apiGroups:
103+
- "coordination.k8s.io"
104+
resources:
105+
- leases
106+
verbs:
107+
- create
108+
- apiGroups:
109+
- "coordination.k8s.io"
110+
resources:
111+
- leases
112+
resourceNames:
113+
- aws-load-balancer-controller-leader
114+
verbs:
115+
- get
116+
- update
117+
- patch
118+
---
119+
apiVersion: rbac.authorization.k8s.io/v1
120+
kind: RoleBinding
121+
metadata:
122+
name: {{ template "aws-load-balancer-controller.fullname" . }}-leader-election-rolebinding
123+
namespace: {{ .Release.Namespace }}
124+
labels:
125+
{{- include "aws-load-balancer-controller.labels" . | nindent 4 }}
126+
roleRef:
127+
apiGroup: rbac.authorization.k8s.io
128+
kind: Role
129+
name: {{ template "aws-load-balancer-controller.fullname" . }}-leader-election-role
130+
subjects:
131+
- kind: ServiceAccount
132+
name: {{ template "aws-load-balancer-controller.serviceAccountName" . }}
133+
namespace: {{ .Release.Namespace }}
134+
---
135+
apiVersion: rbac.authorization.k8s.io/v1
136+
kind: ClusterRole
137+
metadata:
138+
name: {{ template "aws-load-balancer-controller.fullname" . }}-role
139+
labels:
140+
{{- include "aws-load-balancer-controller.labels" . | nindent 4 }}
141+
rules:
142+
HELM_HEADER
143+
144+
# Append the generated rules (from kubebuilder source of truth)
145+
echo "# AUTO-GENERATED from config/rbac/role.yaml by hack/sync-rbac-to-helm.sh" >> "${HELM_RBAC}"
146+
echo "# Do not edit these rules manually. Run 'make manifests' to update." >> "${HELM_RBAC}"
147+
echo "${GENERATED_RULES}" >> "${HELM_RBAC}"
148+
149+
# Append helm-specific conditional rules and the ClusterRoleBinding
150+
cat >> "${HELM_RBAC}" << 'HELM_FOOTER'
151+
{{- if .Values.clusterSecretsPermissions.allowAllSecrets }}
152+
- apiGroups: [""]
153+
resources: [secrets]
154+
verbs: [get, list, watch]
155+
{{- end }}
156+
---
157+
apiVersion: rbac.authorization.k8s.io/v1
158+
kind: ClusterRoleBinding
159+
metadata:
160+
name: {{ template "aws-load-balancer-controller.fullname" . }}-rolebinding
161+
labels:
162+
{{- include "aws-load-balancer-controller.labels" . | nindent 4 }}
163+
roleRef:
164+
apiGroup: rbac.authorization.k8s.io
165+
kind: ClusterRole
166+
name: {{ template "aws-load-balancer-controller.fullname" . }}-role
167+
subjects:
168+
- kind: ServiceAccount
169+
name: {{ template "aws-load-balancer-controller.serviceAccountName" . }}
170+
namespace: {{ .Release.Namespace }}
171+
{{- end }}
172+
HELM_FOOTER
173+
174+
echo "Synced RBAC rules from ${KUBEBUILDER_ROLE} to ${HELM_RBAC}"

hack/verify-rbac-sync.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright 2025 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# Verifies that the helm chart RBAC rules are in sync with the
18+
# kubebuilder-generated role.yaml. Fails if they have drifted.
19+
20+
set -o errexit
21+
set -o nounset
22+
set -o pipefail
23+
24+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
25+
26+
"${SCRIPT_DIR}/sync-rbac-to-helm.sh"
27+
28+
changed_files=$(git status --porcelain --untracked-files=no -- helm/aws-load-balancer-controller/templates/rbac.yaml || true)
29+
if [ -n "${changed_files}" ]; then
30+
echo "Detected that helm RBAC is out of sync with kubebuilder RBAC; run 'make sync-rbac'"
31+
echo "changed files:"
32+
printf "%s\n" "${changed_files}"
33+
echo "git diff:"
34+
git --no-pager diff -- helm/aws-load-balancer-controller/templates/rbac.yaml
35+
echo "To fix: run 'make sync-rbac'"
36+
exit 1
37+
fi

helm/aws-load-balancer-controller/templates/rbac.yaml

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -54,83 +54,82 @@ metadata:
5454
labels:
5555
{{- include "aws-load-balancer-controller.labels" . | nindent 4 }}
5656
rules:
57-
- apiGroups: ["elbv2.k8s.aws"]
58-
resources: [targetgroupbindings]
59-
verbs: [create, delete, get, list, patch, update, watch]
60-
- apiGroups: ["elbv2.k8s.aws"]
61-
resources: [ingressclassparams]
62-
verbs: [get, list, watch]
63-
- apiGroups: ["elbv2.k8s.aws"]
64-
resources: [albtargetcontrolconfigs]
65-
verbs: [get]
57+
# AUTO-GENERATED from config/rbac/role.yaml by hack/sync-rbac-to-helm.sh
58+
# Do not edit these rules manually. Run 'make manifests' to update.
6659
- apiGroups: [""]
67-
resources: [events]
68-
verbs: [create, patch]
60+
resources: [configmaps]
61+
verbs: [create, delete, get, update]
6962
- apiGroups: [""]
70-
resources: [pods]
71-
verbs: [get, list, watch]
72-
- apiGroups: ["networking.k8s.io"]
73-
resources: [ingressclasses]
63+
resources: [endpoints, namespaces, nodes, pods]
7464
verbs: [get, list, watch]
75-
- apiGroups: ["", "extensions", "networking.k8s.io"]
76-
resources: [services, ingresses]
77-
verbs: [get, list, patch, update, watch]
7865
- apiGroups: [""]
79-
resources: [nodes, namespaces, endpoints]
80-
verbs: [get, list, watch]
66+
resources: [events]
67+
verbs: [create, patch]
8168
- apiGroups: [""]
82-
resources: [configmaps]
83-
verbs: [get, delete, create, update]
84-
{{- if .Values.clusterSecretsPermissions.allowAllSecrets }}
69+
resources: [pods/status, services/status]
70+
verbs: [patch, update]
8571
- apiGroups: [""]
86-
resources: [secrets]
87-
verbs: [get, list, watch]
88-
{{- end }}
89-
- apiGroups: ["elbv2.k8s.aws", "", "extensions", "networking.k8s.io"]
90-
resources: [targetgroupbindings/status, pods/status, services/status, ingresses/status]
91-
verbs: [update, patch]
72+
resources: [services]
73+
verbs: [get, list, patch, update, watch]
74+
- apiGroups: ["aga.k8s.aws"]
75+
resources: [globalaccelerators]
76+
verbs: [get, list, patch, watch]
77+
- apiGroups: ["aga.k8s.aws"]
78+
resources: [globalaccelerators/finalizers, globalaccelerators/status]
79+
verbs: [patch, update]
9280
- apiGroups: ["discovery.k8s.io"]
9381
resources: [endpointslices]
9482
verbs: [get, list, watch]
83+
- apiGroups: ["elbv2.k8s.aws"]
84+
resources: [albtargetcontrolconfigs]
85+
verbs: [get]
86+
- apiGroups: ["elbv2.k8s.aws"]
87+
resources: [ingressclassparams]
88+
verbs: [get, list, watch]
89+
- apiGroups: ["elbv2.k8s.aws"]
90+
resources: [targetgroupbindings]
91+
verbs: [create, delete, get, list, patch, update, watch]
92+
- apiGroups: ["elbv2.k8s.aws"]
93+
resources: [targetgroupbindings/status]
94+
verbs: [patch, update]
95+
- apiGroups: ["extensions", "networking.k8s.io"]
96+
resources: [ingresses]
97+
verbs: [get, list, patch, update, watch]
98+
- apiGroups: ["extensions", "networking.k8s.io"]
99+
resources: [ingresses/status]
100+
verbs: [patch, update]
95101
- apiGroups: ["gateway.k8s.aws"]
96-
resources: [loadbalancerconfigurations, targetgroupconfigurations, listenerruleconfigurations]
97-
verbs: [get, list, watch, patch]
102+
resources: [listenerruleconfigurations, loadbalancerconfigurations, targetgroupconfigurations]
103+
verbs: [get, list, patch, watch]
98104
- apiGroups: ["gateway.k8s.aws"]
99-
resources: [loadbalancerconfigurations/finalizers, targetgroupconfigurations/finalizers, listenerruleconfigurations/finalizers]
100-
verbs: [update, patch]
105+
resources: [listenerruleconfigurations/finalizers, loadbalancerconfigurations/finalizers, targetgroupconfigurations/finalizers]
106+
verbs: [patch, update]
101107
- apiGroups: ["gateway.k8s.aws"]
102-
resources: [loadbalancerconfigurations/status, targetgroupconfigurations/status, listenerruleconfigurations/status]
103-
verbs: [get, patch, watch]
104-
- apiGroups: ["gateway.networking.k8s.io"]
105-
resources: [gatewayclasses, gateways]
106-
verbs: [get, list, watch, patch]
108+
resources: [listenerruleconfigurations/status, loadbalancerconfigurations/status, targetgroupconfigurations/status]
109+
verbs: [get, patch, update]
107110
- apiGroups: ["gateway.networking.k8s.io"]
108-
resources: [referencegrants]
109-
verbs: [get, list, watch]
111+
resources: [gatewayclasses, gateways, referencegrants]
112+
verbs: [get, list, patch, watch]
110113
- apiGroups: ["gateway.networking.k8s.io"]
111114
resources: [gatewayclasses/finalizers, gateways/finalizers]
112-
verbs: [update, patch]
115+
verbs: [patch, update]
113116
- apiGroups: ["gateway.networking.k8s.io"]
114-
resources: [gatewayclasses/status, gateways/status]
117+
resources: [gatewayclasses/status, gateways/status, grpcroutes/status, httproutes/status, listenersets/status, tcproutes/status, tlsroutes/status, udproutes/status]
115118
verbs: [get, patch, update]
116119
- apiGroups: ["gateway.networking.k8s.io"]
117-
resources: [grpcroutes, httproutes, tcproutes, tlsroutes, udproutes, listenersets]
120+
resources: [grpcroutes, httproutes, listenersets, tcproutes, tlsroutes, udproutes]
118121
verbs: [get, list, watch]
119122
- apiGroups: ["gateway.networking.k8s.io"]
120-
resources: [grpcroutes/finalizers, httproutes/finalizers, tcproutes/finalizers, tlsroutes/finalizers, udproutes/finalizers, listenersets/finalizers]
123+
resources: [grpcroutes/finalizers, httproutes/finalizers, listenersets/finalizers, tcproutes/finalizers, tlsroutes/finalizers, udproutes/finalizers]
121124
verbs: [update]
122-
- apiGroups: ["gateway.networking.k8s.io"]
123-
resources: [grpcroutes/status, httproutes/status, tcproutes/status, tlsroutes/status, udproutes/status, listenersets/status]
124-
verbs: [get, patch, update]
125-
- apiGroups: ["aga.k8s.aws"]
126-
resources: [globalaccelerators]
127-
verbs: [get, list, patch, watch]
128-
- apiGroups: ["aga.k8s.aws"]
129-
resources: [globalaccelerators/finalizers]
130-
verbs: [patch, update]
131-
- apiGroups: ["aga.k8s.aws"]
132-
resources: [globalaccelerators/status]
133-
verbs: [patch, update]
125+
- apiGroups: ["networking.k8s.io"]
126+
resources: [ingressclasses]
127+
verbs: [get, list, watch]
128+
{{- if .Values.clusterSecretsPermissions.allowAllSecrets }}
129+
- apiGroups: [""]
130+
resources: [secrets]
131+
verbs: [get, list, watch]
132+
{{- end }}
134133
---
135134
apiVersion: rbac.authorization.k8s.io/v1
136135
kind: ClusterRoleBinding

0 commit comments

Comments
 (0)