feat(test-browser): pre-install Let's Encrypt staging roots in Firefox

Every K8s ingress in the test plane uses cert-manager's
letsencrypt-staging ClusterIssuer, so browsing any *.renner.uno
hostname from inside the test-browser Firefox produced a manual
SEC_ERROR_UNKNOWN_ISSUER click-through per host.

Install the two LE staging roots (X1 and X2) via Firefox Enterprise
Policy:

- New ConfigMap firefox-policies.yaml carries a policies.json that
  sets Certificates.Install to point at the two cert files the
  init container drops at pod start.
- Init container fetches the roots from letsencrypt.org into a
  shared emptyDir (read-only mount in the main container). Means
  LE's live staging hierarchy is always what's trusted — no stale
  embedded PEM to rotate.
- Main container mounts the ConfigMap at
  /etc/firefox/policies/policies.json and the cert emptyDir at
  /etc/firefox/certs/, both read-only.
- ImportEnterpriseRoots: true is also set as a belt-and-braces
  measure so any cert dropped into the system store (via future
  automation) is also trusted.

Pod-restart re-fetches. If letsencrypt.org is unreachable at
pod start the init container fails; the pod won't come up until
it can fetch, which is acceptable for a test harness.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-22 15:00:27 +02:00
co-authored by Claude Opus 4.7
parent 2568afb266
commit 6c05798209
3 changed files with 69 additions and 0 deletions
@@ -35,6 +35,34 @@ spec:
- dash.renner.uno
- audiobooks.renner.uno
- ical-proxy.renner.uno
initContainers:
# Fetch the Let's Encrypt staging root CAs at pod start so
# Firefox trusts the staging-issued certs that every K8s
# ingress serves. Writes into a shared emptyDir volume
# that the firefox container mounts read-only.
- name: fetch-le-staging-roots
image: curlimages/curl:8.10.1
command:
- sh
- -c
- |
set -eu
curl -sfL -o /certs/letsencrypt-stg-root-x1.pem \
https://letsencrypt.org/certs/staging/letsencrypt-stg-root-x1.pem
curl -sfL -o /certs/letsencrypt-stg-root-x2.pem \
https://letsencrypt.org/certs/staging/letsencrypt-stg-root-x2.pem
chmod 0644 /certs/*.pem
echo "Fetched LE staging roots:"
ls -l /certs/
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop: ["ALL"]
volumeMounts:
- name: le-certs
mountPath: /certs
containers:
- name: firefox
image: kasmweb/firefox:1.17.0-rolling-daily
@@ -62,8 +90,23 @@ spec:
volumeMounts:
- name: shm
mountPath: /dev/shm
- name: firefox-policies
mountPath: /etc/firefox/policies/policies.json
subPath: policies.json
readOnly: true
- name: le-certs
mountPath: /etc/firefox/certs
readOnly: true
volumes:
- name: shm
emptyDir:
medium: Memory
sizeLimit: 512Mi
- name: firefox-policies
configMap:
name: test-browser-firefox-policies
items:
- key: policies.json
path: policies.json
- name: le-certs
emptyDir: {}
@@ -0,0 +1,25 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: test-browser-firefox-policies
namespace: apps
data:
# Firefox Enterprise Policy. Tells Firefox to trust the two
# Let's Encrypt staging roots that cert-manager's
# letsencrypt-staging ClusterIssuer chains from. Without this,
# every *.renner.uno hostname browsed inside the test-browser
# Firefox produces a SEC_ERROR_UNKNOWN_ISSUER warning.
#
# Docs: https://mozilla.github.io/policy-templates/#certificates
policies.json: |
{
"policies": {
"Certificates": {
"ImportEnterpriseRoots": true,
"Install": [
"/etc/firefox/certs/letsencrypt-stg-root-x1.pem",
"/etc/firefox/certs/letsencrypt-stg-root-x2.pem"
]
}
}
}
@@ -4,3 +4,4 @@ resources:
- deployment.yaml
- service.yaml
- ingress.yaml
- firefox-policies.yaml