From 0cd1acd3bb7a5fa2e5bd8e2c5e5f581e152030b2 Mon Sep 17 00:00:00 2001 From: Vishwak Thatikonda Date: Wed, 3 Jun 2026 23:29:29 -0700 Subject: [PATCH 1/2] feat(chart): expose podSecurityContext and securityContext values Add `podSecurityContext` (pod-level) and `securityContext` (container-level) values and wire them into both the Deployment and DaemonSet templates. Secure defaults are provided so the controller no longer runs as root with a writable root filesystem out of the box, satisfying the Pod Security "restricted" profile and lint gates such as kube-linter's `run-as-non-root` and `no-read-only-root-fs`: - podSecurityContext: runAsNonRoot, runAsUser 65532, RuntimeDefault seccomp - securityContext: readOnlyRootFilesystem, no privilege escalation, drop ALL The runtime does not write to its root filesystem, so readOnlyRootFilesystem is safe. Both blocks are `with`-guarded so operators can relax them by overriding the values. Closes #1253 Co-Authored-By: Claude Opus 4.8 --- chart/.snapshots/default.yaml | 14 ++++++++++++++ chart/.snapshots/full.daemonset.yaml | 14 ++++++++++++++ chart/templates/daemonset.yaml | 8 ++++++++ chart/templates/deployment.yaml | 8 ++++++++ chart/values.yaml | 21 +++++++++++++++++++++ deploy/ccm-networks.yaml | 14 ++++++++++++++ deploy/ccm.yaml | 14 ++++++++++++++ 7 files changed, 93 insertions(+) diff --git a/chart/.snapshots/default.yaml b/chart/.snapshots/default.yaml index f5ed1322f..59c8a86f5 100644 --- a/chart/.snapshots/default.yaml +++ b/chart/.snapshots/default.yaml @@ -5,6 +5,7 @@ kind: ServiceAccount metadata: name: hcloud-cloud-controller-manager namespace: kube-system + --- # Source: hcloud-cloud-controller-manager/templates/clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 @@ -70,6 +71,7 @@ rules: - list - watch - update + --- # Source: hcloud-cloud-controller-manager/templates/clusterrolebinding.yaml kind: ClusterRoleBinding @@ -86,6 +88,7 @@ subjects: - kind: ServiceAccount name: hcloud-cloud-controller-manager namespace: kube-system + --- # Source: hcloud-cloud-controller-manager/templates/deployment.yaml apiVersion: apps/v1 @@ -107,6 +110,11 @@ spec: app.kubernetes.io/name: 'hcloud-cloud-controller-manager' spec: serviceAccountName: hcloud-cloud-controller-manager + securityContext: + runAsNonRoot: true + runAsUser: 65532 + seccompProfile: + type: RuntimeDefault dnsPolicy: Default tolerations: # Allow HCCM itself to schedule on nodes that have not yet been initialized by HCCM. @@ -128,6 +136,12 @@ spec: effect: "NoExecute" containers: - name: hcloud-cloud-controller-manager + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true args: - "--allow-untagged-cloud" - "--cloud-provider=hcloud" diff --git a/chart/.snapshots/full.daemonset.yaml b/chart/.snapshots/full.daemonset.yaml index b4369cba8..fc512950f 100644 --- a/chart/.snapshots/full.daemonset.yaml +++ b/chart/.snapshots/full.daemonset.yaml @@ -5,6 +5,7 @@ kind: ServiceAccount metadata: name: hcloud-cloud-controller-manager namespace: kube-system + --- # Source: hcloud-cloud-controller-manager/templates/clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 @@ -70,6 +71,7 @@ rules: - list - watch - update + --- # Source: hcloud-cloud-controller-manager/templates/clusterrolebinding.yaml kind: ClusterRoleBinding @@ -86,6 +88,7 @@ subjects: - kind: ServiceAccount name: hcloud-cloud-controller-manager namespace: kube-system + --- # Source: hcloud-cloud-controller-manager/templates/daemonset.yaml apiVersion: apps/v1 @@ -109,6 +112,11 @@ spec: pod-annotation: pod-annotation spec: serviceAccountName: hcloud-cloud-controller-manager + securityContext: + runAsNonRoot: true + runAsUser: 65532 + seccompProfile: + type: RuntimeDefault dnsPolicy: Default tolerations: # Allow HCCM itself to schedule on nodes that have not yet been initialized by HCCM. @@ -137,6 +145,12 @@ spec: foo: bar containers: - name: hcloud-cloud-controller-manager + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true command: - "/bin/hcloud-cloud-controller-manager" - "--allow-untagged-cloud" diff --git a/chart/templates/daemonset.yaml b/chart/templates/daemonset.yaml index 4a72d18f6..f6a8af112 100644 --- a/chart/templates/daemonset.yaml +++ b/chart/templates/daemonset.yaml @@ -26,6 +26,10 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "hcloud-cloud-controller-manager.name" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} dnsPolicy: Default tolerations: # Allow HCCM itself to schedule on nodes that have not yet been initialized by HCCM. @@ -60,6 +64,10 @@ spec: {{- end }} containers: - name: hcloud-cloud-controller-manager + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} command: - "/bin/hcloud-cloud-controller-manager" {{- range $key, $value := $.Values.args }} diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml index f3be3c54a..c9177dd37 100644 --- a/chart/templates/deployment.yaml +++ b/chart/templates/deployment.yaml @@ -31,6 +31,10 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "hcloud-cloud-controller-manager.name" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} dnsPolicy: {{ .Values.dnsPolicy }} {{- with .Values.dnsConfig }} dnsConfig: @@ -74,6 +78,10 @@ spec: {{- end }} containers: - name: hcloud-cloud-controller-manager + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} args: {{- range $key, $value := $.Values.args }} {{- if not (eq $value nil) }} diff --git a/chart/values.yaml b/chart/values.yaml index 33f17ff05..23359a0cb 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -120,6 +120,27 @@ resources: cpu: 100m memory: 50Mi +# Pod-level security context for the hccm Pod. +# The defaults run the controller as a non-root user with a RuntimeDefault +# seccomp profile, satisfying the Pod Security "restricted" profile. +# Set to {} (or override individual fields) to relax these constraints. +podSecurityContext: + runAsNonRoot: true + runAsUser: 65532 + seccompProfile: + type: RuntimeDefault + +# Container-level security context for the hccm container. +# The controller does not write to its root filesystem at runtime, so a +# read-only root filesystem with all capabilities dropped is safe by default. +# Set to {} (or override individual fields) to relax these constraints. +securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + selectorLabels: app.kubernetes.io/name: '{{ include "hcloud-cloud-controller-manager.name" $ }}' app.kubernetes.io/instance: "{{ $.Release.Name }}" diff --git a/deploy/ccm-networks.yaml b/deploy/ccm-networks.yaml index 499948ddd..261a13ac9 100644 --- a/deploy/ccm-networks.yaml +++ b/deploy/ccm-networks.yaml @@ -5,6 +5,7 @@ kind: ServiceAccount metadata: name: hcloud-cloud-controller-manager namespace: kube-system + --- # Source: hcloud-cloud-controller-manager/templates/clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 @@ -70,6 +71,7 @@ rules: - list - watch - update + --- # Source: hcloud-cloud-controller-manager/templates/clusterrolebinding.yaml kind: ClusterRoleBinding @@ -86,6 +88,7 @@ subjects: - kind: ServiceAccount name: hcloud-cloud-controller-manager namespace: kube-system + --- # Source: hcloud-cloud-controller-manager/templates/deployment.yaml apiVersion: apps/v1 @@ -105,6 +108,11 @@ spec: app: hcloud-cloud-controller-manager spec: serviceAccountName: hcloud-cloud-controller-manager + securityContext: + runAsNonRoot: true + runAsUser: 65532 + seccompProfile: + type: RuntimeDefault dnsPolicy: Default tolerations: # Allow HCCM itself to schedule on nodes that have not yet been initialized by HCCM. @@ -127,6 +135,12 @@ spec: hostNetwork: true containers: - name: hcloud-cloud-controller-manager + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true args: - "--allow-untagged-cloud" - "--cloud-provider=hcloud" diff --git a/deploy/ccm.yaml b/deploy/ccm.yaml index 001a8a187..fa010f8fe 100644 --- a/deploy/ccm.yaml +++ b/deploy/ccm.yaml @@ -5,6 +5,7 @@ kind: ServiceAccount metadata: name: hcloud-cloud-controller-manager namespace: kube-system + --- # Source: hcloud-cloud-controller-manager/templates/clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 @@ -70,6 +71,7 @@ rules: - list - watch - update + --- # Source: hcloud-cloud-controller-manager/templates/clusterrolebinding.yaml kind: ClusterRoleBinding @@ -86,6 +88,7 @@ subjects: - kind: ServiceAccount name: hcloud-cloud-controller-manager namespace: kube-system + --- # Source: hcloud-cloud-controller-manager/templates/deployment.yaml apiVersion: apps/v1 @@ -105,6 +108,11 @@ spec: app: hcloud-cloud-controller-manager spec: serviceAccountName: hcloud-cloud-controller-manager + securityContext: + runAsNonRoot: true + runAsUser: 65532 + seccompProfile: + type: RuntimeDefault dnsPolicy: Default tolerations: # Allow HCCM itself to schedule on nodes that have not yet been initialized by HCCM. @@ -126,6 +134,12 @@ spec: effect: "NoExecute" containers: - name: hcloud-cloud-controller-manager + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true args: - "--allow-untagged-cloud" - "--cloud-provider=hcloud" From 9f37319b416c412b9370a8a1d35fe5a801341aa3 Mon Sep 17 00:00:00 2001 From: lukasmetzner Date: Mon, 6 Jul 2026 09:02:06 +0200 Subject: [PATCH 2/2] fix: remaining issues --- .pre-commit-config.yaml | 2 +- chart/.snapshots/default.yaml | 4 +--- chart/.snapshots/full.daemonset.yaml | 4 +--- chart/values.yaml | 9 +++------ deploy/ccm-networks.yaml | 4 +--- deploy/ccm.yaml | 4 +--- 6 files changed, 8 insertions(+), 19 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8ce459dfd..b073e15d5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -64,7 +64,7 @@ repos: require_serial: false additional_dependencies: [prettier@3.9.4] files: \.(md|ya?ml)$ - exclude: ^(CHANGELOG.md|chart/templates/.*|chart/.snapshots/.*|docs/reference/load_balancer_.*\.md|)$ + exclude: ^(CHANGELOG.md|chart/templates/.*|chart/.snapshots/.*|deploy/.*|docs/reference/load_balancer_.*\.md|)$ - repo: local hooks: diff --git a/chart/.snapshots/default.yaml b/chart/.snapshots/default.yaml index 59c8a86f5..32a481688 100644 --- a/chart/.snapshots/default.yaml +++ b/chart/.snapshots/default.yaml @@ -5,7 +5,6 @@ kind: ServiceAccount metadata: name: hcloud-cloud-controller-manager namespace: kube-system - --- # Source: hcloud-cloud-controller-manager/templates/clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 @@ -71,7 +70,6 @@ rules: - list - watch - update - --- # Source: hcloud-cloud-controller-manager/templates/clusterrolebinding.yaml kind: ClusterRoleBinding @@ -88,7 +86,6 @@ subjects: - kind: ServiceAccount name: hcloud-cloud-controller-manager namespace: kube-system - --- # Source: hcloud-cloud-controller-manager/templates/deployment.yaml apiVersion: apps/v1 @@ -111,6 +108,7 @@ spec: spec: serviceAccountName: hcloud-cloud-controller-manager securityContext: + runAsGroup: 65532 runAsNonRoot: true runAsUser: 65532 seccompProfile: diff --git a/chart/.snapshots/full.daemonset.yaml b/chart/.snapshots/full.daemonset.yaml index fc512950f..735e39edb 100644 --- a/chart/.snapshots/full.daemonset.yaml +++ b/chart/.snapshots/full.daemonset.yaml @@ -5,7 +5,6 @@ kind: ServiceAccount metadata: name: hcloud-cloud-controller-manager namespace: kube-system - --- # Source: hcloud-cloud-controller-manager/templates/clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 @@ -71,7 +70,6 @@ rules: - list - watch - update - --- # Source: hcloud-cloud-controller-manager/templates/clusterrolebinding.yaml kind: ClusterRoleBinding @@ -88,7 +86,6 @@ subjects: - kind: ServiceAccount name: hcloud-cloud-controller-manager namespace: kube-system - --- # Source: hcloud-cloud-controller-manager/templates/daemonset.yaml apiVersion: apps/v1 @@ -113,6 +110,7 @@ spec: spec: serviceAccountName: hcloud-cloud-controller-manager securityContext: + runAsGroup: 65532 runAsNonRoot: true runAsUser: 65532 seccompProfile: diff --git a/chart/values.yaml b/chart/values.yaml index 23359a0cb..f282c7ddc 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -121,19 +121,16 @@ resources: memory: 50Mi # Pod-level security context for the hccm Pod. -# The defaults run the controller as a non-root user with a RuntimeDefault -# seccomp profile, satisfying the Pod Security "restricted" profile. -# Set to {} (or override individual fields) to relax these constraints. +# See https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ podSecurityContext: runAsNonRoot: true runAsUser: 65532 + runAsGroup: 65532 seccompProfile: type: RuntimeDefault # Container-level security context for the hccm container. -# The controller does not write to its root filesystem at runtime, so a -# read-only root filesystem with all capabilities dropped is safe by default. -# Set to {} (or override individual fields) to relax these constraints. +# See https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false diff --git a/deploy/ccm-networks.yaml b/deploy/ccm-networks.yaml index 261a13ac9..550d60cef 100644 --- a/deploy/ccm-networks.yaml +++ b/deploy/ccm-networks.yaml @@ -5,7 +5,6 @@ kind: ServiceAccount metadata: name: hcloud-cloud-controller-manager namespace: kube-system - --- # Source: hcloud-cloud-controller-manager/templates/clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 @@ -71,7 +70,6 @@ rules: - list - watch - update - --- # Source: hcloud-cloud-controller-manager/templates/clusterrolebinding.yaml kind: ClusterRoleBinding @@ -88,7 +86,6 @@ subjects: - kind: ServiceAccount name: hcloud-cloud-controller-manager namespace: kube-system - --- # Source: hcloud-cloud-controller-manager/templates/deployment.yaml apiVersion: apps/v1 @@ -109,6 +106,7 @@ spec: spec: serviceAccountName: hcloud-cloud-controller-manager securityContext: + runAsGroup: 65532 runAsNonRoot: true runAsUser: 65532 seccompProfile: diff --git a/deploy/ccm.yaml b/deploy/ccm.yaml index fa010f8fe..99d33c055 100644 --- a/deploy/ccm.yaml +++ b/deploy/ccm.yaml @@ -5,7 +5,6 @@ kind: ServiceAccount metadata: name: hcloud-cloud-controller-manager namespace: kube-system - --- # Source: hcloud-cloud-controller-manager/templates/clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 @@ -71,7 +70,6 @@ rules: - list - watch - update - --- # Source: hcloud-cloud-controller-manager/templates/clusterrolebinding.yaml kind: ClusterRoleBinding @@ -88,7 +86,6 @@ subjects: - kind: ServiceAccount name: hcloud-cloud-controller-manager namespace: kube-system - --- # Source: hcloud-cloud-controller-manager/templates/deployment.yaml apiVersion: apps/v1 @@ -109,6 +106,7 @@ spec: spec: serviceAccountName: hcloud-cloud-controller-manager securityContext: + runAsGroup: 65532 runAsNonRoot: true runAsUser: 65532 seccompProfile: