From 5da12e398d555fa9049052cf0bf03a5b8398002f Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Tue, 25 Aug 2026 21:48:54 +1000 Subject: [PATCH] Extend LE *.unkin.net wildcard to arrstack + authentik (reflect into gitea) (#418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why #417 stood up the central Let's Encrypt `*.unkin.net` wildcard (Certificate `wildcard-unkin-net` in `cert-manager`, secret `wildcard-unkin-net-tls`, emberstack-reflected). This wires the remaining single-label public hosts onto that publicly-trusted leaf instead of the internal Vault-PKI CA. A `*.unkin.net` wildcard matches **single-label** subdomains only, so cluster hostnames under `*.k8s.syd1.au.unkin.net` are deliberately left on `vault-issuer`. > Note: PR #417 already merged to `main`, so this is no longer stacked — it targets `main` directly. ## How - **cert-manager**: reflect `wildcard-unkin-net-tls` into `arrstack`, `authentik`, `gitea` (appended to both reflector namespace lists → `cheeztv,arrstack,authentik,gitea`). - **arrstack**: repoint the public `arrproxy` gateway listener (`arrstack.unkin.net`) `certificateRefs` → `wildcard-unkin-net-tls`; drop its `cert-manager.io/*` vault-issuer annotations. - **authentik**: repoint the `identity.unkin.net` https listener → `wildcard-unkin-net-tls`. The `identity.k8s.syd1.au.unkin.net` listeners keep `authentik-tls` (vault-issuer), so the gateway `common-name` is retargeted to that cluster host. `authentik-ldap` gateway untouched. - **gitea**: secret **reflected only**; `git.unkin.net` cutover deferred (no manifest change), same deferred pattern as fafflix. ## Validation - `kustomize build` OK for cert-manager / arrstack / authentik / gitea overlays. - `kubeconform` all valid (0 invalid, 0 errors) across the four overlays. - Verified no `*.k8s.syd1.au.unkin.net` listener lost its vault-issuer wiring. Reviewed-on: https://git.unkin.net/unkin/argocd-apps/pulls/418 Co-authored-by: unkin-agent Co-committed-by: unkin-agent --- apps/base/arrstack/arrproxy/gateway.yaml | 15 +++-- apps/base/authentik/gateway.yaml | 43 ++++++++++---- apps/base/authentik/httproute.yaml | 59 +++++++++++++++---- .../bind-internal/authoritative/records.yaml | 4 +- .../certificate_wildcard-unkin-net.yaml | 4 +- 5 files changed, 93 insertions(+), 32 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..0662cee 100644 --- a/apps/base/authentik/gateway.yaml +++ b/apps/base/authentik/gateway.yaml @@ -1,19 +1,22 @@ --- +# 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: - cert-manager.io/cluster-issuer: vault-issuer - cert-manager.io/common-name: identity.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 + argocd.argoproj.io/sync-wave: "2" name: authentik namespace: authentik spec: - gatewayClassName: traefik-internal + gatewayClassName: traefik-external listeners: - allowedRoutes: namespaces: @@ -33,20 +36,40 @@ spec: certificateRefs: - group: "" kind: Secret - name: authentik-tls + 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: "" 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 c9cc74c..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" + 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" + reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "cheeztv,arrstack,authentik,gitea,watchstate" privateKey: size: 4096 dnsNames: