diff --git a/README.md b/README.md index 67fa400..101f6c5 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ For a private repo you need an auth strategy: | 004 | purge-haveged | reclaim ~8MB RAM (package removed) | | 005 | mount-pgdata | /dev/sdb (20G) -> /var/lib/postgresql, fstab | | 006 | install-postgres | PG 18 via PGDG repo, cluster on the disk | +| 007 | postgres-admin-role | iwanhae OS user -> PG superuser (peer auth) | ## Roadmap diff --git a/migrations/007-postgres-admin-role.sh b/migrations/007-postgres-admin-role.sh new file mode 100644 index 0000000..34a0e75 --- /dev/null +++ b/migrations/007-postgres-admin-role.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# 007-postgres-admin-role - Make the iwanhae Linux user a PostgreSQL +# superuser so it can administer the cluster via peer auth (psql with no +# password, like the postgres OS user). Requires 006 (cluster running). +# up: CREATE ROLE iwanhae LOGIN SUPERUSER (idempotent; re-run promotes) +# down: DROP ROLE iwanhae (with hint if it owns objects in some database) +set -euo pipefail + +ROLE=iwanhae + +role_exists() { + runuser -u postgres -- psql -v ON_ERROR_STOP=1 -tAc \ + "SELECT 1 FROM pg_roles WHERE rolname='$ROLE'" | grep -q 1 +} + +case "${1:-}" in + up) + if role_exists; then + runuser -u postgres -- psql -v ON_ERROR_STOP=1 -qc \ + "ALTER ROLE $ROLE WITH LOGIN SUPERUSER" + echo " role $ROLE already existed - promoted to LOGIN SUPERUSER" + else + runuser -u postgres -- psql -v ON_ERROR_STOP=1 -qc \ + "CREATE ROLE $ROLE WITH LOGIN SUPERUSER" + echo " role $ROLE created: LOGIN SUPERUSER" + fi + # end-to-end proof: connect over the unix socket as the OS user (peer) + check=$(runuser -u "$ROLE" -- psql -d postgres -tAc \ + "SELECT current_user || ' (superuser=' || rolsuper || ')' FROM pg_roles WHERE rolname = current_user") + echo " peer-auth check: $check" + ;; + down) + if role_exists; then + if runuser -u postgres -- psql -v ON_ERROR_STOP=1 -qc "DROP ROLE $ROLE"; then + echo " role $ROLE dropped" + else + echo "cannot drop $ROLE - it owns objects. In EVERY database it has objects run:" >&2 + echo " runuser -u postgres -- psql -d -c 'DROP OWNED BY $ROLE;'" >&2 + exit 1 + fi + else + echo " role $ROLE does not exist - nothing to do" + fi + ;; +esac