Skip to content

Commit bd0586c

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

33 files changed

+3785
-434
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,10 @@ helm-template-test:
378378
helm-update-template-version:
379379
charts/headlamp/tests/update-version.sh
380380

381+
.PHONY: helm-test-pre-upgrade-hook
382+
helm-test-pre-upgrade-hook:
383+
charts/headlamp/tests/test-pre-upgrade-hook.sh
384+
381385
# TODO: add windows compatibility
382386
.PHONY: run-jaeger
383387
run-jaeger:

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: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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+
allowPrivilegeEscalation: false
116+
runAsNonRoot: true
117+
capabilities:
118+
drop:
119+
- ALL
120+
seccompProfile:
121+
type: RuntimeDefault
122+
volumeMounts:
123+
- name: tmp
124+
mountPath: /tmp
125+
volumes:
126+
- name: tmp
127+
emptyDir: {}

0 commit comments

Comments
 (0)