Database owner does not have (implicit) usage permissions for pg_database_owner
unless triggered by "related" query.
First false, then true
initech=> \conninfo
You are connected to database "initech" as user "initech_admin" on host "initech.cthulhu4u2u1.us-east-1.rds.amazonaws.com" (address "10.108.77.201") at port "5432".
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, compression: off)
initech=> SELECT
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'member') AS member,
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'usage') AS usage;
member | usage
--------+-------
t | f
(1 row)
initech=> SELECT
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'member') AS member,
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'usage') AS usage;
member | usage
--------+-------
t | f
(1 row)
initech=> SELECT
pg_catalog.pg_has_role('initech_master_user', 'pg_database_owner', 'member') AS member,
pg_catalog.pg_has_role('initech_master_user', 'pg_database_owner', 'usage') AS usage;
member | usage
--------+-------
t | t
(1 row)
initech=> SELECT
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'member') AS member,
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'usage') AS usage;
member | usage
--------+-------
t | t
(1 row)
Note from the \conninfo
, the active role in the session is initech_admin
. The usage=f
is consistent until the initech_master_user
query occurs, after which usage=t
is consistent. Note the initech_master_user
is the RDS master user for this PostgreSQL instance and that role has been granted initech_admin
:
initech=> \du initech_master_user
List of roles
Role name | Attributes | Member of
---------------------+-------------------------------+-------------------------------
initech_master_user | Create role, Create DB +| {initech_admin,rds_superuser}
| Password valid until infinity |
initech=> \l initech
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
---------+---------------+----------+-------------+-------------+------------+-----------------+-------------------
initech | initech_admin | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
(1 row)
From non-database owner
If we connect as a different role initech_app
(which is neither the database owner nor the RDS master user), the usage=t
returns immediately for the initech_admin
role:
psql (15.2 (Homebrew))
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, compression: off)
Type "help" for help.
initech=> \conninfo
You are connected to database "initech" as user "initech_app" on host "initech.cthulhu4u2u1.us-east-1.rds.amazonaws.com" (address "10.108.77.201") at port "5432".
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, compression: off)
initech=> SELECT
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'member') AS member,
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'usage') AS usage;
member | usage
--------+-------
t | t
(1 row)
Note this role is not a member of any other roles (and from the above, is not the database owner):
initech=> \du initech_app
List of roles
Role name | Attributes | Member of
-------------+-------------------------------+-----------
initech_app | Password valid until infinity | {}
Comparison to non-RDS PostgreSQL
On the other hand, a Dockerized PostgreSQL does not have this issue:
initech=> \conninfo
You are connected to database "initech" as user "initech_admin" on host "127.0.0.1" at port "16077".
initech=> SELECT
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'member') AS member,
pg_catalog.pg_has_role('initech_admin', 'pg_database_owner', 'usage') AS usage;
member | usage
--------+-------
t | t
(1 row)
Note the database is set up in roughly the same way:
initech=> \du initech_master_user
List of roles
Role name | Attributes | Member of
---------------------+-------------------------------+-----------------
initech_master_user | Create role, Create DB +| {initech_admin}
| Password valid until infinity |
initech=> \l initech
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
---------+---------------+----------+-------------+-------------+------------+-----------------+-------------------
initech | initech_admin | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
(1 row)