When managing heterogeneous environments where each server has distinct sudo passwords, Ansible's default -K
(--ask-become-pass) behavior falls short. The system attempts to reuse a single sudo password across all hosts, causing authentication failures when passwords differ.
Option 1: SSH Agent Forwarding with Sudo Password Caching
# In ~/.ansible.cfg
[privilege_escalation]
become = True
become_method = sudo
become_ask_pass = True
Option 2: Per-Host Vault Variables
# group_vars/all/vault.yml
ansible_become_pass: "{{ vault_sudo_pass }}"
# Command to encrypt:
ansible-vault encrypt group_vars/all/vault.yml
# To run:
ansible-playbook playbook.yml --ask-vault-pass
Create a custom vars plugin (requires Python):
# In ansible.cfg
vars_plugins = /path/to/plugins
# per_host_passwords.py
from ansible.plugins.vars import BaseVarsPlugin
class VarsModule(BaseVarsPlugin):
def get_vars(self, loader, path, entities):
sudo_passwords = {
'host1': 'secret1',
'host2': 'secret2'
}
return {'ansible_become_pass': sudo_passwords.get(entities[0].name)}
Always ensure:
- Vault files are encrypted at rest
- Custom plugins have strict file permissions (600)
- Limit sudo privileges in /etc/sudoers
# inventory.ini
[web_servers]
host1 ansible_become_pass="{{ lookup('env', 'HOST1_PASS') }}"
host2 ansible_become_pass="{{ lookup('vault', 'host2_pass') }}"
# Execution:
HOST1_PASS=secret1 ansible-playbook -i inventory.ini deploy.yml
When managing heterogeneous environments with Ansible, the sudo password heterogeneity problem emerges as a significant operational hurdle. Unlike SSH key authentication which scales seamlessly, sudo password prompts create a bottleneck in parallel execution. Let's examine why the traditional -K
approach fails:
# Typical failure scenario
ansible-playbook -i inventory.ini deploy.yml --ask-become-pass
# Host1 success | Host2-N failure due to password mismatch
1. Vault-Protected Host Variables
The most secure approach combines Ansible Vault with host variables:
# inventory.ini
[web_servers]
host1 ansible_become_pass="{{ vaulted_host1_pass }}"
host2 ansible_become_pass="{{ vaulted_host2_pass }}"
# Encrypt with vault
ansible-vault encrypt_string 's3cret1' --name 'vaulted_host1_pass'
2. Dynamic Password Retrieval
For environments with existing secret management:
# playbook.yml
- name: Retrieve sudo passwords
hosts: all
tasks:
- name: Fetch per-host sudo creds
set_fact:
ansible_become_pass: "{{ lookup('hashi_vault',
'secret=sshcreds/data/{{ inventory_hostname }}:password') }}"
3. Privilege Escalation Proxy
Create a dedicated bastion for privilege escalation:
# ansible.cfg
[privilege_escalation]
become_method = enable
become_flags = '-u {{ vaulted_user }} -p {{ vaulted_pass }}'
become_plugin = teleport_proxy
4. SSH Certificate Authority
Transition to short-lived certificates:
# Issue host-specific certs
ssh-keygen -s ca_key -I host1 -n root host1.pub
# ansible.cfg
[ssh_connection]
ssh_args = -o CertificateFile=creds/{{ inventory_hostname }}-cert.pub
When evaluating these solutions, consider:
- Audit trail requirements (vault provides clearest logging)
- Rotation frequency (dynamic lookup most flexible)
- Performance impact (certificates add ~200ms per host)
Combining vault with dynamic inventory:
# group_vars/all/vault.yml
host_passwords:
host1: !vault |
$ANSIBLE_VAULT;1.1;AES256
306132633632...
# tasks/main.yml
- name: Apply host-specific sudo
ansible.builtin.raw: "echo {{ host_passwords[inventory_hostname] }} | sudo -S command"
become: false