可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm running Ansible playbook and it works fine on one machine.
On a new machine when I try for the first time, I get the following error.
17:04:34 PLAY [appservers] *************************************************************
17:04:34
17:04:34 GATHERING FACTS ***************************************************************
17:04:34 fatal: [server02.cit.product-ref.dev] => {'msg': "FAILED: (22, 'Invalid argument')", 'failed': True}
17:04:34 fatal: [server01.cit.product-ref.dev] => {'msg': "FAILED: (22, 'Invalid argument')", 'failed': True}
17:04:34
17:04:34 TASK: [common | remove old ansible-tmp-*] *************************************
17:04:34 FATAL: no hosts matched or all hosts have already failed -- aborting
17:04:34
17:04:34
17:04:34 PLAY RECAP ********************************************************************
17:04:34 to retry, use: --limit @/var/lib/jenkins/site.retry
17:04:34
17:04:34 server01.cit.product-ref.dev : ok=0 changed=0 unreachable=1 failed=0
17:04:34 server02.cit.product-ref.dev : ok=0 changed=0 unreachable=1 failed=0
17:04:34
17:04:34 Build step 'Execute shell' marked build as failure
17:04:34 Finished: FAILURE
This error can be resolved, if I first go to the source machine (from where I'm running the ansible playbook) and manually ssh to the target machine (as the given user) and enter "yes" for known_hosts file entry.
Now, if I run the same ansible playbook second time, it works without an error.
Therefore, how can I suppress the prompt what SSH gives while making ssh known_hosts entry for the first time for a given user (~/.ssh folder, file known_hosts)?
I found I can do this if I use the following config entries in ~/.ssh/config file.
~/.ssh/config
# For vapp virtual machines
Host *
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null
User kobaloki
LogLevel ERROR
i.e. if I place the above code in the user's ~/.ssh/config file of a remote machine and try Ansible playbook for the first time, I won't be prompted for entring "yes" and playbook will run successfully (without requiring the user to manually create a known_hosts file entry from the source machine to the target/remote machine).
My questions:
1. What security issues I should take care if I go ~/.ssh/config way
2. How can I pass the settings (what's there in the config file) as parameters/options to ansible at command line so that it will run first time on a new machine (without prompting / depending upon the known_hosts file entry on the source machine for the target machine?
回答1:
The ansible docs have a section on this. Quoting:
Ansible 1.2.1 and later have host key checking enabled by default.
If a host is reinstalled and has a different key in ‘known_hosts’, this will result in an error message until corrected. If a host is not initially in ‘known_hosts’ this will result in prompting for confirmation of the key, which results in an interactive experience if using Ansible, from say, cron. You might not want this.
If you understand the implications and wish to disable this behavior, you can do so by editing /etc/ansible/ansible.cfg or ~/.ansible.cfg:
[defaults]
host_key_checking = False
Alternatively this can be set by an environment variable:
$ export ANSIBLE_HOST_KEY_CHECKING=False
Also note that host key checking in paramiko mode is reasonably slow, therefore switching to ‘ssh’ is also recommended when using this feature.
回答2:
To update local known_hosts
file, I ended up using a combination of ssh-keyscan
(with dig
to resolve a hostname to IP address) and ansible module known_hosts
as follows: (filename ssh-known_hosts.yml
)
- name: Store known hosts of 'all' the hosts in the inventory file
hosts: localhost
connection: local
vars:
ssh_known_hosts_command: "ssh-keyscan -T 10"
ssh_known_hosts_file: "{{ lookup('env','HOME') + '/.ssh/known_hosts' }}"
ssh_known_hosts: "{{ groups['all'] }}"
tasks:
- name: For each host, scan for its ssh public key
shell: "ssh-keyscan {{ item }},`dig +short {{ item }}`"
with_items: "{{ ssh_known_hosts }}"
register: ssh_known_host_results
ignore_errors: yes
- name: Add/update the public key in the '{{ ssh_known_hosts_file }}'
known_hosts:
name: "{{ item.item }}"
key: "{{ item.stdout }}"
path: "{{ ssh_known_hosts_file }}"
with_items: "{{ ssh_known_host_results.results }}"
To execute such yml, do
ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook path/to/the/yml/above/ssh-known_hosts.yml
As a result, for each host in the inventory, all supported algorithms will be added/updated in the known_hosts
file under hostname,ipaddress pair record; such as
atlanta1.my.com,10.0.5.2 ecdsa-sha2-nistp256 AAAAEjZHN ... NobYTIGgtbdv3K+w=
atlanta1.my.com,10.0.5.2 ssh-rsa AAAAB3NaC1y ... JTyWisGpFeRB+VTKQ7
atlanta1.my.com,10.0.5.2 ssh-ed25519 AAAAC3NaCZD ... UteryYr
denver8.my.com,10.2.13.3 ssh-rsa AAAAB3NFC2 ... 3tGDQDSfJD
...
(Provided the inventory file looks like:
[master]
atlanta1.my.com
atlanta2.my.com
[slave]
denver1.my.com
denver8.my.com
)
As opposed to the Xiong's answer, this would properly handle the content of the known_hosts
file.
This play is especially helpful if using virtualized environment where the target hosts get re-imaged (thus the ssh pub keys get changed).
回答3:
Disabling host key checking entirely is a bad idea from a security perspective, since it opens you up to man-in-the-middle attacks.
If you can assume the current network isn't compromised (that is, when you ssh to the machine for the first time and are presented a key, that key is in fact of the machine and not an attacker's), then you can use ssh-keyscan
and the shell module to add the new servers' keys to your known hosts file (edit: Stepan's answer does this a better way):
- name: accept new ssh fingerprints
shell: ssh-keyscan -H {{ item.public_ip }} >> ~/.ssh/known_hosts
with_items: ec2.instances
(Demonstrated here as you would find after ec2 provisioning.)
回答4:
Following @Stepan Vavra's correct answer. A shorter version is:
- known_hosts:
name: "{{ item }}"
key: "{{ lookup('pipe', 'ssh-keyscan {{ item }},`dig +short {{ item }}`') }}"
with_items:
- google.com
- github.com
回答5:
Wouldn't doing something like this work for priming the known_hosts file:
ANSIBLE_HOST_KEY_CHECKING=false ansible all -m ping
This should connect to each hosts in the inventory, updating the known_hosts file for each host without having to enter "yes" for each prompt, then runs the "ping" module on each host?
A quick test (deleting my known_hosts file then running the above, done on an Ubuntu 16.04 instance) seemed to populate the known_hosts file with their current fingerprints.
@Stepan Vavra's solution didn't work for me as I was using aliased hosts (was connecting to internal IPs which didn't have DNS available for them, so I wanted more descriptive names to refer to each hosts in the inventory and having ansible_host variable point to the actual IP for each). Running the above was much simpler and primed my known_hosts file without having to disable host key checking in ansible or ssh.
回答6:
you can also set this from the server os level. you will need to configure the ssh config file in order to avoid ssh check to prompt:
edit the file path:
/etc/ssh/ssh_config
now uncomment the line:
StrictHostKeyChecking no
save the changes and that's it