Skip to content
Back to skills

Ansible

ASecurity

Write, review, and debug Ansible playbooks, roles, inventories, Ansible Vault, Molecule tests, and AWX/AAP.

  • 7 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 24, 2026
devopspythonrustgoshellbashsqlnodedockerkubernetesterraform

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 8 files and shows the line behind each finding

Scanned October 3, 2026

npx -y skills add iuliandita/skills --skill ansible --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ansible?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ansible
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/iuliandita-ansible/badge)](https://www.skillsdirectory.com/skills/iuliandita-ansible)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ansible
description: >
  Write, review, and debug Ansible playbooks, roles, inventories, Ansible Vault, Molecule tests, and AWX/AAP.
license: MIT
compatibility: "Requires ansible-core; target controller Python 3.12+. Check managed-node support separately. Optional: ansible-lint, molecule, ansible-navigator"
metadata:
  source: iuliandita/skills
  date_added: "2026-03-24"
  effort: high
  argument_hint: "[playbook-or-task]"
---

# Ansible: 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](https://docs.ansible.com/projects/ansible-core/devel/reference_appendices/release_and_maintenance.html) 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](https://access.redhat.com/support/policy/updates/ansible-automation-platform) 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`, not `copy`). AI almost never does this unprompted.
- [ ] `become: true` present where privilege escalation is needed (AI often forgets this)
- [ ] `no_log: true` on 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`/`raw` when an Ansible module exists for the operation
- [ ] Tasks are idempotent - running twice produces the same result (watch `command`/`shell` tasks without `creates`/`removes`)
- [ ] No hardcoded values - IPs, paths, package versions, usernames go in variables with defaults
- [ ] `ansible.builtin.apt`/`ansible.builtin.dnf` use `state: present`, not `state: latest` (unless explicitly upgrading)
- [ ] Loop variable is `item` (default) or renamed via `loop_var` in nested loops (AI conflates loop variables)
- [ ] `block`/`rescue`/`always` used for error handling, not bare `ignore_errors: true`
- [ ] No `ansible.builtin.template` with `src:` pointing to a non-`.j2` file (confusing, even if it works)
- [ ] `changed_when`/`failed_when` set on `command`/`shell` tasks 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 `--limit` for 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.yml` for production automation.
- Run destructive playbooks with `--check --diff` first 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 --diff` clean (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**: `become` method (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.

```bash
# 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:

```bash
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:

```bash
# 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

```yaml
---
- 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):
1. Role defaults (`defaults/main.yml`) - weakest, meant to be overridden
2. Inventory vars (`group_vars/`, `host_vars/`)
3. Play vars
4. Task vars
5. 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_handlers` if 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

```bash
# 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` (use `ansible.builtin.apt`)
- `shell: systemctl restart nginx` (use `ansible.builtin.systemd`)
- `shell: useradd deploy` (use `ansible.builtin.user`)
- `copy` without `mode:` on sensitive files (defaults to umask, unpredictable)
- `template` without `.j2` extension on the source file
- `ignore_errors: true` without a comment explaining why (use `block`/`rescue` instead)
- Blind `with_items` to `loop` rewrites: both are supported; prefer `loop` for simple lists, and preserve single-level flattening with `flatten(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: latest` in 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`, not `vars/main.yml`.
- Use FQCNs everywhere.
- Prefix role variables to avoid collisions.
- Treat Molecule idempotence checks as mandatory, not optional polish.

---

## Operations
- Read `references/operations-and-execution.md` for inventory layout, `ansible.cfg`, execution environments, CI/CD integration, and `ansible-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 with `no_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)**:
- `smart` transport value - choose `ssh` or `paramiko` explicitly
- Galaxy v2 API support - Galaxy servers must support v3
- `PARAMIKO_HOST_KEY_AUTO_ADD` and `PARAMIKO_LOOK_FOR_KEYS` config keys
- `passlib_or_crypt` API from encrypt utility

**Deprecations (removal in 2.24)**:
- `INJECT_FACTS_AS_VARS` defaults to True but will flip to False. Access facts via `ansible_facts['hostname']` instead of `ansible_hostname`.
- `ansible.module_utils._text` imports (`to_bytes`, `to_native`, `to_text`) - use `ansible.module_utils.common.text.converters` instead
- `vars` internal 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.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](https://access.redhat.com/security/cve/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: true` to secret-handling tasks.
- AI generates non-idempotent `command`/`shell` tasks 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 work
- `references/production-checklist.md` - playbook, role, operations, and PCI-DSS checklists; run before finishing any build or review
- `references/roles-and-collections.md` - role anatomy, collection structure, Galaxy patterns, and Molecule workflows
- `references/operations-and-execution.md` - inventory layout, ansible.cfg, execution environments, CI/CD integration, and navigator usage
- `references/vault-and-secrets.md` - Vault usage, secret handling, and external secret-manager integration
- `references/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.md` and write the deliverable to `docs/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.core` collection, 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.

1. **Idempotent by default.** Every task must be safe to run multiple times. `command`/`shell` tasks need `creates`/`removes` or `changed_when`.
2. **`no_log: true` on secrets.** Every task handling passwords, tokens, API keys, or sensitive data. CVE-2024-8775 proved the cost of forgetting this.
3. **Vault for secrets.** Not plaintext in `group_vars`, not `ansible_ssh_pass` in inventory, not environment variables in playbooks.
4. **Test with Molecule.** Every role gets a Molecule scenario with converge + idempotence check + verification.
5. **Pin collection versions.** In `requirements.yml` and EE definitions. Unpinned collections are a supply chain risk.
6. **`ansible-lint` clean.** Production profile. In CI. On every change.
7. **Separate inventory per environment.** Production, staging, dev. Never a single inventory with `--limit` for environment selection.
8. **`--check --diff` before apply.** Review what will change before applying, especially in CI/CD.

Files in this skill

  • SKILL.md24.6 KB
  • references/agent-hygiene.md1.1 KB
  • references/compliance.md15.6 KB
  • references/operations-and-execution.md7 KB
  • references/output-contract.md2.8 KB
  • references/playbook-patterns.md17.9 KB
  • references/roles-and-collections.md15.2 KB
  • references/vault-and-secrets.md12.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…