Score:1

Run NextCloud PHP script ‘occ’ as webserver user, on Ansible connection

co flag

How do I write an Ansible task to run a PHP script as a third user; not the root user and not the connecting user, but the “webserver” user?

The NextCloud administration program occ, according to the documentation, must be run as the webserver user:

sudo -u www-data php occ

To become a different user for running a command, Ansible provides the become feature. The Ansible documentation sternly recommends against attempting to run commands as a different, non-root user:

Everything is fine if the module file is executed without using become, when the become_user is root, or when the connection to the remote machine is made as root. In these cases Ansible creates the module file with permissions that only allow reading by the user and root, or only allow reading by the unprivileged user being switched to.

However, when both the connection user and the become_user are unprivileged, the module file is written as the user that Ansible connects as (the remote_user), but the file needs to be readable by the user Ansible is set to become.

Using become_user to that user

The connection user has sudo permission to run commands as the third user:

$ sudo -u www-data whoami
www-data

When I use become_user on the task, to run the command as that user:

- name: "NextCloud: Instance configuration"
  become_user: "{{ web_process_user }}"
  command:
    cmd: >-
        php "{{ apache_nextcloud_dir }}/occ" maintenance:install
            --no-interaction
            …

UPDATE: um, it works. I don't know what changed, but in trying to reproduce the problem, it stopped.

Using shell with an explicit sudo invocation as that user

When I configure the Ansible task with a shell command:

shell: >-
    su '{{ web_process_user }}' --shell '/bin/bash' -c ' \
        php "{{ apache_nextcloud_dir }}/occ" …

Ansible complains:

[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running su

I'd love to do that. Ansible's become would be a much more graceful way than this shell: su hack.

But when using become, the problems described in the Ansible documentation occur: the task module sent across the connection for running that command, fails to get the privilege to create its temporary files.

The Ansible documentation advises to either:

  • “use pipelining”: That loses the advantages of the default task-module system.
  • “avoid becoming an unprivileged user”: Not an option, because the unprivileged webserver user is required for running this command correctly.

How should I make an Ansible task that runs php "{{ apache_nextcloud_dir }}/occ" as the unprivileged, third user {{ web_process_user }}?

UPDATE: the become functionality appears to work correctly now.

solarchemist avatar
in flag
You can avoid the whole mess by making sure `setfacl` is installed on the target (`apt install acl`). Then it just works. Might not work on hosts using filesystems without ACL support, but I've never encountered such systems so far. See this section in the Ansible docs https://docs.ansible.com/ansible/latest/user_guide/become.html#risks-of-becoming-an-unprivileged-user
Score:0
cz flag

There are two ways I know of to deal with this issue. The first one you are already aware of, but seem to have been scared away from it by the documentation. However, the documentation tells you exactly what you need to do to make it work, so you should go through it carefully if this doesn't succeed the first time.

So you need to do two things:

  1. Set become_user to the unprivileged user (here, www-data). This will cause ansible to sudo to that user instead of root.

  2. Configure sudoers to allow for your remote_user to sudo to www-data. For example, if your remote_user is ansible:

    ansible ALL=(www-data) NOPASSWD:ALL
    

    Note that this is probably optional, because it is typical to have already configured sudo to allow the ansible user to sudo to any user, something like:

    ansible ALL=(ALL) NOPASSWD:ALL
    

    or by placing it in a group that can already do that.


The second way is to have Ansible connect directly to the remote system as the desired user (here, www-data) and not sudo. You do this as follows:

  1. Add Ansible's ssh public key to the remote user's .ssh/authorized_keys.

  2. Set remote_user=www-data and become=no for the task, block, playbook, role, etc., that needs to run as this user.

co flag
“scared away from it by the documentation” — quite the opposite; the documentation scared me *into* trying to get this working. But now I've updated the question with the fact I'm unable to reproduce the problem; the recommended `become` feature works correctly now. Thanks for the prompts.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.