Vault — Infisical self-hosted (ns vault)¶
What is it?¶
Infisical is the platform's secrets manager for humans and for agent
profiles (machine identities via Universal Auth). ADR-0009 (accepted
2026-08-31) fixes the shape: self-hosted in cluster wetopi3, namespace
vault, with persistent PostgreSQL and Redis datastores in the same
cluster, the Infisical → Kubernetes Operator for Secret sync, Universal Auth
restricted to the private network, and SOPS+age demoted to bootstrap/recovery
only. The operator's decision explicitly replaced the dedicated-VM variant
with the in-cluster deployment.
How is it mounted?¶
All objects Git-owned under kubernetes/vault/ (images digest-pinned):
- Deployment
vault—infisical/infisical:v0.164.1@sha256:d3ff9f82…(multi-arch index digest), non-root uid 1001, replicas 1,Recreatestrategy, readiness/liveness on:8080/api/status. A ConfigMapvault-entrypointwrapper buildsDB_CONNECTION_URIat container start from Secret env (URL-encoded, never a YAML literal). - Datastores:
postgres:17.6-alpine3.22(digest-pinned, non-root uid 70) - PVC
vault-postgres-data5Gi;redis:7.4-alpine(digest-pinned,noeviction + appendonly yes, uid 999) + PVCvault-redis-data1Gi. Both on StorageClassceph-rbd→ depends on Ceph CSI (below). - Services:
vault(FULL API — in-cluster only, NO edge route) andvault-ui(edge UI backend). - Edge: HTTPRoute
vault(nsvault) → Gatewaywetopi-edgehttps listener; Certificatevault-tls(LE PROD DNS-01, kube-system). - Secrets (references, never values — operator-provisioned on the
cluster, excluded from Argo sync):
vault-infra-credentials(ENCRYPTION_KEY, AUTH_SECRET) andvault-postgres-credentials(POSTGRES_USER, POSTGRES_PASSWORD); shapes:secret.infra.example.yaml,secret.postgres.example.yaml. - Operator (separate lifecycle):
infisical/kubernetes-operator:v0.11.8(digest-pinned) in namespaceinfisical-operator-system(kubernetes/infisical-operator/); anchoring its Argo Application is a future reviewed change. CRDs are v1beta1 (Secrets Operator v1beta1).
Diagram¶
flowchart TD
AGENTS["agents / profiles (machine identities)"]
HUMANS["operators (browser, login+TOTP)"]
subgraph CL["cluster wetopi3"]
subgraph NSV["namespace vault"]
APP["Deployment vault — Infisical v0.164.1"]
PG["PostgreSQL 17.6 — PVC 5Gi"]
RD["Redis 7.4 noeviction — PVC 1Gi"]
SVAULT["Service vault (FULL API, in-cluster only)"]
SUI["Service vault-ui (UI edge backend)"]
end
OP["Infisical Operator v0.11.8 (ns infisical-operator-system)"]
GW["Gateway wetopi-edge (kube-system) + cert vault-tls"]
SC["StorageClass ceph-rbd (Ceph CSI)"]
end
CEPH["Ceph cluster 192.168.96.0/20 (VLAN 2)"]
AGENTS -->|"http://vault.vault.svc.cluster.local (NEVER the edge)"| SVAULT
HUMANS -->|"https://vault.wetopi.net"| GW --> SUI
SVAULT --> APP
SUI --> APP
APP --> PG
APP --> RD
PG --> SC
RD --> SC
SC --> CEPH
OP -->|"pulls from internal endpoint"| SVAULT
How is it deployed?¶
GitOps: the Argo CD Application vault (anchored in the root path at
kubernetes/platform/vault.yaml) syncs kubernetes/vault/ with an
include-only filter ({namespace.yaml,postgres.yaml,redis.yaml,infisical.yaml,certificate-vault.yaml,httproute-vault.yaml}) and prune + selfHeal —
the two operator Secrets are excluded on purpose and must exist before
the first sync (runbook: kubernetes/vault/README.md §provisioning —
APPLY card t_89a254ce). TLS: Certificate vault-tls must be Ready
BEFORE the Gateway certificateRefs edit is applied (fail-safe order in
certificate-vault.yaml header). The Infisical Operator directory has its
own lifecycle (not yet anchored to the root app).
Dependencies¶
Depends on: Ceph CSI / StorageClass ceph-rbd for both PVCs
(SVC-CEPH-CSI) — if CSI is not live, the datastores cannot
bind; edge Gateway wetopi-edge + the nftables 443→8443 redirect
(SVC-TRAEFIK-EDGE); cert-manager for vault-tls
(SVC-CERT-MANAGER); DNS A records vault.wetopi.net →
edge IPs (tofu-owned, tfvars); operator Secrets vault-infra-credentials
+ vault-postgres-credentials (APPLY S0–S2, card t_89a254ce); RKE2
etcd encryption at rest is the at-rest story (etcd keys on ops01).
Depended on by: every machine identity (agent profiles) — the ai-hub
vault.* contract (vault.get/put/update/delete/list/exists) resolves
against http://vault.vault.svc.cluster.local:80; long-term the ceph-csi
csi-rbd-secret and other bootstrap secrets migrate from ops01 files into
the Vault (ADR-0009).
Operation¶
- Access (human):
https://vault.wetopi.net— native Infisical login - password + TOTP. No basic-auth middleware (deliberate — ADR-0009 decision 2; it would break interactive flows).
- Access (machine):
http://vault.vault.svc.cluster.local:80only — the public route carries DENY rules (D1–D6: universal-auth login, identity,/api/v1|v2|v3|v4secret surfaces all point at the nonexistentvault-api-denyService — fail-closed 5xx by Gateway API spec). The proof contract (public 5xx / internal 200 drill) is inkubernetes/vault/README.md§5 and runs on the ops card after apply. - Health:
kubectl -n vault get pods(vault/postgres/redis Ready),GET http://vault.vault.svc.cluster.local/api/statusfrom inside the cluster; edge probe:vault-tlsReady + https listener ResolvedRefs. - Backup/recovery: ADR-0009 AC8 —
pg_dump+ age-encrypted off-host backup, restore REHEARSED before the service is considered production (recovery contract compensates the accepted correlated-failure trade-off of in-cluster datastores).
Estado honesto (live, 2026-08-31 20:14Z)¶
LIVE — vault.wetopi.net serving HTTPS 200 with LE cert. End-to-end
verify after the operator's tofu DNS apply (vault.wetopi.net →
79.137.114.193/.194): Web UI 200 via both edge IPs, certificate
vault-tls (Let's Encrypt, valid 2026-08-31→2026-11-29), pods 3/3
Running (infisical + postgres + redis on ceph-rbd PVCs), /api/status
Ok with Redis configured. Two lead-direct hotfixes landed in Git during
the apply: commit 3a87ee94 (entrypoint ConfigMap defaultMode: 0755 —
runAsUser 1001 exec permission, crashloop fix) and 7e0b3a0b (infisical
memory limit 1Gi→2Gi after an OOMKill at 19:59Z, V8 heap 2.3GB).
The deny rules D1–D3 (machine-API paths → nonexistent Service
vault-api-deny) are fail-closed BY SPEC — verified: /api/v1/secrets
returns 500 from the public edge; the Argo Degraded on the app is the
documented false positive of this mechanism (ResolvedRefs=False is the
deny working, not a fault). PENDING: operator admin bootstrap + TOTP QR
(human step).
Relay links (enlaces de relevo)¶
- Repo: platform-infisical — infisical-server · infisical-operator
- Manifests (GitHub): kubernetes/vault, kubernetes/infisical-operator
- Vault (https://vault.wetopi.net → project
wetopi-harness): this is the service that hosts the rest of the platform's secrets — machine identities and secret paths live under projectwetopi-harness(e.g. the drill identitydrill-probe-<date>in the README proof). Secret values are never in this repo or the docs; reference paths only (DocOps §8). - Related docs: ADR-0009 (accepted — the decision this ficha documents), OBJ-VAULT-001 (objective + execution ledger), vault-system spec, services index.