Skip to main content
RunBook Academy

AnsibleXIX · Privilege EscalationPrivilege escalation

Escalation methods and where they apply

Intermediate⏱ ~16 minansible-docansible-galaxy

What you'll learn

  • List the become plugins shipped in ansible-core and name where the others come from
  • Choose an escalation method appropriate to a platform and account model
  • Set become_method per group in inventory rather than globally
  • Explain why su behaves differently from sudo for a non-interactive run
  • Recognise the plugins that belong to platforms other than a Linux server fleet

Prerequisites

Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11

Not yet marked complete on this device.

Lists of Ansible escalation methods circulate freely — sudo, su, pbrun, pfexec, doas, dzdo, ksu, machinectl, runas, enable — and they are misleading in a way that costs a debugging session. Most of those are not in ansible-core.

Ask the installation:

Read-only / Safethe become plugins actually available
$ ansible-doc -t become -l
ansible.builtin.runas Run As user
ansible.builtin.su    Substitute User
ansible.builtin.sudo  Substitute User DO

Everything else lives in a collection. doas, dzdo, ksu, machinectl, pbrun, pfexec, pmrun, sesu and sudosu come from community.general; enable, for network devices, comes from ansible.netcommon.

What is relevant to a Linux server fleet

PluginCollectionRelevance to a Linux fleet
sudoansible.builtinThe default and the right answer in almost every case
suansible.builtinHosts with no sudo, or a policy that forbids it
doascommunity.generalOpenBSD, and Linux hosts that deliberately chose doas over sudo
machinectlcommunity.generalWhen a full pam_systemd session is genuinely required
dzdocommunity.generalCentrify-managed estates
pbrun, pmruncommunity.generalBeyondTrust PowerBroker estates
ksucommunity.generalKerberos-authenticated escalation
sesucommunity.generalCA Privileged Access Manager
sudosucommunity.generalsudo su - as one step, for policies that mandate it
pfexeccommunity.generalSolaris RBAC — not a Linux plugin
runasansible.builtinWindows only
enableansible.netcommonNetwork devices, covered in Part XLII

Three of those rows exist because a commercial privilege-management product owns escalation in that estate. If you are in one, the product’s rules — not sudoers — are where least privilege is expressed, and the Ansible side is just naming the method. The design questions in lesson 4 still apply; the file you edit is different.

su is not sudo with a different name

su is the fallback when sudo is absent, and it behaves differently in three ways that matter for unattended runs.

It always requires a password. sudo can be configured NOPASSWD for a specific rule. su authenticates as the target user, so it wants that user’s password, every time. For root, that means the root password is in your automation — which is a considerably worse secret to hold than a service account’s, because it is the same on every host in most estates.

It cannot be restricted. There is no su-equivalent of a sudoers rule listing permitted commands. Access to su as root is total access. Any least-privilege design that depends on restricting what the automation may do is unavailable.

Prompt detection is fragile. The plugin matches the password prompt by string, and ansible-doc -t become su documents a prompt_l10n option for exactly this reason: a localised system prints a translated prompt the built-in list does not match, and the run fails with a timeout rather than an authentication error. The option’s own note warns against adding a colon to custom entries, because the plugin appends one.

Read-only / Safesu plugin defaults
$ ansible-doc -t become su | grep -A2 'become_flags\\|become_user  User'
   become_flags  Options to pass to su
      default: ''

 become_user  User you 'become' to execute the task
      default: root

Setting the method where it belongs

become_method can be set in ansible.cfg, on the command line, as a play or task keyword, or as ansible_become_method in inventory. Inventory is usually right, because the correct method is a property of the host, not of the playbook.

Configuration changemethod as a property of the group
# inventories/prod/group_vars/all.yml
ansible_become_method: sudo
ansible_become_user: root

# inventories/prod/group_vars/openbsd_hosts.yml
ansible_become_method: community.general.doas

# inventories/prod/group_vars/centrify_estate.yml
ansible_become_method: community.general.dzdo

Two habits make this hold up.

Use the fully qualified name for anything outside ansible.builtin. become_method: doas resolves through the collection search path and depends on what happens to be installed; community.general.doas names exactly one plugin. The same argument as for module FQCNs, for the same reason.

Do not set it globally in ansible.cfg for a mixed estate. A global setting is invisible at the point of use and wrong for some subset of hosts. Inventory keeps the exception next to the hosts it applies to, and ansible-inventory --host will show you the effective value.

Read-only / Safewhat method will this host actually use?
ansible-inventory -i inventories/prod --host bsd01.example.com \
| grep -E 'ansible_become'

When the method choice is really an environment problem

The become documentation notes that escalated processes may not have access to environment variables set by pam_systemd, and offers become_method: machinectl as the way to force a new systemd session.

That is worth understanding rather than copying. sudo by default does not create a login session in the systemd sense, so XDG_RUNTIME_DIR and the user session bus are absent. Anything that needs them — a user-level systemd unit, systemctl --user, some desktop or container tooling — fails with an error about a missing bus rather than about permissions.

Switching the whole fleet’s become method to fix one task is disproportionate. The alternatives, in order of preference: use the system service manager rather than the user one; set the variables explicitly on the task with environment:; or set the method on that single task with become_method rather than for the play.

Knowledge check

Knowledge check · 4 questions

  1. Q1. Which become plugins ship with ansible-core 2.21?

  2. Q2. Which are genuine operational differences between su and sudo for unattended automation? Select all that apply.

  3. Q3. Setting become_method: doas in a playbook is safe on any controller, because ansible-playbook --syntax-check will report the missing plugin before the run.

  4. Q4. A mixed estate has Linux hosts using sudo and a handful of OpenBSD hosts using doas. Where does the method belong?

Passing score: 75%. Answers are checked in this browser.