audit-core/deploy/externalsecrets.yaml
tegwick 7636e83dcc
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Deliver database credentials as a rotatable mounted directory
AUDIT-WP-0005-T02 (progress). rapp-postgres has landed platform-pg with the
audit_core database, roles, and dynamic credential provisioning, so
audit-core's side is now built against it.

In-cluster delivery is a mounted directory rather than environment variables.
A dynamic lease rotates while the pod runs and an env var is fixed at process
start, so env delivery would force a restart on every rotation - and every
restart is a delivery gap, which is what this task forbids.
CredentialDirectory is re-read on every connection attempt via psycopg_pool's
callable kwargs, so a rotated lease takes effect with no restart. Rotation is
logged by password fingerprint, never by value.

deploy/externalsecrets.yaml follows the ClusterSecretStore -> ExternalSecret ->
Secret pattern already used by activity-core and rapp-qonto, at a 15m refresh
rather than the default 1h since the interval bounds how long a revoked lease
can stay mounted. All manifests validated --dry-run=server --validate=strict.

The rotation test was initially vacuous: it passed against a deliberately naive
implementation that read credentials once at startup, because pooled sessions
stay authenticated after a password change and nothing forced a reconnect. It
now terminates the role's sessions first, and is verified to fail against the
naive implementation and pass against the real one. Tests 82 -> 84.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 01:36:28 +02:00

75 lines
2.6 KiB
YAML

# Credential delivery for audit-core (AUDIT-WP-0005-T02).
#
# Follows the ClusterSecretStore -> ExternalSecret -> Secret pattern already in
# use by activity-core and rapp-qonto. audit-core never holds a credential in
# its own configuration; it reads whatever is currently mounted.
#
# PREREQUISITE (rapp-postgres / railiance-platform, not this repo):
# - a ClusterSecretStore named openbao-audit-core, scoped to this namespace
# - the OpenBao database role rapp-postgres/audit-core-runtime issuing leases
# against the audit_core_app group role
# Apply order: ClusterSecretStore, then this, then the Deployment.
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: audit-core-database
namespace: audit-core
spec:
# Shorter than the platform default of 1h: these are dynamic leases, and the
# refresh interval bounds how long a revoked lease can remain mounted.
refreshInterval: 15m
secretStoreRef:
kind: ClusterSecretStore
name: openbao-audit-core
target:
name: audit-core-database
creationPolicy: Owner
deletionPolicy: Retain
template:
engineVersion: v2
# One value per file. The pod mounts this Secret as a directory and
# audit-core re-reads it on every connection attempt, so a rotated lease
# takes effect without a restart and without a delivery gap.
data:
username: "{{ .username }}"
password: "{{ .password }}"
host: platform-pg-rw.databases.svc.cluster.local
port: "5432"
dbname: audit_core
data:
- secretKey: username
remoteRef:
key: platform/workloads/audit-core/database/audit-core-runtime
property: username
- secretKey: password
remoteRef:
key: platform/workloads/audit-core/database/audit-core-runtime
property: password
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: audit-core-senders
namespace: audit-core
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: openbao-audit-core
target:
name: audit-core-senders
creationPolicy: Owner
deletionPolicy: Retain
data:
# The sender registry: which credential may write for which tenant and
# source, and each sender's secret_policy. Held in OpenBao rather than the
# manifest because it contains bearer tokens.
#
# Rotation is overlap-first: add the replacement to a sender's `tokens`
# list, move the sender, then drop the predecessor. Both are valid in
# between, so there is no delivery gap.
- secretKey: senders.json
remoteRef:
key: platform/workloads/audit-core/senders
property: senders.json