From b53a639889d42c12db4a5c13d2654e86c6f84f05 Mon Sep 17 00:00:00 2001 From: Maicon Berlofa Date: Tue, 11 Aug 2026 11:09:59 -0300 Subject: [PATCH 1/3] fix(certimate): provide writable temporary storage --- charts/certimate/DESIGN.md | 4 ++++ charts/certimate/README.md | 1 + charts/certimate/templates/deployment.yaml | 4 ++++ charts/certimate/tests/templates_test.yaml | 17 +++++++++++++++++ 4 files changed, 26 insertions(+) diff --git a/charts/certimate/DESIGN.md b/charts/certimate/DESIGN.md index 25f8fb72..a01a7d37 100644 --- a/charts/certimate/DESIGN.md +++ b/charts/certimate/DESIGN.md @@ -28,6 +28,10 @@ Disabling persistence is a breaking, explicit choice: users must set keeps disposable CI and demo installs available while preventing accidental loss of certificates, ACME accounts, provider credentials, and workflow state. +Certificate workflows create temporary processing files under `/tmp`. The chart +mounts a dedicated ephemeral `emptyDir` there so these workflows remain +functional while `securityContext.readOnlyRootFilesystem` stays enabled. + ## Exposure The chart supports Kubernetes Ingress and Gateway API HTTPRoute. TLS termination is expected at the ingress controller or gateway. Certimate itself remains an internal HTTP service. diff --git a/charts/certimate/README.md b/charts/certimate/README.md index 7979d4cc..cc33efd4 100644 --- a/charts/certimate/README.md +++ b/charts/certimate/README.md @@ -11,6 +11,7 @@ This chart packages the official `certimate/certimate:v0.4.30` image and follows - explicit `persistence.ephemeral=true` opt-in for disposable emptyDir installs - default resource requests and memory limit for scheduler and Kubescape hygiene - restricted ServiceAccount token mounting by default +- ephemeral writable `/tmp` storage while the container root filesystem remains read-only - Kubernetes Ingress and Gateway API HTTPRoute support - optional NetworkPolicy with explicit additional egress for ACME DNS APIs, DNS, SMTP, webhooks, and target deployment systems - ExternalSecret support for environment variables or other integration secrets diff --git a/charts/certimate/templates/deployment.yaml b/charts/certimate/templates/deployment.yaml index 331af9b2..3427f000 100644 --- a/charts/certimate/templates/deployment.yaml +++ b/charts/certimate/templates/deployment.yaml @@ -112,6 +112,8 @@ spec: volumeMounts: - name: data mountPath: {{ .Values.persistence.mountPath | quote }} + - name: tmp + mountPath: /tmp {{- with .Values.extraVolumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} @@ -126,6 +128,8 @@ spec: {{- else }} emptyDir: {} {{- end }} + - name: tmp + emptyDir: {} {{- with .Values.extraVolumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/charts/certimate/tests/templates_test.yaml b/charts/certimate/tests/templates_test.yaml index e418814d..a2cd665a 100644 --- a/charts/certimate/tests/templates_test.yaml +++ b/charts/certimate/tests/templates_test.yaml @@ -96,3 +96,20 @@ tests: - equal: path: spec.template.spec.containers[0].resources.limits.cpu value: 500m + - it: provides writable temporary storage with a read-only root filesystem + template: templates/deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: true + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: tmp + mountPath: /tmp + - equal: + path: spec.template.spec.volumes[1].name + value: tmp + - equal: + path: spec.template.spec.volumes[1].emptyDir + value: {} From 1a812070d59427dd12388d9a55886feff00a14f9 Mon Sep 17 00:00:00 2001 From: Maicon Berlofa Date: Tue, 11 Aug 2026 12:47:40 -0300 Subject: [PATCH 2/3] fix(certimate): address writable tmp review --- charts/certimate/templates/deployment.yaml | 6 ++++++ charts/certimate/tests/templates_test.yaml | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/charts/certimate/templates/deployment.yaml b/charts/certimate/templates/deployment.yaml index 3427f000..e6d6a018 100644 --- a/charts/certimate/templates/deployment.yaml +++ b/charts/certimate/templates/deployment.yaml @@ -1,4 +1,9 @@ {{/* SPDX-License-Identifier: Apache-2.0 */}} +{{- range .Values.extraVolumeMounts }} +{{- if eq (get . "mountPath") "/tmp" }} +{{- fail "extraVolumeMounts must not use the reserved mountPath /tmp" }} +{{- end }} +{{- end }} apiVersion: apps/v1 kind: Deployment metadata: @@ -114,6 +119,7 @@ spec: mountPath: {{ .Values.persistence.mountPath | quote }} - name: tmp mountPath: /tmp + readOnly: false {{- with .Values.extraVolumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/certimate/tests/templates_test.yaml b/charts/certimate/tests/templates_test.yaml index a2cd665a..bd18a5ed 100644 --- a/charts/certimate/tests/templates_test.yaml +++ b/charts/certimate/tests/templates_test.yaml @@ -107,9 +107,19 @@ tests: content: name: tmp mountPath: /tmp + readOnly: false - equal: path: spec.template.spec.volumes[1].name value: tmp - equal: path: spec.template.spec.volumes[1].emptyDir value: {} + - it: rejects an extra volume mount that duplicates the reserved tmp path + template: templates/deployment.yaml + set: + extraVolumeMounts: + - name: custom-tmp + mountPath: /tmp + asserts: + - failedTemplate: + errorMessage: extraVolumeMounts must not use the reserved mountPath /tmp From 6ed004f868a09abf883e820fc88b509239eef22b Mon Sep 17 00:00:00 2001 From: Maicon Berlofa Date: Tue, 11 Aug 2026 23:58:39 -0300 Subject: [PATCH 3/3] fix(certimate): complete temporary storage safeguards --- charts/certimate/DESIGN.md | 4 ++- charts/certimate/README.md | 1 + charts/certimate/templates/deployment.yaml | 22 +++++++++++++++- charts/certimate/tests/templates_test.yaml | 30 ++++++++++++++++++++++ charts/certimate/values.schema.json | 7 +++++ charts/certimate/values.yaml | 4 +++ 6 files changed, 66 insertions(+), 2 deletions(-) diff --git a/charts/certimate/DESIGN.md b/charts/certimate/DESIGN.md index a01a7d37..f3182bef 100644 --- a/charts/certimate/DESIGN.md +++ b/charts/certimate/DESIGN.md @@ -30,7 +30,9 @@ of certificates, ACME accounts, provider credentials, and workflow state. Certificate workflows create temporary processing files under `/tmp`. The chart mounts a dedicated ephemeral `emptyDir` there so these workflows remain -functional while `securityContext.readOnlyRootFilesystem` stays enabled. +functional while `securityContext.readOnlyRootFilesystem` stays enabled. Operators +can set `tmpStorage.sizeLimit` to bound the volume and apply the same value as the +container's ephemeral-storage request and limit. ## Exposure diff --git a/charts/certimate/README.md b/charts/certimate/README.md index cc33efd4..7bc87dd2 100644 --- a/charts/certimate/README.md +++ b/charts/certimate/README.md @@ -12,6 +12,7 @@ This chart packages the official `certimate/certimate:v0.4.30` image and follows - default resource requests and memory limit for scheduler and Kubescape hygiene - restricted ServiceAccount token mounting by default - ephemeral writable `/tmp` storage while the container root filesystem remains read-only +- optional `tmpStorage.sizeLimit` with matching ephemeral-storage request and limit - Kubernetes Ingress and Gateway API HTTPRoute support - optional NetworkPolicy with explicit additional egress for ACME DNS APIs, DNS, SMTP, webhooks, and target deployment systems - ExternalSecret support for environment variables or other integration secrets diff --git a/charts/certimate/templates/deployment.yaml b/charts/certimate/templates/deployment.yaml index e6d6a018..a0fa3403 100644 --- a/charts/certimate/templates/deployment.yaml +++ b/charts/certimate/templates/deployment.yaml @@ -1,9 +1,24 @@ {{/* SPDX-License-Identifier: Apache-2.0 */}} +{{- if eq .Values.persistence.mountPath "/tmp" }} +{{- fail "persistence.mountPath must not use the reserved mountPath /tmp" }} +{{- end }} {{- range .Values.extraVolumeMounts }} {{- if eq (get . "mountPath") "/tmp" }} {{- fail "extraVolumeMounts must not use the reserved mountPath /tmp" }} {{- end }} {{- end }} +{{- range .Values.extraVolumes }} +{{- if eq (get . "name") "tmp" }} +{{- fail "extraVolumes must not use the reserved volume name tmp" }} +{{- end }} +{{- end }} +{{- $resources := deepCopy .Values.resources }} +{{- if .Values.tmpStorage.sizeLimit }} +{{- if not (hasKey $resources "requests") }}{{- $_ := set $resources "requests" dict }}{{- end }} +{{- if not (hasKey $resources "limits") }}{{- $_ := set $resources "limits" dict }}{{- end }} +{{- $_ := set (get $resources "requests") "ephemeral-storage" .Values.tmpStorage.sizeLimit }} +{{- $_ := set (get $resources "limits") "ephemeral-storage" .Values.tmpStorage.sizeLimit }} +{{- end }} apiVersion: apps/v1 kind: Deployment metadata: @@ -110,7 +125,7 @@ spec: timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }} failureThreshold: {{ .Values.probes.readiness.failureThreshold }} {{- end }} - {{- with .Values.resources }} + {{- with $resources }} resources: {{- toYaml . | nindent 12 }} {{- end }} @@ -135,7 +150,12 @@ spec: emptyDir: {} {{- end }} - name: tmp + {{- if .Values.tmpStorage.sizeLimit }} + emptyDir: + sizeLimit: {{ .Values.tmpStorage.sizeLimit | quote }} + {{- else }} emptyDir: {} + {{- end }} {{- with .Values.extraVolumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/charts/certimate/tests/templates_test.yaml b/charts/certimate/tests/templates_test.yaml index bd18a5ed..f20afb63 100644 --- a/charts/certimate/tests/templates_test.yaml +++ b/charts/certimate/tests/templates_test.yaml @@ -123,3 +123,33 @@ tests: asserts: - failedTemplate: errorMessage: extraVolumeMounts must not use the reserved mountPath /tmp + - it: rejects persistence mounted at the reserved tmp path + template: templates/deployment.yaml + set: + persistence.mountPath: /tmp + asserts: + - failedTemplate: + errorMessage: persistence.mountPath must not use the reserved mountPath /tmp + - it: rejects an extra volume using the reserved tmp name + template: templates/deployment.yaml + set: + extraVolumes: + - name: tmp + emptyDir: {} + asserts: + - failedTemplate: + errorMessage: extraVolumes must not use the reserved volume name tmp + - it: bounds temporary storage when configured + template: templates/deployment.yaml + set: + tmpStorage.sizeLimit: 1Gi + asserts: + - equal: + path: spec.template.spec.volumes[1].emptyDir.sizeLimit + value: 1Gi + - equal: + path: spec.template.spec.containers[0].resources.requests.ephemeral-storage + value: 1Gi + - equal: + path: spec.template.spec.containers[0].resources.limits.ephemeral-storage + value: 1Gi diff --git a/charts/certimate/values.schema.json b/charts/certimate/values.schema.json index c35a798f..c8699258 100644 --- a/charts/certimate/values.schema.json +++ b/charts/certimate/values.schema.json @@ -59,6 +59,13 @@ "externalSecrets": { "$ref": "#/definitions/externalSecrets" }, "probes": { "$ref": "#/definitions/probes" }, "resources": { "type": "object" }, + "tmpStorage": { + "type": "object", + "required": ["sizeLimit"], + "properties": { + "sizeLimit": { "type": "string", "default": "", "pattern": "^$|^[0-9]+(\\.[0-9]+)?(Ei|Pi|Ti|Gi|Mi|Ki|E|P|T|G|M|k)?$" } + } + }, "test": { "type": "object", "properties": { diff --git a/charts/certimate/values.yaml b/charts/certimate/values.yaml index 797dfd02..cca08110 100644 --- a/charts/certimate/values.yaml +++ b/charts/certimate/values.yaml @@ -136,6 +136,10 @@ resources: cpu: 500m memory: 512Mi +tmpStorage: + # -- Optional limit for writable /tmp storage. When set, the same value is applied to the container ephemeral-storage request and limit. + sizeLimit: "" + test: resources: requests: