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