Introduction

Ansible's become feature handles privilege escalation — running tasks as root or another user when your connection user lacks the required permissions. It replaces the deprecated sudo: directive with a flexible, pluggable system supporting sudo, su, doas, pfexec, runas (Windows), and network enable mode. This article covers every become directive, practical examples, password handling, security best practices, and troubleshooting.

Quick Start

---
- name: Install and start nginx
  hosts: webservers
  become: true              # Escalate to root for all tasks
  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present

    - name: Start nginx
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

Run with:

ansible-playbook site.yml --ask-become-pass

Become Directives Reference

DirectiveDefaultScopeDescription
becomefalseplay, task, blockEnable privilege escalation
become_userrootplay, task, blockUser to escalate to
become_methodsudoplay, task, blockEscalation method
become_flags—play, task, blockExtra flags for the method
become_exe—play, task, blockPath to the escalation binary

Command-Line Equivalents

CLI FlagDirectiveDescription
-b / --becomebecome: trueEnable become
-K / --ask-become-pass—Prompt for become password
--become-user USERbecome_userSet become user
--become-method METHODbecome_methodSet become method

Connection Variables

# inventory
[webservers]
web01 ansible_become=true ansible_become_user=root
web02 ansible_become_method=su ansible_become_pass={{ vault_su_pass }}
VariableDescription
ansible_becomeEnable become for host
ansible_become_userBecome user
ansible_become_methodBecome method
ansible_become_passBecome password
ansible_become_flagsExtra flags
ansible_become_exePath to binary

Practical Examples

Run as Root (Default)

- name: Manage system service
  ansible.builtin.service:
    name: httpd
    state: started
  become: true
  # become_user defaults to root

Run as Specific User

- name: Run application as app user
  ansible.builtin.command: /opt/myapp/start.sh
  become: true
  become_user: appuser

Run as Nobody (nologin Shell)

- name: Run as nobody user
  ansible.builtin.command: /opt/check-permissions.sh
  become: true
  become_method: su
  become_user: nobody
  become_flags: '-s /bin/sh'

Different Methods Per Task

---
- name: Mixed privilege escalation
  hosts: servers
  tasks:
    - name: Install package (sudo to root)
      ansible.builtin.apt:
        name: nginx
        state: present
      become: true
      become_method: sudo

    - name: Configure app (su to appuser)
      ansible.builtin.template:
        src: app.conf.j2
        dest: /opt/app/config.yml
        owner: appuser
        mode: '0640'
      become: true
      become_method: su
      become_user: appuser

Play-Level vs Task-Level

---
# Play-level: ALL tasks run as root
- name: System setup
  hosts: servers
  become: true
  tasks:
    - name: Install packages
      ansible.builtin.apt:
        name: [nginx, postgresql, redis]
        state: present

    - name: Create app user
      ansible.builtin.user:
        name: myapp
        system: true

    # Override: this task runs as myapp, not root
    - name: Initialize application
      ansible.builtin.command: /opt/myapp/init.sh
      become_user: myapp

Block-Level Become

- name: Application deployment
  hosts: appservers
  tasks:
    - name: System tasks (no become needed)
      ansible.builtin.debug:
        msg: "Running as connection user"

    - name: Root tasks
      become: true
      block:
        - name: Install dependencies
          ansible.builtin.apt:
            name: [python3, python3-pip]
            state: present

        - name: Create directories
          ansible.builtin.file:
            path: /opt/myapp
            state: directory
            owner: appuser
            mode: '0755'

    - name: App tasks
      become: true
      become_user: appuser
      block:
        - name: Deploy code
          ansible.builtin.git:
            repo: https://github.com/example/app.git
            dest: /opt/myapp/current

        - name: Install Python deps
          ansible.builtin.pip:
            requirements: /opt/myapp/current/requirements.txt
            virtualenv: /opt/myapp/venv

Become Methods

MethodBinaryPlatformDescription
sudo/usr/bin/sudoLinux/macOSDefault, most common
su/usr/bin/suLinux/macOSSwitch user
doas/usr/bin/doasOpenBSD/LinuxSimpler sudo alternative
pfexec/usr/bin/pfexecSolarisProfile-based execution
runas—WindowsRun as different Windows user
enable—NetworkNetwork device enable mode
machinectl/usr/bin/machinectlLinuxsystemd-nspawn containers

Configure Default Method

# ansible.cfg
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false

Password Handling

Interactive Prompt

ansible-playbook site.yml -K
# or
ansible-playbook site.yml --ask-become-pass

Vault-Encrypted Password

# group_vars/all/vault.yml (encrypted with ansible-vault)
vault_become_pass: "s3cret_sudo_p@ss"
# group_vars/all/vars.yml
ansible_become_pass: "{{ vault_become_pass }}"

Per-Host Passwords

# host_vars/web01.yml
ansible_become_pass: "{{ vault_web01_pass }}"

# host_vars/db01.yml
ansible_become_method: su
ansible_become_pass: "{{ vault_db01_su_pass }}"

Configure sudoers on target hosts:

# /etc/sudoers.d/ansible
ansible ALL=(ALL) NOPASSWD: ALL
# No password needed
- hosts: all
  become: true
  tasks:
    - ansible.builtin.ping:

Network Automation Enable Mode

---
- name: Configure network devices
  hosts: switches
  gather_facts: false
  connection: ansible.netcommon.network_cli
  become: true
  become_method: ansible.netcommon.enable
  vars:
    ansible_become_pass: "{{ vault_enable_password }}"
  tasks:
    - name: Show running config
      cisco.ios.ios_command:
        commands:
          - show running-config
      register: config

    - name: Configure interface
      cisco.ios.ios_config:
        lines:
          - description Managed by Ansible
          - ip address 10.0.0.1 255.255.255.0
        parents: interface GigabitEthernet0/1

Windows runas

---
- name: Windows privilege escalation
  hosts: windows
  tasks:
    - name: Install IIS as Administrator
      ansible.windows.win_feature:
        name: Web-Server
        state: present
      become: true
      become_method: runas
      become_user: Administrator

Precedence Order

When become settings conflict, Ansible uses this precedence (highest first):

  1. Task-level directives
  2. Block-level directives
  3. Play-level directives
  4. Command-line flags (-b, --become-user)
  5. Connection variables (ansible_become*)
  6. ansible.cfg [privilege_escalation] section
  7. Plugin defaults

Troubleshooting

"Missing sudo password"

fatal: [server]: FAILED! => {"msg": "Missing sudo password"}

Fix: Add -K flag or set ansible_become_pass:

ansible-playbook site.yml -K

"Sorry, user is not allowed to execute"

fatal: [server]: FAILED! => {"msg": "sudo: user not allowed to execute '/bin/sh'"}

Fix: Add user to sudoers:

echo "ansible ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/ansible

"Timeout waiting for privilege escalation prompt"

# ansible.cfg — increase timeout
[defaults]
timeout = 30

Become with Unprivileged Users

When both connection user and become_user are unprivileged, Ansible can't use /tmp for module transfer. Fix:

# ansible.cfg
[defaults]
remote_tmp = /tmp/.ansible-${USER}/tmp

[privilege_escalation]
become_flags = -H -S

Or use pipelining:

[connection]
pipelining = true

Best Practices

  1. Use passwordless sudo — configure sudoers with NOPASSWD for the Ansible user
  2. Vault all passwords — never hardcode ansible_become_pass
  3. Minimize become scope — use task-level become instead of play-level when only some tasks need it
  4. Use no_log: true on tasks that handle passwords
  5. Prefer sudo over su — sudo provides better audit logging
  6. Create a dedicated Ansible user — don't use personal accounts
  7. Restrict sudoers — limit to specific commands if NOPASSWD: ALL is too broad:
ansible ALL=(ALL) NOPASSWD: /usr/bin/apt-get, /usr/bin/systemctl, /usr/bin/cp
  1. Test with --check — dry-run before applying become changes

Conclusion

Ansible become handles privilege escalation across Linux (sudo, su, doas), Windows (runas), and network devices (enable mode). Set become: true at the task, block, or play level with become_user and become_method to control exactly how privileges escalate. Use passwordless sudo with a dedicated Ansible user and Vault-encrypted passwords for the most secure and practical setup.