feat(k8s): terminate TLS in the cluster for a public domain (closes #177) #178
Open
not
wants to merge 3 commits from
feat/177-public-tls-edge into main
pull from: feat/177-public-tls-edge
merge into: :main
:main
:ci/175-deploy-on-merge
:feat/177-public-tls-edge
:ci/168-helm-chart-ci-gate
:docs/169-mkdocs-nav
:feat/25-helm-kubernetes-caddy
:fix/161-e2e-bounded-and-diagnosable
:feat/162-werkbak-live-refresh
:feat/132-medewerker-mfa
:fix/156-tempo-ingester-healthcheck
:feat/153-projection-sourced-from-objecten
:feat/152-objecten-publishes-to-nrc
:feat/149-acl-writes-registerrecord
:feat/141-registerrecord-objecttype
:perf/verify-stack-uwsgi-oz-nrc
:fix/144-verify-stack-uwsgi
:feat/140-objecten-up
:feat/139-objecttypen-up
:feat/131-default-fill-crud
:chore/136-ci-job-summaries
:fix/134-verify-stack-scheduling
:feat/130-beheer-catalogi
:feat/124-metrics-dashboards
:ci/127-parallel-jobs
:feat/123-distributed-traces
:feat/111-self-service-resume
:feat/113-acl-zaaktype-by-identificatie
:fix/110-compose-local-flow
:fix/115-e2e-single-worker
:docs/111-backlog-s26
:feat/106-close-zaak-on-timeout
:feat/103-diploma-upload-documenten
:feat/102-document-wait-timeout
:feat/14-dmn-diploma-eligibility
:feat/15-beoordeling-escalation
:fix/portal-nginx-resolver
:fix/local-eventsubscriber-acl
:feat/12-withdrawal-portal
:fix/91-local-compose-parity
:feat/12-withdrawal-bff
:feat/12-withdrawal-workflow
:feat/12-withdrawal
:feat/13-behandel-portal
:feat/13-behandel-decide
:feat/13-behandel-bff-auth-werkbak
:feat/13-workflow-user-tasks
:feat/13-behandel-decision-model
:chore/release-2026.07.0
:feat/78-reference-correlation
:feat/75-approval-flow
:feat/10-openbaar-portal
:chore/73-ci-speedups
:feat/68-e2e
:feat/67-self-service-form
:feat/66-api-client
:feat/65-nx-workspace
:feat/8-bff
:feat/6-domain-service
:feat/7-event-subscriber-projection
:feat/56-nrc-notification-wiring
:test/46-acl-openzaak-integration
:feat/47-acl-mutation-baseline
:ci/30-gitea-actions-ci
:feat/5-acl-open-zaak
:feat/4-flowable
:feat/3-keycloak
:feat/2-opennotificaties
:feat/2-catalogus-seed
:feat/10-openzaak-compose
:feat/32-docs-scaffold
:feat/31-contributor-workflow
:feat/30-gitea-actions-ci
:feat/29-bff-docker-compose
:chore/remove-bootstrap-scripts
:feat/28-bff-health
:docs/split-s00
No Reviewers
Milestone
No items
No Milestone
Iteration 6 — Production Posture
Projects
Clear projects
No projects
Assignees
eho (Edwin van den Houdt)
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: eho/register-referentie#178
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What & why
The stack on the Talos VM is currently only reachable through five SSH forwards: PKCE needs
a secure context, so the OIDC origin is pinned to
localhostand every viewer has toforward all five browser-facing ports. This publishes it on real hostnames with real
certificates, terminated in the cluster.
public.domainis the entire switch:templates/edge.yamlrenders. Compose, CI and alaptop cluster are byte-identical to before.
register./mijn./behandel./beheer./auth.<domain>to the ClusterIPservices, so a public deployment doesn't use the browser-facing NodePorts at all.
Caddy rather than Traefik/ingress-nginx: the four portals already run
caddy:2-alpine(ADR-0034, whose ceiling note called this exact change out), so it adds no dependency — no
cert-manager, no CRDs, no Ingress objects for five hostnames that never change.
KC_HOSTNAMEand the portals'config.jsonnow both come from one helper,big.keycloakUrl, so the issuer a browser token carries and the authority the BFF discoversare the same string by construction rather than by two templates agreeing (ADR-0010).
The host keeps a layer-4 forward and nothing else — the public IP is on the Fedora host
and nothing in the cluster can claim it. Two
firewall-cmd --add-forward-portrules plus--add-masquerade, in runbook §10.Closes #177
Definition of Done
88fda30addsinfra/helm/check-issuer.pyand it failsagainst the unchanged chart with all seven assertions (
KC_HOSTNAME is 'http://192.168.122.100:30180', not https://auth.example.test, five unpublishedhostnames).
56cba9cmakes it pass.refs #177), test → feat → docs.make k8s-lint(now including the new check),make k8s-driftandinfra/check-docs-nav.pyall pass.docker compose upunaffected — no compose file, service or image is touched.troubleshooting), and §5 now points at §10 as the thing that removes the forwards.
docs/architecture/adr-0035-public-tls-edge-in-cluster.md, in the nav.happy to add it in this PR if you'd rather it lands together.
Notes for reviewers
and beheer, which approve registrations and administer the register — behind synthetic
accounts with known passwords, and MFA on the medewerker realm (ADR-0031). That was the
explicit choice for this demo environment; it is in the ADR rather than a comment because
it is the first decision to revisit if the stack ever holds anything real. The alternative
is one
remote_ipmatcher in the Caddyfile.persistence.storageClassstops being optional. Certificates live in/data; on thedefault
emptyDira handful of pod restarts hits Let's Encrypt's five-duplicates-per-weeklimit and the edge then serves an untrusted certificate until it resets. The runbook says
to install local-path first; the PVC carries
resource-policy: keep.a deploy proves anything: five A records to
46.224.220.37, and the firewalld rules(which need sudo on the host). Until then the chart change is provable only by rendering,
which is what the new check does.
docs/runbooks/kubernetes-talos.md(that PR adds §9, this one §10). #176 also needs aone-line
--set public.domain=…in the deploy workflow to actually switch this on; I'veput it on that branch rather than duplicating deploy.yaml here.
🤖 Generated with Claude Code
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.