Privilege escalation errors occur when Ansible cannot switch to a user with sufficient permissions to execute a task. Most commonly, this means the become directive is missing or misconfigured. This guide covers every common privilege escalation error and how to fix it.
How Privilege Escalation Works in Ansible
When you set become: true, Ansible:
- Connects to the target host as the connection user (e.g.,
deploy) - Switches to the become user (default:
root) using the become method (default:sudo) - Executes the task with the elevated privileges
- Returns results to the connection user
Control Node → SSH as 'deploy' → sudo → root → Execute task
The Most Common Error
Missing become: true
Error:
fatal: [webserver]: FAILED! => {
"msg": "This command has to be run under the root user.",
"rc": 1
}
Or:
fatal: [webserver]: FAILED! => {
"msg": "Permission denied"
}
Wrong — no privilege escalation:
---
- name: Install packages
hosts: all
become: false # or become not specified at all
tasks:
- name: Install git
ansible.builtin.yum:
name: git
state: present
Correct — become enabled:
---
- name: Install packages
hosts: all
become: true
tasks:
- name: Install git
ansible.builtin.yum:
name: git
state: present
Where to Set become
Play Level (All Tasks in Play)
- name: System setup
hosts: all
become: true # All tasks run as root
tasks:
- name: Install packages
ansible.builtin.apt:
name: nginx
state: present
Task Level (Specific Tasks Only)
- name: Mixed privilege play
hosts: all
become: false
tasks:
- name: Check disk space (no root needed)
ansible.builtin.command: df -h
register: disk_info
- name: Install package (needs root)
ansible.builtin.apt:
name: nginx
state: present
become: true # Only this task escalates
Block Level
- name: Grouped escalation
hosts: all
tasks:
- block:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
become: true # Both tasks in block escalate
In ansible.cfg
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False
In Inventory
[webservers:vars]
ansible_become=true
ansible_become_method=sudo
ansible_become_user=root
Common Error Messages and Fixes
"sudo: a password is required"
fatal: [host]: FAILED! => {"msg": "Missing sudo password"}
Fix options:
- Pass password interactively:
ansible-playbook site.yml -K
- Configure passwordless sudo on the target:
# /etc/sudoers.d/deploy
deploy ALL=(ALL) NOPASSWD: ALL
- Use Ansible Vault:
# group_vars/all/vault.yml (encrypted)
ansible_become_password: "sudo_password"
"sudo: no tty present and no askpass program specified"
fatal: [host]: FAILED! => {"msg": "sudo: no tty present and no askpass program specified"}
Cause: The sudoers file requires a TTY for sudo.
Fix: Add to sudoers on the target:
Defaults:deploy !requiretty
Or in ansible.cfg:
[ssh_connection]
ssh_args = -o RequestTTY=yes
"User deploy is not allowed to execute"
fatal: [host]: FAILED! => {"msg": "Sorry, user deploy is not allowed to execute '/bin/yum' as root"}
Cause: The user's sudoers entry restricts which commands they can run.
Fix: Update sudoers to allow the needed commands:
deploy ALL=(ALL) NOPASSWD: /usr/bin/yum, /usr/bin/apt-get, /usr/bin/systemctl
Or allow all commands:
deploy ALL=(ALL) NOPASSWD: ALL
"become_user requires become"
ERROR! become_user requires become to be set to True
Fix: Add become: true alongside become_user:
- name: Run as postgres
ansible.builtin.command: psql -c "SELECT 1"
become: true
become_user: postgres
Becoming a Non-Root User
Sometimes you need to run as a service account, not root:
- name: Run database migration
ansible.builtin.command: python manage.py migrate
become: true
become_user: django
args:
chdir: /opt/myapp
- name: Check PostgreSQL status
ansible.builtin.command: pg_isready
become: true
become_user: postgres
become_method Options
| Method | Use Case |
|---|---|
sudo | Default, most Linux systems |
su | Switch user (needs target user's password) |
pbrun | PowerBroker |
pfexec | Solaris privilege exec |
doas | OpenBSD |
dzdo | Centrify |
ksu | Kerberos |
runas | Windows (with ansible.builtin.runas) |
machinectl | systemd-nspawn containers |
enable | Network devices (enable mode) |
- name: Task on OpenBSD
ansible.builtin.command: pkg_add nginx
become: true
become_method: doas
Debugging Privilege Escalation
Test sudo Manually
# SSH to the host
ssh deploy@webserver
# Test sudo
sudo -l # List allowed commands
sudo whoami # Should print "root"
sudo -u postgres whoami # Should print "postgres"
Use Verbose Mode
ansible-playbook site.yml -vvv
Look for lines containing BECOME and sudo to see the exact escalation command.
Check become Works with ping
ansible webserver -m ping --become
Links
Related Articles
- Ansible Sudo Password Guide
- How to Fix Ansible Connection Failures
- Ansible Indentation Errors
- macOS Fork Error in Ansible
- Ansible Tutorial for Beginners
- Protecting Sensitive Information with no_log
- Ansible Vault: Encrypt and Decrypt
Conclusion
Most Ansible privilege escalation errors come down to one missing line: become: true. For production environments, configure passwordless sudo for your Ansible service account and set become = True in ansible.cfg. For tasks requiring specific service accounts, combine become: true with become_user. Always test privilege escalation with ansible host -m ping --become before running full playbooks.