Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible dynamic inventory for Azure VM with private IP only

On Azure I've got a resource group with 1 vnet containing 2 servers; master and worker. Only master has a public IP.

Using "plain" Ansible I can manage both servers by defining worker's private IP as ansible_host in the hosts file and creating a group_vars file with a ssh ProxyCommand arguments to apply for worker's group as described for a jump host here (note there are older methods too which involve direct ssh config but the group_vars approach is preferable I think as it is more portable to other users).

However this approach needs IPs to be hardcoded which isn't great on Azure. There's an azure_rm inventory script or plugin (depending on Ansible version) which will provide dynamic inventory, avoiding the need for a hosts file, but how I can I do the equivalent of the ProxyCommand setup in this case?

This situation must be pretty common so I feel like I must be missing something.

like image 897
lost Avatar asked Sep 05 '25 02:09

lost


1 Answers

Bastion hosts

To use a proxy / bastion host / jump host with Ansible, you need to specify ansible_ssh_common_args in the ansible.cfg.

  • There should be an environment variable ANSIBLE_SSH_COMMON_ARGS, but this is missing due to this Ansible issue - not yet fixed as of Ansible 2.9.3.

You can set this in a static inventory at the all group level to experiment with this (easier to try this first without dynamic inventory) - see this blog for more details.

[all:vars]
ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p my-bastion.example.com"'

Once you have this working, you can use dynamic inventory - create a file group_vars/all.yml (test with static inventory first), converting the above INI format inventory to YAML (change the = to :).

ansible_ssh_common_args: '-o ProxyCommand="ssh -W %h:%p my-bastion.example.com"'

Using private IPs with dynamic inventory

To ensure that ansible_host in inventory output uses the private IP, you must use export AZURE_USE_PRIVATE_IP=true (with the classic azure_rm.py inventory script, haven't tried yet with plugin inventory).

  • without this, ansible_host may be null or set to a public IP / domain name
  • you may not need this if you are using domain names that resolve to private IPs

Testing dynamic inventory

Be sure to test that the dynamic inventory is generating the right JSON data before you start using it for playbooks.

To check specific inventory values are mapping to the right hosts, try:

$ AZURE_USE_PRIVATE_IP=true ansible -i azure_rm.py mygroup -m debug -a var=ansible_host
test01 | SUCCESS => {
    "ansible_host": "10.0.0.1"
}

You can also check Ansible SSH is working like this, with -vvvvv when debugging:

$ AZURE_USE_PRIVATE_IP=true ansible -i azure_rm.py mygroup -m debug -a var=ansible_host
test01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Classic vs plugin-based inventory

I used the older 'classic' azure_rm.py dynamic inventory here - the same approach works with the current plugin-based dynamic inventory (since Ansible 2.4, includes inventory caching).

To see dynamic inventory JSON output in either mode:

  • Classic: AZURE_USE_PRIVATE_IP=true python azure_rm.py | jq .
  • Plugin based: ansible-inventory -i azure.yml --graph

Use of jq is optional, it just formats the output for readability.

like image 181
RichVel Avatar answered Sep 07 '25 21:09

RichVel