About ansible
A skill for writing, reviewing, and planning Ansible automation, from playbooks and reusable roles to operational workflows and compliance hardening. It is intended for infrastructure teams and coding agents, emphasizing idempotence, validation, and safe production practices.
Key features
- 01Playbook, role, and collection guidance
- 02Inventory, Vault, and execution environment operations
- 03Compliance hardening patterns
- 04Molecule testing and linting workflow
- 05Idempotence and production safety checks
- 06CI/CD integration guidance
Use cases
- 01Automating server configuration after provisioning
- 02Hardening hosts against compliance requirements
- 03Creating reusable roles and testing them
- 04Reviewing playbooks before production execution
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ iuliandita/ skills --skill ansibleAfter installing, type/ansiblein Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/agent-hygiene.mdcompliance.mdoperations-and-execution.mdoutput-contract.mdplaybook-patterns.mdproduction-checklist.mdroles-and-collections.mdvault-and-secrets.mdDetails
From the project READMEAnsible: Production Configuration Management
Write, review, and architect Ansible automation - from single playbooks to multi-tier, compliance-hardened infrastructure management. The goal is idempotent, auditable, maintainable automation that works the same locally and in CI/CD.
Target versions (October 2026):
- ansible-core 2.21.4 (current stable, Python 3.12+ controller); verify managed-node Python support and branch EOL in the support matrix before pinning
- ansible (community package) 14.4.0 (depends on ansible-core 2.21)
- molecule 26.9.0, ansible-lint 26.9.0, ansible-navigator 26.9.0 (CalVer)
- ansible-builder 3.1.1 (EE definition v3)
- AWX 24.6.1 (last formal release Jul 2024; upstream AWX releases paused for a major refactor, devel branch active - track ansible/awx; awx-operator ~2.19.x still ships for K8s deploys). Verify current AWX/AAP release status before recommending a specific version or install path.
- AAP 2.7 (current stream); verify supported installation methods and patch builds in the vendor lifecycle documentation before deployment
This skill covers four domains depending on context:
- Playbooks - tasks, handlers, variables, conditions, loops, blocks, templates, Jinja2
- Roles & Collections - role structure, collection packaging, Galaxy/Automation Hub, Molecule testing
- Operations - inventory, Execution Environments, CI/CD integration, Vault, ansible-navigator
- Compliance - PCI-DSS 4.0 hardening, CIS benchmarks, Ansible-Lockdown, audit logging
When to use
- Writing or reviewing Ansible playbooks, roles, or collections
- Configuring servers after Terraform provisions them (day-2 operations)
- OS hardening (CIS benchmarks, STIG, PCI-DSS configuration requirements)
- Managing packages, services, users, firewall rules, cron jobs, config files
- Testing automation with Molecule or tox-ansible
- Setting up Ansible Vault for secrets management
- Designing inventory structures (static, dynamic, multi-environment)
- Building Execution Environments for consistent runtime
- Integrating Ansible into CI/CD pipelines (GitLab CI, GitHub Actions)
- Reviewing AI-generated playbooks for correctness and idiomatic patterns
When NOT to use
- Infrastructure provisioning (VPCs, RDS, EC2, cloud resources) - use terraform
- Kubernetes manifests, Helm charts, cluster architecture - use kubernetes
- Dockerfiles, Compose stacks, container image optimization - use docker
- CI/CD pipeline design (stages, runners, caching) - use ci-cd
- Security audits of application code (SAST, dependency scanning) - use security-audit
- Shell scripting or one-off commands - use shell-scripting
- Firewall appliance management (OPNsense/pfSense) - use opnsense-pfsense
- Single-machine OS-level admin questions (package setup, user management, service config without automation context) - use the appropriate distro skill: debian-ubuntu, rhel-fedora, kali-linux, or arch-linux
AI Self-Check
AI tools consistently produce the same Ansible mistakes. Before returning any generated playbook, role, or task, verify against this list:
- FQCNs used everywhere (
ansible.builtin.copy, notcopy). AI almost never does this unprompted. -
become: truepresent where privilege escalation is needed (AI often forgets this) -
no_log: trueon every task handling secrets, passwords, tokens, or API keys (CVE-2024-8775 proved this matters) - Every task has a descriptive
name:field (AI sometimes omits names on simple tasks) - Handler names are unique and
notify:strings match exactly (typos = silent failures) - Variables use
{{ var }}with quotes:"{{ my_var }}"not{{ my_var }}(bare Jinja2 without quotes breaks YAML parsing) - No
command/shell/rawwhen an Ansible module exists for the operation - Tasks are idempotent - running twice produces the same result (watch
command/shelltasks withoutcreates/removes) - No hardcoded values - IPs, paths, package versions, usernames go in variables with defaults
-
ansible.builtin.apt/ansible.builtin.dnfusestate: present, notstate: latest(unless explicitly upgrading) - Loop variable is
item(default) or renamed vialoop_varin nested loops (AI conflates loop variables) -
block/rescue/alwaysused for error handling, not bareignore_errors: true - No
ansible.builtin.templatewithsrc:pointing to a non-.j2file (confusing, even if it works) -
changed_when/failed_whenset oncommand/shelltasks to prevent false change reports - Tags present on logical task groups for selective execution
- Collection docs checked: module arguments and return values match the installed collection version
- Idempotence proven: changed/ok behavior is verified with check mode or a second run where practical
- Cross-cutting agent hygiene applied - see
references/agent-hygiene.md
Performance
- Use targeted inventories, tags, and
--limitfor large fleets; avoid full-fleet runs while iterating on a single role. - Gather only required facts and cache facts where supported for slow or high-latency environments.
- Prefer native modules over shell loops so Ansible can batch work, diff safely, and report idempotence.
Best Practices
- Pin collection versions in
requirements.ymlfor production automation. - Run destructive playbooks with
--check --difffirst and require a human-reviewed limit for production hosts. - Keep Vault values out of diffs, logs, callback output, and generated examples.
Workflow
Copy this checklist and track progress:
- Step 1: Domain identified
- Step 2: Requirements gathered (target OS, privilege, connection, secrets, inventory)
- Step 3: Playbook, role, or config built
- Step 4: Syntax check, lint, and
--check --diffclean (on any failure, fix and return to Step 3) - Production checklist and AI Self-Check passed
Step 1: Determine the domain
Based on the request:
- "Write a playbook to configure X" -> Playbooks
- "Create a reusable role for X" -> Roles & Collections
- "Set up inventory" / "CI/CD" / "vault" / "EE" -> Operations
- "Harden this server" / "CIS benchmark" / "PCI compliance" -> Compliance
- "Review this playbook/role" -> Apply production checklist + critical rules + AI self-check
Most real tasks blend domains. Start with the playbook, extract to roles when reuse is clear, wire into operations last.
Step 2: Gather requirements
Before writing YAML, determine:
- Target OS: RHEL/CentOS, Ubuntu/Debian, Alpine, Windows - affects module choices
- Python version on targets: check managed-node support for the pinned ansible-core in the support matrix linked under Target versions
- Privilege escalation:
becomemethod (sudo, su, doas, runas for Windows) - Connection: SSH (default), WinRM (Windows), local, network_cli (network devices)
- Idempotency: every task must be safe to run multiple times
- Secrets: Ansible Vault, HashiCorp Vault, CI/CD secrets, environment variables
- Testing: Molecule scenario? tox-ansible matrix? Integration tests?
- Compliance: PCI-DSS scope? CIS benchmark level? STIG profile?
- Inventory: static, dynamic (cloud), or hybrid? Multi-environment?
- Execution: ansible-playbook (direct), ansible-navigator (EE), AWX/AAP (platform)?
Step 3: Build
Follow the domain-specific section below. Always run Step 4, the production checklist in references/production-checklist.md, and the AI self-check before finishing.
Step 4: Validate
Run syntax check, lint, and --check --diff in order. On any failure, fix the reported issue, return to Step 3, and rerun from the syntax check; finish only when all three are clean.
# Syntax check (fast, no connection needed)
ansible-playbook playbook.yml --syntax-check
# Lint (use production profile for strictest checks)
if command -v ansible-lint >/dev/null; then
ansible-lint --profile production playbook.yml
else
echo "ansible-lint not installed: lint NOT run; report it as unverified"
fi
# Dry run (needs inventory + connectivity)
ansible-playbook playbook.yml --check --diff
For roles only, add Molecule when a scenario exists:
if command -v molecule >/dev/null; then
molecule test # full cycle: create, converge, verify, destroy
# molecule converge # just apply (dev loop)
# molecule verify # run verification only
else
echo "molecule not installed: role tests NOT run; report them as unverified"
fi
Any non-check run applies changes. Run it only with --limit, and get human approval before targeting production hosts:
# Navigator (EE-based execution)
ansible-navigator run playbook.yml --mode stdout --eei <ee-image> --limit <hosts>
Playbooks
Read references/playbook-patterns.md for complete, copy-pasteable task examples (services, packages, files, templates, users, firewall, cron, systemd, OpenRC) and Jinja2 patterns.
Structure
---
- name: Configure web servers
hosts: webservers
become: true
gather_facts: true
vars:
app_port: 8080
app_user: appuser
pre_tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
when: ansible_os_family == "Debian"
roles:
- role: common
tags: [common]
- role: nginx
tags: [nginx]
tasks:
- name: Ensure application directory exists
ansible.builtin.file:
path: /opt/app
state: directory
owner: "{{ app_user }}"
mode: "0755"
handlers:
- name: Restart nginx
ansible.builtin.systemd:
name: nginx
state: restarted
daemon_reload: true
Key patterns
Variable precedence (22 levels; the most important are, in ascending priority):
- Role defaults (
defaults/main.yml) - weakest, meant to be overridden - Inventory vars (
group_vars/,host_vars/) - Play vars
- Task vars
- Extra vars (
-e) - strongest, overrides everything
Rule of thumb: put defaults in role defaults/, environment-specific values in group_vars/, one-off overrides in host_vars/, and emergency overrides via -e.
Handlers: only run when notified by a changed task, execute once at the end of the play (not immediately). Key gotchas:
- Handler names must be unique across all included roles
- Handlers don't run if the play fails before reaching them (use
meta: flush_handlersif needed) - Handlers run in definition order, not notification order
- Multiple notifications to the same handler = one execution
Blocks: use block/rescue/always for error handling and rollback - see playbook-patterns.md for complete deploy-with-rollback examples. Prefer block/rescue over ignore_errors: true.
Loops: prefer loop: over the older with_* lookup syntax. Use loop_control.label for clean output.
Conditional execution: when: ansible_os_family == "Debian" etc. For multi-OS roles, use conditionals or include_tasks per OS family. See playbook-patterns.md for Alpine/OpenRC patterns.
Service management: use ansible.builtin.service (generic) for cross-distro roles - it auto-detects systemd, OpenRC, SysV via ansible_service_mgr. Only use ansible.builtin.systemd when you need systemd-specific features (daemon_reload, scope). See playbook-patterns.md for OpenRC patterns.
Shell profile changes: when converting a manual shell profile tweak into Ansible,
prefer a dedicated reusable role with ansible.builtin.blockinfile, role-prefixed
defaults, and a dedicated rollout playbook. See references/operations-and-execution.md;
the block must guard on SSH, not already inside
tmux, real TTY on stdin/stdout, and usable TERM, so automation, scp, rsync,
and remote SSH commands are not hijacked.
Registering results: register: result_var stores task output. Use when: result_var.stat.exists, result_var.rc == 0, etc. See playbook-patterns.md for patterns.
Vault Quick Reference
# Encrypt a single variable (inline in YAML)
ansible-vault encrypt_string --prompt --name 'db_password'
# Encrypt an entire file
ansible-vault encrypt group_vars/production/secrets.yml
# Edit encrypted file
ansible-vault edit group_vars/production/secrets.yml
# Run playbook with vault
ansible-playbook site.yml --ask-vault-pass
# Or with a password file (for CI/CD)
ansible-playbook site.yml --vault-password-file ~/.vault_pass
Never store the vault password in plaintext alongside the repo. Use --ask-vault-pass, a password file outside the repo, or a vault script that fetches from a secret manager.
What NOT to write
command: apt-get install -y nginx(useansible.builtin.apt)shell: systemctl restart nginx(useansible.builtin.systemd)shell: useradd deploy(useansible.builtin.user)copywithoutmode:on sensitive files (defaults to umask, unpredictable)templatewithout.j2extension on the source fileignore_errors: truewithout a comment explaining why (useblock/rescueinstead)- Blind
with_itemstolooprewrites: both are supported; preferloopfor simple lists, and preserve single-level flattening withflatten(1)when needed - Bare
{{ var }}without quotes (YAML parses it as a dict start) gather_facts: true+ never using facts (wasted 5-15 seconds per host)- Tasks without
name:(legal but unreadable in output) state: latestin production playbooks (non-deterministic - pin versions)
Roles & Collections
Read references/roles-and-collections.md for detailed role anatomy, collection structure, Galaxy patterns, and Molecule testing workflows.
- Use one responsibility per role.
- Put user-tunable values in
defaults/main.yml, notvars/main.yml. - Use FQCNs everywhere.
- Prefix role variables to avoid collisions.
- Treat Molecule idempotence checks as mandatory for roles that have a scenario, not optional polish.
Operations
- Read
references/operations-and-execution.mdfor inventory layout,ansible.cfg, execution environments, CI/CD integration, andansible-navigator. - Keep inventory split by environment.
- Prefer YAML inventory over legacy INI when touching existing inventories.
- Treat
pipelining = True, fact caching, and callback configuration as standard production defaults. - Use execution environments for repeatable local and CI runs.
- Keep vault usage in
references/vault-and-secrets.md; secrets stay encrypted, prefixed, and wrapped withno_log: true.
Compliance
Read references/compliance.md for the full PCI-DSS 4.0 requirements mapping to Ansible controls, CIS benchmark automation, and hardening patterns.
- Ansible owns OS and service enforcement, not application-level security review.
- CIS and PCI controls should be treated as role and template inputs, not blindly applied defaults.
- Test benchmark hardening in staging before broad rollout.
- Preserve audit evidence with callback plugins, AWX/AAP activity streams, or CI artifacts.
Deprecations and Breaking Changes
ansible-core 2.20
Removals (already removed):
smarttransport value - choosesshorparamikoexplicitly- Galaxy v2 API support - Galaxy servers must support v3
PARAMIKO_HOST_KEY_AUTO_ADDandPARAMIKO_LOOK_FOR_KEYSconfig keyspasslib_or_cryptAPI from encrypt utility
Deprecations (removal in 2.24):
INJECT_FACTS_AS_VARSdefaults to True but will flip to False. Access facts viaansible_facts['hostname']instead ofansible_hostname.ansible.module_utils._textimports (to_bytes,to_native,to_text) - useansible.module_utils.common.text.convertersinsteadvarsinternal variable cache
ansible-core 2.19 (previous)
- Data Tagging overhaul: improved error reporting but some loop templates broke (GitHub issue #85605). If loops fail with type errors after upgrading, check for native Jinja2 type handling conflicts.
CalVer migration
All Ansible DevTools projects (molecule, ansible-lint, ansible-navigator, tox-ansible) switched from SemVer to CalVer (YY.MM.MICRO) in 2024. Don't be confused by the version jump (e.g., ansible-lint 6.x -> 26.x).
Security Considerations
CVEs to know
| CVE | Severity | Description | Mitigation |
|---|---|---|---|
| CVE-2024-11079 | Low | Hostvars bypass unsafe content protections, enabling arbitrary code execution via templated content | Upgrade to ansible-core >= 2.16.14, 2.17.7, or 2.18.1 |
| CVE-2024-8775 | Medium | Vault-encrypted variables exposed in plaintext via include_vars without no_log | Add no_log: true to all secret-handling tasks |
| CVE-2025-14010 | Medium | community.general exposes Keycloak credentials in verbose output | Upgrade to community.general >= 12.0.0 (or 11.4.1 / 10.7.6), i.e. the ansible package >= 12.2.0 |
| CVE-2025-49520 | High | EDA authenticated argument injection in Git URL (command execution) | Patch AAP/EDA |
| CVE-2025-49521 | High | EDA template injection via Git branch/refspec (command execution) | Patch AAP/EDA |
Checked 2026-09-10: CVE-2026-16493
is a high-severity collection-install argument injection, missed by the role-install fix for
CVE-2026-11332. Review git sources in requirements.yml; use trusted Galaxy/Automation Hub
sources and the vendor's fixed build. The retrieved vendor record does not establish an upstream
fixed-version range, so do not assume the target pin alone proves remediation.
Supply chain
- Galaxy has no package signing or hash verification. Academic research (2025) found 45 vulnerable dependency chains across 482 Galaxy repos, with 38-54% code overlap propagating vulnerabilities.
- Pin collection versions in
requirements.yml. Prefer Automation Hub (Red Hat certified) over Galaxy for production-critical collections. - Pin GitHub Actions to commit SHAs in CI/CD (not mutable tags).
- Scan EE images for CVEs like any container image.
AI-generated playbook risks
- AI tools hallucinate module names and parameters. Verify every module exists in the target collection version.
- AI rarely adds
no_log: trueto secret-handling tasks. - AI generates non-idempotent
command/shelltasks where modules exist. - AI uses bare module names instead of FQCNs.
- Slopsquatting: AI may suggest Galaxy roles or collections that don't exist. Verify on Galaxy before adding to
requirements.yml.
Reference Files
references/playbook-patterns.md- playbook and task patterns for common automation workreferences/production-checklist.md- playbook, role, operations, and PCI-DSS checklists; run before finishing any build or reviewreferences/roles-and-collections.md- role anatomy, collection structure, Galaxy patterns, and Molecule workflowsreferences/operations-and-execution.md- inventory layout, ansible.cfg, execution environments, CI/CD integration, and navigator usagereferences/vault-and-secrets.md- Vault usage, secret handling, and external secret-manager integrationreferences/compliance.md- PCI-DSS and CIS-oriented hardening guidance
Output Contract
See references/output-contract.md for the full contract.
- Skill name: ANSIBLE
- Deliverable bucket:
audits - Mode: conditional. When invoked to analyze, review, audit, or improve existing repo content, apply the reporting size and evidence rules in
references/output-contract.mdand write the deliverable todocs/local/audits/ansible/<YYYY-MM-DD>-<slug>.md. When invoked to answer a question, teach a concept, build a new artifact, or generate content, respond freely without the contract. - Severity scale:
P0 | P1 | P2 | P3 | info(see shared contract; only used in audit/review mode).
Related Skills
- terraform - provisions infrastructure (VMs, networks, cloud resources). Ansible configures what Terraform creates. Day-1 provisioning = terraform; day-2 configuration = ansible.
- kubernetes - for K8s manifests, Helm charts, cluster architecture. Ansible can deploy to
K8s via
kubernetes.corecollection, but manifest design belongs in the kubernetes skill. - docker - for Dockerfile and Compose patterns. Ansible can manage containers via
community.docker, but image building and Compose design belong in the docker skill. - databases - for engine configuration (postgresql.conf, pg_hba.conf). Ansible automates the deployment of those configs; databases skill owns the tuning decisions.
- ci-cd - for pipeline design. Ansible can be called from CI/CD pipelines, but pipeline structure (stages, jobs, caching) belongs in the ci-cd skill.
- security-audit - for auditing Ansible playbooks for credential exposure, vault misuse, or supply chain risks in Galaxy dependencies.
- debian-ubuntu - for Debian/Ubuntu/Mint OS-level admin questions outside an automation context.
- rhel-fedora - for RHEL/Fedora/CentOS OS-level admin questions outside an automation context.
- kali-linux - for Kali Linux administration outside an automation context.
- arch-linux - for Arch Linux / CachyOS OS-level admin questions outside an automation context.
Rules
These are non-negotiable. Violating any of these is a bug.
- Idempotent by default. Every task must be safe to run multiple times.
command/shelltasks needcreates/removesorchanged_when. no_log: trueon secrets. Every task handling passwords, tokens, API keys, or sensitive data. CVE-2024-8775 proved the cost of forgetting this.- Vault for secrets. Not plaintext in
group_vars, notansible_ssh_passin inventory, not environment variables in playbooks. - Test with Molecule. Shared or non-trivial roles get a Molecule scenario with converge + idempotence check + verification of the role's observable outcome, not of every task.
- Pin collection versions. In
requirements.ymland EE definitions. Unpinned collections are a supply chain risk. ansible-lintclean. Production profile. In CI. On every change.- Separate inventory per environment. Production, staging, dev. Never a single inventory with
--limitfor environment selection. --check --diffbefore apply. Review what will change before applying, especially in CI/CD.