ADR-0009: Secrets vault harness — Infisical self-hosted in-cluster (ns vault), identidades por perfil y contrato ai-hub¶
Date: 2026-08-31
Status: Accepted (2026-08-31). Lifecycle: el ADR abrió como proposed;
el operador decidió el 2026-08-31 dejar Infisical "totalmente operativo
internamente por el cluster service endpoint, con el service provider
instalado en Kubernetes", lo que sustituye la VM dedicada por un despliegue
IN-CLUSTER (namespace vault) y trae el Operator/CRDs v1beta1 a ESTA fase.
Esta transición in-PR (front matter, status line, decisiones 1 y 8 y el
índice de decisions, actualizados atómicamente, patrón ADR-0008) registra
esa decisión del operador con su fecha; el despliegue concreto se materializa
y revisa independiente en infra PR #27 (feat/vault-infra).
Contexto¶
Hoy hay ocho ficheros plaintext bajo ops01:~/secrets/, copias manuales en
.env de perfiles, credenciales GHCR de alcance excesivo, dos credenciales
expuestas pendientes de revocación (t_b904ba3f), un acceso argocd admin
estático y ausencia de trazabilidad de lecturas. El master plan §10 ya
seleccionó Infisical self-hosted, SOPS+age únicamente para bootstrap/recovery
y el contrato estable vault.get/put/update/delete/list/exists en ai-hub. La
validación de licencia, machine identities e integración Kubernetes (§10.6,
t_7459a827) estaba en curso al redactar el handoff y es gate obligatorio
antes de producción; su veredicto se registra bajo
Estado de la validación §10.6.
Decisión¶
- Ejecutar Infisical self-hosted IN-CLUSTER, en el namespace
vaultdewetopi3(decisión del operador, 2026-08-31: Infisical totalmente operativo internamente vía el service endpoint del clúster, con el service provider instalado en Kubernetes). Esta decisión SUSTITUYE la VM dedicada fuera del clúster del borradorproposed: el datastore soportado (PostgreSQL + Redisnoevictionpersistentes) corre en el mismo clúster, con backup cifrado off-host, restauración ensayada y Universal Auth privado (sólo service interno). El trade-off de fallo correlacionado conwetopi3se acepta explícitamente y se compensa con el contrato de recovery (pg_dump + age ensayado, AC8) — la alternativa de VM dedicada queda registrada como alternativa considerada y descartada por decisión del operador con fecha 2026-08-31. - Publicar
vault.wetopi.netdetrás del edge aprobado, con TLS LE production y autenticación nativa Infisical siempre obligatoria. La ruta pública sirva SÓLO la UI humana: el API de machine identities (Universal Auth) NO es alcanzable por el hostname público — enforcement verificable en el edge (path-filter con DENY explícito del resto, infra #27). Basic Auth se evalúa sólo como defensa adicional de la UI humana; no puede sustituir la autenticación del vault ni interceptar/romper el API de machine identities. Si no puede separarse con rutas inequívocas o un hostname administrativo distinto, no se activa. - Crear una machine identity distinta por perfil Hermes activo; no se comparte identidad ni bootstrap secret entre perfiles. Política default-deny y privilegios por proyecto/environment/path. El llamador no puede elegir o suplantar otra identidad.
- ai-hub es la única interfaz consumida por agentes. Su adaptador traduce el contrato estable a la API versionada de Infisical. Los agentes no importan SDKs, endpoints ni modelos de Infisical.
- El único secreto persistente local de cada perfil es su credencial
bootstrap de machine identity, en fichero owner-only fuera de Git y fuera
de
.env; el access token derivado es corto, sólo en memoria y nunca se registra. Client ID/referencias no secretas pueden declararse en configuración. - Infisical es la autoridad runtime de valores, políticas operativas y eventos de auditoría. Git es autoridad L2 de arquitectura, contratos, referencias y policy-as-code sin valores. El registro canónico de perfiles de Hermes determina el inventario de identidades. SOPS+age sólo es autoridad durante bootstrap/recovery declarado; Kanban sólo refleja estado L1 y no contiene secretos.
- La migración no copia deuda: toda credencial expuesta, broad-scope, compartida o sin propietario se reemplaza por una de mínimo alcance, se verifica el consumidor y se revoca la anterior. No se importan credenciales expuestas como estado final.
- La materialización de Kubernetes Secrets y el Infisical Secrets Operator
suceden EN ESTA FASE (decisión del operador, 2026-08-31, que sustituye el
"objetivo posterior" del borrador
proposed): el Operator v0.11.8 con CRDs v1beta1 (InfisicalAuth+InfisicalStaticSecret; la superficieInfisicalSecretv1alpha1 está deprecated upstream y NO se usa en instalaciones nuevas) se instala junto al vault in-cluster y sincroniza secrets hacia los K8s Secrets de los workloads vía Universal Auth por el endpoint interno.
Alternativas consideradas¶
- Infisical dentro de
wetopi3: la versiónproposedde este ADR (2026-08-31 por la mañana) lo descartó por fallo correlacionado y pérdida de acceso durante recuperación del clúster, y propuso una VM dedicada. El operador reconsideró esa premisa el mismo día (chat 2026-08-31: dejar Infisical totalmente operativo internamente por el cluster service endpoint, service provider instalado en Kubernetes) y la decisión vigente es IN-CLUSTER; el trade-off de fallo correlacionado se mitiga con el contrato de recovery (decisión 1) y queda registrado aquí para trazabilidad. - SOPS+age como vault diario: descartado porque no ofrece lectura dinámica por identidad ni auditoría runtime suficiente; se conserva para bootstrap/recovery.
- API/SDK Infisical directa desde cada agente: descartado por acoplamiento, proliferación de credenciales y semánticas inconsistentes.
- Una identidad compartida para Hermes/ai-hub: descartada porque impide atribución y amplía el blast radius.
- Copiar secretos a
.env: prohibido como mecanismo normal; sólo referencias no secretas y una credencial bootstrap local por perfil. - Edge Basic Auth como control único: descartado; no expresa autorización por secreto y dificulta atribución de machine identities.
Consecuencias y compliance ADR-0003¶
El vault in-cluster y su backup pasan a ser infraestructura Tier-0; se exige
hardening (securityContexts non-root, secretos nunca en Git), monitorización,
parcheo y runbook de recuperación. El fallo correlacionado con wetopi3 es
un riesgo aceptado explícitamente (decisión 1) — la disponibilidad del vault
queda ligada a la del clúster, y el recovery ensayado es el compensatorio
obligatorio. Se añade un adaptador ai-hub y una política por identidad, pero
los agentes quedan desacoplados.
Las autoridades quedan explícitas: Infisical runtime; Git L2; registro Hermes
para perfiles; SOPS+age sólo bootstrap/recovery; auditoría append-only para
evidencia; Kanban no es fuente de verdad del diseño.
El architecture pack normativo (boundary y topología, namespaces y
referencias, contrato vault.*, matriz de identidades y permisos, bootstrap
y ciclo de credenciales, rotación, backup y recovery, migración del estado
vivo, auditoría, riesgos y diagramas) vive como pill de arquitectura en
ARCH-VAULT-SYSTEM; el ADR
registra aquí sólo la decisión y sus consecuencias.
Estado de la validación §10.6¶
El addendum de integración del handoff THINK (que registraba la validación
en curso) se sustituye por el veredicto final de la discovery
(t_7459a827, 2026-08-31): GO para Infisical self-hosted como vault del
harness, con TRES condicionales. Informe completo:
findings-infisical-selfhosted.md (adjunto a las cards t_7459a827 y
t_e2292367).
Hechos materiales verificados (con fuente oficial)¶
| # | Hecho | Fuente oficial |
|---|---|---|
| 1 | Licensing: core MIT Expat; directorio ee/ bajo Infisical Enterprise License; activación self-hosted por LICENSE_KEY (online u offline) |
https://github.com/Infisical/infisical/blob/main/LICENSE · https://github.com/Infisical/infisical/blob/main/backend/src/ee/LICENSE.md · https://infisical.com/docs/self-hosting/ee |
| 2 | Machine identities / Universal Auth completo en MIT core: clientId/secret → JWT de corta vida, TTL/renew, rotación y revocación de client secrets, expiry alerts | https://infisical.com/docs/documentation/platform/identities/machine-identities · https://infisical.com/docs/documentation/platform/identities/universal-auth |
| 3 | Audit logs en self-hosted es feature de pago (Enterprise license) | https://infisical.com/docs/documentation/platform/audit-logs |
| 4 | Audit log streams (SIEM/Splunk/Datadog) también paid EE | https://infisical.com/docs/documentation/platform/audit-log-streams/audit-log-streams |
| 5 | Point-in-Time Recovery (rollback de folder/env a snapshot) es paid EE | https://infisical.com/docs/documentation/platform/pit-recovery |
| 6 | Trusted IPs sobre client secret / access token de identidades es paid EE | https://infisical.com/docs/documentation/platform/identities/universal-auth |
| 7 | Contrato vault.* mapea 1:1 a la API v4 (/api/v4/secrets*), verificada contra el OpenAPI oficial |
https://app.infisical.com/api/docs/json |
| 8 | Secrets Operator K8s vivo (v0.11.8; CRDs v1beta1 recomendados; InfisicalSecret v1alpha1 deprecated) |
https://github.com/Infisical/kubernetes-operator/releases · https://infisical.com/docs/integrations/platforms/kubernetes/infisical-static-secret-crd |
| 9 | Datastore: PostgreSQL es la única BD soportada y Redis es dependencia dura y persistente (noeviction, AOF/RDB) |
https://infisical.com/docs/self-hosting/configuration/requirements.md |
| 10 | Recovery SOPS+age viable vía pg_dump + age; no existe export cifrado nativo programático |
https://infisical.com/docs/self-hosting/configuration/requirements.md · https://infisical.com/docs/self-hosting/guides/rotating-the-encryption-key |
| 11 | Secret versioning base (MIT) con lectura por ?version=N |
https://infisical.com/docs/documentation/platform/secret-versioning |
Decisión explícita por condicional¶
- Audit logs (EE, paid) — DECISIÓN: NO-GO sin licencia EE aceptada; sin
control compensatorio admisible. El audit append-only sin valores es
requisito normativo (AC7) y la alternativa a nivel ingress/infraestructura
no cubre actor identity, decisión allow/deny ni retención 365 días.
Por tanto, la compra de la licencia Enterprise (
LICENSE_KEY) que habilita el audit es condición de cierre de S1. Si el operador no la acepta, S1 es NO-GO y el objetivo se detiene antes de S3. Fuente: https://infisical.com/docs/documentation/platform/audit-logs - PIT recovery (EE, paid) — DECISIÓN: control compensatorio; NO compra.
El PIT de Infisical (rollback por folder/env a snapshot) no es requisito
del contrato: la ruta de recovery normativa es backup/restore SOPS+age
vía
pg_dump+ age con restore drill aislado (AC8), y la lectura de versiones históricas usa el versioning base MIT. PIT queda como mejora opcional futura. Reapertura: si en S7 el restore drill demostrara que la ventana de recuperación exigida no es alcanzable sin PIT, vuelve aquí la decisión — compra de licencia EE o NO-GO, nunca promesa abierta. Fuente: https://infisical.com/docs/documentation/platform/pit-recovery - Trusted IPs (EE, paid) — DECISIÓN: control compensatorio de red; NO
compra. La restricción de IP nativa de Universal Auth no se compra: el
binding de origen se compensa a nivel de red. Con la decisión de
despliegue in-cluster (2026-08-31) la forma del compensatorio es el
AISLAMIENTO DE RED DEL SERVICE: Universal Auth sólo es alcanzable por el
service interno
vault.vault.svc.cluster.local; la ruta públicavault.wetopi.netsirve exclusivamente la UI humana con DENY explícito de los endpoints de API (infra #27), y los StorageClasses PVC no exponen nada a Internet.
NOTA (2026-08-31) — RESUELTO por la decisión del operador: la exposición de Universal Auth quedó decidida como private-network-only in-cluster ( Universal Auth sólo por
vault.vault.svc.cluster.local, ruta pública = sólo UI humana con DENY de API; chat del operador 2026-08-31 e infra #27). Este era el OPEN "a resolverse en S0 antes del primer identity bootstrap"; la decisión de arriba y el enforcement de infra #27 lo cierran. La eficacia del control (login público rechazado / login interno autorizado) se demuestra antes del primer bootstrap.
Consecuencia normativa para S1: la etapa exige firma conjunta approver+operador que fije versión/edición/componentes y acepte explícitamente licencia/coste (licencia base + audit EE, según las decisiones de arriba). No se puede degradar AC7 para usar una edición gratuita. Si el condicional audit no queda cubierto por una licencia aceptada, el resultado es NO-GO y se detiene antes de S3.
OPEN explícitos¶
- Requisitos exactos de edición/licencia, audit log, Universal Auth, CRUD
API, datastore, export y operator: resueltos por el veredicto §10.6 de
t_7459a827(arriba); pendiente la aceptación explícita de licencia/coste por el operador (gate S1). - Inventario exacto de perfiles Hermes activos y scopes; se deriva del registro canónico, no de esta conversación.
- Decisión operador: activar Basic Auth adicional en UI sólo después de prueba de no interferencia y valorar hostname/ruta administrativa separada.
- Retención 365 días y periodicidad de restore drill: confirmar coste/operación en S1/S2.
Related documents¶
- OBJ-VAULT-001 — el Objective con ACs, dashboard S0-S10, gates y promotion matrix.
- ADR-0003 — el patrón de fuentes de verdad separadas y explícitas por ciclo de vida (compliance registrado en Consecuencias).