187

A recurring theme that's in my ansible playbooks is that I often must execute a command with sudo privileges (sudo: yes) because I'd like to do it for a certain user. Ideally I'd much rather use sudo to switch to that user and execute the commands normally. Because then I won't have to do my usual post commands clean up such as chowning directories. Here's a snippet from one of my playbooks:

- name: checkout repo
  git: repo=https://github.com/some/repo.git version=master dest={{ dst }}
  sudo: yes
- name: change perms
  file: dest={{ dst }} state=directory mode=0755 owner=some_user
  sudo: yes

Ideally I could run commands or sets of commands as a different user even if it requires sudo to su to that user.

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
rgrinberg
  • 9,638
  • 7
  • 27
  • 44

5 Answers5

276

With Ansible 1.9 or later

Ansible uses the become, become_user, and become_method directives to achieve privilege escalation. You can apply them to an entire play or playbook, set them in an included playbook, or set them for a particular task.

- name: checkout repo
  git: repo=https://github.com/some/repo.git version=master dest={{ dst }}
  become: yes
  become_user: some_user

You can use become_with to specify how the privilege escalation is achieved, the default being sudo.

The directive is in effect for the scope of the block in which it is used (examples).

See Hosts and Users for some additional examples and Become (Privilege Escalation) for more detailed documentation.

In addition to the task-scoped become and become_user directives, Ansible 1.9 added some new variables and command line options to set these values for the duration of a play in the absence of explicit directives:

As of Ansible 2.0.2.0, the older sudo/sudo_user syntax described below still works, but the deprecation notice states, "This feature will be removed in a future release."


Previous syntax, deprecated as of Ansible 1.9 and scheduled for removal:

- name: checkout repo
  git: repo=https://github.com/some/repo.git version=master dest={{ dst }}
  sudo: yes
  sudo_user: some_user
Davi Alves
  • 1,704
  • 2
  • 19
  • 24
Brett
  • 4,341
  • 2
  • 19
  • 17
  • 4
    To specify the sudo_user from a variable, use quotes around your variable template, like this - `sudo_user: "{{ ansible_ssh_user }}"` or you would get a yaml syntax error. – Sumeet Pareek Apr 19 '15 at 18:26
  • Good catch. I was trying to match the OP's formulation of the problem as closely as possible, but I agree that using variable interpolation will be the most common choice. – Brett Apr 19 '15 at 19:55
  • 5
    From Ansible 1.9, it's the [`become` system](https://docs.ansible.com/ansible/become.html) instead of "sudo*". – AndiDog Jul 24 '15 at 14:42
  • 2
    1.9+ syntax for "become" is right. You may also want to check "become_method", as "su" could be sometimes better than default "sudo", depending on your system setup. – ElementalStorm Feb 11 '16 at 17:40
  • `New Ansible variables and command line options are added to set these values for the duration of a play. ` @Brett so does that mean the succeeding tasks after this will be ran by `some_user` and not the original user `remote_user` which was used to connect to the host, is that correct? – JohnnyQ May 20 '16 at 03:47
  • @JohnnyQ if you use the command line options, I would certainly expect them to be effective for each task in the play, assuming no contrary directives inside the playbook itself. However the documentation doesn't explicitly say this and I have not had occasion to verify this assumption. Remember you have to set **both** `become` and `become_user` for escalation to happen (via directive or the equivalent command line argument). – Brett May 20 '16 at 15:47
  • @Brett Tried it [here](https://gist.github.com/janzenz/8030b104c109df3b59f26d133c8af03b) Turns out that the user escalation goes back to the original user which you used to connect to as shown in my example. – JohnnyQ May 22 '16 at 04:06
  • `become_with` seems to have become `become_method`, https://docs.ansible.com/ansible/latest/user_guide/become.html#using-become – markson edwardson Jan 13 '22 at 02:04
51

In Ansible 2.x, you can use the block for group of tasks:

- block:
    - name: checkout repo
      git:
        repo: https://github.com/some/repo.git
        version: master
        dest: "{{ dst }}"
    - name: change perms
      file:
      dest: "{{ dst }}"
      state: directory
      mode: 0755
      owner: some_user
  become: yes
  become_user: some user
Arbab Nazar
  • 22,378
  • 10
  • 76
  • 82
29

In Ansible >1.4 you can actually specify a remote user at the task level which should allow you to login as that user and execute that command without resorting to sudo. If you can't login as that user then the sudo_user solution will work too.

---
- hosts: webservers
  remote_user: root
  tasks:
    - name: test connection
      ping:
      remote_user: yourname

See http://docs.ansible.com/playbooks_intro.html#hosts-and-users

trcarden
  • 881
  • 1
  • 9
  • 17
7

A solution is to use the include statement with remote_user var (describe there : http://docs.ansible.com/playbooks_roles.html) but it has to be done at playbook instead of task level.

  • This isn't a good solution for the use case above. However I wasn't aware of this solution for a long time. I thought I can only include roles. – ArjanSchouten Sep 19 '15 at 19:30
1

You can specify become_method to override the default method set in ansible.cfg (if any), and which can be set to one of sudo, su, pbrun, pfexec, doas, dzdo, ksu.

- name: I am confused
  command: 'whoami'
  become: true
  become_method: su
  become_user: some_user
  register: myidentity

- name: my secret identity
  debug:
    msg: '{{ myidentity.stdout }}'

Should display

TASK [my-task : my secret identity] ************************************************************
ok: [my_ansible_server] => {
    "msg": "some_user"
}
avi.elkharrat
  • 6,100
  • 6
  • 41
  • 47