【问题标题】:ansible ssh prompt known_hosts issueansible ssh 提示 known_hosts 问题
【发布时间】:2015-07-25 09:46:24
【问题描述】:

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

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

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 文件条目目标机器?

【问题讨论】:

    标签: ssh command-prompt ansible ansible-playbook hosts-file


    【解决方案1】:

    ansible 文档有a section on this。引用:

    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”。

    【讨论】:

    • 它有效。如果我不想更改 ~/.ansible.cfg,我仍然可以使用该导出变量。我在这一点上唯一看到的是:如果我的库存文件有一个主机作为 xxxx 即 IP,那么 ansible 能够成功地在源机器上运行 playbook(运行 ansible 的地方)但是,如果我使用 hostname.company。 fqdn.or.short.hostname.com 在清单文件中,则 ansible 无法解析源计算机上的主机名。如果我将我的 DNS 服务器条目(名称服务器 10.11.12.133)添加到 /etc/resolv.conf,那么它工作正常。任何想法 ?如何在命令行将 DNS 服务器条目传递给 ansible?
    • 也可以试试这个:ansible-playbook -e 'host_key_checking=False' yourplaybook.yml
    • 如您所述,Ansible 使用您主机的 DNS 解析。如果主机名解析为 IP,它将起作用,但 Ansible 没有(也不应该)为此提供另一种机制。如果系统不在 DNS 中,我使用的一种技巧是在 /etc/hosts 中添加一个条目。
    • 仅作记录,请参阅我的答案(如下)stackoverflow.com/a/39083724/3114959,它为您提供了一种更新本地known_hosts 文件的方法。
    • 另一个选项是在 ansible.cfg 中设置它: "ssh_args = -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" 如果您这样做,它还有一个额外的好处是不会使您的主机密钥文件膨胀'例如,启动很长时间不存在的 EC2 实例
    【解决方案2】:

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

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

    编辑文件路径:

    /etc/ssh/ssh_config
    

    现在取消注释该行:

    StrictHostKeyChecking no
    

    保存更改,就是这样

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

    【讨论】:

    • 出于安全原因,这种方法非常糟糕。它将禁用该系统上所有形式的 SSH 主机密钥验证。
    • @gertvdijk,感谢您的来信。我将其添加到答案中。这种方法会起作用,因此即使这种方法有一些风险,它也应该是一个公认的答案,决定采用这种方法的用户应该考虑到风险,这是他的责任。
    【解决方案3】:

    我已经创建了这个 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

    【讨论】:

      【解决方案4】:

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

      - known_hosts:
          name: "{{ item }}"
          key: "{{ lookup('pipe', 'ssh-keyscan {{ item }},`dig +short {{ item }}`') }}"
        with_items:
         - google.com
         - github.com
      

      【讨论】:

        【解决方案5】:

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

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

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

        (在此处演示,就像您在 ec2 provisioning 之后找到的那样。)

        【讨论】:

        • 同意,最好用这个:become_user "{{ someUser }}"
        • 绝对是更好更安全的方式。还有一个模块可以做到这一点docs.ansible.com/ansible/known_hosts_module.html
        • 查看我的答案stackoverflow.com/a/39083724/3114959(下面),我使用known_hosts 模块,而不是像这里建议的那样简单连接到known_hosts 文件。
        • 使用此方法或以下方法运行 ssh-keyscan 对我不起作用,直到我添加了 retries 关键字。我使用的是新创建的 EC2 实例,第一次总是什么都不返回,第二次按预期工作
        • 这不是幂等的
        【解决方案6】:

        不会做这样的事情来启动 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 文件。

        【讨论】:

        • 我喜欢这种方法,它封装了该命令/运行的配置。
        【解决方案7】:

        为了更新本地 known_hosts 文件,我最终使用了 ssh-keyscan (使用 dig 将主机名解析为 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
        

        因此,对于 inventory 中的每个主机,所有支持的算法都将在 hostname,ipaddress 对记录下的 known_hosts 文件中添加/更新;比如

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

        (假设 inventory 文件看起来像:

        [master]
        atlanta1.my.com
        atlanta2.my.com
        
        [slave]
        denver1.my.com
        denver8.my.com
        

        )

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

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

        【讨论】:

        • 您可以将 ssh 端口添加到 ssh-keyscan,如 {{ hostvars[item]['ansible_port'] }} 一样可用
        • shell 参数最好使用quote 过滤器。
        • 如果有人想知道,我将它用于 ssh-keyscan:"ssh-keyscan {{ item.value }} -T 10 2> /dev/null | grep ssh-ed25519",我还使用了 no_log: "true"changed_when: false 来隐藏所有可怕的输出。
        猜你喜欢
        • 1970-01-01
        • 2012-06-01
        • 1970-01-01
        • 1970-01-01
        • 2022-09-27
        • 1970-01-01
        • 1970-01-01
        • 2020-02-01
        • 2017-09-15
        相关资源
        最近更新 更多