#!/bin/sh set -eu read_secret_file() { secret_path=$1 if [ ! -r "$secret_path" ]; then echo "Не удалось прочитать обязательный PostgreSQL secret file" >&2 return 1 fi # Маркер сохраняет переводы строк внутри command substitution. secret_with_marker="$(cat "$secret_path"; printf '\001')" secret=${secret_with_marker%?} carriage_return="$(printf '\r')" newline=' ' case "$secret" in *"${carriage_return}${newline}") secret=${secret%"${carriage_return}${newline}"} ;; *"${newline}") secret=${secret%"${newline}"} ;; *"${carriage_return}") secret=${secret%"${carriage_return}"} ;; esac if [ -z "$(printf '%s' "$secret" | tr -d '[:space:]')" ]; then echo "PostgreSQL secret file содержит пустое значение" >&2 return 1 fi printf '%s' "$secret" } if [ -z "${APP_DB_USER:-}" ]; then echo "APP_DB_USER должен содержать имя роли приложения" >&2 exit 1 fi if [ "$APP_DB_USER" = "$POSTGRES_USER" ]; then echo "APP_DB_USER не должен совпадать с PostgreSQL admin role" >&2 exit 1 fi app_db_password="$(read_secret_file /run/secrets/db_password)" # Официальный entrypoint уже прочитал secret file и применил собственную # нормализацию конечных переводов строк. Сравниваем именно фактический пароль. if [ -z "$(printf '%s' "${POSTGRES_PASSWORD:-}" | tr -d '[:space:]')" ]; then echo "POSTGRES_PASSWORD должен содержать пароль admin role" >&2 exit 1 fi postgres_admin_password=$POSTGRES_PASSWORD if [ "$app_db_password" = "$postgres_admin_password" ]; then echo "Пароли PostgreSQL admin и application roles должны различаться" >&2 exit 1 fi export DZENTRA_APP_DB_PASSWORD="$app_db_password" psql \ --no-psqlrc \ --single-transaction \ --set ON_ERROR_STOP=1 \ --username "$POSTGRES_USER" \ --dbname "$POSTGRES_DB" <<'SQL' \getenv app_user APP_DB_USER \getenv app_password DZENTRA_APP_DB_PASSWORD SELECT format( 'CREATE ROLE %I LOGIN PASSWORD %L NOSUPERUSER NOCREATEDB ' 'NOCREATEROLE INHERIT NOREPLICATION NOBYPASSRLS', :'app_user', :'app_password' ) WHERE NOT EXISTS ( SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = :'app_user' ) \gexec SELECT format( 'ALTER ROLE %I WITH LOGIN PASSWORD %L NOSUPERUSER NOCREATEDB ' 'NOCREATEROLE INHERIT NOREPLICATION NOBYPASSRLS', :'app_user', :'app_password' ) \gexec SELECT format( 'ALTER DATABASE %I OWNER TO %I', current_database(), :'app_user' ) \gexec SELECT format( 'REVOKE ALL ON DATABASE %I FROM PUBLIC', current_database() ) \gexec SELECT format( 'GRANT CONNECT, TEMPORARY ON DATABASE %I TO %I', current_database(), :'app_user' ) \gexec REVOKE CREATE ON SCHEMA public FROM PUBLIC; SELECT format( 'GRANT USAGE, CREATE ON SCHEMA public TO %I', :'app_user' ) \gexec SQL unset DZENTRA_APP_DB_PASSWORD unset app_db_password unset postgres_admin_password