5

I'd like to run ansible such that:

  • remote user is 'normal' user

  • ... who becomes root via sudo to run a bunch of tasks

  • ... who 'becomes postgres user via su - postgres, from root, to create a PostgreSQL database.

This is typical procedure for PostgreSQL world: a special user accessible only via su from root.

Specifying become-ish parameters in a play works only when connecting as root, as the CLI options override whatever is defined in a play.

Are there more elegant ways to achieve this other than adding sudo rules or running

command: /usr/bin/su - postgres -c '/bin/createuser -D -R -S myuser

from ansible, telling it to shut the warnings up?

badbishop
  • 928
  • 4
  • 12
  • 21
  • Did you eventually managed to get somewhere? I am trying to achieve almost the same thing and the answer does not exactly address this issue to my understanding. – Nicolas Garnier Apr 30 '21 at 07:49

2 Answers2

5

Why would you have to change effective users twice?

You can specify the effective user ID that ansible needs to run as per task, so when you need to run a command as the postgres user, set that directly.

tasks:
  - name: Create Postgres User
    shell: /bin/createuser -D -R -S myuser
    become: yes
    become_user: postgres

Frequently when a user gets sudo permissions to become root they already get ALL and become any user, including postgres.

Alternative, create an additional sudo permission such that your ansible user can execute (specific) commands as the postgres user.

Note: Consider using the Ansible Postgres database modules to manage your databases, roles and permissions.


In response to your comment: I connect with Ansible as a regular user:

ansible example -a "/bin/whoami"
example | SUCCESS | rc=0 >>
hbruijn

I have a fairly typical "/etc/sudoers.d/hbruijn" snippet that doesn't place any restrictions on what I (my Ansible user) can do:

# /etc/sudoers.d/hbruijn
hbruijn  ALL = NOPASSWD: ALL

And then I can become any user to execute commands under a different user ID and task without calling on sudo or su first:

ansible example -b --become-user=root  -a "/bin/whoami"
example | SUCCESS | rc=0 >>
root

or:

ansible example -b --become-user=postgres  -a "/bin/whoami"
example | SUCCESS | rc=0 >>
postgres

all without Ansible connecting directly as the superuser.

HBruijn
  • 77,029
  • 24
  • 135
  • 201
  • 1
    first, your code example doesn't work unless you connect as superuser directly, that's why I've posted the question in the first place. Second, if you run createuser as root, you will get "createuser: could not connect to database postgres: FATAL: role "root" does not exist". As for Postgres database modules, they require additional Python libraries. IMHO, this is too much for running just two basic commands. – badbishop Dec 13 '17 at 13:44
  • 2
    No, `become` will attempt to switch to `become_user` with `become_method`. If I connect with user john, and I have a sudo rule allowing john to run things as postgres, this can work. There is a `become_method` for su, but that is subject to the su limitation of requiring credentials unless you are already root. – John Mahowald Dec 13 '17 at 14:26
  • @HBruin: with this sudo rule in place "hbruijn" in your example IS effectively a superuser, it just has a different name. – badbishop Dec 15 '17 at 07:21
1

Basically you need to run tasks for postgres user in root block. Example as below:

pb.yml

- hosts: testingserver
  gather_facts: false
  tasks:
    - name: this is me without become
      command: whoami

    - name: this is my sudo `root` block
      become: true
      block:
        - name: checking who I am
          command: whoami

        - name: this is me becoming `postgres`
          become_user: postgres
          command: whoami

output:

$ ANSIBLE_CONFIG=ansible.cfg ansible-playbook -i inven pb.yml -K -v
BECOME password:

PLAY [testingserver] ***********************************************************************************************************************************************************************************************

TASK [this is me without become] ***********************************************************************************************************************************************************************************
changed: [testingserver] => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": ["whoami"], "delta": "0:00:00.006233", "end": "2023-07-05 11:01:57.229844", "msg": "", "rc": 0, "start": "2023-07-05 11:01:57.223611", "stderr": "", "stderr_lines": [], "stdout": "testinguser", "stdout_lines": ["testinguser"]}

TASK [checking who I am] *******************************************************************************************************************************************************************************************
changed: [testingserver] => {"changed": true, "cmd": ["whoami"], "delta": "0:00:00.006191", "end": "2023-07-05 11:01:57.964360", "msg": "", "rc": 0, "start": "2023-07-05 11:01:57.958169", "stderr": "", "stderr_lines": [], "stdout": "root", "stdout_lines": ["root"]}

TASK [this is me becoming `postgres`] *************************************************************************************************************************************************************************
changed: [testingserver] => {"changed": true, "cmd": ["whoami"], "delta": "0:00:00.003580", "end": "2023-07-05 11:01:58.768622", "msg": "", "rc": 0, "start": "2023-07-05 11:01:58.765042", "stderr": "", "stderr_lines": [], "stdout": "postgres", "stdout_lines": ["postgres"]}

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

This is my linux box environment as per your case:

  • normal user is testinguser
  • normal user su to postgres require password
  • normal user sudo to root
  • root su to postgres
$ ssh testingserver
[testinguser@testingserver ~]$ su - postgres
Password:
[testinguser@testingserver ~]$ sudo -i
[sudo] password for testinguser:
[root@testingserver ~]# su - postgres
[postgres@testingserver ~]$ whoami
postgres
skycrew
  • 111
  • 3