Skip to content
Back to skills

Ansible Fundamentals

ASecurity

Core principles and golden rules for writing production-quality Ansible automation, covering FQCN requirements, module selection guidance, and execution patterns using uv run.

  • 2 stars
  • 0 votes
  • 0 copies
  • 6 views
  • Added September 11, 2026
devopsgoshellbashdockerterraformapidatabasesecuritydocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 11, 2026

npx -y skills add jcasnellie69/homelab-config --skill ansible-fundamentals --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ansible Fundamentals?

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

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

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-fundamentals
description: >
  Core principles and golden rules for writing production-quality Ansible automation,
  covering FQCN requirements, module selection guidance, and execution patterns using
  uv run.
when_to_use: >
  Use when writing Ansible playbooks, creating Ansible tasks, running ansible-playbook
  commands, selecting Ansible modules, or working with Ansible collections.
---

# Ansible Fundamentals

Core principles and golden rules for writing production-quality Ansible automation.

## Golden Rules

These rules apply to ALL Ansible code in this repository:

1. **Use `uv run` prefix** - Execute all Ansible commands through uv:

   ```bash
   uv run ansible-playbook playbooks/my-playbook.yml
   uv run ansible-lint
   uv run ansible-galaxy collection install -r requirements.yml
   ```

2. **Fully Qualified Collection Names (FQCN)** - Avoid short module names:

   ```yaml
   # CORRECT
   - name: Install package
     ansible.builtin.apt:
       name: nginx
       state: present

   # WRONG - deprecated short names
   - name: Install package
     apt:
       name: nginx
   ```

3. **Control command/shell modules** - Add `changed_when` and `failed_when`:

   ```yaml
   - name: Check if service exists
     ansible.builtin.command: systemctl status myservice
     register: service_check
     changed_when: false
     failed_when: false
   ```

4. **Use `set -euo pipefail`** - In all shell scripts and shell module calls:

   ```yaml
   - name: Run pipeline command
     ansible.builtin.shell: |
       set -euo pipefail
       cat file.txt | grep pattern | wc -l
     args:
       executable: /bin/bash
   ```

5. **Tag sensitive tasks** - Use `no_log: true` for secrets:

   ```yaml
   - name: Set database password
     ansible.builtin.command: set-password {{ db_password }}
     no_log: true
   ```

6. **Idempotency first** - Check before create, verify after.

7. **Descriptive task names** - Start with action verbs (Ensure, Configure, Install, Create).

## Module Selection Guide

### Decision Matrix

| Need | Use | Why |
|------|-----|-----|
| Install packages | `ansible.builtin.apt/yum/dnf` | Native modules handle state |
| Manage files | `ansible.builtin.copy/template/file` | Idempotent by default |
| Edit config lines | `ansible.builtin.lineinfile` | Surgical edits, not full replace |
| Run commands | `ansible.builtin.command` | When no native module exists |
| Need shell features | `ansible.builtin.shell` | Pipes, redirects, globs |
| Manage services | `ansible.builtin.systemd/service` | State management built-in |
| Manage users | `ansible.builtin.user` | Cross-platform, idempotent |

### Prefer Native Modules

Native modules provide:

- Built-in idempotency (no need for `changed_when`)
- Better error handling
- Cross-platform compatibility
- Clear documentation

```yaml
# PREFER native module
- name: Create user
  ansible.builtin.user:
    name: deploy
    groups: docker
    state: present

# AVOID command when module exists
- name: Create user
  ansible.builtin.command: useradd -G docker deploy
  # Requires: changed_when, failed_when, idempotency logic
```

### When Command/Shell is Acceptable

Use `command` or `shell` modules when:

1. No native module exists for the operation
2. Interacting with vendor CLI tools (pvecm, pveceph, kubectl)
3. Running one-off scripts

Add proper controls:

```yaml
- name: Create Proxmox API token
  ansible.builtin.command: >
    pveum user token add {{ username }}@pam {{ token_name }}
  register: token_result
  changed_when: "'already exists' not in token_result.stderr"
  failed_when:
    - token_result.rc != 0
    - "'already exists' not in token_result.stderr"
  no_log: true
```

## Collections in Use

This repository uses these Ansible collections:

| Collection | Purpose | Example Modules |
|------------|---------|-----------------|
| `ansible.builtin` | Core functionality | copy, template, command, user |
| `ansible.posix` | POSIX systems | authorized_key, synchronize |
| `community.general` | General utilities | interfaces_file, ini_file |
| `community.proxmox` | Proxmox VE | proxmox_vm, proxmox_kvm |
| `infisical.vault` | Secrets management | read_secrets |
| `community.docker` | Docker management | docker_container, docker_image |

### Installing Collections

```bash
# Install from requirements
cd ansible && uv run ansible-galaxy collection install -r requirements.yml

# Install specific collection
uv run ansible-galaxy collection install community.proxmox
```

## Common Execution Patterns

### Running Playbooks

```bash
# Basic execution
uv run ansible-playbook playbooks/my-playbook.yml

# With extra variables
uv run ansible-playbook playbooks/create-vm.yml \
  -e "vm_name=docker-01" \
  -e "vm_memory=4096"

# Limit to specific hosts
uv run ansible-playbook playbooks/update.yml --limit proxmox

# Check mode (dry run)
uv run ansible-playbook playbooks/deploy.yml --check --diff

# With tags
uv run ansible-playbook playbooks/setup.yml --tags "network,storage"
```

### Linting

```bash
# Run ansible-lint
mise run ansible-lint

# Or directly
uv run ansible-lint ansible/playbooks/
```

## Task Naming Conventions

Use descriptive names with action verbs:

| Verb | Use When |
|------|----------|
| Ensure | Verifying state exists |
| Configure | Modifying settings |
| Install | Adding packages |
| Create | Making new resources |
| Remove | Deleting resources |
| Deploy | Releasing applications |
| Update | Modifying existing resources |

Examples:

```yaml
- name: Ensure Docker is installed
- name: Configure SSH security settings
- name: Create admin user account
- name: Deploy application configuration
```

## Variable Naming

Use snake_case with descriptive names:

```yaml
# GOOD - clear, descriptive
proxmox_api_user: terraform@pam
docker_compose_version: "2.24.0"
vm_memory_mb: 4096

# BAD - vague, abbreviated
pve_usr: terraform@pam
dc_ver: "2.24.0"
mem: 4096
```

## Quick Reference Commands

```bash
# Lint all Ansible files
mise run ansible-lint

# Run playbook with secrets from Infisical
cd ansible && uv run ansible-playbook playbooks/my-playbook.yml

# Check syntax
uv run ansible-playbook --syntax-check playbooks/my-playbook.yml

# List hosts in inventory
uv run ansible-inventory --list

# Test connection
uv run ansible all -m ping
```

## Common Anti-Patterns

### Missing FQCN

```yaml
# BAD
- name: Copy file
  copy:
    src: file.txt
    dest: /tmp/

# GOOD
- name: Copy file
  ansible.builtin.copy:
    src: file.txt
    dest: /tmp/
```

### Uncontrolled Commands

```yaml
# BAD - always shows changed, no error handling
- name: Check status
  ansible.builtin.command: systemctl status app

# GOOD
- name: Check status
  ansible.builtin.command: systemctl status app
  register: status_check
  changed_when: false
  failed_when: false
```

### Using shell When command Suffices

```yaml
# BAD - shell not needed
- name: List files
  ansible.builtin.shell: ls -la /tmp

# GOOD - command is sufficient
- name: List files
  ansible.builtin.command: ls -la /tmp
  changed_when: false
```

### Missing no_log on Secrets

```yaml
# BAD - password in logs
- name: Set password
  ansible.builtin.command: set-password {{ password }}

# GOOD
- name: Set password
  ansible.builtin.command: set-password {{ password }}
  no_log: true
```

## Related Skills

- **ansible-idempotency** - Detailed changed_when/failed_when patterns
- **ansible-secrets** - Infisical integration and security
- **ansible-proxmox** - Proxmox-specific module selection
- **ansible-error-handling** - Block/rescue, retry patterns

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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.