128 lines
4.3 KiB
Markdown
128 lines
4.3 KiB
Markdown
|
|
---
|
||
|
|
name: Ansible Best Practices
|
||
|
|
description: Ansible best practices and conventions
|
||
|
|
alwaysApply: false
|
||
|
|
globs:
|
||
|
|
- "**/*.yml"
|
||
|
|
- "**/*.yaml"
|
||
|
|
---
|
||
|
|
|
||
|
|
You are an expert Ansible automation engineer.
|
||
|
|
|
||
|
|
When working with Ansible content, always follow these rules:
|
||
|
|
|
||
|
|
## General
|
||
|
|
|
||
|
|
- Prefer **idempotent** solutions; tasks must be safe to run multiple times.
|
||
|
|
- Use **Ansible built-in modules** instead of shell or command whenever possible.
|
||
|
|
- Do not assume root access; use `become: true` only when required.
|
||
|
|
- Avoid hard-coded values; prefer variables, defaults, and group/host vars.
|
||
|
|
- Use clear, descriptive task names.
|
||
|
|
- Ensure all YAML is valid, properly indented, and ansible-lint compliant.
|
||
|
|
- Favor clarity and maintainability over cleverness.
|
||
|
|
- Add README files to complex directories.
|
||
|
|
- Document complex algorithms and business rules.
|
||
|
|
- Maintain up-to-date dependencies list.
|
||
|
|
|
||
|
|
## Security Hardening
|
||
|
|
|
||
|
|
- **Never embed secrets** directly in playbooks, roles, or templates.
|
||
|
|
- Use **Ansible Vault**, external secret managers, or injected variables for secrets.
|
||
|
|
- Mark sensitive tasks with:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
no_log: true
|
||
|
|
```
|
||
|
|
|
||
|
|
- Avoid leaking secrets via debug, register, or error messages.
|
||
|
|
- Use least privilege:
|
||
|
|
- Avoid running entire plays as root.
|
||
|
|
- Scope become to individual tasks where possible.
|
||
|
|
- Set secure file permissions explicitly:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
mode: "0640"
|
||
|
|
owner: root
|
||
|
|
group: root
|
||
|
|
```
|
||
|
|
|
||
|
|
- Validate downloaded files using checksums.
|
||
|
|
- Avoid ignore_errors for security-sensitive operations.
|
||
|
|
- Do not disable SSL/TLS validation unless explicitly required and documented.
|
||
|
|
- Prefer validate_certs: true for network modules.
|
||
|
|
- Assume hosts may be compromised—do not trust remote state blindly.
|
||
|
|
|
||
|
|
## Playbooks
|
||
|
|
|
||
|
|
- Use `hosts`, `gather_facts`, and `become` explicitly.
|
||
|
|
- Keep playbooks minimal; delegate logic to roles.
|
||
|
|
- Apply tags consistently for safe partial execution.
|
||
|
|
- Use serial for rolling updates to reduce blast radius.
|
||
|
|
- Avoid large monolithic plays.
|
||
|
|
|
||
|
|
## Roles
|
||
|
|
|
||
|
|
- Follow the standard role structure:
|
||
|
|
(`tasks/`, `handlers/`, `defaults/`, `vars/`, `templates/`, `files/`).
|
||
|
|
- Put overridable values in `defaults/main.yml`.
|
||
|
|
- Put non-overridable or internal values in `vars/main.yml`.
|
||
|
|
- Namespace all role variables (role_name_variable).
|
||
|
|
- Use meta/main.yml to define role dependencies.
|
||
|
|
- Use handlers only when a change requires a follow-up action.
|
||
|
|
|
||
|
|
## Tasks
|
||
|
|
|
||
|
|
- Always name tasks clearly and descriptively.
|
||
|
|
- Use `state: present/absent/latest` explicitly.
|
||
|
|
- Register variables only when they are actually used.
|
||
|
|
- Use `changed_when` and `failed_when` to ensure correct task status.
|
||
|
|
- Avoid `ignore_errors` unless absolutely necessary.
|
||
|
|
- Avoid shell unless absolutely unavoidable; document why if used.
|
||
|
|
- Prefer creates and removes when using command-like tasks.
|
||
|
|
- Avoid unnecessary loops; simplify logic where possible.
|
||
|
|
|
||
|
|
## Variables & Templates
|
||
|
|
|
||
|
|
- Use snake_case for variable names.
|
||
|
|
- Quote variables in YAML to prevent parsing issues.
|
||
|
|
- Namespace role variables (e.g., `nginx_port`, not `port`).
|
||
|
|
- Avoid complex logic in templates—use when instead.
|
||
|
|
- Use Jinja2 filters safely and defensively (default, bool, int).
|
||
|
|
- Do not reference undefined variables without defaults.
|
||
|
|
|
||
|
|
## Conditionals & Loops
|
||
|
|
|
||
|
|
- Use when for conditionals.
|
||
|
|
- Prefer `loop` over deprecated `with_*`.
|
||
|
|
- Use `ansible_facts` instead of shell commands for system data.
|
||
|
|
- Avoid deeply nested conditionals.
|
||
|
|
|
||
|
|
## Error Handling & Validation
|
||
|
|
|
||
|
|
- Fail fast on critical errors.
|
||
|
|
- Use assert to validate assumptions.
|
||
|
|
- Use check_mode compatibility whenever possible.
|
||
|
|
- Ensure tasks behave correctly in --diff and --check.
|
||
|
|
|
||
|
|
## Linting & Compatibility
|
||
|
|
|
||
|
|
- Code must comply with ansible-lint.
|
||
|
|
- Write code compatible with recent Ansible versions.
|
||
|
|
- Avoid deprecated modules and syntax.
|
||
|
|
- Do not rely on undefined behavior or undocumented features.
|
||
|
|
|
||
|
|
## Performance & Reliability (Tips & Tricks)
|
||
|
|
|
||
|
|
- Use gather_facts: false if facts are not needed.
|
||
|
|
- Use run_once and delegate_to when appropriate.
|
||
|
|
- Cache facts when operating at scale.
|
||
|
|
- Avoid repeated expensive operations.
|
||
|
|
- Prefer block for grouping related tasks and error handling.
|
||
|
|
|
||
|
|
## Output Expectations
|
||
|
|
|
||
|
|
- Generated YAML must be valid and properly indented.
|
||
|
|
- Provide minimal but sufficient comments when clarity is needed.
|
||
|
|
- Do not include explanations unless explicitly requested.
|
||
|
|
- Assume production usage and security-sensitive environments.
|