redshift

create user

CREATE USER "example_user" WITH PASSWORD 'mysecretpassword';

create readonly group and add user

CREATE GROUP "example_group_ro";
GRANT USAGE ON SCHEMA "example_schema" TO GROUP "example_group_ro";
ALTER DEFAULT PRIVILEGES IN SCHEMA "example_schema" GRANT SELECT ON TABLES TO GROUP "example_group_ro";
GRANT SELECT ON ALL TABLES IN SCHEMA "example_schema" TO GROUP "example_group_ro";
ALTER GROUP "example_group_ro" ADD USER "my_user"

locate schemas without readonly group

SELECT
	n.nspname
FROM
	pg_namespace AS n
WHERE
	n.nspname NOT IN ( 'pg_internal', 'pg_toast', 'pg_catalog', 'admin' )
	AND n.nspname NOT LIKE 'pg_temp_%'
	AND CONCAT (n.nspname, '_ro') NOT IN (SELECT pg_group.groname FROM pg_group)
ORDER BY
	n.nspname ASC;

create readonly groups for each schema

SCHEMAS=(
	schema1
	schema2
)
for SCHEMA_NAME in ${SCHEMAS[@]}; do
	GROUP_NAME="${SCHEMA_NAME}_ro"
	echo "CREATE GROUP ${GROUP_NAME};"
	echo "GRANT USAGE ON SCHEMA ${SCHEMA_NAME} TO GROUP ${GROUP_NAME};"
	echo "ALTER DEFAULT PRIVILEGES IN SCHEMA ${SCHEMA_NAME} GRANT SELECT ON TABLES TO GROUP ${GROUP_NAME};"
	echo "GRANT SELECT ON ALL TABLES IN SCHEMA ${SCHEMA_NAME} TO GROUP ${GROUP_NAME};"
done

user groups

SELECT
	u.usename AS "rolname",
	u.usesuper AS "rolsuper",
	u.usecreatedb AS "rolcreatedb",
	u.valuntil AS "rolvaliduntil",
    g.groname A "groname"
FROM
	pg_catalog.pg_user AS u
INNER JOIN
    pg_catalog.pg_group AS g ON u.usesysid = ANY(g.grolist)
ORDER BY
	rolname;

user schemas

SELECT
	u.usename,
	n.nspname
FROM
	pg_user AS u
CROSS JOIN
	pg_namespace AS n
WHERE
	n.nspname NOT IN ('pg_internal', 'pg_toast', 'pg_catalog', 'admin', 'public')
	AND n.nspname NOT LIKE 'pg_temp_%'
	AND u.usename NOT IN ('admin')
	AND u.usename NOT LIKE 'app_%'
	AND has_schema_privilege (u.usename, n.nspname, 'usage')
ORDER BY
	u.usename ASC,
	n.nspname ASC;

user selectable tables

SELECT
	u.usename,
	n.nspname,
	t.table_name,
	has_table_privilege(u.usename, n.nspname || '.' || t.table_name, 'select') AS has_select
FROM
	pg_user AS u
CROSS JOIN
	pg_namespace AS n
INNER JOIN
	information_schema.tables t ON t.table_schema = n.nspname
WHERE
	n.nspname NOT IN ('pg_internal', 'pg_toast', 'pg_catalog', 'admin', 'public')
	AND n.nspname NOT LIKE 'pg_temp_%'
	AND u.usename NOT IN ('admin')
	AND u.usename NOT LIKE 'app_%'
	AND has_schema_privilege(u.usename, n.nspname, 'usage')
ORDER BY
	u.usename ASC,
	n.nspname ASC;

table ownership

SELECT
	n.nspname AS schema_name,
	CASE
		WHEN c.relkind = 'v' THEN
		'view' ELSE'table'
	END AS table_type,
	c.relname AS table_name,
	pg_get_userbyid(c.relowner) AS table_owner,
	d.description AS table_description
FROM
	pg_class AS c
	LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
	LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
	LEFT JOIN pg_description AS d ON ( d.objoid = c.oid AND d.objsubid = 0 )
WHERE
	c.relkind IN ( 'r', 'v' )
	AND schema_name = 'my_schema'
	AND table_name = 'my_table'
	AND table_owner = 'my_user'
ORDER BY
	n.nspname ASC,
	c.relname ASC;