53

我正在运行 Ansible 剧本,它在一台机器上运行良好。

在我第一次尝试的新机器上,我收到以下错误。

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

如果我首先转到源计算机(从我运行 ansible playbook 的位置)并手动 ssh 到目标计算机(作为给定用户)并为 known_hosts 文件条目输入“yes”,则可以解决此错误。

现在,如果我第二次运行相同的 ansible playbook,它可以正常工作。

因此,如何在第一次为给定用户(~/.ssh 文件夹,文件 known_hosts)创建 ssh known_hosts 条目时抑制 SSH 给出的提示?

我发现如果我在~/.ssh/config文件中使用以下配置条目,我可以做到这一点。

~/.ssh/config

# For vapp virtual machines
Host *
  StrictHostKeyChecking no
  UserKnownHostsFile=/dev/null
  User kobaloki
  LogLevel ERROR

即如果我将上述代码放在远程机器的用户的 ~/.ssh/config 文件中并第一次尝试 Ansible playbook,我将不会被提示输入“yes”并且 playbook 将成功运行(不需要用户手动创建从源机器到目标/远程机器的 known_hosts 文件条目)。

我的问题: 1. 如果我去 ~/.ssh/config 方式,我应该注意哪些安全问题 2. 如何将设置(配置文件中的内容)作为参数/选项传递给命令行中的 ansible 以便它将在新机器上首次运行(不提示 / 取决于目标机器上的 known_hosts 文件条目?

4

7 回答 7

57

ansible 文档对此有一个部分。报价:

Ansible 默认启用主机密钥检查。

如果重新安装主机并且在“known_hosts”中有不同的密钥,这将导致错误消息,直到更正为止。如果主机最初不在“known_hosts”中,这将导致提示确认密钥,如果使用 Ansible(例如 cron),则会产生交互式体验。你可能不想要这个。

如果您了解其中的含义并希望禁用此行为,您可以通过编辑 /etc/ansible/ansible.cfg 或 ~/.ansible.cfg 来实现:

[defaults]
host_key_checking = False

或者,这可以由ANSIBLE_HOST_KEY_CHECKING 环境变量设置:

$ export ANSIBLE_HOST_KEY_CHECKING=False

另请注意,在 paramiko 模式下检查主机密钥相当慢,因此在使用此功能时也建议切换到“ssh”。

于 2015-05-14T00:05:11.090 回答
43

为了更新本地known_hosts文件,我最终使用了ssh-keyscandig将主机名解析为 IP 地址)和 ansible 模块的组合known_hosts,如下所示:(文件名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 }}"

要执行这样的 yml,请执行

ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook path/to/the/yml/above/ssh-known_hosts.yml

因此,对于清单中的每个主机,所有支持的算法都将添加/更新到known_hosts文件中的主机名、IP 地址对记录下;如

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
...

(假设清单文件如下所示:

[master]
atlanta1.my.com
atlanta2.my.com

[slave]
denver1.my.com
denver8.my.com

)

与熊的回答相反,这将正确处理known_hosts文件的内容。

如果使用目标主机重新映像的虚拟化环境(因此 ssh pub 密钥被更改),此操作特别有用。

于 2016-08-22T15:45:33.970 回答
20

从安全角度来看,完全禁用主机密钥检查是一个坏主意,因为它会使您面临中间人攻击。

如果您可以假设当前网络没有受到威胁(也就是说,当您第一次 ssh 到计算机并获得密钥时,该密钥实际上是计算机的,而不是攻击者的),那么您可以使用ssh-keyscan和将新服务器的密钥添加到已知主机文件的 shell 模块(编辑: Stepan 的回答这样做更好):

- name: accept new ssh fingerprints
  shell: ssh-keyscan -H {{ item.public_ip }} >> ~/.ssh/known_hosts
  with_items: ec2.instances

(在这里演示,就像您在ec2 配置之后发现的那样。)

于 2016-02-04T23:43:22.803 回答
11

遵循@Stepan Vavra 的正确答案。一个较短的版本是:

- known_hosts:
    name: "{{ item }}"
    key: "{{ lookup('pipe', 'ssh-keyscan {{ item }},`dig +short {{ item }}`') }}"
  with_items:
   - google.com
   - github.com
于 2017-04-13T12:48:14.507 回答
8

不会做这样的事情来启动 known_hosts 文件:

ANSIBLE_HOST_KEY_CHECKING=false ansible all -m ping

这应该连接到清单中的每个主机,更新每个主机的 known_hosts 文件,而不必为每个提示输入“yes”,然后在每个主机上运行“ping”模块?

一个快速测试(删除我的 known_hosts 文件然后运行上述,在 Ubuntu 16.04 实例上完成)似乎用他们当前的指纹填充 known_hosts 文件。

@Stepan Vavra 的解决方案对我不起作用,因为我使用的是别名主机(正在连接到没有 DNS 可用的内部 IP,所以我想要更多描述性的名称来引用清单中的每个主机并具有 ansible_host 变量指向每个的实际IP)。运行上面的内容要简单得多,并且无需在 ansible 或 ssh 中禁用主机密钥检查,就可以为我的 known_hosts 文件做准备。

于 2017-06-02T17:17:32.313 回答
0

警告:主机(以及 Ansible)将不再对具有上述设置的任何 ssh 连接执行 SSH 主机密钥验证。这可能存在风险,强烈不建议在生产环境中使用

您也可以从服务器操作系统级别进行设置。您将需要配置 ssh 配置文件以避免 ssh 检查提示:

编辑文件路径:

/etc/ssh/ssh_config

现在取消注释该行:

StrictHostKeyChecking no

保存更改,就是这样

警告:主机(以及 Ansible)将不再对具有上述设置的任何 ssh 连接执行 SSH 主机密钥验证。这可能存在风险,强烈不建议在生产环境中使用

于 2017-01-05T15:13:09.990 回答
0

我已经创建了这个 shell 脚本(也适用于 Jenkins,顺便说一句)

my_known_hosts="$HOME/.ssh/known_hosts"
## housekeeping ##
if [ -f $my_known_hosts".old" ] 
    then rm -f $my_known_hosts".old"
fi
## housekeeping ##
## backup ##
if [ -f $my_known_hosts ] 
    then mv $my_known_hosts "$my_known_hosts.old"
fi
## backup ##
## query aws for active hosts and add to known_hosts
aws ec2 describe-instances --query 'Reservations[*].Instances[*].NetworkInterfaces[*].Association.PublicDnsName' --output text | xargs -L1 ssh-keyscan -H >> $my_known_hosts
## query aws for active hosts and add to known_hosts

https://admin-o-mat.blogspot.com/2020/09/ansible-and-aws-adding-hosts-to.html

于 2020-09-06T00:11:26.247 回答