Best way to get the IP address of the Ansible cont

2019-05-10 01:23发布

问题:

I am using Ansible and ufw to setup a firewall on my servers. As part of the ufw rules I would like to allow SSH from the Ansible control machine, but not from anywhere else. My question is - what is the best way to get the IP address of the control machine itself so I can put it into the rule?

I'm aware that I can use facts to get the IP address of the machine I am running the playbook on, but I don't see any easy way to get it automatically for the machine that is running ansible.

I'd like to avoid adding a new variable to represent this if possible since it would be nice if it was automatically discoverable, though if that's the only known best way to do it then I will just do that.

EDIT: I found this duplicate question which is the same as mine, however it also is unanswered so will leave this open for a bit.

回答1:

{{ ansible_env['SSH_CLIENT'].split() | first }}

works, but you have to gather facts about connection variables from default user, so eighter:

  • Set «gather_facts: yes» and not «become: yes» on playbook level
  • More reliable: run «setup» task (without «become: yes» and before this «ansible_env» usage — better on «pre_tasks» section).

If you run «gather/setup» with «become», you will later get «One or more undefined variables: 'dict object' has no attribute 'SSH_CLIENT'» (this is becase sudoed «setup» can catch only small set of variables).



回答2:

The easiset way is to add connection local

---
 - name: get my public IP
   ipify_facts: api_url=http://api.ipify.org
   connection: local

 - firewalld: rich_rule='rule family=ipv4 source address={{ ipify_public_ip }} accept' permanent=no state=enabled timeout=300
   become: true


回答3:

I just hacked this solution and it worked. Is this something you are looking for?

- debug var="{{hostvars[inventory_hostname]['ansible_env']['SSH_CLIENT'].split(' ')[0]}}"


回答4:

The "ipify_facts" method described in a different answer should work if:

  1. Your control host has only one interface, or if it has multiple interfaces and the interface used for reaching towards the ipify api_url is the same as for reaching towards your remote host, -and-
  2. Your control host has a public IP (no NAT used at all), or your control host is inside NAT but the remote host is outside.

If either of the above conditions is not met (that is, if your control host has multiple interfaces and/or your control host as well as your remote host are both behind NAT and using private addresses), then a different (albeit slightly more complex) way is to replicate the following in Ansible:

$ ip route get 203.0.113.4
203.0.113.4 via 172.26.232.1 dev enp0s3  src 172.26.232.125
                  cache
$

This will show you the interface and the source address (172.26.232.125) to be used for reaching towards a specific destination (203.0.113.4).

One way to implement this in Ansible would be:

---
- name: Obtain local IP address
  local_action: shell ip route get {{ inventory_hostname }} | awk '{ for (x=1;x<=NF;x++) if ($x=="src") print $(x+1) }'
  register: local_address
  changed_when: false

- name: Print my local address
  debug: msg="Source address towards {{ inventory_hostname }} is {{ local_address.stdout }}"

Output:

$ ansible-playbook test.yml  -i inventory.txt

PLAY [test] ********************************************************************

TASK [Obtain local IP address] *************************************************
ok: [203.0.113.4 -> localhost]

TASK [Print my local address] **************************************************
ok: [203.0.113.4] => {
    "msg": "Source address towards 203.0.113.4 is 172.26.232.125"
}

This should also work if you have multiple remote hosts reachable via different interfaces.

An additional step in the "shell" action would be needed if your inventory_hostname was a DNS hostname as opposed to a numerical IP address.



回答5:

{{ ansible_env['SSH_CLIENT'].split()[0] }}


回答6:

{{ ansible_env['SSH_CLIENT'].split() | first }}