I setup a constrained example consisting of 2 VMs hosted in GCE and a Linux PC acting as the control node. The VMs are setup using metadata based authentication with an SSH key setup at the project level and are internal-only. The VMs have outbound connectivity via a NAT router. The control node will use the feature of the GCloud CLI to establish a tunnel through the IAP service to connect to the VMs on port 22 which is allowed by the default firewall rules. This same setup should work for Windows VMs using WinRM by forwarding the port for WinRM instead of 22 through the IAP service and allowing it to the VM from IAP’s well known IP range as the source.
An inventory like:
[project]
managed-node-1
managed-node-2
[project:vars]
gce_project = project
[us_central1:children]
project
[us_central1:vars]
gce_zone = us-central1
[all:vars]
ansible_ssh_common_args="-o ‘ProxyCommand gcloud compute start-iap-tunnel %h 22 --listen-on-stdin --project {{ gce_project }} --zone {{ gce_zone }}’"
ansible_user = selvaraj
A playbook like:
---
- name: Activate the `gcloud` CLI
hosts: localhost
tasks:
- name: Activate the `gcloud` CLI
ansible.builtin.command:
argv:
- gcloud
- auth
- activate-service-account
- --key-file
- '{{ lookup("ansible.builtin.env", "GCE_CREDENTIALS_FILE_PATH") }}'
changed_when: false
- name: Take action on GCP based managed nodes
hosts: all
tasks:
- name: Print hostname
ansible.builtin.debug:
var: ansible_hostname
ansible-navigator
configured like ( ansible-navigator.yml
):
The mode is set to stdout really just so I could copy and paste the play output easier
---
ansible-navigator:
execution-environment:
environment-variables:
set:
ANSIBLE_HOST_KEY_CHECKING: false
GCE_CREDENTIALS_FILE_PATH: /.gce.json
image: localhost/selvaraj:2
volume-mounts:
- src: ~/.gce.json
dest: /.gce.json
options: Z
mode: stdout
playbook-artifact:
enable: false
Ran via:
ansible-navigator run playbook.yml --inventory hosts
Results in:
$ ansible-navigator run playbook.yml --inventory hosts
PLAY [Activate the `gcloud` CLI] *************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Activate the `gcloud` CLI] *************************************************************************************************************************************************************************************************************
ok: [localhost]
PLAY [Take action on GCP based managed nodes] ************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
[WARNING]: Platform linux on host managed-node-1 is using the discovered Python interpreter at /usr/bin/python3.11, but future installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible-core/2.18/reference_appendices/interpreter_discovery.html for more information.
ok: [managed-node-1]
[WARNING]: Platform linux on host managed-node-2 is using the discovered Python interpreter at /usr/bin/python3.11, but future installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible-core/2.18/reference_appendices/interpreter_discovery.html for more information.
ok: [managed-node-2]
TASK [Print hostname] ************************************************************************************************************************************************************************************************************************
ok: [managed-node-1] => {
"ansible_hostname": "managed-node-1"
}
ok: [managed-node-2] => {
"ansible_hostname": "managed-node-2"
}
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
managed-node-1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
managed-node-2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0