Skip to content

OBJ-EDGE-DWETOPI-001: Subdominios de desarrollo *.d.wetopi.com en el edge v1

Objective ID: OBJ-EDGE-DWETOPI-001 Status: completed (2026-09-10 — TODAS las fases ejecutadas y verificadas: cert staging/prod Ready, DNS live, Gateway certRef aplicado, SNI público verificado, co-tenants sin regresión; ver SVC-DEV-WILDCARD) Drafted by: wetopi-lead (Orchestrator) — Owned by: platform Ejecución: wetopi-coder (PRs) · Applies: operator (DNS tofu + Gateway)

Outcome

https://<wepod>.d.wetopi.com responde desde internet con un certificado Let's Encrypt production wildcard válido (*.d.wetopi.com, DNS-01 vía Cloudflare) terminado en el Gateway kube-system/wetopi-edge (Traefik, edge v1 según ADR-0006), con routing catch-all a los backends que los wepods registren. Añadir un wepod nuevo NO toca el edge: el equipo de desarrollo crea (o reutiliza) una HTTPRoute con hostname <wepod>.d.wetopi.com — o un backend en la route catch-all — y el dominio funciona sin tickets de DNS, sin certificados nuevos y sin applies.

Why

  • d es el sandbox de iteración (decisión rev1 2026-09-09: wepods de prueba sin mecánica canary): el flujo de despliegue dev debe ser rápido; un cert por dominio rompe esa velocidad (LE prod rate limits + espera de emisión + certRef por servicio en el Gateway con su apply manual).
  • Requisito del operador (2026-09-10): exponer muchos subdominios *.d.wetopi.com (subdominios de desarrollo de wetopi) con 443, optimizando el tiempo de despliegue → wildcard.
  • La maquinaria ya existe y está live-verified: edge v1 (ADR-0006), cert-manager + LE prod DNS-01 (4+ certificados prod emitidos por esa cadena), Gateway wetopi-edge con 11 certRefs y DNS tofu-owned. El wildcard es una adición declarativa al patrón probado, no un sistema nuevo.
  • ADR-0019 (proposed, §D-tls DECIDIDO) fija el modelo TLS: offloading en Traefik, HTTP interno hasta el wepod — exactamente lo que este objetivo monta para d.wetopi.com.

Decisions (bound for executor)

  • D1 — Wildcard LE PROD, no cert por servicio. Un único Certificate dev-wildcard-tls (kube-system, dnsNames: ["*.d.wetopi.com"], issuer letsencrypt-prod). Justificación: velocidad de despliegue (requisito del operador), 1 challenge DNS-01 (vs 1 por subdominio = rate-limit LE), rotación única. El precedente "no wildcard" de certificate-infer.yaml protegía *.wetopi.net compartido entre servicios de platforma; aquí el scope del wildcard es un dominio de desarrollo (.d.), de blast radius delimitado — y los hosts siguen estando en manos de GitOps, no del Secret.
  • D2 — Token Cloudflare RESUELTO (operador 2026-09-10): token existente ampliado a la zona wetopi.com (misma referencia BY NAME cloudflare-dns-api-token en ns cert-manager; sin Secret nuevo ni issuers clonados). Verificación en la emisión staging (solver con zone-discovery sobre wetopi.com); si el token hubiese rotado de valor, rotar el Secret desde el env 0600 de ops01 antes de emitir.
  • D3 — CNAME apex de la zona de servicio. En vez de 2 A records por subdominio, se declara UN registro: d.wetopi.com CNAME/A → los 2 edge IPs, y cada wepod.d.wetopi.com es implícito (resuelve por el CNAME del apex si el proveedor lo permite) — PERO Cloudflare NO permite CNAME en apex hacia fuera de la zona: la implementación tofu son los 2 A records d → 79.137.114.193/.194 (grey-cloud, TTL 300, mismo patrón que edge-test/docs/vault). Los subdominios wepod.* se sirven por el mecanismo del resolver + el HTTPRoute catch-all: cualquier subdominio NO declarado explícitamente en Cloudflare NO resuelve → D3bis.
  • D3bis — ¿wildcard DNS o subdominios explícitos? Cloudflare free/pro sí permite registros wildcard (*.d.wetopi.com A .193/.194) grey-cloud. Decisión por defecto: declarar el wildcard DNS (1 entrada tofu, 2 records) + el cert wildcard — cualquier wepod.d.wetopi.com resuelve y sirve al momento sin tocar DNS nunca más. Riesgo aceptado y documentado: cualquier subdominio resuelve al edge (igual que hoy hace *.wetopi.net → .76 legacy). El operador puede pedir la variante conservadora (subdominios explícitos por wepod en tfvars).
  • D4 — Routing: per-wepod route exacta (primario) + catch-all opcional. Se crea namespace wepods-d. Mecanismo primario de onboarding (probado en producción): cada wepod declara SU HTTPRoute con hostname EXACTO (wepod.d.wetopi.com) + Service en su namespace (o en wepods-d), parentRef al Gateway wetopi-edge sectionName https (allowedRoutes from:All ya abierto) — el mismo patrón que docs-site/argo sirven hoy. El cert wildcard los cubre a todos sin tocar cert-manager. Mejora opcional a validar en build: HTTPRoute catch-all dev-catchall con hostnames: ["*.d.wetopi.com"] + backend default 404 (el soporte de hostname wildcard en HTTPRoute por el provider Gateway de Traefik no está documentado explícitamente — validarlo con un wepod real antes de depender de él).
  • D5 — Traefik no requiere config extra: el provider Gateway de Traefik enlaza las HTTPRoutes nuevas al vuelo (recarga automática observada en los edge-change flows); el matching de hosts es por las hostnames de cada route (exactas en el patrón probado). No se toca HelmChartConfig (8000/8443 + REDIRECT intactos).
  • D6 — No HTTP-01: el edge solo expone 80/443 con el patrón web→websecure ya probado; DNS-01 es port-mapping-immune (SVC-CERT-MANAGER).
  • D7 — Wepods NO van en kube-system: namespace dedicado wepods-d (o uno por wepod si el aislamiento lo pide — decisión en build). Los Certificates/Secrets del Gateway viven en kube-system; las HTTPRoutes de wepods en wepods-d (allowedRoutes from:All ya configurado en el listener https).

Acceptance criteria (DONE)

# AC Verificación
AC1 Cert wildcard LE PROD dev-wildcard-tls Ready en kube-system kubectl -n kube-system get certificate dev-wildcard-tls -o jsonpath='{.status.conditions[*].type}' = Ready; openssl s_client -connect <edge>:443 -servername demo-joan.d.wetopi.com muestra *.d.wetopi.com en SAN, issuer LE
AC2 Gateway https listener ResolvedRefs=True + Programmed=True con el nuevo certRef kubectl -n kube-system get gateway wetopi-edge -o jsonpath='{.status.conditions}' — sin regresión de co-tenant (docs/argo/vault/infer/grafana/prometheus/alertmanager/cerebro/otlp sirven 200/401/403 esperados)
AC3 DNS: demo-joan.d.wetopi.com y d.wetopi.com resuelven a .193/.194 dig +short demo-joan.d.wetopi.com ×2 IPs; declarado en cloudflare_dns_records (tfvars)
AC4 HTTPS público demo: https://demo-joan.d.wetopi.com responde con la route catch-all (404 default o backend del wepod demo) curl -sSI desde ops01 → respuesta con cert válido; SAN *.d.wetopi.com; sin 5xx de infraestructura
AC5 Un wepod nuevo se expone SIN tocar el edge: añadir Service + entry en la HTTPRoute (o nueva HTTPRoute) es el único cambio simulado en PR: 2º wepod añadido por manifest; verificación de que NO hay delta en cert-manager ni en el Gateway
AC6 Sin regresión de seguridad: 401/403 en docs/argo/vault/infer/memoria/grafana/prometheus/alertmanager/cerebro/otlp siguen como hoy re-run de los probes públicos de co-tenant (checklist go-live del skill wetopi-gitops-ops)

Verification contract

  • Todo AC con salida de comando real en el ledger (sin verify=False).
  • DNS apply y Gateway apply: cards ops + hard gate operador (mismo patrón que el cutover docs .76 → .193/.194 y F5).
  • Certificado: fail-safe order obligatorio (Certificate Ready ANTES del certRef en el Gateway — un Secret ausente tumba el listener completo, SVC-TRAEFIK-EDGE). Staging-first: emitir el wildcard primero contra letsencrypt-staging para validar el solver en la zona wetopi.com, y CORTAR a prod solo tras el gate (protege el rate budget de LE).

Constraints

  • ADR-0006 ventana v1 sigue vigente: wepods DEV son operator-only por ahora (no external paying customers — la condición dura del ADR se mantiene: v2 edge antes de clientes externos). El carácter "dev" se defiende con: (a) el namespace no es productivo, (b) el default 404, (c) futura capa WAF/IP-allowlist según ADR-0019 (out of scope aquí).
  • Ningún delta sobre edge_lb nftables ni HelmChartConfig (contrato "three concerns together" intacto).
  • El cert wildcard NO se reutiliza para otros dominios (no *.wetopi.com).
  • Secret del token Cloudflare wetopi.com: operator material, vault + Secret k8s por nombre; NUNCA en Git.
  • Build ≠ Apply: PRs declarativos; applies de DNS/tofu y Gateway = cards ops con gate humano (runbook del repo edge).

Boundaries

  • No se toca la zona wetopi.net ni sus records (solo se AÑADE material en wetopi.com + kube-system).
  • No se despliegan wepods productivos ni clientes externos (ADR-0006 hard condition 1 sigue).
  • No L4 (v2 edge), no WAF, no egress policies (ADR-0019 track, out of scope).

Stop conditions

  • ~~El token Cloudflare para wetopi.com no se puede provisionar → BLOCK~~ RESUELTO 2026-09-10 (operador amplió el token a ambas zonas). Nueva condición: si la emisión STAGING falla por permisos del token ampliado (zone-discovery sobre wetopi.com) tras 2 intentos limpios → BLOCK con logs del solver y escalar al operador.
  • LE staging falla en la zona wetopi.com tras 2 intentos limpios → BLOCK con logs del solver (zona discovery / permisos del token).
  • Cualquier regresión de co-tenant tras el Gateway apply → ROLLBACK inmediato (revert del certRef) + incident record.
  • Si el operador revoca la excepción para wepods dev → abandon (revert DNS wildcard + certRef).

Review boundaries

  • PRs: infrastructure (tfvars DNS + certificate-dev-wildcard.yaml), platform-edge (Gateway certRef), platform-gitops (nueva Application wepods-d si el routing catch-all va GitOps).
  • Review independiente obligatoria (approver) para el cert wildcard y el Gateway delta (patrón F2/F3: el operador ejecuta applies).
  • Lead no aprueba su propio ADR; reviewer = wetopi-reviewer/approver.

Out of scope

  • Capa L4 / v2 edge (VRRP/IPVS/DSR) — precondición futura para clientes externos, no para wepods dev.
  • WAF per-site (ADR-0019 D-waf-toggle) — siguiente iteración de seguridad para estos mismos hostnames.
  • Egress policies de wepods (ADR-0019 perfiles egress) — plano aparte.
  • TLS re-encrypt por-pod (rechazado en ADR-0019 D-tls).

Promotion matrix

  • Éxito → ficha SVC platform/edge/subdomains-dev.md (o sección en SVC-TRAEFIK-EDGE) + update del id-registry + Hindsight.
  • Decisión wildcard → ADR-0020 (attached).
  • Si el operador elige subdominios explícitos → mismo OBJ con D3bis variante B (solo cambia el tfvars).