From 44ae8e0da68944644065d3b9eb777b0a85a29019 Mon Sep 17 00:00:00 2001 From: Sten Date: Tue, 9 Jun 2026 16:49:15 +0200 Subject: [PATCH] feat(forte-drop): wildcard cert *.drop.forteapps.net for subdomain-per-drop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit forte_drop is moving to per-slug subdomains: forte-login drops served at .drop.forteapps.net (sidecar-gated), public/password drops at drop.forteapps.net/shared/. That needs a wildcard TLS cert. - letsencrypt-issuer.yaml: add '*.drop.forteapps.net' + 'drop.forteapps.net' to the dns01 azureDNS solver selector in BOTH issuers. The existing '*.forteapps.net' selector only matches single-label children, so it does NOT cover the two-label '*.drop.forteapps.net' — without this the wildcard challenge has no matching solver and issuance fails. SP already has zone-level rights on forteapps.net. - new Certificate wildcard-drop-forteapps-net in the forte-drop namespace -> secret wildcard-drop-forteapps-net-tls (dnsNames *.drop + apex). Issued in-namespace so the app's Traefik IngressRoute can reference it directly (the secret-cloner can't help: generateExisting:false + forte-drop ns already exists). Added to the overlay kustomization so ArgoCD manages it (the Application is prune+selfHeal). This is the SINGLE issuer of that secret. The forte-helm chart must reference it verbatim and must NOT create its own Certificate into the same secret. Depends on: DNS *.drop.forteapps.net resolving + ACME TXT in the flat forteapps.net zone (no delegated drop. child zone). Do NOT merge until that's confirmed. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../upc-dev/forte-drop/kustomization.yaml | 1 + .../wildcard-drop-tls-certificate.yaml | 34 +++++++++++++++++++ cluster-resources/letsencrypt-issuer.yaml | 8 +++++ 3 files changed, 43 insertions(+) create mode 100644 apps/overlays/upc-dev/forte-drop/wildcard-drop-tls-certificate.yaml diff --git a/apps/overlays/upc-dev/forte-drop/kustomization.yaml b/apps/overlays/upc-dev/forte-drop/kustomization.yaml index 8dc592b..410825a 100644 --- a/apps/overlays/upc-dev/forte-drop/kustomization.yaml +++ b/apps/overlays/upc-dev/forte-drop/kustomization.yaml @@ -5,3 +5,4 @@ resources: - keycloak-client-forte-drop.yaml - forte-drop-pdb.yaml - forte-drop-secrets-sealed.yaml +- wildcard-drop-tls-certificate.yaml diff --git a/apps/overlays/upc-dev/forte-drop/wildcard-drop-tls-certificate.yaml b/apps/overlays/upc-dev/forte-drop/wildcard-drop-tls-certificate.yaml new file mode 100644 index 0000000..fde30ec --- /dev/null +++ b/apps/overlays/upc-dev/forte-drop/wildcard-drop-tls-certificate.yaml @@ -0,0 +1,34 @@ +--- +# Wildcard TLS cert for the per-slug drop subdomains: .drop.forteapps.net. +# forte_drop serves forte-login drops on their own subdomain (gated by the auth +# sidecar), so each drop needs a valid cert for *.drop.forteapps.net. +# +# Issued DIRECTLY into the forte-drop namespace (not cert-manager) so the app's +# Traefik IngressRoute — which must reference a TLS secret in its OWN namespace — +# can use it without cross-namespace cloning. The secret-cloner Kyverno policy +# can't help here: it only clones on NEW namespace creation (generateExisting:false) +# and forte-drop already exists. +# +# This is the SINGLE issuer of secret `wildcard-drop-forteapps-net-tls`. The +# forte-helm chart must reference this secret VERBATIM and must NOT also create a +# Certificate into the same secret (else cert-manager thrashes). The dns01 solver +# in letsencrypt-prod is authorized for these names via its selector.dnsNames. +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: wildcard-drop-forteapps-net + namespace: forte-drop +spec: + secretName: wildcard-drop-forteapps-net-tls + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - '*.drop.forteapps.net' # per-slug forte drop subdomains + - 'drop.forteapps.net' # apex (admin + /shared public drops) + duration: 2160h0m0s # 90 days + renewBefore: 720h0m0s # renew 30 days before expiry + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 diff --git a/cluster-resources/letsencrypt-issuer.yaml b/cluster-resources/letsencrypt-issuer.yaml index 8881362..2f1689b 100644 --- a/cluster-resources/letsencrypt-issuer.yaml +++ b/cluster-resources/letsencrypt-issuer.yaml @@ -25,6 +25,10 @@ spec: key: client-secret selector: dnsNames: + # *.forteapps.net only matches single-label children, NOT *.drop.forteapps.net, + # so the per-drop subdomain wildcard needs its own selector entry. + - '*.drop.forteapps.net' + - 'drop.forteapps.net' - '*.forteapps.net' - 'forteapps.net' # HTTP-01 fallback for non-wildcard certificates @@ -59,6 +63,10 @@ spec: key: client-secret selector: dnsNames: + # *.forteapps.net only matches single-label children, NOT *.drop.forteapps.net, + # so the per-drop subdomain wildcard needs its own selector entry. + - '*.drop.forteapps.net' + - 'drop.forteapps.net' - '*.forteapps.net' - 'forteapps.net' # HTTP-01 fallback for non-wildcard certificates