community.postgresql icon indicating copy to clipboard operation
community.postgresql copied to clipboard

postgresql_membership doesn't recognize ADMIN, SET and INHERIT options

Open HauserV opened this issue 4 months ago • 3 comments

SUMMARY

Make it possible to control the ADMIN, SET and INHERIT options when GRANTing roles.

ISSUE TYPE
  • Feature Idea
COMPONENT NAME

community.postgresql.postgresql_membership

ADDITIONAL INFORMATION

When a non-superuser creates a role in PostgreSQL 16, it is automatically granted the new role only with ADMIN option set. However, that's not enough to create objects owned by the user. To quote the documentation:

To create an object owned by another role or give ownership of an existing object to another role, you must have the ability to SET ROLE to that role; otherwise, commands such as ALTER ... OWNER TO or CREATE DATABASE ... OWNER will fail.

In earlier versions of PostgreSQL, I simply could use the community.postgresql.postgresql_membership to grant the new role to the non-superuser, but that doesn't work anymore because the module doesn't do anything now because the grant is there (albeit not with the options I need).

In my scenario, I cannot use a superuser to do this (superuser wouldn't receive this automatic grant) because I'm using a managed database as a service.

- name: Demo
  hosts: integration
  gather_facts: true
  tasks:
    - name: Create role
      community.postgresql.postgresql_user:
        name: ansible_new_role
        password: dummy123!
        login_host: example.com
        login_db: postgres
        login_user: dbadmin
        login_password: password
        login_port: 5432
    - name: Grant new role to the admin user
      community.postgresql.postgresql_membership:
        group: ansible_new_role
        target_role: dbadmin
        login_host: example.com
        login_db: postgres
        login_user: dbadmin
        login_password: password
        login_port: 5432
    - name: Create database owned by the new role
      community.postgresql.postgresql_db:
        name: ansible_new_database
        owner: ansible_new_role
        login_host: example.com
        login_user: dbadmin
        login_password: password
        login_port: 5432
$ ansible-playbook play.yml -v -i inventory.yml 
Using /etc/ansible/ansible.cfg as config file

PLAY [Demo] **********************************************************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************************************************
[WARNING]: Platform linux on host integration is using the discovered Python interpreter at /usr/bin/python3.6, but future installation of another Python interpreter could
change the meaning of that path. See https://docs.ansible.com/ansible-core/2.16/reference_appendices/interpreter_discovery.html for more information.
ok: [integration]

TASK [Create role] ***************************************************************************************************************************************************************
changed: [integration] => changed=true 
  queries:
  - 'ALTER USER "ansible_new_role" WITH ENCRYPTED PASSWORD %(password)s '
  user: ansible_new_role

TASK [Grant new role to the admin user] ******************************************************************************************************************************************
ok: [integration] => changed=false 
  granted:
    ansible_new_role: []
  groups:
  - ansible_new_role
  queries: []
  state: present
  target_roles:
  - dbadmin

TASK [Create database owned by the new role] *************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: psycopg2.errors.InsufficientPrivilege: must be able to SET ROLE "ansible_new_role"
fatal: [integration]: FAILED! => changed=false 
  msg: |-
    Database query failed: must be able to SET ROLE "ansible_new_role"

PLAY RECAP ***********************************************************************************************************************************************************************
integration                : ok=3    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

It seems to me that this is partly a bug report because the module would otherwise run a regular GRANT statement which defaults to SET and INHERIT options enabled. In my case, however, it doesn't do anything because it sees the implicit GRANT with the ADMIN option only. There's the obvious workaround to use the community.postgresql.postgresql_query to apply the GRANT no matter what, but that's not clean.

HauserV avatar Oct 18 '24 10:10 HauserV