diff --git a/services/postgres/README.md b/services/postgres/README.md new file mode 100644 index 00000000000..014aeeddb5b --- /dev/null +++ b/services/postgres/README.md @@ -0,0 +1,5 @@ +## Postgres configuration + +Read and follow instructons in `./scripts/init.sql` script. This needs to be executed once in every postgres database we run (both self-hosted and RDS) + +Create role and users scripts need to be run on demand (e.g. in case we need a readonly user). Generate scripts using repo config values, read and follow instructions inside. This needs to be executed once. diff --git a/services/postgres/scripts/.gitignore b/services/postgres/scripts/.gitignore index 9072771094f..dd4d95097db 100644 --- a/services/postgres/scripts/.gitignore +++ b/services/postgres/scripts/.gitignore @@ -1,3 +1,4 @@ * !.gitignore -!*.template.* +!*.template +!init.sql diff --git a/services/postgres/scripts/create-readonly-role.sql.template b/services/postgres/scripts/create-readonly-role.sql.template new file mode 100644 index 00000000000..5e12dc94822 --- /dev/null +++ b/services/postgres/scripts/create-readonly-role.sql.template @@ -0,0 +1,32 @@ +/* +Create read-only role for ${POSTGRES_DB} database. + +This role can be used to give read-only access to the ${POSTGRES_DB} database +to users. + +Permission grants inspired from: https://stackoverflow.com/questions/760210/how-do-you-create-a-read-only-user-in-postgresql/762649#762649 +IMPORTANT: must be executed while connected to the ${POSTGRES_DB} database + as it refers to public schema in that database. +*/ + +CREATE ROLE ${POSTGRES_DB}_readonly NOLOGIN; + +GRANT CONNECT ON DATABASE ${POSTGRES_DB} TO ${POSTGRES_DB}_readonly; + +-- https://stackoverflow.com/questions/17338621/what-does-grant-usage-on-schema-do-exactly +GRANT USAGE ON SCHEMA public TO ${POSTGRES_DB}_readonly; + +-- Grant permissions for (existing) tables, sequences, functions +GRANT SELECT ON ALL TABLES IN SCHEMA public TO ${POSTGRES_DB}_readonly; +GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO ${POSTGRES_DB}_readonly; +GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO ${POSTGRES_DB}_readonly; + +-- Grant permissions for (future) tables, sequences, functions +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT SELECT ON TABLES TO ${POSTGRES_DB}_readonly; +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT SELECT ON SEQUENCES TO ${POSTGRES_DB}_readonly; +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT EXECUTE ON FUNCTIONS TO ${POSTGRES_DB}_readonly; + +SELECT * FROM pg_roles WHERE rolname NOT LIKE 'pg_%'; diff --git a/services/postgres/scripts/create-readonly-user.sql.template b/services/postgres/scripts/create-readonly-user.sql.template index 28b14f53d4f..8f3dbd19d8f 100644 --- a/services/postgres/scripts/create-readonly-user.sql.template +++ b/services/postgres/scripts/create-readonly-user.sql.template @@ -1,22 +1,6 @@ --- SQL script to create a read-only user and grant privileges - - ---Create the read-only user with a password CREATE USER ${POSTGRES_READONLY_USER} WITH PASSWORD '${POSTGRES_READONLY_PASSWORD}'; ---Grant CONNECT privilege to the database (e.g., 'foo' is the database name) -GRANT CONNECT ON DATABASE ${POSTGRES_DB} TO ${POSTGRES_READONLY_USER}; - ---Grant USAGE privilege on the **public** schema -GRANT USAGE ON SCHEMA public TO ${POSTGRES_READONLY_USER}; - ---Grant SELECT privilege on all existing tables and sequencies in the **public** schema -GRANT SELECT ON ALL TABLES IN SCHEMA public TO ${POSTGRES_READONLY_USER}; -GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO ${POSTGRES_READONLY_USER}; - ---Ensure that future tables created in the public schema and sequencies will have SELECT privilege for the read-only user -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO ${POSTGRES_READONLY_USER}; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO ${POSTGRES_READONLY_USER}; +-- Grant read-only role (privilages) to the user +GRANT ${POSTGRES_DB}_readonly TO ${POSTGRES_READONLY_USER}; --- Listing all users -SELECT * FROM pg_roles; +SELECT * FROM pg_roles WHERE rolname NOT LIKE 'pg_%'; diff --git a/services/postgres/scripts/init.sql b/services/postgres/scripts/init.sql new file mode 100644 index 00000000000..532499ac6a7 --- /dev/null +++ b/services/postgres/scripts/init.sql @@ -0,0 +1,13 @@ +/* +Do not allow users to create new objects in the public schema + +Must be executed against every created database (e.g. for simcore, for metabase, ...) +(as long as we use Postgres 14 or earlier) + +Sources: +* https://wiki.postgresql.org/wiki/A_Guide_to_CVE-2018-1058:_Protect_Your_Search_Path +* https://www.reddit.com/r/PostgreSQL/comments/1hvxw0s/understanding_the_public_schema_in_postgresql/ +*/ + +-- As a superuser, run the following command in all of your databases +REVOKE CREATE ON SCHEMA public FROM PUBLIC; diff --git a/services/postgres/scripts/remove-readonly-role.sql.template b/services/postgres/scripts/remove-readonly-role.sql.template new file mode 100644 index 00000000000..1b8b03c5a3a --- /dev/null +++ b/services/postgres/scripts/remove-readonly-role.sql.template @@ -0,0 +1,17 @@ +-- Make sure this role is not used by any user or else this script will fail + +REVOKE CONNECT ON DATABASE ${POSTGRES_DB} FROM ${POSTGRES_DB}_readonly; + +REVOKE ALL PRIVILEGES ON SCHEMA public FROM ${POSTGRES_DB}_readonly; + +REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM ${POSTGRES_DB}_readonly; +REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM ${POSTGRES_DB}_readonly; +REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public FROM ${POSTGRES_DB}_readonly; + +ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON TABLES FROM ${POSTGRES_DB}_readonly; +ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON SEQUENCES FROM ${POSTGRES_DB}_readonly; +ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM ${POSTGRES_DB}_readonly; + +DROP ROLE IF EXISTS ${POSTGRES_DB}_readonly; + +SELECT * FROM pg_roles WHERE rolname NOT LIKE 'pg_%'; diff --git a/services/postgres/scripts/remove-readonly-user.sql.template b/services/postgres/scripts/remove-readonly-user.sql.template index 5a1435ed978..693cefd80a8 100644 --- a/services/postgres/scripts/remove-readonly-user.sql.template +++ b/services/postgres/scripts/remove-readonly-user.sql.template @@ -1,16 +1,6 @@ --- Revoke all privileges the user has on the public schema -REVOKE ALL PRIVILEGES ON SCHEMA public FROM ${POSTGRES_READONLY_USER}; +-- Revoke readonly role from user +REVOKE ${POSTGRES_DB}_readonly FROM ${POSTGRES_READONLY_USER}; --- Revoke all privileges the user has on tables and sequences in the public schema -REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM ${POSTGRES_READONLY_USER}; -REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM ${POSTGRES_READONLY_USER}; +DROP USER IF EXISTS ${POSTGRES_READONLY_USER}; --- Revoke any future privileges set via ALTER DEFAULT PRIVILEGES -ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON TABLES FROM ${POSTGRES_READONLY_USER}; -ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON SEQUENCES FROM ${POSTGRES_READONLY_USER}; - --- Drop the user -DROP USER ${POSTGRES_READONLY_USER}; - --- Listing all users -SELECT * FROM pg_roles; +SELECT * FROM pg_roles WHERE rolname NOT LIKE 'pg_%';