ADR proposal: publish the portals over TLS from an in-cluster Caddy edge #177

Open
opened 2026-09-18 14:26:24 +00:00 by not · 0 comments
Contributor

Decision to record

Serve the four portals and Keycloak publicly over TLS on *.labs.respellion.tech, terminated by a Caddy deployment inside the cluster, not by a proxy on the Fedora host and not by an ingress controller.

Context

The stack is deployed to a Talos VM on the lab server (#175). Today it is only usable through five SSH port-forwards, because the portals' PKCE flow needs a secure context and the OIDC origin is pinned to localhost (runbook §5). We want a shareable demo URL, and we want the routing and the certificates to live in the cluster rather than in host-side config.

Options

  1. Caddy on the Fedora host. Fewest moving parts, but the routing and the certs live outside the cluster, which is what we are trying to avoid.
  2. Traefik or ingress-nginx + cert-manager in-cluster. The standard answer, but it buys Ingress objects and CRDs for five hostnames that never change.
  3. A Caddy deployment in the chart (proposed). The four portal images already run caddy:2-alpine, so this adds no new dependency: one Deployment, one Caddyfile ConfigMap, one NodePort Service. Caddy does ACME itself, so no cert-manager.

Consequences to record in the ADR

  • The public IP is on the Fedora host, so a dumb L4 forward there is irreducible: two firewall-cmd --add-forward-port rules 80/443 → the VM's NodePorts. No TLS and no routing on the host.
  • KC_HOSTNAME and the portals' config.json stop being host + NodePort and become a full https://auth.<domain> URL — one new value, two template lines.
  • Certificates need a volume, or Let's Encrypt is re-asked on every pod restart and we hit rate limits. That means the chart's persistence.storageClass stops being optional for a public deployment.
  • All five names are published, including behandel and beheer, which approve registrations and administer the register. They are protected by the synthetic test users and, for the medewerker realm, MFA (ADR-0031). This is a deliberate choice for a demo environment and belongs in the ADR's consequences, not in a comment.
  • The other NodePorts (admin UIs) stay as they are; only the browser-facing five go through the edge.

Done when

  • ADR-0035 written and merged with the implementation.
  • DNS: five A records under labs.respellion.tech46.224.220.37.
  • The two firewalld forward rules applied on the host (needs sudo there).
  • https://register.labs.respellion.tech serves the public register and https://mijn.labs.respellion.tech completes a DigiD login without any SSH forward.
## Decision to record Serve the four portals and Keycloak publicly over TLS on `*.labs.respellion.tech`, terminated by **a Caddy deployment inside the cluster**, not by a proxy on the Fedora host and not by an ingress controller. ## Context The stack is deployed to a Talos VM on the lab server (#175). Today it is only usable through five SSH port-forwards, because the portals' PKCE flow needs a secure context and the OIDC origin is pinned to `localhost` (runbook §5). We want a shareable demo URL, and we want the routing and the certificates to live in the cluster rather than in host-side config. ## Options 1. **Caddy on the Fedora host.** Fewest moving parts, but the routing and the certs live outside the cluster, which is what we are trying to avoid. 2. **Traefik or ingress-nginx + cert-manager in-cluster.** The standard answer, but it buys Ingress objects and CRDs for five hostnames that never change. 3. **A Caddy deployment in the chart (proposed).** The four portal images already run `caddy:2-alpine`, so this adds no new dependency: one Deployment, one Caddyfile ConfigMap, one NodePort Service. Caddy does ACME itself, so no cert-manager. ## Consequences to record in the ADR - The public IP is on the Fedora host, so a dumb L4 forward there is irreducible: two `firewall-cmd --add-forward-port` rules 80/443 → the VM's NodePorts. No TLS and no routing on the host. - `KC_HOSTNAME` and the portals' `config.json` stop being `host` + NodePort and become a full `https://auth.<domain>` URL — one new value, two template lines. - Certificates need a volume, or Let's Encrypt is re-asked on every pod restart and we hit rate limits. That means the chart's `persistence.storageClass` stops being optional for a public deployment. - All five names are published, including behandel and beheer, which approve registrations and administer the register. They are protected by the synthetic test users and, for the medewerker realm, MFA (ADR-0031). This is a deliberate choice for a demo environment and belongs in the ADR's consequences, not in a comment. - The other NodePorts (admin UIs) stay as they are; only the browser-facing five go through the edge. ## Done when - [ ] ADR-0035 written and merged with the implementation. - [ ] DNS: five A records under `labs.respellion.tech` → `46.224.220.37`. - [ ] The two firewalld forward rules applied on the host (needs sudo there). - [ ] `https://register.labs.respellion.tech` serves the public register and `https://mijn.labs.respellion.tech` completes a DigiD login without any SSH forward.
not added this to the Iteration 6 — Production Posture milestone 2026-09-18 14:26:24 +00:00
not added the type:adr-proposalarea:infra labels 2026-09-18 14:26:30 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eho/register-referentie#177