AnsibleVI · Configuration and PrecedenceConfiguration and precedence
The settings you will be tempted to weaken
What you'll learn
- State exactly what host_key_checking = False disables and what it does not
- Replace it with a managed known_hosts, an SSH certificate authority, or provisioning-time key capture
- Detect a StrictHostKeyChecking=no override that HOST_KEY_CHECKING still reports as True
- Judge deprecation warnings and retry files by what turning them off costs later
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
Four settings account for most of the security debt in Ansible configurations, and all four get changed for the same reason: something was in the way and turning it off made the run work.
This lesson takes each one, says precisely what it disables, names the incident it enables, and gives the compensating control — because “do not turn it off” is not useful advice to somebody whose run is failing right now.
host_key_checking = False
$ ansible-config dump | grep '^HOST_KEY_CHECKING'HOST_KEY_CHECKING(default) = TrueWhat it actually disables
It disables authentication of the server. Nothing else.
Your traffic is still encrypted. Your key still authenticates you to the far end. What stops is the check that the machine answering on that address is the machine whose host key you recorded previously.
That distinction matters, because “it is still encrypted” is the argument people reach for, and it is true and irrelevant. An encrypted session with an attacker is an encrypted session with an attacker.
The incident it enables
The classic scenario is not a hypothetical MITM on the wire. It is this:
A production database host is re-provisioned. It comes up with a new host
key. Ansible fails on it, because the key does not match known_hosts.
Somebody sets host_key_checking = False in the project config, the run
succeeds, and the setting stays.
Now consider the same symptom with a different cause. An attacker who can influence DNS, ARP or a jump host redirects that hostname to a machine they control. Ansible connects, sees a key that does not match, and — with checking disabled — proceeds. It authenticates with your key, runs your playbook, and hands the attacker whatever the playbook carries: vault contents, deployment credentials, sudo access on a machine they now control, and a confirmed inventory of your fleet.
Host key checking is the only mechanism that distinguishes those two cases. Disabling it means you have decided never to be able to tell them apart, permanently, for the convenience of a re-provisioning event that happens a few times a year.
StrictHostKeyChecking=no in ssh_args
This is the same weakening through a different door, and it is worse in two specific ways.
The default ssh_args on 2.21.3 is:
$ ansible-config dump -t connection | grep '^ssh_args'ssh_args(default) = -C -o ControlMaster=auto -o ControlPersist=60sSet ssh_args = -o StrictHostKeyChecking=no in [ssh_connection] and two
things happen.
ssh_args replaces rather than appends. Verified on 2.21.3: the
effective value becomes exactly -o StrictHostKeyChecking=no, and
compression plus connection multiplexing are silently gone. Losing
ControlMaster=auto and ControlPersist=60s means a fresh SSH handshake
for every task on every host, which on a large fleet is a substantial and
mystifying slowdown that arrives bundled with the security regression.
No audit sees it. This is the part worth remembering:
$ ansible-config dump | grep '^HOST_KEY_CHECKING'HOST_KEY_CHECKING(default) = True$ ansible-config dump --only-changedCONFIG_FILE() = /srv/estate/ansible.cfg
GALAXY_SERVERS:Illustrative output
Both confirmed on 2.21.3. An estate carrying this override passes a review
that greps for HOST_KEY_CHECKING, and passes a review that runs
ansible-config dump --only-changed, while host key verification is off.
deprecation_warnings = False
$ ansible-config dump | grep '^DEPRECATION_WARNINGS'DEPRECATION_WARNINGS(default) = TrueDeprecation warnings are the only advance notice you get that an upgrade will break something. Each one names a construct that still works today and will not in some future release, which is precisely the information you need to plan an upgrade rather than to discover one.
Turning them off does not remove the deprecation. It removes the warning,
and converts a planned migration into an outage on the day somebody
upgrades ansible-core.
The temptation is real: one noisy deprecation from one third-party collection can produce hundreds of lines per run and drown output you need to read.
The compensating control is to fix or ticket the specific warning
rather than to silence the category. If you must silence it while the
ticket is open, do it per invocation — ANSIBLE_DEPRECATION_WARNINGS=False
in the one job that is drowning — not in the project config, and record
the expiry the same way an inventory exception carries one. A silenced
warning with no ticket and no date is an upgrade you have decided to be
surprised by.
retry_files_enabled
This one is worth correcting, because the advice you will read online predates the current default:
$ ansible-config dump | grep -E '^RETRY_FILES'RETRY_FILES_ENABLED(default) = False
RETRY_FILES_SAVE_PATH(default) = NoneSo this is not a setting you are tempted to weaken — it is one you are
tempted to enable, usually after a partial failure, so that a rerun
can target only the hosts that failed with --limit @site.retry.
Two reasons to be careful.
It writes a fleet host list to disk. The .retry file contains the
names of the hosts that failed, written next to the playbook by default —
which for a shared controller may be a directory other people can read.
That is an inventory disclosure, small on its own and useful to anybody
enumerating your estate.
A retry file is a stale target set. It records which hosts failed at the moment the run ended. By the time you rerun, some may have recovered, others may have been fixed by hand, and the set may no longer correspond to anything meaningful. Re-running against a saved list is a change with a blast radius nobody re-derived.
If you enable it, set retry_files_save_path to a directory only the
automation account can read, and treat the file as evidence — a record
of which hosts failed, to be read — rather than as an input to be piped
back into --limit. When you do rerun, re-derive the target set from the
current state of the fleet.
Knowledge check
Knowledge check · 4 questions
Q1. What exactly does host_key_checking = False disable?
Q2. Setting ssh_args = -o StrictHostKeyChecking=no in [ssh_connection] on 2.21.3 has which effects? Select all that apply.
Q3. An SSH certificate authority removes the operational problem that motivates disabling host key checking, rather than trading the check away for convenience.
Q4. On ansible-core 2.21.3, what is the correct statement about retry_files_enabled?
Passing score: 75%. Answers are checked in this browser.