feat(deploy): db-init one-shot service — paste-and-go bootstrap for the runtime role
The role split previously required a one-time manual script run on existing volumes (initdb.d only fires on fresh ones). This folds the bootstrap into the compose file the way split-account deployments standardly do it: a one-shot db-init service runs z_rls_role.sh (idempotent, network mode via PGHOST=db + PGPASSWORD from DBPASS) on every 'compose up', and the app gates on db-init: condition: service_completed_successfully. - Zero manual steps for fresh AND existing deployments: update compose, add DBSRVPASS to .env, 'compose pull && up -d'. - Security posture improves: the superuser password is now held ONLY by the init service — the app container connects exclusively as the non-superuser runtime role. - z_rls_role.sh gains dual connection modes (local socket for docker exec, network for the init service) with the DBPASS requirement enforced only in network mode. - Verified on the dev stack: init runs and exits clean, app gates on it and comes up healthy, second 'up' re-converges idempotently, invariant test passes through the new dependency chain. The initdb.d mount stays as-is (harmless double coverage on fresh volumes; both paths are idempotent).
This commit is contained in:
1 parent
1457dc7289
commit
313268a7ae
3 files changed
+41
-13
No files matched your search
@@ -9,15 +9,11 @@
|
||||
# remains the cluster/database bootstrap account; the app never connects
|
||||
# as it.
|
||||
#
|
||||
# Runs AUTOMATICALLY on fresh volumes: docker-entrypoint-initdb.d executes
|
||||
# initdb.d entries in alphabetical order — "z_rls_role.sh" sorts AFTER
|
||||
# "schema.sql" (digits/uppercase sort before lowercase 's'), so the tables
|
||||
# exist before ownership transfers. It runs as the postgres superuser with
|
||||
# the db container's env (DBSRVPASS comes from .env via compose env_file).
|
||||
#
|
||||
# EXISTING volumes (initdb.d never re-runs): apply manually ONCE, as the
|
||||
# superuser, BEFORE switching the app's DATABASE_USER:
|
||||
# docker exec -i bookhoard_db bash -s < database/schema/z_rls_role.sh
|
||||
# Runs on EVERY `docker compose up` via the one-shot `db-init` service
|
||||
# (idempotent — the app's depends_on gates on its success), AND on
|
||||
# fresh volumes via docker-entrypoint-initdb.d ('z' sorts after
|
||||
# 'schema.sql'). Manual equivalent for existing volumes:
|
||||
# docker exec -i -e DBSRVPASS=... bookhoard_db bash -s < database/schema/z_rls_role.sh
|
||||
#
|
||||
# IDEMPOTENT: safe to re-run (role creation is guarded; ownership ALTERs
|
||||
# and the password set are idempotent).
|
||||
@@ -30,7 +26,17 @@ set -euo pipefail
|
||||
: "${POSTGRES_USER:?POSTGRES_USER must be set (the image sets it)}"
|
||||
: "${POSTGRES_DB:?POSTGRES_DB must be set (the image sets it)}"
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" \
|
||||
# Connection mode: local socket (docker exec into the db container) or
|
||||
# network (the db-init compose service, which sets PGHOST=db and needs
|
||||
# the bootstrap password for scram auth).
|
||||
PSQL_OPTS=(-v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB")
|
||||
if [ -n "${PGHOST:-}" ]; then
|
||||
: "${DBPASS:?DBPASS is required when connecting over the network (PGHOST set)}"
|
||||
PSQL_OPTS+=(-h "$PGHOST")
|
||||
export PGPASSWORD="$DBPASS"
|
||||
fi
|
||||
|
||||
psql "${PSQL_OPTS[@]}" \
|
||||
-v role_pass="$DBSRVPASS" <<'EOSQL'
|
||||
\echo '== RLS role bootstrap: creating/refreshing bookhoard_srv =='
|
||||
|
||||
|
||||
Reference in new issue
Block a user