-- 10_pgbouncer_auth.sql -- pgbouncer SCRAM passthrough auth: dedicated role + user_lookup() function. -- Runbook: 260507_pgbouncer_deployment.md -- -- Idempotent. Re-applying is a no-op: -- * Role created only when missing (placeholder password, replaced on every -- container startup by run_migrations.py:sync_role_passwords from -- PGBOUNCER_AUTH_PASSWORD). -- * Function uses CREATE OR REPLACE. -- * GRANT/REVOKE are safe to re-run. DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'pgbouncer') THEN CREATE ROLE pgbouncer LOGIN PASSWORD 'SET_PASSWORD_IN_ENV'; END IF; END $$; CREATE OR REPLACE FUNCTION public.user_lookup(in_user text, OUT uname text, OUT phash text) RETURNS record AS $$ BEGIN SELECT usename, passwd FROM pg_catalog.pg_shadow WHERE usename = in_user INTO uname, phash; RETURN; END; $$ LANGUAGE plpgsql SECURITY DEFINER; REVOKE ALL ON FUNCTION public.user_lookup(text) FROM public; GRANT EXECUTE ON FUNCTION public.user_lookup(text) TO pgbouncer;