I want to provision Windows host that is in subnet accessible only with Linux jump host.
Windows machine uses winrm connection method. Linux jump server is available via SSH.
I have no problem accessing windows host if available directly with:
ansible_connection: winrm
If I try to delegate the task to the Linux jump server (that has direct access to Windows) by:
- name: Ping windows
hosts: windows_machines
tasks:
- name: ping
win_ping:
delegate_to: "{{ item }}"
with_items: "{{ groups['jump_servers'][0] }}"
it tries to connect to establish WINRM connection to the jump host. Not exactly what I had in mind.
Note that for windows_machines group I have group_vars defined:
ansible_port: 5986
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore
How should I provision Windows hosts via a bastion host?
My priority was to have all the configuration in one place and not distribute part of Ansible to the bastion/jump host. I went for establishing ssh tunnel for the 5986 port. Here is the complete task:
- name: Tunneled configuration of Windows host in a subnet
hosts: windows
connection: local #This is the trick to connect to localhost not actual host
gather_facts: no
tasks:
- name: First setup a tunnel
local_action: command ssh -Nf -4 -o ControlPersist=1m -o ControlMaster=auto -o ControlPath="~/.ssh/mux2win-%r@%h:%p" -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o UserKnownHostsFile="/dev/null" -i {{ hostvars[item].ansible_ssh_private_key_file }} {{ hostvars[item].ansible_ssh_user }}@{{ hostvars[item].ansible_host }} -L {{ ansible_port }}:{{ actual_host }}:{{ ansible_port }}
with_items:
- "{{ groups['jump_servers'][0] }}" #I know my topology so I know which host to use
- name: (optional) Second ensure it is up
local_action: command ssh -O check -S "~/.ssh/mux2win-%r@%h:%p" {{ hostvars[item].ansible_ssh_user }}@{{ hostvars[item].ansible_host }}
with_items:
- "{{ groups['jump_servers'][0] }}"
# ------- actual windows tasks (from ansible examples) ------------
- name: Ping
connection: local
win_ping:
- name: test raw module- run ipconfig
raw: ipconfig
register: ipconfig
- debug: var=ipconfig
- name: Test stat module- test stat module on file
win_stat: path="C:/Windows/win.ini"
register: stat_file
- debug: var=stat_file
- name: Check stat_file result
assert:
that:
- "stat_file.stat.exists"
- "not stat_file.stat.isdir"
- "stat_file.stat.size > 0"
- "stat_file.stat.md5"
# ------- end of actual windows tasks ------------
- name: Stop the tunnel. It would stop anyway after 1m.
local_action: command ssh -O stop -S "~/.ssh/mux2win-%r@%h:%p" {{ hostvars[item].ansible_ssh_user }}@{{ hostvars[item].ansible_host }}
with_items:
- "{{ groups['jump_servers'][0] }}"
For this to work I had to modify slightly the inventory file:
[windows]
windows1 ansible_host=127.0.0.1 ansible_ssh_user=Administrator actual_host=192.168.0.2 (...)
Ansible can connect by accessing 5986
port on local host, so ansible_host has to be set to 127.0.0.1
and to have the information on the actual ip of the Windows machine a custom variable actual_host
is set.
That's not what the delegate_to
option on a task does.
Instead, delegate_to
will make sure that the task only runs against a specific node rather than the group that is listed in the role/playbook.
So for example you may have a role that sets up MySQL on a cluster of boxes that are defined generically but then want to do specific configuration/tasks on the master alone, leaving the master to then replicate these out to the slaves.
You can do SSH proxying where you forward SSH connections through a bastion/jump host but that obviously needs your connection to be SSH throughout which doesn't help you.
The only thing I can think of to help you here would be to use Ansible directly from the bastion/jump host possibly triggered by Ansible (or anything else really) from your machine outside of the protected zone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With