Azure Inventory
Dynamic inventory is pulled from Azure using the azure.azcollection.azure_rm plugin, configured in inventory.azure_rm.yml.
All inventory files are registered in ansible-azure.cfg (Azure's config file, not ansible.cfg) so no -i flag is needed on any command — including any additional subscription inventories:
Current configuration
# inventory.azure_rm.yml
plugin: azure.azcollection.azure_rm
subscription_id: <subscription-id>
auth_source: msi
conditional_groups:
azure_rm: true
has_attached_disks: "data_disks | count > 0"
platform_azure: true
os_windows: "os_profile.system == 'windows'"
os_linux: "os_profile.system == 'linux'"
hostnames:
- name
keyed_groups:
- prefix: azure_rm
key: os_profile.system
# Application tier — keyed off the `application` VM tag (app_kuiper, app_nginx, …)
- key: tags.application
default_value: unclassified
prefix: "app"
separator: "_"
# Environment tiers — <env>_azure_app_<app> and <env>_azure_platform, keyed off the
# `environment` tag (see Application & Environment Groups for the full expressions)
- key: >-
(tags.environment | default('unknown') | regex_replace('-', '_'))
~ '_azure_app_' ~ (tags.application | default('unclassified'))
- key: >-
(tags.environment | default('unknown') | regex_replace('-', '_'))
~ '_azure_platform'
# Restrict inventory to one environment's VMs
include_host_filters:
- tags.environment | default('') == 'ire-copier'
compose:
application: tags.application | default('unclassified')
Key settings
auth_source: msi — authenticates using a managed identity. No credentials to rotate or store.
hostnames — uses the VM's Azure name directly as the Ansible inventory hostname.
conditional_groups — creates groups based on boolean expressions evaluated against each VM's facts:
| Group | Condition | Purpose |
|---|---|---|
azure_rm |
always true | Legacy — every Azure VM (superseded by platform_azure) |
has_attached_disks |
has one or more data disks | VMs with attached storage beyond the OS disk |
platform_azure |
always true | Every Azure VM — cloud tier of the group taxonomy |
os_windows |
os_profile.system == 'windows' |
Windows VMs |
os_linux |
os_profile.system == 'linux' |
Linux VMs |
os_profile.system already returns exactly linux/windows, so the OS groups compare it directly (unlike AWS, which matches a substring of platform_details).
keyed_groups — the first entry creates the legacy azure_rm_linux / azure_rm_windows groups (prefixed with azure_rm, derived from os_profile.system), kept for --limit backward-compat; new work should target os_linux / os_windows. The remaining entries build the tag-driven app_* and <env>_azure_* groups from the application and environment VM tags — the application and environment tiers of the group taxonomy, detailed in Application & Environment Groups.
include_host_filters — scopes the inventory to a single environment by tag (tags.environment == 'ire-copier'), so only that environment's VMs are discovered. subscription_id pins discovery to one subscription. Without a filter, all accessible VMs the managed identity can read would be included.
Authentication
Authentication uses a user-assigned managed identity associated with the Ansible controller VM or container. No credentials, secrets, or service principal details are required. The managed identity must have the Reader role assigned at the subscription level (or at each resource group level if scoping to specific groups).
To verify the managed identity can reach the Azure API:
Multiple Azure subscriptions
When managing VMs across multiple Azure subscriptions, create a separate inventory file for each additional subscription with subscription_id set. The managed identity's default subscription is accessed automatically — subscription_id is only required for subscriptions beyond the default.
For each additional subscription, create a dedicated inventory file:
# inventory.azure_rm_sub2.yml
plugin: azure.azcollection.azure_rm
auth_source: msi
subscription_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
conditional_groups:
azure_rm: true
has_attached_disks: "data_disks | count > 0"
platform_azure: true
os_windows: "os_profile.system == 'windows'"
os_linux: "os_profile.system == 'linux'"
hostnames:
- name
keyed_groups:
- prefix: azure_rm
key: os_profile.system
Add each file to ansible-azure.cfg alongside the default inventory:
# ansible-azure.cfg
[defaults]
inventory = inventory.azure_rm.yml,inventory.azure_rm_sub2.yml,inventory.group_priority.yml
The managed identity must have the Reader role in each additional subscription for discovery to succeed.
Verifying the inventory
# List all discovered Azure hosts
ansible-inventory --list --yaml
# Show the full group tree
ansible-inventory --graph
# Inspect variables for a specific host
ansible-inventory --host my-azure-vm
Application & environment groups
Beyond platform and OS, inventory.azure_rm.yml also builds the app_* and <env>_azure_* groups directly from the application and environment VM tags (the keyed_groups/compose shown above) — this is how groups like app_kuiper and ire_copier_azure_platform 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.