From c3863492711f954ea37a7e9a8348df726b1f3ec2 Mon Sep 17 00:00:00 2001 From: Patrik Lundin Date: Thu, 14 Nov 2024 13:01:06 +0100 Subject: [PATCH] cdn db init: secure schema usage Trying to run goose for creating database contents failed: ``` 2024/11/14 11:59:13 goose run: failed to ensure DB version: ERROR: permission denied for schema public (SQLSTATE 42501) ``` This seems to be because PostgreSQL 15 removed the default CREATE permission in the public schema for users other than the database owner. Instead we create a user-specific schema owned by that same user and leave the public schema unused. --- .../puppet/modules/cdn/files/db/init-cdn-db.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/global/overlay/etc/puppet/modules/cdn/files/db/init-cdn-db.sh b/global/overlay/etc/puppet/modules/cdn/files/db/init-cdn-db.sh index 3584c07..4e7b23a 100644 --- a/global/overlay/etc/puppet/modules/cdn/files/db/init-cdn-db.sh +++ b/global/overlay/etc/puppet/modules/cdn/files/db/init-cdn-db.sh @@ -1,10 +1,25 @@ #!/bin/bash set -e +# shellcheck source=/dev/null . /conf/init-cdn-db.conf +# Create database named after user, then create a schema named the same as the +# user which is also owned by that user. Because search_path (SHOW +# search_path;) starts with "$user" by default this means any tables will be +# created in that user-specific SCHEMA by default instead of falling back to +# "public". This follows the "secure schema usage pattern" summarized as +# "Constrain ordinary users to user-private schemas" from +# https://www.postgresql.org/docs/current/ddl-schemas.html#DDL-SCHEMAS-PATTERNS +# +# "In PostgreSQL 15 and later, the default configuration supports this usage +# pattern. In prior versions, or when using a database that has been upgraded +# from a prior version, you will need to remove the public CREATE privilege +# from the public schema" psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL - CREATE USER cdn WITH PASSWORD '$cdn_password'; + CREATE USER cdn WITH PASSWORD '${cdn_password:?}'; CREATE DATABASE cdn; GRANT ALL PRIVILEGES ON DATABASE cdn TO cdn; + \c cdn; + CREATE SCHEMA cdn AUTHORIZATION cdn; EOSQL