Every Ansible task runs in two stages: an SSH login as a regular user (called the
connection user), then optionally a privilege escalation via sudo
or su to become root or another account. The two steps are configured separately
so you can SSH in as deploy but install packages as root.
# ed25519 is faster and stronger than the default RSA-2048
ssh-keygen -t ed25519 -C "ansible@$(hostname)" -f ~/.ssh/id_ed25519
# leave passphrase empty if you'll run from CI/cron, otherwise set one
# (you'll typically use ssh-agent to unlock it once per session)
ls -l ~/.ssh/id_ed25519*
# id_ed25519 (private — never share)
# id_ed25519.pub (public — distribute freely)
id_ed25519) to git. Add id_* patterns to .gitignore in any repo that contains a ~/.ssh/ mirror. The public key (.pub) is safe to commit and copy around.# the easy way: ssh-copy-id (asks for the user's password once)
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@192.168.56.11
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@192.168.56.12
# the manual way (if ssh-copy-id is not available)
cat ~/.ssh/id_ed25519.pub | ssh deploy@192.168.56.11 \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# verify password-less login works
ssh deploy@192.168.56.11 hostname
# → db1.example.com (no password prompt)
Ansible can pass the sudo password through --ask-become-pass, but for unattended
runs you'll want a passwordless sudo entry for the deploy user. Add this on each managed
node (one time, manually):
# on each managed node, as root:
echo 'deploy ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/deploy
sudo chmod 0440 /etc/sudoers.d/deploy
# validate the file before logging out
sudo visudo -c -f /etc/sudoers.d/deploy
# → /etc/sudoers.d/deploy: parsed OK
NOPASSWD: ALL means anyone who can SSH as deploy can also become root. Protect the deploy account: enforce key-only auth, no password login, and restrict ~/.ssh/authorized_keys with from= entries to your control node IP.
become: true tells Ansible to escalate privilege for that task. By default it uses
sudo to become root. You can target a different user with become_user:
---
- name: Configure database servers
hosts: databases
remote_user: deploy # SSH in as deploy
become: true # then sudo to root for tasks below
become_method: sudo # default — also sudo, su, doas, pbrun, ...
tasks:
- name: Install MySQL package
ansible.builtin.dnf:
name: mysql-server
state: present
- name: Initialise mysql data dir
ansible.builtin.command: mysqld --initialize-insecure
become_user: mysql # this single task runs as the mysql account
args:
creates: /var/lib/mysql/ibdata1
You can also override become at the task level:
---
- name: Run two tasks with different escalation
hosts: webservers
remote_user: deploy
tasks:
- name: Read user's own files (no escalation needed)
ansible.builtin.command: cat ~/notes.txt
# become defaults to false — runs as deploy
- name: Restart nginx (root needed)
ansible.builtin.systemd:
name: nginx
state: restarted
become: true # this single task escalates
# inventory file
cat > hosts.ini <<EOF
[databases]
192.168.56.11
192.168.56.12
[databases:vars]
ansible_user=deploy
EOF
# ping (tests SSH only)
ansible -i hosts.ini databases -m ansible.builtin.ping
# whoami without become — should report 'deploy'
ansible -i hosts.ini databases -m ansible.builtin.command -a "whoami"
# whoami with become — should report 'root'
ansible -i hosts.ini databases -m ansible.builtin.command -a "whoami" --become
root for every host, your auth chain is correct. From here on, every playbook in this series will assume key-based SSH + passwordless sudo.