Chapter 3: Implementing an Ansible Playbook
Managing Ansible configuration files
Two small files in your project directory shape how every command behaves: ansible.cfg tells Ansible where the inventory is, how to log in and how to become root, and ansible-navigator.yml tells navigator which execution environment to use and how to run.
- Write an
ansible.cfgwith[defaults]and[privilege_escalation]sections. - Predict which configuration file Ansible and navigator will actually use.
- Set up SSH key authentication and sudo so playbooks run without prompts.
Two files per project
Configures Ansible itself: inventory location, remote user, connection options, privilege escalation. Read by every Ansible tool.
Configures ansible-navigator: which execution environment image, when to pull it, whether to write playbook artifacts, default mode.
Writing ansible.cfg
The file is made of sections, each holding key = value settings. Section names are in square brackets. For basic work you need two sections:
[defaults]sets defaults for how Ansible operates and connects.[privilege_escalation]configures how Ansible becomes another user (usually root) on managed hosts.
[defaults]
inventory = ./inventory
remote_user = user
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false| Directive | What it does |
|---|---|
inventory | Path to the inventory file (or a directory of inventory files and scripts). |
remote_user | User to log in as on managed hosts. If unset, the current user's name is used. Inside an execution environment run by ansible-navigator, that is always root. |
ask_pass | Prompt for an SSH password? false is the default and is right when you use SSH keys. |
become | Switch user on the managed host (typically to root) after connecting? Plays can override this. |
become_method | How to switch users. sudo is the default; su is an alternative. |
become_user | User to switch to. Defaults to root. |
become_ask_pass | Prompt for the become_method password? Defaults to false. |
Here is how those settings line up along the path from your terminal to a task running as root:
Connecting and escalating privileges: Ansible logs in as the remote user with an SSH key, then uses sudo to become root before running the task.
Which configuration file wins?
Ansible looks for its configuration in several places, uses the first file it finds, and ignores the rest. Settings are not merged across files. Toggle the files below to see which one Ansible would use.
Checking the active settings
ansible-navigator config shows every setting, its default, where the current value came from, and the value in effect:
Name Default Source Current
...output omitted...
44│Default ask pass True default False
45│Default ask vault pass True default False
46│Default become False /home/student/project/ansible.cfg True
47│Default become ask pass False /home/student/project/ansible.cfg True
...output omitted...
50│Default become method False /home/student/project/ansible.cfg sudo
51│Default become user False /home/student/project/ansible.cfg rootRead the Default column carefully: True means "this setting is still at its default value", not that the setting itself is true. Here become and become_ask_pass were set in the project's ansible.cfg (Default is False, Source is the file, Current is True). Press Esc or type :q to leave.
Configuring automation content navigator
Navigator reads its own settings file, in YAML (.yml or .yaml) or JSON. It uses the first one it finds:
Like ansible.cfg, each project can have its own navigator settings. A typical file:
ansible-navigator:
execution-environment:
image: utility.lab.example.com/ee-supported-rhel8:latest
pull:
policy: missing
playbook-artifact:
enable: falseexecution-environmentgroups the settings for the EE that navigator uses.imageis the container image to run.pull.policy: missingpulls the image only if it is not already present locally.playbook-artifact.enable: falsestops navigator writing a JSON log of each run. You must disable artifacts whenever a playbook needs to prompt for a password.
At home there is no image to name. The file from section 1.6 switches the execution environment off instead, so navigator runs workstation's own ansible-core:
---
ansible-navigator:
mode: stdout
playbook-artifact:
enable: false
execution-environment:
enabled: falseA project-level ansible-navigator.yml replaces this file rather than adding to it. If an exercise has you create one, keep the execution-environment: enabled: false lines in it.
Configuring connections
Ansible needs to know several things to reach its managed hosts:
- where the inventory is,
- which protocol to use (SSH by default) and whether a non-standard port is needed,
- which remote user to log in as, and
- whether and how to escalate privileges, and whether to prompt for passwords.
Inventory location
[defaults]
inventory = ./inventoryThe path can point at a single static file or at a directory holding several inventory files and dynamic inventory scripts.
SSH key authentication
By default Ansible logs in as the same user name as the person running it; remote_user changes that. If the local user has an SSH private key that the remote user trusts, Ansible logs in automatically. That is how you should set things up.
[user@controlnode ~]$ ssh-keygenssh-copy-id also records the host key in your ~/.ssh/known_hosts.
[user@controlnode ~]$ ssh-copy-id root@web1.example.com
The authenticity of host 'web1.example.com (192.0.2.181)' can't be established.
ECDSA key fingerprint is 70:9c:03:cd:de:ba:2f:11:98:fa:a0:b3:7c:40:86:4b.
Are you sure you want to continue connecting (yes/no)? yes
...output omitted...
Number of key(s) added: 1[user@controlnode ~]$ ssh root@web1.example.comIf you must use passwords
Password-based SSH works, but ansible-navigator then needs playbook artifacts disabled so it can prompt you:
ansible-navigator:
playbook-artifact:
enable: falseThen run with -m stdout and --ask-pass (or set ask_pass = true in ansible.cfg to always be prompted):
[user@controlnode ~]$ ansible-navigator run -m stdout --ask-pass site.ymlEscalating privileges
For security and auditing, you often connect as an unprivileged user and then escalate to root. That is configured in [privilege_escalation]:
become = trueturns escalation on by default. Ad hoc commands and plays can still override it, for example for a play that should run unprivileged.become_methodchooses how (defaultsudo) andbecome_userchooses whom to become (defaultroot).- If the method needs a password, set
become_ask_pass = true. Withansible-navigatorthat also means disabling playbook artifacts and using-m stdout.
On RHEL 8 and 9, members of the wheel group can use sudo after typing their password. To let an automation user use sudo without a password, drop a file into /etc/sudoers.d/ (owned by root, mode 0400):
## password-less sudo for Ansible user
someuser ALL=(ALL) NOPASSWD:ALLWith key-based SSH as someuser and password-less sudo, the whole configuration becomes:
[defaults]
inventory = ./inventory
remote_user = someuser
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = falseComments
Both files accept # at the start of a line as a comment. ansible.cfg also accepts ;, which comments out everything to its right.
# The whole line is a comment
[defaults]
inventory = ./inventory ; the rest of this line is a comment- Your project has `./ansible.cfg` and you also have `~/.ansible.cfg`. `ANSIBLE_CONFIG` is not set. Which settings apply?
- You set `become_ask_pass = true`, and `ansible-navigator run site.yml` hangs. What is most likely missing?
- Which `ansible.cfg` directive names the user Ansible logs in as on managed hosts?
Takeaway
Write an ansible.cfg with [defaults] and [privilege_escalation] sections. Use the chapter lab to check this on a real host.