The orchestration of remote systems necessitates a robust mechanism for privilege escalation, allowing a non-privileged user to execute commands with the authority of another user, typically the root account. While sudo (superuser do) is the contemporary industry standard for this purpose, there are numerous enterprise and legacy scenarios where sudo is absent, disabled, or prohibited by security mandates. In these environments, Ansible provides native support for the su (substitute user) method as a become_method. Implementing su for privilege escalation requires a fundamental shift in how passwords are managed and how shell environments are handled, as the behavioral logic of su differs significantly from that of sudo.
The Strategic Implementation of su Over sudo
Selecting the appropriate method for privilege escalation is not merely a technical preference but often a requirement dictated by the target environment's architecture and security posture. There are several critical scenarios where su is the only viable or correct choice for system administration via Ansible.
Legacy systems, such as CentOS 5 or older iterations of Debian, frequently lack the sudo package by default. In these environments, installing sudo might introduce unwanted dependencies or violate the original system image's integrity. Using su allows these systems to be managed without the overhead of installing new software.
Minimalist environments, specifically lightweight Docker containers or specialized embedded systems, are often stripped of all non-essential binaries to reduce the attack surface and image size. Because sudo is a relatively large utility with its own set of configuration requirements, it is often omitted. The su utility, being a part of the core shadow-utils package, is almost universally present, making it the reliable fallback for containerized orchestration.
Security policies in highly regulated environments may mandate the use of su over sudo to centralize password management. In some organizations, the root password is known and rotated centrally, while individual user-level sudo passwords are not managed or are considered a security risk. When only the root password is known, su becomes the primary mechanism for escalation.
The fundamental technical distinction lies in the password authentication model. sudo requires the password of the current user (the one initiating the command), assuming that user has been granted permissions in the /etc/sudoers file. Conversely, su requires the password of the target user. When escalating to root, su demands the root account's password, regardless of who the initiating user is.
Comprehensive Configuration of the su Method
Ansible provides flexibility in how su is configured, allowing administrators to define escalation settings at the global configuration level, within the inventory, or at the specific task level.
Global Configuration via ansible.cfg
The ansible.cfg file allows for a baseline configuration across all playbooks and inventories. This is ideal for environments where every target system follows the same escalation logic.
ini
[privilege_escalation]
become = true
become_method = su
become_user = root
become_ask_pass = true
In this configuration, become = true enables the escalation mechanism. The become_method = su explicitly tells Ansible to use the su binary instead of the default sudo. The become_user = root specifies the target identity. Crucially, become_ask_pass = true ensures that the operator is prompted for the password, as su cannot function without the target user's password unless the current user is already root.
Inventory-Level Configuration
For environments containing a mix of different OS versions or security policies, configuration is best handled within the inventory file. This allows for granular control over which groups of servers use which method.
```ini
[legacyservers]
legacy1 ansiblehost=192.168.1.50 ansibleuser=operator
legacy2 ansiblehost=192.168.1.51 ansible_user=operator
[legacyservers:vars]
ansiblebecome=true
ansiblebecomemethod=su
ansiblebecomeuser=root
```
By placing these variables under the [legacy_servers:vars] section, Ansible applies the su method only to the hosts within that group. This prevents the system from attempting to use su on modern servers where sudo might be the required method.
Execution Dynamics and Playbook Implementation
Running a playbook with the su method requires the provision of the target user's password. While Ansible handles the interaction with the shell, certain environment-specific factors can interfere with the password prompt.
Handling Custom and Internationalized Prompts
Ansible identifies the password prompt by looking for specific strings. In non-English locales or customized shell environments, the standard "Password:" prompt might be different, leading to authentication failures because Ansible does not recognize the prompt. This can be mitigated by using the ansible_su_prompt_l10n variable.
yaml
- name: Handle custom su prompts
hosts: legacy_servers
become: true
become_method: su
become_flags: '-'
vars:
ansible_su_prompt_l10n:
- "Password:"
- "Mot de passe:"
- "Contraseña:"
tasks:
- name: Test connectivity
ansible.builtin.ping:
The become_flags: '-' ensures that a login shell is started, which is critical for loading the target user's environment variables. The ansible_su_prompt_l10n list provides a set of possible strings that Ansible should recognize as the password prompt, ensuring compatibility across multi-lingual deployments.
Comparative Analysis: su vs sudo in Ansible
The behavioral differences between su and sudo extend beyond password requirements. These differences impact the environment and the auditability of the operations.
| Feature | su (Substitute User) | sudo (Superuser Do) |
|---|---|---|
| Password Required | Target user's password (e.g., root) | Current user's password |
| Shell Behavior | Starts a new login shell by default | Executes command in current shell context |
| Environment Variables | Reset to target user's defaults | Often preserves some caller environment |
| Granularity | All or nothing (full user access) | Fine-grained (specific commands allowed) |
| Auditing | No default command logging | Detailed audit trail via /var/log/secure |
Environmental Impact of su
Because su typically starts a new login shell, the environment variables are reset. This is a critical consideration when running scripts that rely on specific paths or configuration variables.
yaml
- name: su-specific considerations
hosts: legacy_servers
become: true
become_method: su
tasks:
- name: Show the environment (su starts a login shell)
ansible.builtin.command: env
register: env_output
- name: Show current user
ansible.builtin.command: whoami
register: user_info
- name: Display results
ansible.builtin.debug:
msg: |
Running as: {{ user_info.stdout }}
HOME: {{ ansible_env.HOME | default('not set') }}
In the above example, the env command reveals that the HOME variable and other environment settings have shifted to those of the root user, rather than maintaining the original session's variables.
Advanced User Escalation Patterns
While su is most commonly used to reach the root account, it can be employed to transition into any service account on the system.
Becoming Non-Root Users
Ansible allows the use of su to assume the identity of service accounts, such as postgres or apache. However, the password requirement remains: the operator must provide the password for that specific service account, or have root access to bypass the password.
```yaml
- name: Run tasks as service accounts
hosts: legacyservers
tasks:
- name: Run database backup as postgres
ansible.builtin.command: pgdump mydb > /tmp/backup.sql
become: true
becomemethod: su
becomeuser: postgres
- name: Check web server files as apache
ansible.builtin.command: ls -la /var/www/html
become: true
become_method: su
become_user: apache
```
In standard Ansible behavior, if you are escalating to a non-root user via su, the system typically escalates to root first and then switches to the target user. This two-step process ensures that the transition to the service account is successful even if the service account itself has no interactive password set.
Managing Hybrid Environments
In large-scale infrastructures, it is common to encounter a "mixed" state where some servers are modern (using sudo) and others are legacy (using su). This requires a flexible approach to inventory and task definition.
Hybrid Inventory Configuration
Using a mixed inventory file allows the administrator to map the correct become_method to the appropriate host group.
```ini
[modernservers]
modern1 ansiblehost=192.168.1.10
[modernservers:vars]
ansiblebecome_method=sudo
[legacyservers]
legacy1 ansiblehost=192.168.1.50
[legacyservers:vars]
ansiblebecomemethod=su
ansiblebecomepass={{ vaultroot_password }}
```
In this setup, modern1 will utilize sudo, while legacy1 will utilize su. The use of {{ vault_root_password }} indicates that the root password is encrypted using Ansible Vault, providing a secure way to handle the sensitive su password.
Task-Level Escalation Overrides
If a specific task requires a different method than the one defined in the inventory, it can be overridden directly within the playbook.
yaml
- name: Tasks on legacy servers
hosts: legacy_servers
tasks:
- name: Install package using su to root
ansible.builtin.yum:
name: httpd
state: present
become: true
become_method: su
become_user: root
Technical Troubleshooting and Diagnostics
When su fails, the error messages can be vague. System administrators should use a combination of manual testing and Ansible's verbosity levels to isolate the root cause.
Manual Validation
Before attempting to automate via Ansible, verify that su is functioning as expected through a manual SSH session.
bash
ssh [email protected] "su - root -c 'whoami'"
This command attempts to SSH into the machine and immediately execute su to root to verify the identity. If this fails manually, the issue is with the system's password or the su configuration, not Ansible.
Ansible Diagnostic Commands
To debug the escalation process, use the -vvvv flag for maximum verbosity and the -K flag to ensure the become password is requested.
bash
ansible legacy_servers -m ping --become --become-method=su -K -vvvv
To verify the presence of the su binary on the remote target, a simple shell module call can be used:
bash
ansible legacy_servers -m shell -a "which su"
Common Error Resolution
There are several recurring errors encountered when using the su method:
su: Authentication failure: This typically indicates that the password provided is incorrect. In the context ofsu, this means the ROOT password was not provided, or the password for the target user is incorrect. Users often mistakenly provide their own user password instead of the root password.su: cannot set groups: Operation not permitted: This error is common in certain containerized environments (like Docker) where the container lacks theSYS_ADMINcapability or the specific permissions to modify group IDs. In such cases, the administrator may need to check the container's security profile or switch thebecome_methodtosudoif available.
Pipelining Considerations with su
Pipelining is an Ansible feature that reduces the number of SSH connections by executing modules without transferring them to the remote server's disk. However, pipelining can be problematic when combined with su.
Because su alters the way commands are passed to the shell and changes the environment, it can interfere with the way Ansible pipes the module code to the remote host. If pipelining is enabled in ansible.cfg, and su is used, you may encounter unexpected failures during the execution of the module. Testing with pipelining disabled can help determine if this is the cause of the failure.
Conclusion
The implementation of su as a become_method in Ansible is a critical capability for managing legacy and restricted environments. While sudo is preferred for modern security and auditability, su remains indispensable for systems where sudo is not an option. The transition to su requires a precise understanding of the target user's password model and the implications of starting a login shell. By leveraging inventory variables, Ansible Vault for password security, and internationalized prompt handling, administrators can maintain a consistent and secure automation framework across diverse and fragmented infrastructure landscapes. The ability to mix escalation methods within a single playbook ensures that Ansible can scale from the most modern cloud-native environments down to the most restrictive legacy hardware.