# Ansible Components

Ansible components run Ansible playbooks for configuration management and
infrastructure automation. They allow you to manage playbook execution with
the same stack-based configuration approach used for Terraform, Helmfile, and
Packer.

## Available Configuration Sections

Ansible components support the common configuration sections:

- **[`vars`](/stacks/vars)**
  Variables passed to ansible via 
  `--extra-vars`
  .
- **[`env`](/stacks/env)**
  Environment variables during execution.
- **[`settings`](/stacks/settings)**

  Integrations, metadata, and Ansible-specific settings like playbook and
  inventory.
- **[`metadata`](/stacks/components/component-metadata)**
  Component behavior and inheritance.
- **[`command`](/stacks/command)**
  Override ansible binary.
- **[`hooks`](/stacks/hooks)**
  Lifecycle event handlers.

## Component Structure

A typical Ansible component configuration:

```yaml
components:
  ansible:
    webserver:
      vars:
        app_name: myapp
        app_port: 8080
        app_version: "1.0.0"
      env:
        ANSIBLE_HOST_KEY_CHECKING: "false"
      settings:
        ansible:
          playbook: site.yml
          inventory: inventory/production
```

## Ansible Directory Structure

Ansible components are located in the path configured in `atmos.yaml`:

```yaml
# atmos.yaml
components:
  ansible:
    base_path: components/ansible
```

Example structure:

```
components/ansible/
├── hello-world/
│   ├── site.yml
│   └── inventory.ini
├── webserver/
│   ├── site.yml
│   ├── roles/
│   │   └── nginx/
│   └── inventory/
│       ├── production
│       └── staging
└── database/
    ├── deploy.yml
    └── inventory.ini
```

## Playbook Configuration

Each Ansible component contains playbooks that use variables passed from Atmos:

**File:** `components/ansible/hello-world/site.yml`

```yaml
---
- name: Hello World
  hosts: localhost
  connection: local
  gather_facts: false
  tasks:
    - name: Say hello
      ansible.builtin.debug:
        msg: "Hello from {{ app_name }} (version {{ app_version }}) on port {{ app_port }}"
```

### Playbook and Inventory Resolution

The playbook and inventory can be specified in two ways, with command line flags taking precedence:

1. **Stack manifest settings** — Define `settings.ansible.playbook` and `settings.ansible.inventory`
2. **Command line flags** — Use `--playbook` / `-p` and `--inventory` / `-i`

```yaml
components:
  ansible:
    webserver:
      settings:
        ansible:
          playbook: site.yml # Default playbook
          inventory: inventory/production # Default inventory
```

## Component-Type Defaults

Define defaults for all Ansible components:

```yaml
# Apply to all Ansible components
ansible:
  vars:
    managed_by: Atmos
  env:
    ANSIBLE_HOST_KEY_CHECKING: "false"
    ANSIBLE_FORCE_COLOR: "true"

# Individual components
components:
  ansible:
    webserver:
      vars:
        app_port: 8080
```

## Complete Example

**File:** `stacks/orgs/acme/plat/prod/us-east-1.yaml`

```yaml
import:
  - catalog/ansible/_defaults
  - orgs/acme/plat/prod/_defaults

vars:
  region: us-east-1
  stage: prod

ansible:
  vars:
    managed_by: Atmos
  env:
    ANSIBLE_HOST_KEY_CHECKING: "false"

components:
  ansible:
    webserver:
      vars:
        app_name: myapp
        app_port: 8080
        app_version: "2.0.0"
      settings:
        ansible:
          playbook: site.yml
          inventory: inventory/production

    database:
      metadata:
        component: database
      vars:
        db_name: acme-prod
        db_port: 5432
      settings:
        ansible:
          playbook: deploy.yml
          inventory: inventory/production
      dependencies:
        components:
          - name: webserver
```

## Variable Handling

Atmos automatically generates a YAML variables file containing all variables from the component's
`vars` section. This file is passed to Ansible using `--extra-vars @<filename>`.

The generated file follows the naming convention: `<context>-<component>.ansible.vars.yaml`

Here, `<context>` is the full Atmos context prefix (e.g., `tenant-account-stage-region`), not just the stack name.
For example, for a component `webserver` with context prefix `acme-plat-prod-us-east-1`, the file would be:
`acme-plat-prod-us-east-1-webserver.ansible.vars.yaml`

The file is automatically cleaned up after playbook execution completes.

## Running Ansible Commands

Atmos provides commands that wrap Ansible operations:

```bash
# Run a playbook
atmos ansible playbook webserver -s prod

# Run with explicit playbook and inventory
atmos ansible playbook webserver -s prod -p site.yml -i inventory/production

# Dry run (shows command without executing)
atmos ansible playbook webserver -s prod --dry-run

# Pass options directly to ansible-playbook
atmos ansible playbook webserver -s prod -- --check -vvv

# Check Ansible version
atmos ansible version
```

## Environment Variables

Common environment variables for Ansible components:

- **`ANSIBLE_HOST_KEY_CHECKING`**
  Disable SSH host key checking (set to 
  `false`
  ).
- **`ANSIBLE_FORCE_COLOR`**
  Force colored output (set to 
  `true`
  ).
- **`ANSIBLE_CONFIG`**
  Path to Ansible configuration file.
- **`ANSIBLE_VAULT_PASSWORD_FILE`**
  Path to Ansible Vault password file.
- **`ANSIBLE_ROLES_PATH`**
  Additional paths to search for roles.
- **`ANSIBLE_COLLECTIONS_PATH`**
  Paths to search for collections.

## Passing Secrets Securely

The generated variables file is written to **disk in plaintext** (world‑readable, `0644`) so Ansible
can read it via `--extra-vars`. Unlike Terraform — which keeps secret‑bearing `vars` off disk —
Ansible performs **no** off‑disk partitioning. **Never put secrets in an Ansible component's `vars`
section.**

:::warning Secrets belong in `env`, not `vars`
Values in the `env` section are injected only into the Ansible subprocess environment and are
**never written to the variables file**. Declare secrets under
[`secrets.vars`](/cli/configuration/secrets#declaring-secrets), reference them with
[`!secret`](/functions/yaml/secret) in `env`, and read them in your playbook with Ansible's
`env` lookup.
:::

**File:** `stacks/deploy/prod.yaml`

```yaml
components:
  ansible:
    webserver:
      secrets:
        vars:
          DB_PASSWORD:
            description: "Application database password"
            store: ssm-secrets        # a `secret: true` store; or use `sops: <provider>`
            required: true
      env:
        # Injected ONLY into the Ansible subprocess environment — never written to the
        # variables file on disk.
        DB_PASSWORD: !secret DB_PASSWORD
      vars:
        http_port: 8080               # non-secret values only
```

Read the secret from the environment in your playbook — not from the on‑disk extra‑vars file:

**File:** `components/ansible/webserver/site.yml`

```yaml
- hosts: all
  vars:
    # `lookup('env', ...)` reads the secret from the environment exported by the `env` section.
    db_password: "{{ lookup('env', 'DB_PASSWORD') }}"
  tasks:
    - name: Configure the application
      ansible.builtin.template:
        src: app.conf.j2
        dest: /etc/app/app.conf
      no_log: true                    # avoid echoing the secret in task output
```

## Try It

See the [demo-ansible](/examples/demo-ansible) example for a minimal hello-world setup demonstrating variable passing:

```bash
cd examples/demo-ansible
atmos ansible playbook hello-world -s dev
```

## Best Practices

1. **Use Settings for Playbook Config:** Define `settings.ansible.playbook` and `settings.ansible.inventory` in stack manifests rather than passing flags every time.

2. **Centralize Defaults:** Define common settings in catalog defaults and override only when necessary.

3. **Use Dependencies:** Define `dependencies.components` when playbooks need to run after infrastructure is provisioned.

4. **Keep Playbooks Small:** Create focused playbooks for specific tasks rather than monolithic automation.

5. **Use Environment Variables:** Configure Ansible behavior through `env` rather than `ansible.cfg` for consistency across environments.

6. **Leverage Inheritance:** Use abstract components and inheritance for shared playbook configurations across environments.

## Related

- [Component Types Overview](/stacks/components)
- [Terraform Components](/stacks/components/terraform)
- [Helmfile Components](/stacks/components/helmfile)
- [Packer Components](/stacks/components/packer)
- [Configure Variables](/stacks/vars)
- [Configure Environment](/stacks/env)
- [Passing Secrets](/cli/configuration/secrets)
- [`!secret` function](/functions/yaml/secret)
- [Component Dependencies](/stacks/dependencies/components)
- [atmos ansible playbook](/cli/commands/ansible/playbook)
