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:
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:
Multiple AWS accounts
When managing instances across multiple AWS accounts, add owner_id to keyed_groups to group hosts by account:
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:
inventory.aws_ec2.yml— so the inventory plugin can discover instances in that account.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.