Description
The KASM Helm chart (1.18.1) cannot deploy into a namespace enforcing pod-security.kubernetes.io/enforce: restricted without extensive post-render patching. Multiple deployments have init containers running as root, missing container-level security contexts, and no writable volumes for paths the application requires.
Related: #33 — the write access denied on configured location error in that issue is the same root cause as finding 5 below.
Environment
- KASM Workspaces: 1.18.1
- Kubernetes: RKE2 v1.33
- Pod Security Standards:
restricted (enforce)
applySecurity: true in values
Findings
1. Init containers run as root (UID 0)
The *-tmp-perms init containers in guac, rdp-gw, rdp-https-gw, and proxy deployments run chown as UID 0. Example from guac-deployment.yaml:
- name: {{ $constants.guac.name }}-tmp-perms
image: {{ $constants.api.image }}
command:
- /bin/sh
- -c
args:
- |
echo "Setting permissions and ownership for /tmp..." && chown -R 1000:1000 /tmp && chmod -R 777 /tmp
echo "Setting permissions and ownership for /opt/kasm/current..." && chown -R 1000:1000 /opt/kasm/current && chmod -R 0770 /opt/kasm/current
echo "Done"
securityContext:
runAsNonRoot: false
runAsUser: 0
These chown calls are unnecessary when fsGroup: 1000 is set in the pod security context (applied by kasm.podSecurity when applySecurity: true). Kubernetes automatically sets group ownership on emptyDir volumes via fsGroup.
Affected: guac-deployment.yaml, rdp-gateway-deployment.yaml, rdp-https-gateway-deployment.yaml, proxy-deployment.yaml
Suggested fix: When applySecurity: true, skip these init containers or replace with a non-root no-op:
{{- if .Values.applySecurity }}
- name: {{ $constants.guac.name }}-tmp-perms
image: {{ $constants.api.image }}
imagePullPolicy: {{ .Values.imagePullPolicy }}
command: ["/bin/sh", "-c", "echo 'fsGroup handles permissions'"]
{{- include "kasm.containerSecurity" . | indent 10 }}
{{- end }}
2. API main container uses wrong values variable for securityContext
api-deployment.yaml line 134 uses .Values.applyPodSecurity instead of .Values.applySecurity:
{{- if .Values.applyPodSecurity }}
{{- include "kasm.containerSecurity" . | indent 10 }}
{{- end }}
applyPodSecurity is not defined in values.yaml — this is a typo. All other templates use applySecurity. The API container gets no securityContext even when applySecurity: true.
Suggested fix:
- {{- if .Values.applyPodSecurity }}
+ {{- if .Values.applySecurity }}
{{- include "kasm.containerSecurity" . | indent 10 }}
{{- end }}
3. db-init-job missing containerSecurity on both containers
db-init-job.yaml applies kasm.podSecurity at the pod level but neither the db-is-ready init container nor kasm-db-init-container includes kasm.containerSecurity. Both violate Restricted PSA.
Suggested fix: Add kasm.containerSecurity to both containers when applySecurity: true:
initContainers:
- name: db-is-ready
image: {{ $constants.api.image }}
imagePullPolicy: {{ .Values.imagePullPolicy }}
{{- if .Values.applySecurity }}
{{- include "kasm.containerSecurity" . | indent 10 }}
{{- end }}
# ... rest of init container
containers:
- name: kasm-db-init-container
image: {{ $constants.api.image }}
imagePullPolicy: {{ .Values.imagePullPolicy }}
{{- if .Values.applySecurity }}
{{- include "kasm.containerSecurity" . | indent 10 }}
{{- end }}
# ... rest of container
4. rdp-https-gw kasm-api-is-ready missing containerSecurity
The kasm.initContainer helper template generates init containers without a securityContext. In most deployments, kasm.containerSecurity is appended after the include. In rdp-https-gateway-deployment.yaml, the kasm-api-is-ready container generated by the helper has no securityContext applied.
5. readOnlyRootFilesystem breaks /opt/kasm/current/log (silent hang)
When readOnlyRootFilesystem: true (set by kasm.containerSecurity), the following components hang silently on startup with no error output:
kasm-db-init-container (db-init-job)
kasm-api-container (api-deployment)
kasm-manager-default-container (manager-deployment)
Root cause: The shared api.app.config.yaml configures Python RotatingFileHandler log handlers writing to /opt/kasm/current/log/. With a read-only root filesystem, this directory cannot be created. The Python logging subsystem hangs silently — no error, no stdout output, no port binding. Healthchecks never pass and the pod restart-loops.
This is the same issue reported in #33 (File based logging has been disabled on one or more handlers due to write access denied on configured location).
Suggested fix: Add emptyDir volumes for /opt/kasm/current/log to all containers that use api.app.config.yaml:
{{- if .Values.applySecurity }}
volumeMounts:
- name: tmp-data
mountPath: /tmp
- name: log-data
mountPath: /opt/kasm/current/log
{{- end }}
# ...
{{- if .Values.applySecurity }}
volumes:
- name: tmp-data
emptyDir:
sizeLimit: 256Mi
- name: log-data
emptyDir:
sizeLimit: 256Mi
{{- end }}
6. readOnlyRootFilesystem breaks /tmp in db-init-job
The db-init-job writes .temp.api.app.config.yaml and default_properties.yaml to /tmp/. With readOnlyRootFilesystem: true:
OSError: [Errno 30] Read-only file system: '/tmp/.temp.api.app.config.yaml'
Suggested fix: Same as #5 — add emptyDir at /tmp for the db-init-job (already shown above).
Workaround
We use Kustomize post-render patches to fix all of the above. Happy to share our patch set if helpful.
Description
The KASM Helm chart (1.18.1) cannot deploy into a namespace enforcing
pod-security.kubernetes.io/enforce: restrictedwithout extensive post-render patching. Multiple deployments have init containers running as root, missing container-level security contexts, and no writable volumes for paths the application requires.Related: #33 — the
write access denied on configured locationerror in that issue is the same root cause as finding 5 below.Environment
restricted(enforce)applySecurity: truein valuesFindings
1. Init containers run as root (UID 0)
The
*-tmp-permsinit containers in guac, rdp-gw, rdp-https-gw, and proxy deployments runchownas UID 0. Example fromguac-deployment.yaml:These
chowncalls are unnecessary whenfsGroup: 1000is set in the pod security context (applied bykasm.podSecuritywhenapplySecurity: true). Kubernetes automatically sets group ownership on emptyDir volumes via fsGroup.Affected:
guac-deployment.yaml,rdp-gateway-deployment.yaml,rdp-https-gateway-deployment.yaml,proxy-deployment.yamlSuggested fix: When
applySecurity: true, skip these init containers or replace with a non-root no-op:2. API main container uses wrong values variable for securityContext
api-deployment.yamlline 134 uses.Values.applyPodSecurityinstead of.Values.applySecurity:applyPodSecurityis not defined invalues.yaml— this is a typo. All other templates useapplySecurity. The API container gets no securityContext even whenapplySecurity: true.Suggested fix:
3. db-init-job missing containerSecurity on both containers
db-init-job.yamlapplieskasm.podSecurityat the pod level but neither thedb-is-readyinit container norkasm-db-init-containerincludeskasm.containerSecurity. Both violate Restricted PSA.Suggested fix: Add
kasm.containerSecurityto both containers whenapplySecurity: true:4. rdp-https-gw kasm-api-is-ready missing containerSecurity
The
kasm.initContainerhelper template generates init containers without a securityContext. In most deployments,kasm.containerSecurityis appended after the include. Inrdp-https-gateway-deployment.yaml, thekasm-api-is-readycontainer generated by the helper has no securityContext applied.5. readOnlyRootFilesystem breaks /opt/kasm/current/log (silent hang)
When
readOnlyRootFilesystem: true(set bykasm.containerSecurity), the following components hang silently on startup with no error output:kasm-db-init-container(db-init-job)kasm-api-container(api-deployment)kasm-manager-default-container(manager-deployment)Root cause: The shared
api.app.config.yamlconfigures PythonRotatingFileHandlerlog handlers writing to/opt/kasm/current/log/. With a read-only root filesystem, this directory cannot be created. The Python logging subsystem hangs silently — no error, no stdout output, no port binding. Healthchecks never pass and the pod restart-loops.This is the same issue reported in #33 (
File based logging has been disabled on one or more handlers due to write access denied on configured location).Suggested fix: Add emptyDir volumes for
/opt/kasm/current/logto all containers that useapi.app.config.yaml:6. readOnlyRootFilesystem breaks /tmp in db-init-job
The db-init-job writes
.temp.api.app.config.yamlanddefault_properties.yamlto/tmp/. WithreadOnlyRootFilesystem: true:Suggested fix: Same as #5 — add emptyDir at
/tmpfor the db-init-job (already shown above).Workaround
We use Kustomize post-render patches to fix all of the above. Happy to share our patch set if helpful.