Dynamic inventory & delegation

Inventory from the cloud; run elsewhere.

Advanced12 min · lesson 10 of 12

A static inventory file goes stale the moment your cloud autoscales. Dynamic inventory replaces the file with a plugin that queries the source of truth — AWS EC2, Azure, GCP, a CMDB — at run time and returns the current hosts, already grouped by tags, region, or instance type. Your playbooks target groups like tag_role_web and Ansible resolves them to whatever instances exist right now.

inventory.aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions: [us-east-1]
keyed_groups:
- key: tags.Role # instances become groups by their Role tag
prefix: tag_role
filters:
instance-state-name: running
# run: ansible-playbook -i inventory.aws_ec2.yml site.yml

Delegation and run-where control

Sometimes a task about host A must run somewhere else — add A to a load balancer by running an API call on the LB, or update DNS from the control node. delegate_to runs a task on a different host while it logically belongs to the current one; run_once runs a task a single time for a whole group. These control where work happens, which is essential for orchestration across tiers.

play
- name: Remove host from LB before upgrade
community.general.haproxy: { state: disabled, host: "{{ inventory_hostname }}" }
delegate_to: "{{ groups['lb'][0] }}" # runs on the load balancer, about this host
- name: Run DB migration once for the whole group
ansible.builtin.command: /opt/app/migrate
run_once: true
Dynamic inventory needs cloud read credentials
An inventory plugin querying AWS/Azure/GCP needs credentials to list instances, and those credentials now live wherever Ansible runs. Scope them to read-only describe permissions (least privilege), supply them via workload identity or the CI secret store rather than a static key on disk, and cache inventory carefully — a stale or over-permissioned inventory source is both an operational and a security liability.