Become and Permission Problems¶
What You'll Learn¶
- How to tell a
becomefailure apart from an SSH failure in seconds - The exact error messages for the common cases, and the fix for each
- Why command-restricted sudo rules don't work for Ansible
- How to diagnose "Permission denied" when the connection and escalation both worked
Why This Exists¶
SSH auth succeeding and become succeeding are two independent checks — a task can fail here with a working connection, and the fix is entirely different from an SSH fix.
Mental Model¶
Three separate identities are in play: the SSH user (who logs in), the become user (who the task runs as — root by default), and the file or process owner the task touches. "Permission denied" means one of those three doesn't line up.
flowchart TD
A[Task failed] --> B{"UNREACHABLE?"}
B -->|Yes| SSH["SSH problem — see SSH and Connection Problems"]
B -->|No| C{"Message mentions sudo,<br>password, or privilege escalation?"}
C -->|Yes| BEC["become problem — this page"]
C -->|No| D{"Permission denied<br>on a path?"}
D -->|Yes| PERM["Check which user the task ran as — this page"]
D -->|No| MOD["Module/execution error"]
First, confirm the connection itself is fine without escalation:
ansible web01 -m ansible.builtin.command -a whoami # expect: deploy
ansible web01 -m ansible.builtin.command -a whoami --become # expect: root
If the first works and the second fails, it's a become problem.
"Missing sudo password"¶
The remote user's sudo requires a password and Ansible wasn't given one. Two fixes — choose by context:
| Context | Fix |
|---|---|
| A human running a playbook interactively | Prompt for it: ansible-playbook site.yml -K (--ask-become-pass) |
| CI or unattended automation | Give the automation account passwordless sudo, or supply ansible_become_password from Vault |
Manage that file with Ansible too, always with validate: /usr/sbin/visudo -cf %s.
Command-restricted sudo doesn't work for Ansible
A rule like deploy ALL=(root) NOPASSWD: /usr/bin/systemctl looks like least privilege, but Ansible doesn't run systemctl through sudo. It runs a shell that executes a Python module from a temporary path:
sudo -H -S -n -u root /bin/sh -c 'echo BECOME-SUCCESS-abc123 ; /usr/bin/python3 /home/deploy/.ansible/tmp/ansible-tmp-.../AnsiballZ_systemd.py'
That never matches a command-specific rule. Restrict the automation account in other ways instead: a dedicated user, key-only login from known control nodes, from= restrictions in authorized_keys, and auditing of its sessions.
"Incorrect sudo password"¶
Usually one of:
ansible_become_passwordis set ingroup_varsfor a different environment and overrides the value you meant — check withansible-inventory --host web01 | grep become.- The password differs between hosts, but one value is supplied for all of them.
- The account is locked or its password expired (
chage -l deployon the host).
"Timeout waiting for privilege escalation prompt"¶
Ansible expected a password prompt and didn't recognize what it got. Causes:
- A customized sudo prompt or a PAM module (MFA push, a lecture banner) that changes the prompt text.
- A slow directory service (LDAP/SSSD) lookup delaying sudo; increase
timeoutinansible.cfgas a test. become_method: suagainst a host wheresuprints a localized prompt.
Test manually with the same user: ssh deploy@web01 'sudo -S -n true'. For automation accounts, passwordless sudo avoids prompt matching entirely.
"sorry, you must have a tty to run sudo"¶
This often appears right after enabling pipelining. The host's sudoers has Defaults requiretty; pipelining doesn't allocate a terminal. Fix it for the automation user only:
Modern distributions don't set requiretty by default, so this is mostly seen on older or custom-hardened images. Background: Connection Plugins.
"Failed to set permissions on the temporary files"¶
fatal: [web01]: FAILED! => {"msg": "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user ... chmod: invalid mode: 'A+user:checkout:rx:allow'"}
You connect as deploy and become_user: checkout (not root). The module file written by deploy must be readable by checkout. Fixes, best first:
- Enable pipelining — no temporary module file is written, so there's nothing to share.
- Install
aclon the managed node (apt install acl/dnf install acl) so Ansible can grant access withsetfacl. - Last resort:
allow_world_readable_tmpfiles = Trueinansible.cfg, which makes module files readable by every local user.
"Permission denied" After a Successful Escalation¶
fatal: [web01]: FAILED! => {"changed": false, "msg": "Destination /opt/checkout/current not writable"}
Find out which user the task actually ran as:
In the output, look for the sudo ... -u <user> line. Then compare against the path:
namei -l shows owner and permissions for every directory in the path — a common cause is a parent directory that the become user can't traverse, even though the file itself is writable.
Typical causes:
| Symptom | Cause |
|---|---|
Works as root, fails with become_user: checkout |
Path owned by root or another user |
become: true set on the play, but the task still runs as deploy |
become: false set on the task, block, or role — check with -vvv |
| Fails only on some hosts | Different ownership from a manual change; enforce it with a file task |
| Denied despite correct Unix permissions | SELinux context — check ls -Z and ausearch -m avc -ts recent |
"The powershell shell family is incompatible with the sudo become plugin"¶
fatal: [win01]: FAILED! => {"msg": "The powershell shell family is incompatible with the sudo become plugin"}
A Windows host is running a task with become: true, and the escalation method is the Linux default, sudo. Windows connections (winrm, psrp, or SSH with ansible_shell_type: powershell) run commands through PowerShell, where sudo means nothing.
The usual cause is become: true set too broadly: in ansible.cfg ([privilege_escalation] become = True), in group_vars/all.yml, or on a play that targets Linux and Windows hosts together. Fix it where the Windows hosts are defined:
| Situation | Fix |
|---|---|
| The Windows tasks don't need escalation (the connecting account already has the rights) | Set ansible_become: false for the Windows group, or remove become: true from plays that target Windows |
| A task really needs to run as another Windows account | Use the Windows method, runas, with become_user |
- name: Install IIS as SYSTEM
ansible.windows.win_feature:
name: Web-Server
state: present
become: true
become_user: SYSTEM
Common Mistakes¶
- Treating a
becomefailure as an SSH problem and regenerating keys that were never the issue. - Writing command-restricted sudo rules for the automation account and wondering why every task fails.
- Enabling pipelining fleet-wide without checking for
requirettyon older images. - Setting
allow_world_readable_tmpfilesas the first fix instead of pipelining oracl. - Ignoring SELinux denials because the Unix permissions look right.
Interview Questions¶
- A task fails with
Missing sudo password— what are the two possible fixes, and how do you choose between them? - Why does enabling pipelining sometimes surface a previously hidden
becomefailure? - Why can't you restrict Ansible's sudo access to a list of specific commands?
- How do you find out which user a failing task actually ran as?
Next¶
Continue to YAML and Variable Errors.