feat(k8s): terminate TLS in the cluster for a public domain (refs #177)
`public.domain` is the whole switch. Empty — the default, and what compose, CI and a laptop cluster use — renders nothing new and leaves every manifest as it was. Set it and templates/edge.yaml adds a Caddy deployment that gets its own certificates from Let's Encrypt and proxies the five browser-facing hostnames to the ClusterIP services, so a public deployment doesn't use their NodePorts at all. Caddy rather than an ingress controller because the four portals already run caddy:2-alpine (ADR-0034, whose ceiling note called exactly this out): no new dependency, no cert-manager, no CRDs, no Ingress objects for five hostnames that never change. The Fedora host keeps only a layer-4 forward of 80/443, because the public IP is there and nothing in the cluster can claim it. KC_HOSTNAME and the portals' config.json now both come from `big.keycloakUrl`, so the issuer a token carries and the authority the BFF discovers are one string by construction (ADR-0010) rather than by two templates agreeing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,32 @@ persistence:
|
||||
# the data across pod restarts.
|
||||
storageClass: ""
|
||||
|
||||
# The public TLS edge (ADR-0035). Empty `domain` = no edge at all: nothing in
|
||||
# templates/edge.yaml is rendered and the stack is reached on the NodePorts below,
|
||||
# with `host` above pinning the OIDC origin.
|
||||
#
|
||||
# Set it and an in-cluster Caddy terminates TLS for `<sub>.<domain>`, gets its own
|
||||
# certificates from Let's Encrypt and proxies to the ClusterIP services. The node
|
||||
# only has to be reachable on the two NodePorts here — the Fedora host forwards
|
||||
# 80/443 to them (see docs/runbooks/kubernetes-talos.md).
|
||||
public:
|
||||
domain: ""
|
||||
# ACME registration address; Let's Encrypt uses it for expiry warnings.
|
||||
email: ""
|
||||
image: docker.io/library/caddy:2-alpine
|
||||
# <subdomain>: <in-cluster service:port>. `auth` is not free-form — big.keycloakUrl
|
||||
# builds the pinned issuer from it.
|
||||
routes:
|
||||
register: openbaar:80
|
||||
mijn: self-service:80
|
||||
behandel: behandel:80
|
||||
beheer: beheer:80
|
||||
auth: keycloak:8080
|
||||
# Where the host's 80/443 forward lands. Not 30080/30443: 30080 is the BFF.
|
||||
nodePorts:
|
||||
http: 32080
|
||||
https: 32443
|
||||
|
||||
# The only place a port is published outside the cluster. A workload listed here
|
||||
# gets a NodePort on its single port; everything else stays ClusterIP.
|
||||
nodePorts:
|
||||
@@ -268,7 +294,7 @@ workloads:
|
||||
# Pin the issuer to the address the browser uses, and let backchannel calls
|
||||
# keep using keycloak:8080 — the BFF discovers metadata in-cluster and gets
|
||||
# this issuer back, which is what browser tokens carry (infra/host-browser.yml).
|
||||
KC_HOSTNAME: "http://{{ .Values.host }}:{{ index .Values.nodePorts \"keycloak\" }}"
|
||||
KC_HOSTNAME: '{{ include "big.keycloakUrl" . }}'
|
||||
KC_HOSTNAME_BACKCHANNEL_DYNAMIC: "true"
|
||||
ports: [{ name: http, port: 8080 }]
|
||||
# TCP, not /health/ready on the management port: nothing here gates on realm
|
||||
|
||||
Reference in New Issue
Block a user