Friday, October 7, 2022

[SOLVED] Ansible: How do you properly skip ssh first connection to fresh host?

Issue

Context: I'm trying to automate the provision of a fresh new server, but when a new machine is spawned and my ansible playbook is played against it from my provisioning server the usual message pops out:

The authenticity of host '192.168.1.25 (192.168.1.25)' can't be established.
ECDSA key fingerprint is SHA256:QF/AyFhYXaz5bjZ1O+kvceoOjBzmI8M1PYmg3lukYmE.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

I am aware this question has been answered a couple times already but, I do not want to add this line to my .cfg file or give the relative argument when I launch an ansible-playbook command.

Problem: So this answer came to my attention https://stackoverflow.com/a/54735937/18647199

I copy pasted the two tasks in my playbook and if they're by themselves the script runs properly. Skipping the aforementioned prompt (even though it skips it on one server that I still have to made the first connection) see:


TASK [Check known_hosts for 192.168.1.14] **************************************
ok: [192.168.1.16 -> localhost]
ok: [192.168.1.14 -> localhost]
ok: [192.168.1.25 -> localhost]

TASK [Ignore host key for 192.168.1.14 on first run] ***************************
skipping: [192.168.1.14]
skipping: [192.168.1.16]
skipping: [192.168.1.25]

PLAY RECAP *********************************************************************
192.168.1.14               : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.1.16               : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.1.25               : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0  

But if I add just one more task to it, it asks again for the auth prompt that I'm trying to skip. p.s. using OpenSSH, latest current version.

What I'm trying to run:

---

#all

- hosts: all
  #connection: local
  become: true
  gather_facts: false #otherwise ssh prompt appears
  tasks:

  - name: Check known_hosts
    local_action: shell ssh-keygen -F "{{ inventory_hostname }}"
    register: is_known
    failed_when: false
    changed_when: false
    ignore_errors: yes

  - name: debug message
    debug:
      msg: the "{{ inventory_hostname }}"" was tested with output "{{ is_known }}"


  - name: Ignore host key for "{{ inventory_hostname }}" on first run
    when: is_known.rc == 1
    set_fact:
      ansible_ssh_common_args: '-o StrictHostKeyChecking=no'

 
 
  - name: Bootstrap check
    stat:
      path: /home/bot/bootstrapped-ok
    register: bootstrap_result

[..] more code

Debug output:

    ansible-playbook debug-bootstrap.yml 

PLAY [all] *********************************************************************

TASK [Check known_hosts] *******************************************************
ok: [192.168.1.16 -> localhost]
ok: [192.168.1.14 -> localhost]
ok: [192.168.1.25 -> localhost]

TASK [debug message] ***********************************************************
ok: [192.168.1.14] => {
    "msg": "the \"192.168.1.14\"\" was tested with output \"{'msg': 'non-zero return code', 'cmd': 'ssh-keygen -F \"192.168.1.14\"', 'stdout': '', 'stderr': 'do_known_hosts: hostkeys_foreach failed: No such file or directory', 'rc': 255, 'start': '2022-04-02 12:30:50.940041', 'end': '2022-04-02 12:30:50.943287', 'delta': '0:00:00.003246', 'changed': False, 'failed': False, 'stdout_lines': [], 'stderr_lines': ['do_known_hosts: hostkeys_foreach failed: No such file or directory'], 'failed_when_result': False}\""
}
ok: [192.168.1.16] => {
    "msg": "the \"192.168.1.16\"\" was tested with output \"{'msg': 'non-zero return code', 'cmd': 'ssh-keygen -F \"192.168.1.16\"', 'stdout': '', 'stderr': 'do_known_hosts: hostkeys_foreach failed: No such file or directory', 'rc': 255, 'start': '2022-04-02 12:30:50.937097', 'end': '2022-04-02 12:30:50.941015', 'delta': '0:00:00.003918', 'changed': False, 'failed': False, 'stdout_lines': [], 'stderr_lines': ['do_known_hosts: hostkeys_foreach failed: No such file or directory'], 'failed_when_result': False}\""
}
ok: [192.168.1.25] => {
    "msg": "the \"192.168.1.25\"\" was tested with output \"{'msg': 'non-zero return code', 'cmd': 'ssh-keygen -F \"192.168.1.25\"', 'stdout': '', 'stderr': 'do_known_hosts: hostkeys_foreach failed: No such file or directory', 'rc': 255, 'start': '2022-04-02 12:30:50.978944', 'end': '2022-04-02 12:30:50.982119', 'delta': '0:00:00.003175', 'changed': False, 'failed': False, 'stdout_lines': [], 'stderr_lines': ['do_known_hosts: hostkeys_foreach failed: No such file or directory'], 'failed_when_result': False}\""
}

TASK [Ignore host key for "192.168.1.14" on first run] *************************
skipping: [192.168.1.14]
skipping: [192.168.1.16]
skipping: [192.168.1.25]

TASK [Bootstrap check] *********************************************************
The authenticity of host '192.168.1.25 (192.168.1.25)' can't be established.
ECDSA key fingerprint is SHA256:QF/AyFhYXaz5bjZ1O+kvceoOjBzmI8M1PYmg3lukYmE.
Are you sure you want to continue connecting (yes/no/[fingerprint])? ok: [192.168.1.16]
ok: [192.168.1.14]

So it seems like the command shell ssh-keygen -F "{{ inventory_hostname }}" isn't doing what it's supposed to do as if we had to launch that via terminal.

Question: Does anyone know how to implement that "one-time skip" or has a better way to do this for a fully automated provisioning / deploy?

(I tried to create an unique .yml file with scarce results, I hit a wall and have not many ideas left on how to continue a fully automated provisioning)


Solution

Just added mine answer to How to ignore ansible SSH authenticity checking? which list lots of options.

This is what we are using for stable hosts (when running the playbook from Jenkins and you simply want to accept the host key when connecting to the host for the first time) in inventory file:

[all:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=accept-new'

And this is what we have for temporary hosts (in the end this will ignore they host key at all):

[all:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'

There is also environment variable or you can add it into group/host variables file. No need to have it in the inventory - it was just convenient in our case.

Maybe this could help?



Answered By - jhutar
Answer Checked By - Marie Seifert (WPSolving Admin)