> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/infrastructure-as-code-management/use-iacm/configuration-management/inventories.md).

# Create Ansible Inventories

Create static, dynamic, plugin, and remote Ansible inventories in Harness IaCM, configure dynamic sources from workspace resources, and filter hosts with attribute conditions.

{% hint style="info" %}
This feature is in Beta[^1] and requires enablement. [View all early access features.](/release-notes/features.md)

{% @harness-feature-flag-access/request-feature-flag-access module="infrastructure-as-code-management" pagePath="infrastructure-as-code-management/use-iacm/configuration-management/inventories" featureFlags="%5B%7B%22name%22%3A%22Ansible%20Remote%20Static%20Inventory%22%2C%22key%22%3A%22IACM\_ANSIBLE\_REMOTE\_INVENTORY%22%2C%22status%22%3A%22BETA%22%2C%22description%22%3A%22Adds%20the%20Remote%20inventory%20type%2C%20which%20reads%20a%20static%20inventory%20file%20from%20a%20Git%20repository%20instead%20of%20hosts%20defined%20manually%20in%20Harness.%22%7D%5D" %}
{% endhint %}

An inventory defines the machines your playbooks target and the variables those machines carry. This guide shows you how to create a static inventory with manually defined hosts, a dynamic inventory that derives hosts from the resources in a Terraform or OpenTofu workspace, a plugin inventory that fetches hosts from a cloud provider through an Ansible inventory plugin, and a remote inventory that reads a static inventory file from a Git repository.

***

## What you will learn from this topic

* **Inventory types:** When to choose a static, dynamic, plugin, or remote inventory.
* **Static setup:** Create an inventory and define hosts and groups manually.
* **Dynamic setup:** Add a source that resolves hosts from workspace resources, select the host address attribute, and filter hosts with conditions.
* **Plugin setup:** Point Harness at a Git-stored inventory plugin configuration and a cloud connector.
* **Remote setup:** Point Harness at a Git-stored static inventory file and understand how inventory variables override it.
* **Variables:** Attach inventory-level Ansible variables (passed as `--extra-vars`) and environment variables (injected into the process environment), including secrets.

***

## Before you begin

* **Harness account with IaCM enabled:** You need **Infrastructure as Code Management** under **Infrastructure** in Harness. Go to [Getting started with Harness Platform](https://developer.harness.io/harness-platform/new-to-harness-platform/get-started) to access or create a Harness account.

  <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><strong>Contact Harness support</strong></p><p>If IaCM does not appear, go to <a href="/infrastructure-as-code-management/new-to-iacm/get-started.md">Get started with IaCM</a>, or contact your account administrator or <a href="mailto:support@harness.io">Harness Support</a>.</p></div>
* **Ansible concepts:** Familiarity with hosts, groups, and inventories. Go to [Configuration management with Ansible](/infrastructure-as-code-management/use-iacm/configuration-management.md) to review the concepts.
* **A provisioned workspace (dynamic inventories only):** Dynamic sources resolve hosts from the resources of an IaCM workspace, so the workspace must exist and hold state. Go to [Get started with IaCM](/infrastructure-as-code-management/new-to-iacm/get-started.md) to create and provision a workspace.
* **Git and cloud connectors (plugin inventories only):** The plugin configuration file lives in a Git repository, and provider credentials come from a cloud connector. Go to [Connect to a code repository](https://developer.harness.io/harness-platform/use-harness-platform/connectors/code-repositories/connect-to-code-repo) and [Cloud connectors](https://developer.harness.io/harness-platform/use-harness-platform/connectors/cloud-providers) to set these up.

***

### Choose an inventory type

Harness IaCM supports four inventory types. Choose based on how your hosts come into existence:

* **Static:** You define a list of hosts and groups manually. Best for fixed fleets, bastion hosts, and small stateful clusters where the topology is known and stable.
* **Dynamic:** Hosts are derived dynamically from different sources, such as the resources of a Terraform or OpenTofu workspace. Best when provisioning creates or replaces hosts, because the inventory tracks state without manual updates.
* **Plugin:** Hosts are fetched from a cloud provider by an Ansible inventory plugin, with the plugin configuration file stored in your Git repository. Best when your team already standardizes on plugins such as `aws_ec2` or `azure_rm`.
* **Remote:** Hosts and groups are read from a static inventory file stored in a Git repository, instead of being entered manually in Harness. Best when you already maintain an INI-format inventory file in Git and want Harness to read it directly rather than re-entering hosts.

***

### Create an inventory

Follow the interactive guide or the step-by-step instructions to create an inventory.

{% tabs %}
{% tab title="Interactive guide" %}
{% embed url="<https://app.tango.us/app/embed/458abc24-16d1-4684-81ae-866ad750cbed?skipCover=false&defaultListView=false&skipBranding=false&makeViewOnly=false&hideAuthorAndDetails=true>" %}
Create New Inventory in Harness
{% endembed %}
{% endtab %}

{% tab title="Step-by-step" %}
To create an inventory, do the following:

1. In the Harness UI, navigate to the **IaCM** module.
2. In the left sidebar under **Configuration**, select **Inventories**.
3. Select **+ New Inventory**. The **New Inventory** dialog opens on the **About Inventory** step.
4. Enter a **Name**. An Id is generated automatically and cannot be changed after creation. **Description** and **Tags** are optional.
5. Under **How do you want to set up the inventory?**, select **Static**, **Dynamic**, **Plugin**, or **Remote**.
6. For Static and Dynamic, select **Create**. For Plugin or Remote, select **Next** and complete the extra steps described in the Plugin or Remote tab below.
   {% endtab %}
   {% endtabs %}

After creation, Harness opens the inventory detail page with four tabs: **Hosts**, **Variables**, **Activity History**, and **Configuration**. The remaining setup differs by type.

{% tabs %}
{% tab title="Static" %}
A static inventory starts empty. You add groups and hosts manually on the **Hosts** tab.

1. Select **+ New Group** to add a group, or **+ New Host** to add a host directly.
2. For a group, enter a **Group name** and optionally select existing hosts that belong to it, then select **Apply Changes**.
3. For a host, enter the **Host Address** (for example, `web1.example.com` or `10.0.1.25`), optionally assign it to groups, then select **Apply Changes**.

Go to [Manage hosts and groups](/infrastructure-as-code-management/use-iacm/configuration-management/inventories/hosts.md) for the full host and group workflow, including host-level variables and connection settings.
{% endtab %}

{% tab title="Dynamic" %}
A dynamic inventory resolves hosts from one or more **sources**. Each source points at an IaCM workspace and selects resources from its state.

To add a source, do the following:

1. On the inventory's **Hosts** tab, select **+ Source**. The **Source Configuration** panel opens with three tabs: **Configuration**, **Static Variables**, and **Dynamic Variables**.
2. On the **Configuration** tab, enter a **Name**. The source identifier becomes the Ansible group name for the hosts it resolves.
3. Select the **Workspace** that provisions the hosts you want to configure.
4. Select the **Resource Type** to match (for example, `aws_instance`). The list is populated from the resource types present in the workspace state.
5. Select the **Host Address Attribute**. This is the resource attribute Ansible uses to connect to each host (for example, `public_dns` or `public_ip`).
6. Optionally, under **Filters (optional)**, select **+ Add Filter** to narrow which resources become hosts. Go to [Filter hosts with conditions](#filter-hosts-with-conditions).
7. Select **Apply Changes**.

At pipeline run time, Harness queries the workspace state, applies your filters, and renders each matching resource as a host in the source's group.

{% hint style="success" %}
Add one source per logical tier. For example, a `webservers` source that selects `aws_instance` resources tagged `Role=web`, and a `databases` source that selects instances tagged `Role=db`. Playbooks can then target each group by the source identifier.
{% endhint %}
{% endtab %}

{% tab title="Plugin" %}
A plugin inventory uses an Ansible inventory plugin to fetch hosts from a cloud provider. The plugin configuration file (for example, `aws_ec2.yml`) lives in your Git repository, and a cloud connector supplies the provider credentials. Selecting **Plugin** extends the dialog into a three-step wizard.

1. On the **About Inventory** step, enter the name and select **Plugin**, then select **Next**.
2. On the **Source** step, define where the inventory configuration is stored:
   * **Select Git Provider:** Choose **Harness Code Repository** or **Third-party Git provider**.
   * **Git Connector:** Select the connector with read access to the repository (third-party providers only).
   * **Repository:** Select or enter the repository name.
   * **Git Fetch Type:** Choose **Latest from Branch**, **Git Tag**, or **Commit SHA**, and supply the branch, tag, or SHA.
   * **Folder Path (optional):** Enter the path to the folder containing your plugin configuration.
3. Select **Next**. On the **Provider** step, select a cloud provider for first-class integration (**AWS**, **GCP**, or **Azure**) or select **Custom** to use any other inventory plugin.
4. Select the **Cloud Connector** that holds the provider credentials.
5. Select **Create**.

At pipeline run time, the plugin queries the provider API through the connector credentials and renders the hosts your configuration file selects.

A plugin inventory's detail page differs from the other types: instead of a **Hosts** tab, it opens on an **Inventory Definition** tab that renders your plugin configuration file from Git. A typical `aws_ec2.yaml` looks like this:

```yaml
plugin: amazon.aws.aws_ec2
regions:
  - us-east-1
filters:
  "tag:infra": "ansibleHost"
  instance-state-name: running
hostnames:
  - tag:Name
compose:
  ansible_host: public_ip_address
```

{% endtab %}

{% tab title="Remote" %}
A remote inventory reads a static, INI-format inventory file from a Git repository instead of hosts entered manually in Harness. Selecting **Remote** extends the dialog into a two-step wizard.

1. On the **About Inventory** step, enter the name and select **Remote**, then select **Next**.
2. On the **Source** step, define where the inventory file is stored:
   * **Select Git Provider:** Choose **Harness Code Repository** or **Third-party Git provider**.
   * **Select Repository:** Select or enter the repository name. The field shows a scope badge (**Project**, **Organization**, or **Account**) for the resolved repository.
   * **Git Fetch Type:** Choose **Latest from Branch** or **Git Tag**.
   * **Git Branch:** Select or enter the branch to fetch from (shown when **Git Fetch Type** is **Latest from Branch**). Commit SHA pinning is not supported for Remote inventories.
   * **Inventory Path:** Enter the path to the inventory file within the repository, for example `inventory/hosts.ini`.
3. Select **Create**.

At pipeline run time, Harness fetches the inventory file from Git and parses its hosts and groups.

A remote inventory's detail page differs from the other types: instead of a **Hosts** tab, it opens on an **Inventory Definition** tab that renders the fetched inventory file from Git. A typical `hosts.ini` looks like this:

```ini
[webservers]
web1.example.com
web2.example.com

[databases]
db1.example.com

[webservers:vars]
http_port=80
```

{% hint style="warning" %}
For every other inventory type, an inventory-level **Variables** row is the weakest source of precedence and is overridden by the same key defined in the Git-stored file. For a **Remote** inventory, this is reversed: inventory-level variables you define in the Harness UI are passed as `--extra-vars`, which is the strongest precedence in Ansible. A UI variable overrides the same key defined in `group_vars` or `host_vars` inside the repository, on every run, until you remove it from the **Variables** tab.
{% endhint %}
{% endtab %}
{% endtabs %}

***

### Filter hosts with conditions

Filters control which workspace resources a dynamic source turns into hosts. Each filter is a condition made of an attribute, an operator, and a value. Multiple filters combine with **AND** logic, so a resource must match every condition to be included.

To add a filter in the **Source Configuration** panel, do the following:

1. Select **Add Filter**.
2. Select the resource **attribute** to evaluate (for example, `tags.environment`).
3. Select an operator: **equals**, **not equals**, **contains**, **does not contain**, **starts with**, or **ends with**.
4. Enter the **value** to compare against (for example, `prod`).

Some common filter patterns are:

* **Environment scoping:** `tags.environment` **equals** `prod` so only production resources are configured.
* **Role scoping:** `tags.Role` **contains** `web` so database instances never receive the web playbook.
* **Naming conventions:** `tags.Name` **starts with** `edge-` to select a named subset of a larger fleet.

***

### Use dynamic variables from resource attributes

Dynamic sources can attach variables to every host they resolve, with values drawn from each resource's attributes or the workspace outputs. Use Harness expressions in the value field:

* `<+attributes.ATTRIBUTE_NAME>` reads an attribute from the matched resource, for example `<+attributes.private_ip>`.
* `<+outputs.OUTPUT_NAME>` reads an output from the workspace, for example `<+outputs.cluster_endpoint>`.

For example, a dynamic variable with key `region` and value `<+attributes.availability_zone>` gives every resolved host a `region` host variable your playbook can reference as `{{ region }}`. Static values are also allowed and apply unchanged to every host in the source.

***

### Add inventory variables

The inventory **Variables** tab has two independent editors: **Ansible Variables** and **Environment Variables**. Saving one collection does not affect the other.

![The inventory Variables tab showing separate Environment Variables and Ansible Variables editors](https://3575326923-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ffhx6XzjvtJmfv5gPWZ5m%2Fuploads%2Fgit-blob-1011bcec1e6449f7808025b842fee9588f110f43%2Fiacm-ansible-inventory-variables.png?alt=media)

#### Ansible variables

Ansible variables apply to every host in the inventory. Harness passes them to `ansible-playbook` as `--extra-vars` at run time. They are the right place for connection settings and shared configuration values that your playbook tasks reference directly.

To add Ansible variables, do the following:

1. Open the inventory and select its **Variables** tab.
2. Under **Ansible Variables**, select **+ Add Variable**.
3. Set the **Type** (**string** or **secret**), enter the **Key** and **Value**, then select **Save Changes**.

A common baseline for SSH-based fleets stores the connection user as a string (`ansible_user: ubuntu`) and the private key as a **secret**-type variable (`ansible_ssh_private_key_file`) referencing a [Harness secret](https://developer.harness.io/harness-platform/use-harness-platform/secrets/secrets-management/harness-secret-manager-overview). Secret values are masked in pipeline logs.

{% hint style="info" %}
Group and host variables are Ansible variables only. There are no environment variable editors at the group or host level.
{% endhint %}

The precedence of inventory-level Ansible variables depends on inventory type:

| Inventory type      | Variable precedence                                                                                               |
| ------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **Remote**          | Inventory variables are passed as `--extra-vars` and override variables defined in the Git-stored inventory file. |
| **All other types** | Inventory variables are the weakest precedence and are overridden by variables defined in the inventory file.     |

{% hint style="info" %}
Group and host variables are Ansible variables only. There are no environment variable editors at the group or host level.
{% endhint %}

#### Environment variables

Environment variables are injected into the Ansible process environment before `ansible-playbook` runs. Use them for process-level settings such as `ANSIBLE_HOST_KEY_CHECKING` or custom tool paths. They are not passed as `--extra-vars` and are not available as Ansible variables in playbook tasks.

To add environment variables, do the following:

1. Open the inventory and select its **Variables** tab.
2. Under **Environment Variables**, select **+ Add Variable**.
3. Set the **Type** (**string** or **secret**), enter the **Key** and **Value**, then select **Save Changes**.

Secret-typed environment variables are resolved at run time and masked in logs. Pipeline-defined environment values win collisions with inventory environment variables.

***

### View activity history

The **Activity History** tab lists past executions that used this inventory, including the playbook, the pipeline execution, and the run status. Use it to correlate configuration runs with provisioning events and to audit who changed what, when.

***

## Troubleshooting

<details>

<summary>Dynamic inventory source resolves no hosts from workspace resources in Harness IaCM Ansible</summary>

Confirm the workspace holds state with resources of the selected Resource Type, and that every filter condition matches. Filters combine with AND logic, so one non-matching condition excludes the resource.

</details>

<details>

<summary>Host address is empty or wrong for hosts resolved by a dynamic inventory source in Harness IaCM</summary>

Check the Host Address Attribute on the source. The selected attribute must exist on the matched resource type and contain a reachable address, for example public\_dns or public\_ip.

</details>

<details>

<summary>Cannot edit the inventory identifier after creating an inventory in Harness IaCM</summary>

Inventory identifiers are immutable after creation. Create a new inventory with the desired identifier and delete the old one.

</details>

<details>

<summary>Remote inventory file fails to parse or hosts are missing in Harness IaCM Ansible</summary>

Harness does not validate the inventory file when you save the Remote inventory configuration; a malformed file only surfaces an error at pipeline run time. Confirm the file at the configured path is valid INI-format Ansible inventory syntax, and that the Git connector, repository, and branch or tag are correct.

</details>

<details>

<summary>A Remote inventory variable does not match the value in the Git-stored inventory file</summary>

Inventory-level variables on a Remote inventory are passed as `--extra-vars`, which takes the highest precedence in Ansible. Remove the variable from the inventory's **Variables** tab to fall back to the value defined in `group_vars` or `host_vars` in the repository.

</details>

***

## Next steps

You created an inventory and connected it to real hosts, either manually, from workspace state, or from a Git-stored inventory file.

* Go to [Manage hosts and groups](/infrastructure-as-code-management/use-iacm/configuration-management/inventories/hosts.md) to add host-level variables, groups, and connection settings.
* Go to [Create Ansible playbooks](/infrastructure-as-code-management/use-iacm/configuration-management/playbooks.md) to register the playbook that will run against this inventory.
* Go to [Example Ansible use cases](/infrastructure-as-code-management/use-iacm/configuration-management/example-use-cases.md) to apply inventories to web fleets, patching, and compliance patterns.

{% @harness-feedback/feedback %}

[^1]: Beta features are feature-complete but still being validated. Available on request.
