Skip to content

Commit 1e4179b

Browse files
cacaricoillume
authored andcommitted
charts: Remove ClusterRole default
charts: reduce default ClusterRoleBinding permissions - Change default ClusterRole from 'cluster-admin' to 'view' in values.yaml. - Remove '-admin' suffix from ClusterRoleBinding name to reflect the generic usage. charts: update docs and tests for reduced permissions Update README.md to reflect new default clusterRoleName of "view" instead of "cluster-admin". Update all test expected templates to use the new ClusterRoleBinding name "headlamp" (removed -admin suffix) and roleRef name "view" instead of "cluster-admin". charts: add pre-upgrade hook for ClusterRoleBinding migration Add automated upgrade path for breaking changes introduced by the security improvements. A pre-upgrade hook now automatically removes the old "headlamp-admin" ClusterRoleBinding during upgrades, ensuring existing deployments properly migrate to the new "headlamp" binding with reduced permissions. Changes: - Add pre-upgrade-cleanup.yaml hook template that safely deletes old binding - Hook verifies ClusterRoleBinding was created by Helm before deletion - Checks app.kubernetes.io labels to prevent removing user-created resources - Update Chart.yaml with changelog annotations - Add upgrade documentation to README explaining security changes - Regenerate all test expected templates to include hook resources The hook uses a Job with minimal RBAC permissions to safely clean up the old ClusterRoleBinding. It runs before the upgrade proceeds and is automatically cleaned up after success. User-created ClusterRoleBindings with the same name are preserved. charts: update tests, set clusterrolebiding to false by default and add instructions for creating crb manually fixed expected test after rebasing against main
1 parent efe4781 commit 1e4179b

27 files changed

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

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

Lines changed: 0 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

charts/headlamp/tests/expected_templates/default.yaml

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,6 @@ metadata:
2121
type: Opaque
2222
data:
2323
---
24-
# Source: headlamp/templates/clusterrolebinding.yaml
25-
apiVersion: rbac.authorization.k8s.io/v1
26-
kind: ClusterRoleBinding
27-
metadata:
28-
name: headlamp-admin
29-
labels:
30-
helm.sh/chart: headlamp-0.39.0
31-
app.kubernetes.io/name: headlamp
32-
app.kubernetes.io/instance: headlamp
33-
app.kubernetes.io/version: "0.39.0"
34-
app.kubernetes.io/managed-by: Helm
35-
roleRef:
36-
apiGroup: rbac.authorization.k8s.io
37-
kind: ClusterRole
38-
name: cluster-admin
39-
subjects:
40-
- kind: ServiceAccount
41-
name: headlamp
42-
namespace: default
43-
---
4424
# Source: headlamp/templates/service.yaml
4525
apiVersion: v1
4626
kind: Service

charts/headlamp/tests/expected_templates/extra-args.yaml

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,6 @@ metadata:
2121
type: Opaque
2222
data:
2323
---
24-
# Source: headlamp/templates/clusterrolebinding.yaml
25-
apiVersion: rbac.authorization.k8s.io/v1
26-
kind: ClusterRoleBinding
27-
metadata:
28-
name: headlamp-admin
29-
labels:
30-
helm.sh/chart: headlamp-0.39.0
31-
app.kubernetes.io/name: headlamp
32-
app.kubernetes.io/instance: headlamp
33-
app.kubernetes.io/version: "0.39.0"
34-
app.kubernetes.io/managed-by: Helm
35-
roleRef:
36-
apiGroup: rbac.authorization.k8s.io
37-
kind: ClusterRole
38-
name: cluster-admin
39-
subjects:
40-
- kind: ServiceAccount
41-
name: headlamp
42-
namespace: default
43-
---
4424
# Source: headlamp/templates/service.yaml
4525
apiVersion: v1
4626
kind: Service

charts/headlamp/tests/expected_templates/extra-manifests.yaml

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,6 @@ metadata:
3838
data:
3939
injectedKey: headlamp
4040
---
41-
# Source: headlamp/templates/clusterrolebinding.yaml
42-
apiVersion: rbac.authorization.k8s.io/v1
43-
kind: ClusterRoleBinding
44-
metadata:
45-
name: headlamp-admin
46-
labels:
47-
helm.sh/chart: headlamp-0.39.0
48-
app.kubernetes.io/name: headlamp
49-
app.kubernetes.io/instance: headlamp
50-
app.kubernetes.io/version: "0.39.0"
51-
app.kubernetes.io/managed-by: Helm
52-
roleRef:
53-
apiGroup: rbac.authorization.k8s.io
54-
kind: ClusterRole
55-
name: cluster-admin
56-
subjects:
57-
- kind: ServiceAccount
58-
name: headlamp
59-
namespace: default
60-
---
6141
# Source: headlamp/templates/service.yaml
6242
apiVersion: v1
6343
kind: Service

charts/headlamp/tests/expected_templates/host-users-override.yaml

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,6 @@ metadata:
2121
type: Opaque
2222
data:
2323
---
24-
# Source: headlamp/templates/clusterrolebinding.yaml
25-
apiVersion: rbac.authorization.k8s.io/v1
26-
kind: ClusterRoleBinding
27-
metadata:
28-
name: headlamp-admin
29-
labels:
30-
helm.sh/chart: headlamp-0.39.0
31-
app.kubernetes.io/name: headlamp
32-
app.kubernetes.io/instance: headlamp
33-
app.kubernetes.io/version: "0.39.0"
34-
app.kubernetes.io/managed-by: Helm
35-
roleRef:
36-
apiGroup: rbac.authorization.k8s.io
37-
kind: ClusterRole
38-
name: cluster-admin
39-
subjects:
40-
- kind: ServiceAccount
41-
name: headlamp
42-
namespace: default
43-
---
4424
# Source: headlamp/templates/service.yaml
4525
apiVersion: v1
4626
kind: Service

0 commit comments

Comments
 (0)