ADR-0020: Wildcard TLS DNS-01 para *.d.wetopi.com en el edge¶
Date: 2026-09-10 · Status: Accepted (2026-09-10 — GO del operador + ejecución completa verificada: staging gate, prod Ready, tofu DNS, Gateway apply; ver SVC-DEV-WILDCARD) Related: ADR-0006 (edge v1), ADR-0019 (D-tls offloading), OBJ-EDGE-DWETOPI-001
Context¶
El cluster d (RKE2 wetopi3) será el sandbox donde se despliegan wepods
de desarrollo. El operador requiere exponerlos en
https://<wepod>.d.wetopi.com (muchos subdominios, los de desarrollo de
wetopi) con optimización del tiempo de despliegue.
Estado live verificado 2026-09-10:
- Edge v1 (ADR-0006, accepted): Traefik hostNetwork en rke-wan01/02,
Gateway
kube-system/wetopi-edge(Accepted+Programmed), listeners web:8000/https:8443, nftables REDIRECT 80/443→8000/8443, 11 certRefs LE PROD en producción (argo/docs/vault/infer/memory/grafana/prometheus/ alertmanager/dashboards/otlp).https://docs.wetopi.netsirve LE prod verificado desde el harness. - cert-manager v1.21.1 + ClusterIssuers letsencrypt-staging/prod con solver DNS-01 Cloudflare: patrón probado por 6+ certificados.
- DNS:
wetopi.comya vive en Cloudflare (NS propio).d.wetopi.comhoy NXDOMAIN (sin zona/registro). El token Cloudflare existente (cloudflare-dns-api-token) está scoping a la zonawetopi.net(comentario del ClusterIssuer: "Zone-DNS-Edit AND Zone-Zone-Read on the wetopi.net zone") — NO cubre wetopi.com. - ADR-0019 §D-tls (DECIDIDO): TLS offloading en Traefik, HTTP interno hasta el wepod; re-encrypt por-pod rechazado.
El problema del cert por servicio: cada wepod nuevo requeriría (1) certificado LE por nombre (~1-2 min + riesgo de rate limit), (2) certRef en el Gateway con apply manual (el Secret ausente tumba el listener completo — fail-safe order), (3) DNS A record por subdominio en tofu. Con "muchos subdominios de desarrollo" ese coste se multiplica y el despliegue deja de ser ágil: choca con el requisito de velocidad.
Decision¶
- Un certificado wildcard LE PROD
dev-wildcard-tls(kube-system):dnsNames: ["*.d.wetopi.com"], issuerletsencrypt-prod, vía DNS-01. El wildcard cubredemo-joan.d.wetopi.comy cualquier subdominio futuro ded.wetopi.comSIN nueva emisión. - Emisión staging-first: el wildcard se emite primero con
letsencrypt-staging(valida token nuevo + solver en la zona wetopi.com), gate explícito, y solo entonces se corta a prod. (Protege el rate budget: LE prod permite 50 certs/domain/week y 5 duplicados/7d — un wildcard mal formado quema intentos.) - DNS wildcard en la zona wetopi.com (variante por defecto, D3bis
variante A): registros
*.dA 79.137.114.193/.194 +dA .193/.194 (4 records, grey-cloud, TTL 300, tofu-owned encloudflare_dns_records). Cualquierwepod.d.wetopi.comresuelve desde el minuto uno; no se vuelve a tocar DNS para wepods. Variante B (a decisión del operador): subdominios explícitos por wepod en tfvars — más conservador, cada wepod nuevo toca tofu. - Token Cloudflare: RESUELTO por el operador 2026-09-10 — el token
existente (
cloudflare-dns-api-token, zona wetopi.net) fue AMPLIADO para cubrir también la zona wetopi.com. Consecuencias: el MISMO Secret k8s (cloudflare-dns-api-tokenkeyapi-token, ns cert-manager) sirve a los solvers DNS-01 de ambas zonas; NO se crean Secrets nuevos ni issuers clonados; los ClusterIssuers letsencrypt-staging/prod existentes sirven el wildcard sin cambios. Verificación del permiso ampliado: la emisión STAGING del wildcard es el test (un token sin DNS-Edit en wetopi.com hace fallar el solver con zone-discovery — sin coste de rate-limit prod). Si el valor del token hubiese ROTADO (token nuevo en vez de ampliación), rotar el Secretcloudflare-dns-api-tokendesde el env 0600 de ops01 antes de emitir. - El certRef
dev-wildcard-tlsentra al Gateway con el fail-safe order obligatorio (Certificate Ready → apply Gateway; un Secret ausente tumba el listener completo con los 10 co-tenants). - Routing: namespace
wepods-d+ HTTPRoutedev-catchallconhostnames: ["*.d.wetopi.com"]→ backend default 404 + Services por wepod añadidos por PR (ver OBJ D4). Añadir un wepod = 1 PR al repo del servicio, cero toques en kube-system/edge/cert-manager. MECANISMO MÍNIMO (fall-back probado): el mecanismo de onboarding primario NO depende del catch-all — cada wepod declara su HTTPRoute con hostname EXACTO (wepod.d.wetopi.com) en su propio namespace (patrón docs-site/argo ya live: parentRef sectionName https, allowedRoutes from:All). Esa variante es exact-hostname matching, el camino estándar que ya sirve 13 rutas en producción. El catch-all wildcard-hostname es una mejora opcional cuyo soporte (Traefik findMatchingHostname sobre route hostnames) se valida en build; si Traefik no lo soporta, se despliega la HTTPRoute default-404 conmatchespath catch-all SIN hostname propio — que captura solo lo que ninguna route exacta matchee no es posible en Gateway API (route-less hosts caen a 404 del router, comportamiento por defecto del provider), así que el 404 default se implementa con la route catch-all O se acepta el comportamiento por defecto del proxy (404/503 nativo). Decisión de build, no bloquea el onboarding.
Alternatives considered¶
- Cert por subdominio (patrón infer-tls por wepod): rechazado como mecanismo primario — el tiempo de despliegue por wepod (emisión + certRef
- apply del Gateway) es exactamente lo que el operador pidió evitar; con muchos subdominios quema rate limits. Queda como fallback si el wildcard se bloquea.
- Ampliar el token wetopi.net a wetopi.com: viable y más simple; el operador decide. ~~Por defecto se propone token dedicado (separación dev/ plataforma).~~ DECIDIDO por el operador 2026-09-10: token ampliado a ambas zonas (misma referencia Secret por nombre; sin piezas nuevas).
- cert-manager con issuer propio por wepod (namespace-scoped Issuer): rechazado — multiplica cuentas/emisiones y no mejora el tiempo.
- Traefik default cert wildcard para todo el edge: rechazado — el
wildcard dev no debe cubrir
*.wetopi.net(blast radius). - Cloudflare proxied (orange-cloud) para ocultar los edges: rechazado — rompería el patrón grey-cloud probado (TTL 300, round-robin sin proxy) y añade una capa (WAF CF) fuera del scope; los A records grey-cloud son el patrón de todos los servicios v1.
Consequences¶
- Positivo: despliegue de wepod = crear Service + entry HTTPRoute (o nueva route en el ns del wepod) — minutos, sin cert-manager ni edge applies; un solo cert que renovar; DNS configurado una vez para siempre; coherente con ADR-0019 (offloading, HTTP interno al wepod).
- Negativo: (a) el wildcard da validez TLS a cualquier subdominio presente en DNS — mitigado por el catch-all 404 default + el carácter dev del dominio; (b) requiere un token Cloudflare adicional (una pieza operator + vault); (c) wildcard en LE prod exige gate staging-first (una emisión staging antes de prod); (d) el hostname wildcard en HTTPRoute requiere Gateway API ≥1.0 — el cluster corre Traefik 3.7.8 con provider Gateway y CRDs v1 (verificado en gateway-wetopi-edge.yaml), compatible.
- Neutral: la disponibilidad hereda el modelo ADR-0006 (round-robin 2 A records, sin L4 health-check, remediation operador). Los wepods dev NO son clientes externos: la condición dura del ADR-0006 (v2 antes de hosting externo) NO cambia.
Verification / implementation notes¶
- Orden fail-safe (obligatorio, verificado en 10 certRefs previos):
- Token Cloudflare wetopi.com en vault + Secret en ns cert-manager.
- Certificate
dev-wildcard-tls-staging(letsencrypt-staging) Ready. - Gate operador: revisión del chain staging (fake LE).
- Certificate prod (letsencrypt-prod) Ready → Secret
dev-wildcard-tls. - Gateway certRef (platform-edge PR) + apply desde ops01.
- DNS records ×4 (tofu tfvars + apply operador, grey-cloud TTL 300).
- HTTPRoute catch-all + Services por wepod (GitOps).
- Probes públicos (SAN wildcard, 404 default, co-tenant regression).
- Rollback: revert del certRef → listener cae al resto de certs; Secret queda (cert-manager sigue renovando). DNS wildcard: tofu revert.