Skip to content

AWS EC2 Inventory

Dynamic inventory is pulled from AWS EC2 using the amazon.aws.aws_ec2 plugin, configured in inventory.aws_ec2.yml. Hosts are discovered automatically based on running EC2 instances — no static host lists to maintain.

All inventory files are registered in ansible.cfg so no -i flag is needed on any command — including the group-priority overlay and any additional account inventories:

[defaults]
inventory = inventory.aws_ec2.yml,inventory.group_priority.yml

Current configuration

# inventory.aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
  - us-west-2

groups:
  has_attached_disks: block_device_mappings | length > 1
  platform_aws: true
  os_windows: "'Windows' in platform_details"
  os_linux: "'Windows' not in platform_details"

hostnames:
  - name: 'sapphire.dev'
    separator: '.'
    prefix: tag:Name

keyed_groups:
  - key: state.name
  - key: platform_details
  # Application tier — keyed off the `application` VM tag (app_kuiper, app_nginx, …)
  - key: tags.application
    default_value: unclassified
    prefix: "app"
    separator: "_"
  # Environment tiers — <env>_aws_app_<app> and <env>_aws_platform, keyed off the
  # `environment` tag (see Application & Environment Groups for the full expressions)
  - key: >-
      (tags.environment | default('unknown') | regex_replace('-', '_'))
      ~ '_aws_app_' ~ (tags.application | default('unclassified'))
  - key: >-
      (tags.environment | default('unknown') | regex_replace('-', '_'))
      ~ '_aws_platform'

compose:
  ansible_host: private_ip_address
  application: tags.application | default('unclassified')

Key settings

regions — limits discovery to us-west-2. Add or uncomment other regions if instances are deployed elsewhere.

hostnames — constructs the Ansible inventory name from the EC2 Name tag plus the domain suffix. An instance tagged Name: epic-kpr-sapph1 becomes epic-kpr-sapph1.sapphire.dev in inventory. This makes the inventory name predictable and human-readable rather than using the instance ID.

groups — explicit boolean groups:

Group Condition
has_attached_disks more than one block device mapping (EBS volumes beyond the root disk)
platform_aws always true — every EC2 host
os_windows 'Windows' in platform_details
os_linux 'Windows' not in platform_details

platform_aws, os_windows, and os_linux are the AWS half of the cross-cloud group taxonomy. AWS's platform_details reports a distro string on Linux (Red Hat Enterprise Linux, Linux/UNIX, …) and one starting with Windows on Windows, so the OS split matches the Windows substring rather than keying the raw value.

keyed_groups — two purposes:

Key Example groups created Purpose
state.name running, stopped state groups (kept on state.name)
platform_details _Windows, _Red_Hat_Enterprise_Linux legacy OS groups, --limit backward-compat
tags.application app_kuiper, app_nginx, … application tier of the group taxonomy
environment+application (computed) dev_aws_app_kuiper, dev_aws_platform environment tiers

The last two are the tag-driven application and environment tiers — see Application & Environment Groups for the full expressions and behavior. New work should target os_linux / os_windows instead of the legacy platform_details keyed groups.

compose — sets ansible_host to the instance's private IP address. The commented alternatives show how to use the public IP, instance ID, or tag-based logic if needed.

Authentication

The plugin authenticates via IAM using the standard AWS credential chain (environment variables, instance profile, ~/.aws/credentials). The IAM role or user attached to the Ansible controller (container or VM) must have at least the following permission:

  • ec2:DescribeInstances

Before running any playbook or inventory command, activate the virtualenv and ensure credentials are available:

source ~/venv/aws/bin/activate

Multiple AWS accounts

When managing instances across multiple AWS accounts, add owner_id to keyed_groups to group hosts by account:

keyed_groups:
  - key: owner_id
  - key: state.name
  - key: platform_details

assume_role_arn is only required for accounts other than the one the Ansible controller's own IAM role belongs to — the home account is accessed directly without role assumption. For each additional account it must be defined in two places:

  1. inventory.aws_ec2.yml — so the inventory plugin can discover instances in that account.
  2. group_vars/_<owner_id>.yml — so playbooks and collections that call AWS APIs at run time operate in the correct account context.

Both values must be identical. For example, if the owner_id of an AWS account is 123456789012, the aws_ec2 plugin's owner_id keyed group is named _123456789012, and the group vars file would be group_vars/_123456789012.yml:

assume_role_arn: arn:aws:iam::123456789012:role/YourOrg-AnsibleRole
ou_path: OU=EPIC,OU=PROD,OU=Servers,DC=corp,DC=example,DC=com

Verifying the inventory

# List all discovered hosts and groups
ansible-inventory --list --yaml

# Show the full group tree
ansible-inventory --graph

# Inspect all variables resolved for a specific host
ansible-inventory --host epic-kpr-sapph1.sapphire.dev

Application & environment groups

Beyond platform and OS, inventory.aws_ec2.yml also builds the app_* and <env>_aws_* groups directly from the application and environment VM tags (the keyed_groups/compose shown above) — this is how groups like app_nginx and app_kuiper are created and used as --limit targets and group_vars scopes. There is no separate constructed inventory; see Application & Environment Groups for the full details. Precedence between the tiers is set by inventory.group_priority.yml — see Group priority.