Skip to content

Commit 309f4d7

Browse files
cacaricoillume
authored andcommitted
charts: Remove ClusterRole default
1 parent efe4781 commit 309f4d7

31 files changed

+3639
-434
lines changed

charts/headlamp/Chart.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ annotations:
2828
url: https://keys.openpgp.org/vks/v1/by-fingerprint/2956B7F7167769370C93730C7264DA7B85D08A37
2929
artifacthub.io/category: monitoring-logging
3030
artifacthub.io/license: Apache-2.0
31+
artifacthub.io/changes: |
32+
- kind: changed
33+
description: The default ClusterRoleBinding is no longer created by default (ClusterRoleBinding creation is now disabled). Users who want a ClusterRoleBinding must now explicitly enable it and provide a clusterRoleName value, as the default clusterRoleName is now empty.
34+
- kind: added
35+
description: Pre-upgrade hook automatically removes old ClusterRoleBinding during upgrades
3136
artifacthub.io/screenshots: |
3237
- title: Cluster Overview
3338
url: https://raw.githubusercontent.com/kubernetes-sigs/headlamp/screenshots/screenshots/cluster_overview.png

charts/headlamp/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ $ helm install my-headlamp headlamp/headlamp \
5353
--set ingress.hosts[0].paths[0].path=/
5454
```
5555

56+
## Upgrading
57+
58+
### Security Improvements
59+
60+
Starting from version 0.39.0, the chart implements enhanced security by default:
61+
62+
- **Removed Permissions**: The default ClusterRoleBinding creation has been disabled (`create: false`), removing the previous `cluster-admin` binding.
63+
64+
**Automatic Migration**: A pre-upgrade hook automatically removes the old `headlamp-admin` ClusterRoleBinding during upgrades to help migrate to the new security configuration. The hook only removes ClusterRoleBindings that were created by Helm, preserving any user-created resources with the same name.
65+
5666
## Configuration
5767

5868
### Core Parameters
@@ -148,8 +158,8 @@ config:
148158
| serviceAccount.create | bool | `true` | Create service account |
149159
| serviceAccount.name | string | `""` | Service account name |
150160
| serviceAccount.annotations | object | `{}` | Service account annotations |
151-
| clusterRoleBinding.create | bool | `true` | Create cluster role binding |
152-
| clusterRoleBinding.clusterRoleName | string | `"cluster-admin"` | Kubernetes ClusterRole name |
161+
| clusterRoleBinding.create | bool | `false` | Create cluster role binding |
162+
| clusterRoleBinding.clusterRoleName | string | `""` | Kubernetes ClusterRole name |
153163
| clusterRoleBinding.annotations | object | `{}` | Cluster role binding annotations |
154164
| hostUsers | bool | `true` | Run in host uid namespace |
155165
| podSecurityContext | object | `{}` | Pod security context (e.g., fsGroup: 2000) |

charts/headlamp/templates/NOTES.txt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020
echo "Visit http://127.0.0.1:8080 to use your application"
2121
kubectl --namespace {{ include "headlamp.namespace" . }} port-forward $POD_NAME 8080:$CONTAINER_PORT
2222
{{- end }}
23-
{{- if .Values.clusterRoleBinding.create }}
2423
{{- if and ( ge .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "24" ) }}
25-
2. Get the token using
26-
kubectl create token {{ include "headlamp.serviceAccountName" . }} --namespace {{ include "headlamp.namespace" . }}
24+
2. Create a service account using
25+
kubectl create serviceaccount {{ include "headlamp.serviceAccountName" . }}-admin --namespace {{ include "headlamp.namespace" . }}
26+
3. Create a clusterrolebinding using
27+
kubectl create clusterrolebinding {{ include "headlamp.serviceAccountName" . }}-admin --clusterrole=cluster-admin --serviceaccount={{ include "headlamp.namespace" . }}:{{ include "headlamp.serviceAccountName" . }}-admin
28+
4. Get the token using
29+
kubectl create token {{ include "headlamp.serviceAccountName" . }}-admin --namespace {{ include "headlamp.namespace" . }}
2730
{{- else }}
28-
2. Get the clusterrolebinding token using
31+
5. Get the clusterrolebinding token using
2932
export SECRET=$(kubectl get secrets --namespace {{ include "headlamp.namespace" . }} -o custom-columns=":metadata.name" | grep "{{ include "headlamp.fullname" . }}-token")
3033
kubectl get secret $SECRET --namespace {{ include "headlamp.namespace" . }} --template=\{\{.data.token\}\} | base64 --decode
3134
{{- end }}
32-
{{- end }}

charts/headlamp/templates/clusterrolebinding.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
apiVersion: rbac.authorization.k8s.io/v1
33
kind: ClusterRoleBinding
44
metadata:
5-
name: {{ include "headlamp.fullname" . }}-admin
5+
name: {{ include "headlamp.fullname" . }}
66
labels:
77
{{- include "headlamp.labels" . | nindent 4 }}
88
{{- with .Values.clusterRoleBinding.annotations }}
@@ -12,7 +12,7 @@ metadata:
1212
roleRef:
1313
apiGroup: rbac.authorization.k8s.io
1414
kind: ClusterRole
15-
name: {{ .Values.clusterRoleBinding.clusterRoleName }}
15+
name: {{ required "clusterRoleBinding.clusterRoleName is required when clusterRoleBinding.create is true" .Values.clusterRoleBinding.clusterRoleName }}
1616
subjects:
1717
- kind: ServiceAccount
1818
name: {{ include "headlamp.serviceAccountName" . }}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: {{ include "headlamp.fullname" . }}-pre-upgrade
6+
namespace: {{ include "headlamp.namespace" . }}
7+
labels:
8+
{{- include "headlamp.labels" . | nindent 4 }}
9+
annotations:
10+
"helm.sh/hook": pre-upgrade
11+
"helm.sh/hook-weight": "-5"
12+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
13+
---
14+
apiVersion: rbac.authorization.k8s.io/v1
15+
kind: ClusterRole
16+
metadata:
17+
name: {{ include "headlamp.fullname" . }}-pre-upgrade
18+
labels:
19+
{{- include "headlamp.labels" . | nindent 4 }}
20+
annotations:
21+
"helm.sh/hook": pre-upgrade
22+
"helm.sh/hook-weight": "-5"
23+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
24+
rules:
25+
- apiGroups: ["rbac.authorization.k8s.io"]
26+
resources: ["clusterrolebindings"]
27+
verbs: ["get", "delete"]
28+
---
29+
apiVersion: rbac.authorization.k8s.io/v1
30+
kind: ClusterRoleBinding
31+
metadata:
32+
name: {{ include "headlamp.fullname" . }}-pre-upgrade
33+
labels:
34+
{{- include "headlamp.labels" . | nindent 4 }}
35+
annotations:
36+
"helm.sh/hook": pre-upgrade
37+
"helm.sh/hook-weight": "-4"
38+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
39+
roleRef:
40+
apiGroup: rbac.authorization.k8s.io
41+
kind: ClusterRole
42+
name: {{ include "headlamp.fullname" . }}-pre-upgrade
43+
subjects:
44+
- kind: ServiceAccount
45+
name: {{ include "headlamp.fullname" . }}-pre-upgrade
46+
namespace: {{ include "headlamp.namespace" . }}
47+
---
48+
apiVersion: batch/v1
49+
kind: Job
50+
metadata:
51+
name: {{ include "headlamp.fullname" . }}-pre-upgrade
52+
namespace: {{ include "headlamp.namespace" . }}
53+
labels:
54+
{{- include "headlamp.labels" . | nindent 4 }}
55+
annotations:
56+
"helm.sh/hook": pre-upgrade
57+
"helm.sh/hook-weight": "-3"
58+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
59+
spec:
60+
ttlSecondsAfterFinished: 300
61+
template:
62+
metadata:
63+
name: {{ include "headlamp.fullname" . }}-pre-upgrade
64+
labels:
65+
{{- include "headlamp.labels" . | nindent 8 }}
66+
spec:
67+
serviceAccountName: {{ include "headlamp.fullname" . }}-pre-upgrade
68+
restartPolicy: Never
69+
containers:
70+
- name: pre-upgrade-cleanup
71+
image: alpine/kubectl:1.35.0@sha256:e7e078c7bb25012141e5957d500834b2a5b266d6de20ecfa862b30d8a892fc7e
72+
command:
73+
- /bin/sh
74+
- -c
75+
- |
76+
set -e
77+
CRB_NAME="{{ include "headlamp.fullname" . }}-admin"
78+
RELEASE_NAME="{{ .Release.Name }}"
79+
80+
echo "Checking for old ClusterRoleBinding ${CRB_NAME}..."
81+
82+
if ! kubectl get clusterrolebinding "${CRB_NAME}" 2>/dev/null; then
83+
echo "ClusterRoleBinding ${CRB_NAME} not found, nothing to clean up"
84+
exit 0
85+
fi
86+
87+
echo "Found ClusterRoleBinding ${CRB_NAME}, verifying it was created by Helm..."
88+
89+
# Check if the ClusterRoleBinding has Helm labels indicating it was created by this chart
90+
MANAGED_BY=$(kubectl get clusterrolebinding "${CRB_NAME}" -o jsonpath='{.metadata.labels.app\.kubernetes\.io/managed-by}' 2>/dev/null || echo "")
91+
INSTANCE=$(kubectl get clusterrolebinding "${CRB_NAME}" -o jsonpath='{.metadata.labels.app\.kubernetes\.io/instance}' 2>/dev/null || echo "")
92+
APP_NAME=$(kubectl get clusterrolebinding "${CRB_NAME}" -o jsonpath='{.metadata.labels.app\.kubernetes\.io/name}' 2>/dev/null || echo "")
93+
94+
if [ "${MANAGED_BY}" = "Helm" ] && [ "${INSTANCE}" = "${RELEASE_NAME}" ] && [ "${APP_NAME}" = "headlamp" ]; then
95+
echo "Confirmed: ${CRB_NAME} was created by this Helm release (${RELEASE_NAME})"
96+
echo "Deleting old ClusterRoleBinding..."
97+
kubectl delete clusterrolebinding "${CRB_NAME}"
98+
echo "Successfully deleted old ClusterRoleBinding"
99+
else
100+
echo "WARNING: ${CRB_NAME} exists but was NOT created by this Helm release"
101+
echo " managed-by: ${MANAGED_BY} (expected: Helm)"
102+
echo " instance: ${INSTANCE} (expected: ${RELEASE_NAME})"
103+
echo " app: ${APP_NAME} (expected: headlamp)"
104+
echo "Skipping deletion to preserve user-created resource"
105+
fi
106+
resources:
107+
requests:
108+
cpu: 10m
109+
memory: 64Mi
110+
limits:
111+
cpu: 100m
112+
memory: 128Mi
113+
114+
securityContext:
115+
{{- toYaml .Values.podSecurityContext | nindent 10 }}
116+
volumeMounts:
117+
- name: tmp
118+
mountPath: /tmp
119+
volumes:
120+
- name: tmp
121+
emptyDir: {}

charts/headlamp/tests/expected_templates/azure-oidc-with-validators.yaml

Lines changed: 145 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,6 @@ metadata:
1212
app.kubernetes.io/version: "0.39.0"
1313
app.kubernetes.io/managed-by: Helm
1414
---
15-
# Source: headlamp/templates/clusterrolebinding.yaml
16-
apiVersion: rbac.authorization.k8s.io/v1
17-
kind: ClusterRoleBinding
18-
metadata:
19-
name: headlamp-admin
20-
labels:
21-
helm.sh/chart: headlamp-0.39.0
22-
app.kubernetes.io/name: headlamp
23-
app.kubernetes.io/instance: headlamp
24-
app.kubernetes.io/version: "0.39.0"
25-
app.kubernetes.io/managed-by: Helm
26-
roleRef:
27-
apiGroup: rbac.authorization.k8s.io
28-
kind: ClusterRole
29-
name: cluster-admin
30-
subjects:
31-
- kind: ServiceAccount
32-
name: headlamp
33-
namespace: default
34-
---
3515
# Source: headlamp/templates/service.yaml
3616
apiVersion: v1
3717
kind: Service
@@ -142,3 +122,148 @@ spec:
142122
port: http
143123
resources:
144124
{}
125+
---
126+
# Source: headlamp/templates/pre-upgrade-cleanup.yaml
127+
apiVersion: v1
128+
kind: ServiceAccount
129+
metadata:
130+
name: headlamp-pre-upgrade
131+
namespace: default
132+
labels:
133+
helm.sh/chart: headlamp-0.39.0
134+
app.kubernetes.io/name: headlamp
135+
app.kubernetes.io/instance: headlamp
136+
app.kubernetes.io/version: "0.39.0"
137+
app.kubernetes.io/managed-by: Helm
138+
annotations:
139+
"helm.sh/hook": pre-upgrade
140+
"helm.sh/hook-weight": "-5"
141+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
142+
---
143+
# Source: headlamp/templates/pre-upgrade-cleanup.yaml
144+
apiVersion: rbac.authorization.k8s.io/v1
145+
kind: ClusterRole
146+
metadata:
147+
name: headlamp-pre-upgrade
148+
labels:
149+
helm.sh/chart: headlamp-0.39.0
150+
app.kubernetes.io/name: headlamp
151+
app.kubernetes.io/instance: headlamp
152+
app.kubernetes.io/version: "0.39.0"
153+
app.kubernetes.io/managed-by: Helm
154+
annotations:
155+
"helm.sh/hook": pre-upgrade
156+
"helm.sh/hook-weight": "-5"
157+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
158+
rules:
159+
- apiGroups: ["rbac.authorization.k8s.io"]
160+
resources: ["clusterrolebindings"]
161+
verbs: ["get", "delete"]
162+
---
163+
# Source: headlamp/templates/pre-upgrade-cleanup.yaml
164+
apiVersion: rbac.authorization.k8s.io/v1
165+
kind: ClusterRoleBinding
166+
metadata:
167+
name: headlamp-pre-upgrade
168+
labels:
169+
helm.sh/chart: headlamp-0.39.0
170+
app.kubernetes.io/name: headlamp
171+
app.kubernetes.io/instance: headlamp
172+
app.kubernetes.io/version: "0.39.0"
173+
app.kubernetes.io/managed-by: Helm
174+
annotations:
175+
"helm.sh/hook": pre-upgrade
176+
"helm.sh/hook-weight": "-4"
177+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
178+
roleRef:
179+
apiGroup: rbac.authorization.k8s.io
180+
kind: ClusterRole
181+
name: headlamp-pre-upgrade
182+
subjects:
183+
- kind: ServiceAccount
184+
name: headlamp-pre-upgrade
185+
namespace: default
186+
---
187+
# Source: headlamp/templates/pre-upgrade-cleanup.yaml
188+
apiVersion: batch/v1
189+
kind: Job
190+
metadata:
191+
name: headlamp-pre-upgrade
192+
namespace: default
193+
labels:
194+
helm.sh/chart: headlamp-0.39.0
195+
app.kubernetes.io/name: headlamp
196+
app.kubernetes.io/instance: headlamp
197+
app.kubernetes.io/version: "0.39.0"
198+
app.kubernetes.io/managed-by: Helm
199+
annotations:
200+
"helm.sh/hook": pre-upgrade
201+
"helm.sh/hook-weight": "-3"
202+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
203+
spec:
204+
ttlSecondsAfterFinished: 300
205+
template:
206+
metadata:
207+
name: headlamp-pre-upgrade
208+
labels:
209+
helm.sh/chart: headlamp-0.39.0
210+
app.kubernetes.io/name: headlamp
211+
app.kubernetes.io/instance: headlamp
212+
app.kubernetes.io/version: "0.39.0"
213+
app.kubernetes.io/managed-by: Helm
214+
spec:
215+
serviceAccountName: headlamp-pre-upgrade
216+
restartPolicy: Never
217+
containers:
218+
- name: pre-upgrade-cleanup
219+
image: alpine/kubectl:1.35.0@sha256:e7e078c7bb25012141e5957d500834b2a5b266d6de20ecfa862b30d8a892fc7e
220+
command:
221+
- /bin/sh
222+
- -c
223+
- |
224+
set -e
225+
CRB_NAME="headlamp-admin"
226+
RELEASE_NAME="headlamp"
227+
228+
echo "Checking for old ClusterRoleBinding ${CRB_NAME}..."
229+
230+
if ! kubectl get clusterrolebinding "${CRB_NAME}" 2>/dev/null; then
231+
echo "ClusterRoleBinding ${CRB_NAME} not found, nothing to clean up"
232+
exit 0
233+
fi
234+
235+
echo "Found ClusterRoleBinding ${CRB_NAME}, verifying it was created by Helm..."
236+
237+
# Check if the ClusterRoleBinding has Helm labels indicating it was created by this chart
238+
MANAGED_BY=$(kubectl get clusterrolebinding "${CRB_NAME}" -o jsonpath='{.metadata.labels.app\.kubernetes\.io/managed-by}' 2>/dev/null || echo "")
239+
INSTANCE=$(kubectl get clusterrolebinding "${CRB_NAME}" -o jsonpath='{.metadata.labels.app\.kubernetes\.io/instance}' 2>/dev/null || echo "")
240+
APP_NAME=$(kubectl get clusterrolebinding "${CRB_NAME}" -o jsonpath='{.metadata.labels.app\.kubernetes\.io/name}' 2>/dev/null || echo "")
241+
242+
if [ "${MANAGED_BY}" = "Helm" ] && [ "${INSTANCE}" = "${RELEASE_NAME}" ] && [ "${APP_NAME}" = "headlamp" ]; then
243+
echo "Confirmed: ${CRB_NAME} was created by this Helm release (${RELEASE_NAME})"
244+
echo "Deleting old ClusterRoleBinding..."
245+
kubectl delete clusterrolebinding "${CRB_NAME}"
246+
echo "Successfully deleted old ClusterRoleBinding"
247+
else
248+
echo "WARNING: ${CRB_NAME} exists but was NOT created by this Helm release"
249+
echo " managed-by: ${MANAGED_BY} (expected: Helm)"
250+
echo " instance: ${INSTANCE} (expected: ${RELEASE_NAME})"
251+
echo " app: ${APP_NAME} (expected: headlamp)"
252+
echo "Skipping deletion to preserve user-created resource"
253+
fi
254+
resources:
255+
requests:
256+
cpu: 10m
257+
memory: 64Mi
258+
limits:
259+
cpu: 100m
260+
memory: 128Mi
261+
262+
securityContext:
263+
{}
264+
volumeMounts:
265+
- name: tmp
266+
mountPath: /tmp
267+
volumes:
268+
- name: tmp
269+
emptyDir: {}

0 commit comments

Comments
 (0)