
maverick-ansible
by get2knowio
Highway to the agent zone!
SKILL.md
name: maverick-ansible description: Ansible playbook, role, and security best practices version: 1.0.0 triggers:
- ansible
- playbook
- "tasks:"
- "handlers:"
- "roles:"
- "hosts:"
- ansible-playbook
- ansible-vault
- become
- when:
- notify:
- register:
- with_items
- loop:
- ansible-lint
- galaxy.yml
- requirements.yml
- inventory
Ansible Skill
Expert guidance for Ansible playbooks, roles, and automation best practices.
Playbook Structure
Basic Playbook
---
- name: Configure web servers
hosts: webservers
become: true
vars:
http_port: 80
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Start nginx service
ansible.builtin.service:
name: nginx
state: started
enabled: true
Multiple Plays
---
- name: Configure database servers
hosts: databases
tasks:
- name: Install PostgreSQL
ansible.builtin.apt:
name: postgresql
state: present
- name: Configure web servers
hosts: webservers
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
Idempotency (CRITICAL)
Idempotent tasks can run multiple times without changing the result after the first run.
✅ Idempotent Examples
# Good - using built-in modules (always idempotent)
- name: Ensure nginx is installed
ansible.builtin.apt:
name: nginx
state: present
- name: Ensure config file has correct content
ansible.builtin.copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
mode: '0644'
❌ Non-Idempotent Antipatterns
# BAD - runs every time, always reports "changed"
- name: Configure system
ansible.builtin.shell: echo "config" >> /etc/app.conf
# GOOD - idempotent alternative
- name: Ensure config line exists
ansible.builtin.lineinfile:
path: /etc/app.conf
line: "config"
create: true
Making Shell/Command Idempotent
# Use changed_when and creates/removes
- name: Download file
ansible.builtin.shell: |
curl -o /tmp/file.tar.gz https://example.com/file.tar.gz
args:
creates: /tmp/file.tar.gz
changed_when: false
# Or check conditions first
- name: Check if configured
ansible.builtin.stat:
path: /etc/app/.configured
register: configured
- name: Run configuration script
ansible.builtin.shell: /opt/app/configure.sh
when: not configured.stat.exists
- name: Mark as configured
ansible.builtin.file:
path: /etc/app/.configured
state: touch
when: not configured.stat.exists
Variables & Jinja2 Templating
Variable Precedence (low to high)
- Role defaults (
roles/*/defaults/main.yml) - Inventory vars
- Playbook vars
- Extra vars (
-e/--extra-vars)
Using Variables
---
- name: Deploy application
hosts: app_servers
vars:
app_version: "1.2.3"
app_user: "appuser"
tasks:
- name: Download application version {{ app_version }}
ansible.builtin.get_url:
url: "https://releases.example.com/app-{{ app_version }}.tar.gz"
dest: "/opt/app-{{ app_version }}.tar.gz"
owner: "{{ app_user }}"
Facts
# Gather facts automatically (default: true)
- name: Show system facts
hosts: all
tasks:
- name: Display OS family
ansible.builtin.debug:
msg: "OS family is {{ ansible_os_family }}"
- name: Display IP address
ansible.builtin.debug:
msg: "IP is {{ ansible_default_ipv4.address }}"
Conditionals
- name: Install package on Debian-based systems
ansible.builtin.apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install package on RedHat-based systems
ansible.builtin.yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
Handlers
Handlers run once at the end of a play, after all tasks.
---
- name: Configure web server
hosts: webservers
tasks:
- name: Copy nginx config
ansible.builtin.copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Copy site config
ansible.builtin.template:
src: site.conf.j2
dest: /etc/nginx/sites-available/mysite
notify: Restart nginx
handlers:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
Key points:
- Handlers only run if notified
- Handlers run once, even if notified multiple times
- Handlers run at the end of the play
- Use
meta: flush_handlersto run handlers immediately
Loops
Modern Loop Syntax (Ansible 2.5+)
# Preferred
- name: Install packages
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- nginx
- postgresql
- redis
# With dictionary
- name: Create users
ansible.builtin.user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
loop:
- { name: 'alice', groups: 'admin' }
- { name: 'bob', groups: 'users' }
Legacy Loop Syntax (avoid)
# OLD - avoid in new playbooks
- name: Install packages
ansible.builtin.apt:
name: "{{ item }}"
state: present
with_items:
- nginx
- postgresql
Roles
Role Structure
roles/
└── webserver/
├── tasks/
│ └── main.yml # Main task list
├── handlers/
│ └── main.yml # Handlers
├── templates/
│ └── nginx.conf.j2 # Jinja2 templates
├── files/
│ └── index.html # Static files
├── vars/
│ └── main.yml # Variables
├── defaults/
│ └── main.yml # Default variables
├── meta/
│ └── main.yml # Role metadata/dependencies
└── README.md
Using Roles
---
- name: Configure servers
hosts: webservers
roles:
- common
- webserver
- monitoring
# Or with parameters
- name: Configure servers
hosts: webservers
roles:
- role: webserver
vars:
http_port: 8080
Role Dependencies
# roles/webserver/meta/main.yml
---
dependencies:
- role: common
- role: firewall
vars:
firewall_allowed_ports:
- 80
- 443
Security Best Practices
Ansible Vault (CRITICAL)
Never commit unencrypted secrets!
# Encrypt a file
ansible-vault encrypt secrets.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# Run playbook with vault password
ansible-playbook site.yml --ask-vault-pass
# Or use password file
ansible-playbook site.yml --vault-password-file ~/.vault_pass
Encrypted variables:
# vars/secrets.yml (encrypted with ansible-vault)
---
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653361336136343...
api_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
35323264353938643261623...
Privilege Escalation
Use become carefully:
# Entire play
- name: Configure system
hosts: servers
become: true # Run all tasks as root
tasks:
- name: Install package
ansible.builtin.apt:
name: nginx
# Specific task
- name: Configure system
hosts: servers
tasks:
- name: Install package (requires root)
ansible.builtin.apt:
name: nginx
become: true
- name: Copy user file (no root needed)
ansible.builtin.copy:
src: .bashrc
dest: ~/.bashrc
Become user:
- name: Run as specific user
ansible.builtin.command: whoami
become: true
become_user: appuser
Hiding Sensitive Output
# Don't log sensitive data
- name: Set database password
ansible.builtin.shell: |
psql -c "ALTER USER postgres PASSWORD '{{ db_password }}'"
no_log: true
# Register without logging
- name: Get API token
ansible.builtin.uri:
url: https://api.example.com/token
method: POST
register: token_response
no_log: true
Inventory Security
# Don't commit passwords in inventory
# BAD
[databases]
db1 ansible_host=10.0.1.10 ansible_user=admin ansible_password=secret123
# GOOD - use vault for passwords
[databases]
db1 ansible_host=10.0.1.10 ansible_user=admin
# In encrypted group_vars/databases.yml
ansible_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
...
Module Best Practices
Prefer Specific Modules Over shell/command
# BAD - using shell when module exists
- name: Install package
ansible.builtin.shell: apt-get install -y nginx
# GOOD - using built-in module
- name: Install package
ansible.builtin.apt:
name: nginx
state: present
# BAD - using shell for file operations
- name: Create directory
ansible.builtin.shell: mkdir -p /opt/app
# GOOD - using file module
- name: Create directory
ansible.builtin.file:
path: /opt/app
state: directory
mode: '0755'
Fully Qualified Collection Names (Ansible 2.10+)
# GOOD - explicit collection
- name: Install package
ansible.builtin.apt:
name: nginx
# Also acceptable for clarity
- name: Manage Docker container
community.docker.docker_container:
name: myapp
image: nginx:latest
Common Pitfalls
1. Not Using check_mode
# Always test with --check first
# ansible-playbook site.yml --check
- name: Dangerous operation
ansible.builtin.file:
path: /etc/important-config
state: absent
# Test with --check before running!
2. Ignoring Return Codes
# BAD - ignores failures
- name: Run script
ansible.builtin.shell: /opt/app/script.sh
ignore_errors: true
# GOOD - handle failures explicitly
- name: Run script
ansible.builtin.shell: /opt/app/script.sh
register: script_result
failed_when: script_result.rc != 0 and script_result.rc != 2
3. Not Handling "changed" Status
# BAD - always reports changed
- name: Check status
ansible.builtin.shell: systemctl status nginx
# GOOD - mark as not changed
- name: Check status
ansible.builtin.shell: systemctl status nginx
changed_when: false
check_mode: false
4. Using shell when command suffices
# BAD - unnecessary shell features
- name: List files
ansible.builtin.shell: ls /tmp
# GOOD - use command (safer, no shell injection)
- name: List files
ansible.builtin.command: ls /tmp
changed_when: false
Ansible Lint
Common Rules
yaml[line-length] - Keep lines under 160 characters
name[missing] - All tasks must have names
fqcn[action-core] - Use fully qualified collection names
no-changed-when - shell/command should have changed_when
risky-shell-pipe - Avoid pipes in shell commands
Configuration
# .ansible-lint
---
skip_list:
- yaml[line-length] # Skip if you have long lines
warn_list:
- experimental # Warn on experimental features
exclude_paths:
- .cache/
- test/
Naming Conventions
# GOOD - descriptive names in imperative mood
- name: Ensure nginx is installed
- name: Copy nginx configuration
- name: Restart nginx service
# BAD - vague or missing names
- name: nginx
- name: Task 1
- apt: name=nginx # Missing name entirely
Tags for Selective Execution
---
- name: Configure system
hosts: all
tasks:
- name: Install packages
ansible.builtin.apt:
name: "{{ item }}"
loop:
- nginx
- postgresql
tags:
- packages
- install
- name: Configure firewall
ansible.builtin.ufw:
rule: allow
port: 80
tags:
- firewall
- security
# Run only specific tags
# ansible-playbook site.yml --tags "packages"
# ansible-playbook site.yml --skip-tags "firewall"
Review Severity Guidelines
- CRITICAL: Unencrypted secrets in files, using
shellwith user input, privilege escalation without justification - MAJOR: Non-idempotent tasks, using shell/command when module exists, missing
no_logon sensitive tasks, not using ansible-vault - MINOR: Missing task names, not using FQCN, missing
changed_whenon commands, using legacywith_items - SUGGESTION: Could use tags for organization, could extract to role, could use handlers instead of multiple restarts
References
スコア
総合スコア
リポジトリの品質指標に基づく評価
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
レビュー
レビュー機能は近日公開予定です