From fffc14f8804c1d0e241d33d9457662f48a73ba69 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Tue, 25 Aug 2026 21:05:47 +1000 Subject: [PATCH 1/4] Extend the LE *.unkin.net wildcard to arrstack + authentik (reflect into gitea) why: after #417 stood up the central Let's Encrypt *.unkin.net wildcard (Certificate wildcard-unkin-net, secret wildcard-unkin-net-tls, emberstack- reflected), the remaining single-label public hosts should terminate on the real publicly-trusted leaf instead of the internal Vault-PKI CA. A *.unkin.net wildcard only matches single-label subdomains, so cluster hostnames under *.k8s.syd1.au.unkin.net stay on vault-issuer. - certificate_wildcard-unkin-net: reflect the secret into arrstack, authentik and gitea (append to both reflector namespace lists) - arrstack: point the public arrproxy gateway (arrstack.unkin.net) at wildcard-unkin-net-tls and drop its vault-issuer annotations - authentik: point the identity.unkin.net listener at wildcard-unkin-net-tls; the identity.k8s.syd1.au.unkin.net listeners keep authentik-tls, so the gateway common-name is retargeted to the cluster host - gitea: secret reflected only; git.unkin.net cutover deferred (no manifest change), same deferred pattern as fafflix --- apps/base/arrstack/arrproxy/gateway.yaml | 15 +++++++-------- apps/base/authentik/gateway.yaml | 9 +++++++-- .../certificate_wildcard-unkin-net.yaml | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/base/arrstack/arrproxy/gateway.yaml b/apps/base/arrstack/arrproxy/gateway.yaml index b223d2d..a151d6d 100644 --- a/apps/base/arrstack/arrproxy/gateway.yaml +++ b/apps/base/arrstack/arrproxy/gateway.yaml @@ -1,9 +1,11 @@ --- # External (DMZ) front for the arrstack, served on arrstack.unkin.net via the -# external Traefik (LB VIP 198.18.199.0). cert-manager mints arrproxy-gateway-tls -# (CN arrstack.unkin.net) off the internal Vault-PKI CA. The apex arrstack.unkin.net -# A record lives in the bind-operator unkin.net zone (bind-internal/authoritative), -# NOT external-dns, so no external-dns annotation here. +# external Traefik (LB VIP 198.18.199.0). The apex arrstack.unkin.net A record +# lives in the bind-operator unkin.net zone (bind-internal/authoritative), NOT +# external-dns, so no external-dns annotation here. Public TLS is terminated with +# the real Let's Encrypt *.unkin.net wildcard, centrally minted once in the +# cert-manager namespace (Certificate wildcard-unkin-net) and reflected into this +# namespace by the emberstack reflector as wildcard-unkin-net-tls, not Vault PKI. apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: @@ -11,9 +13,6 @@ metadata: traefik.io/instance: external annotations: argocd.argoproj.io/sync-wave: "2" - cert-manager.io/cluster-issuer: vault-issuer - cert-manager.io/common-name: arrstack.unkin.net - cert-manager.io/private-key-size: "4096" name: arrproxy namespace: arrstack spec: @@ -38,4 +37,4 @@ spec: certificateRefs: - group: "" kind: Secret - name: arrproxy-gateway-tls + name: wildcard-unkin-net-tls diff --git a/apps/base/authentik/gateway.yaml b/apps/base/authentik/gateway.yaml index bc13062..aa8892f 100644 --- a/apps/base/authentik/gateway.yaml +++ b/apps/base/authentik/gateway.yaml @@ -1,4 +1,9 @@ --- +# The public identity.unkin.net listener terminates TLS with the real Let's +# Encrypt *.unkin.net wildcard (Certificate wildcard-unkin-net in cert-manager, +# reflected here as wildcard-unkin-net-tls). The cluster-hostname listeners +# (identity.k8s.syd1.au.unkin.net) keep the Vault-PKI authentik-tls, whose +# cert-manager annotations below now key the common-name off that cluster host. apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: @@ -6,7 +11,7 @@ metadata: traefik.io/instance: internal annotations: cert-manager.io/cluster-issuer: vault-issuer - cert-manager.io/common-name: identity.unkin.net + cert-manager.io/common-name: identity.k8s.syd1.au.unkin.net cert-manager.io/private-key-size: "4096" external-dns.alpha.kubernetes.io/hostname: identity.unkin.net,identity.k8s.syd1.au.unkin.net external-dns.alpha.kubernetes.io/target: 198.18.200.4 @@ -33,7 +38,7 @@ spec: certificateRefs: - group: "" kind: Secret - name: authentik-tls + name: wildcard-unkin-net-tls mode: Terminate - allowedRoutes: namespaces: diff --git a/apps/base/cert-manager/certificate_wildcard-unkin-net.yaml b/apps/base/cert-manager/certificate_wildcard-unkin-net.yaml index c9cc74c..717357d 100644 --- a/apps/base/cert-manager/certificate_wildcard-unkin-net.yaml +++ b/apps/base/cert-manager/certificate_wildcard-unkin-net.yaml @@ -14,9 +14,9 @@ spec: secretTemplate: annotations: reflector.v1.k8s.emberstack.com/reflection-allowed: "true" - reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "cheeztv" + reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "cheeztv,arrstack,authentik,gitea" reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true" - reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "cheeztv" + reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "cheeztv,arrstack,authentik,gitea" privateKey: size: 4096 dnsNames: -- 2.47.3 From b0dce55cd436ac7f1c9bba56cfd5439bc6cc2bfc Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Tue, 25 Aug 2026 21:15:01 +1000 Subject: [PATCH 2/4] Split authentik gateway into public wildcard + internal vault-issuer gateways The single authentik Gateway kept cert-manager.io annotations (vault-issuer, common-name identity.k8s.syd1.au.unkin.net) while its public identity.unkin.net https listener referenced the reflector-managed wildcard-unkin-net-tls. The cert-manager gateway-shim mints a Certificate per distinct listener secretName from Gateway-level annotations, so it would create a competing vault-issuer Certificate for wildcard-unkin-net-tls and fight the emberstack reflector over that secret. Split into two Gateways mirroring the cheeztv/fafflix convention: - authentik (public): identity.unkin.net listeners on wildcard-unkin-net-tls, no cert-manager annotations, external-dns publishes identity.unkin.net. - authentik-internal: identity.k8s.syd1.au.unkin.net listeners on authentik-tls with the vault-issuer cert-manager annotations, external-dns publishes the cluster host. Both target 198.18.200.4. Update HTTPRoutes to attach each hostname's redirect + app route to the matching gateway's http/https sections. --- apps/base/authentik/gateway.yaml | 41 +++++++++++++++------ apps/base/authentik/httproute.yaml | 59 +++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 21 deletions(-) diff --git a/apps/base/authentik/gateway.yaml b/apps/base/authentik/gateway.yaml index aa8892f..ef05aac 100644 --- a/apps/base/authentik/gateway.yaml +++ b/apps/base/authentik/gateway.yaml @@ -1,19 +1,18 @@ --- -# The public identity.unkin.net listener terminates TLS with the real Let's -# Encrypt *.unkin.net wildcard (Certificate wildcard-unkin-net in cert-manager, -# reflected here as wildcard-unkin-net-tls). The cluster-hostname listeners -# (identity.k8s.syd1.au.unkin.net) keep the Vault-PKI authentik-tls, whose -# cert-manager annotations below now key the common-name off that cluster host. +# Public identity.unkin.net listener. external-dns publishes the A record at the +# internal LB VIP (198.18.200.4). Public TLS is terminated with the real Let's +# Encrypt *.unkin.net wildcard, centrally minted once in the cert-manager +# namespace (Certificate wildcard-unkin-net) and reflected into this namespace +# by the emberstack reflector as the secret wildcard-unkin-net-tls. No +# cert-manager annotations here so the gateway-shim does not mint a competing +# Vault-PKI Certificate for the reflected secret. apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: labels: traefik.io/instance: internal annotations: - cert-manager.io/cluster-issuer: vault-issuer - cert-manager.io/common-name: identity.k8s.syd1.au.unkin.net - cert-manager.io/private-key-size: "4096" - external-dns.alpha.kubernetes.io/hostname: identity.unkin.net,identity.k8s.syd1.au.unkin.net + external-dns.alpha.kubernetes.io/hostname: identity.unkin.net external-dns.alpha.kubernetes.io/target: 198.18.200.4 name: authentik namespace: authentik @@ -40,18 +39,38 @@ spec: kind: Secret name: wildcard-unkin-net-tls mode: Terminate +--- +# Cluster hostname variant, identity.k8s.syd1.au.unkin.net. Internal Traefik, +# external-dns at 198.18.200.4. Own leaf from the Vault PKI issuer via the +# cert-manager gateway-shim; the common-name keys off this cluster host. +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + labels: + traefik.io/instance: internal + annotations: + cert-manager.io/cluster-issuer: vault-issuer + cert-manager.io/common-name: identity.k8s.syd1.au.unkin.net + cert-manager.io/private-key-size: "4096" + external-dns.alpha.kubernetes.io/hostname: identity.k8s.syd1.au.unkin.net + external-dns.alpha.kubernetes.io/target: 198.18.200.4 + name: authentik-internal + namespace: authentik +spec: + gatewayClassName: traefik-internal + listeners: - allowedRoutes: namespaces: from: Same hostname: identity.k8s.syd1.au.unkin.net - name: http-internal + name: http port: 80 protocol: HTTP - allowedRoutes: namespaces: from: Same hostname: identity.k8s.syd1.au.unkin.net - name: https-internal + name: https port: 443 protocol: HTTPS tls: diff --git a/apps/base/authentik/httproute.yaml b/apps/base/authentik/httproute.yaml index bd4892e..3e85185 100644 --- a/apps/base/authentik/httproute.yaml +++ b/apps/base/authentik/httproute.yaml @@ -7,16 +7,11 @@ metadata: spec: hostnames: - identity.unkin.net - - identity.k8s.syd1.au.unkin.net parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: authentik sectionName: http - - group: gateway.networking.k8s.io - kind: Gateway - name: authentik - sectionName: http-internal rules: - filters: - type: RequestRedirect @@ -36,16 +31,60 @@ metadata: spec: hostnames: - identity.unkin.net - - identity.k8s.syd1.au.unkin.net parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: authentik sectionName: https - - group: gateway.networking.k8s.io - kind: Gateway - name: authentik - sectionName: https-internal + rules: + - backendRefs: + - group: "" + kind: Service + name: authentik-server + port: 80 + weight: 1 + matches: + - path: + type: PathPrefix + value: / +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: authentik-http-redirect-internal + namespace: authentik +spec: + hostnames: + - identity.k8s.syd1.au.unkin.net + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: authentik-internal + sectionName: http + rules: + - filters: + - type: RequestRedirect + requestRedirect: + scheme: https + statusCode: 301 + matches: + - path: + type: PathPrefix + value: / +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: authentik-internal + namespace: authentik +spec: + hostnames: + - identity.k8s.syd1.au.unkin.net + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: authentik-internal + sectionName: https rules: - backendRefs: - group: "" -- 2.47.3 From 68c8ec79e1f4ed3de924f2466c8e9bf17b50cfb7 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Tue, 25 Aug 2026 21:39:45 +1000 Subject: [PATCH 3/4] Move public identity gateway to external traefik proxy The public authentik gateway (identity.unkin.net) now uses traefik-external and removes external-dns management, matching the arrproxy external gateway convention. DNS remains managed out-of-band via bind-operator. The internal authentik-internal gateway stays on traefik-internal. --- apps/base/authentik/gateway.yaml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/base/authentik/gateway.yaml b/apps/base/authentik/gateway.yaml index ef05aac..0662cee 100644 --- a/apps/base/authentik/gateway.yaml +++ b/apps/base/authentik/gateway.yaml @@ -1,23 +1,22 @@ --- -# Public identity.unkin.net listener. external-dns publishes the A record at the -# internal LB VIP (198.18.200.4). Public TLS is terminated with the real Let's -# Encrypt *.unkin.net wildcard, centrally minted once in the cert-manager -# namespace (Certificate wildcard-unkin-net) and reflected into this namespace -# by the emberstack reflector as the secret wildcard-unkin-net-tls. No -# cert-manager annotations here so the gateway-shim does not mint a competing -# Vault-PKI Certificate for the reflected secret. +# External (DMZ) front for public identity.unkin.net, served via the external +# Traefik (LB VIP 198.18.199.0). The apex identity.unkin.net A record lives in +# the bind-operator unkin.net zone (bind-internal/authoritative), NOT +# external-dns, so no external-dns annotation here. Public TLS is terminated with +# the real Let's Encrypt *.unkin.net wildcard, centrally minted once in the +# cert-manager namespace (Certificate wildcard-unkin-net) and reflected into this +# namespace by the emberstack reflector as wildcard-unkin-net-tls, not Vault PKI. apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: labels: - traefik.io/instance: internal + traefik.io/instance: external annotations: - external-dns.alpha.kubernetes.io/hostname: identity.unkin.net - external-dns.alpha.kubernetes.io/target: 198.18.200.4 + argocd.argoproj.io/sync-wave: "2" name: authentik namespace: authentik spec: - gatewayClassName: traefik-internal + gatewayClassName: traefik-external listeners: - allowedRoutes: namespaces: -- 2.47.3 From 7d7b5fb6f203efbb1d706714cb16d0e5f85ff2e6 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Tue, 25 Aug 2026 21:43:19 +1000 Subject: [PATCH 4/4] Identity gateway migrated to traefik-external (198.18.199.0); watchstate added to wildcard cert reflector lists --- apps/base/bind-internal/authoritative/records.yaml | 4 ++-- apps/base/cert-manager/certificate_wildcard-unkin-net.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/base/bind-internal/authoritative/records.yaml b/apps/base/bind-internal/authoritative/records.yaml index 3f7a30a..9135948 100644 --- a/apps/base/bind-internal/authoritative/records.yaml +++ b/apps/base/bind-internal/authoritative/records.yaml @@ -16,9 +16,9 @@ spec: type: A ttl: 600 values: - # traefik-internal gateway VIP; the authentik Gateway serves the + # traefik-EXTERNAL (DMZ) gateway VIP; the authentik Gateway serves the # identity.unkin.net hostname there. - - 198.18.200.4 + - 198.18.199.0 --- # PRODUCTION CUTOVER RECORD — intentionally commented out. # git.unkin.net currently resolves to the LIVE VM forge (HAProxy VRRP VIP diff --git a/apps/base/cert-manager/certificate_wildcard-unkin-net.yaml b/apps/base/cert-manager/certificate_wildcard-unkin-net.yaml index 717357d..93afdbc 100644 --- a/apps/base/cert-manager/certificate_wildcard-unkin-net.yaml +++ b/apps/base/cert-manager/certificate_wildcard-unkin-net.yaml @@ -14,9 +14,9 @@ spec: secretTemplate: annotations: reflector.v1.k8s.emberstack.com/reflection-allowed: "true" - reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "cheeztv,arrstack,authentik,gitea" + reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "cheeztv,arrstack,authentik,gitea,watchstate" reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true" - reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "cheeztv,arrstack,authentik,gitea" + reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "cheeztv,arrstack,authentik,gitea,watchstate" privateKey: size: 4096 dnsNames: -- 2.47.3