feat(chart): pg password via ExternalSecret/OpenBao (A-Chunk 1)

Per-instance Postgres password sourced from OpenBao via External
Secrets Operator. Dual-mode for the migration window:

  - postgres.passwordVaultPath unset → legacy postgres-secret.yaml
    renders with .Values.postgres.password (helm lookup + random
    fallback, bit-exact existing behaviour for live instances).
  - postgres.passwordVaultPath set → postgres-password-externalsecret.yaml
    renders an ExternalSecret that produces the same <release>-pg
    Secret (POSTGRES_USER/PASSWORD/DB) from OpenBao path
    `tenants/<tenant.id>/instances/<instance.code>/pg`.

Exactly one of the two templates ships per instance (mutually
exclusive `if`s on .Values.postgres.passwordVaultPath). The Postgres
StatefulSet envFroms <release>-pg unchanged.

OpenBao policy already grants the per-cluster ESO read on
`v3/data/tenants/<tenantID>/*` (buildEsoPolicy in tower's
openbao_auth_setup.go) — the new instances/<code>/pg subpath is
covered. No policy change required.

A `required` directive on the ExternalSecret asserts tenant.id is
present when passwordVaultPath is set — fails loud at helm template
time if Tower forgot to populate it.

deletionPolicy: Retain on the ExternalSecret. Postgres PGDATA on
disk hashes to the password in the Secret; an accidental ESO
removal must not cascade into the Secret disappearing.

Chart 0.1.6 → 0.1.7. Verified locally: helm template both modes,
helm lint clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
OdooSky v3
2026-05-12 12:56:54 +03:00
parent d7c1b2f895
commit 96071aec8e
4 changed files with 95 additions and 1 deletions

View File

@@ -1,3 +1,11 @@
{{- if not .Values.postgres.passwordVaultPath }}
# Legacy postgres-secret.yaml — chart-rendered Secret carrying
# POSTGRES_USER/PASSWORD/DB for the postgres StatefulSet. Used when
# `.Values.postgres.passwordVaultPath` is empty (the pre-ESO path).
# When that field is set, postgres-password-externalsecret.yaml
# renders an ExternalSecret producing the same Secret name + shape
# from OpenBao instead, and this template skips. Exactly one of the
# two ships per instance.
apiVersion: v1
kind: Secret
metadata:
@@ -9,3 +17,4 @@ stringData:
POSTGRES_USER: {{ .Values.postgres.user | quote }}
POSTGRES_PASSWORD: {{ include "instance.pgPassword" . | quote }}
POSTGRES_DB: {{ .Values.postgres.database | quote }}
{{- end }}