Ansible中的SSH代理转发

74
我正在使用 Ansible 1.5.3 和带有 ssh 代理转发功能的 Git(https://help.github.com/articles/using-ssh-agent-forwarding)。我可以登录到由 Ansible 管理的服务器并测试我的与 git 的连接是否正确配置:
ubuntu@test:~$ ssh -T git@github.com
Hi gituser! You've successfully authenticated, but GitHub does not provide shell access.

我也可以使用这个帐户克隆和更新我的一个存储库,以便我的git配置看起来不错,并且在直接通过ssh登录到我的服务器时使用ssh转发。
问题:当我尝试使用Ansible命令模块进行上述相同的测试时,它会失败并显示“权限被拒绝”。部分Ansible输出(带有详细日志记录)如下所示:
failed: [xxx.xxxxx.com] => {"changed": true, "cmd": ["ssh", "-T", "git@github.com"], "delta": "0:00:00.585481", "end": "2014-06-09 14:11:37.410907", "rc": 255, "start": "2014-06-09 14:11:36.825426"}
stderr: Permission denied (publickey).

这是一个简单的playbook,用于运行此命令:
- hosts: webservers
  sudo: yes
  remote_user: ubuntu

  tasks:

  - name: Test that git ssh connection is working.
    command: ssh -T git@github.com

问题:为什么我手动通过ssh登录并运行命令时一切正常,但当使用Ansible以同一用户身份运行相同命令时会失败?
如果没有其他人比我更快地回答,我很快就会发布答案。虽然我使用git来演示问题,但它可能发生在任何依赖于ssh代理转发的模块上。它不是特定于Ansible,但我怀疑许多人将首先在此场景中遇到此问题。
4个回答

54

通过从playbook中删除此行解决了问题:

sudo: yes
当在远程主机上运行sudo时,ssh在登录期间设置的环境变量不再可用。特别是SSH_AUTH_SOCK,它“标识用于与代理通信的UNIX域套接字的路径”不再可见,因此ssh代理转发无法工作。
避免在不需要时使用sudo是解决问题的一种方法。另一种方法是通过创建sudoers文件确保SSH_AUTH_SOCK在sudo会话期间保持存在:
/etc/sudoers:

     Defaults    env_keep += "SSH_AUTH_SOCK"

4
可能需要明确设置sudo: no - Daniel Da Cunha
3
如果你选择使用SSH_AUTH_SOCK,请至少了解安全风险。http://serverfault.com/a/371788/67801 - SystematicFrank
3
@SystematicFrank:你链接中的安全风险在于chmod 777,而不是SSH_AUTH_SOCK。 - Bryan Larsen
1
这对我很有用。我使用以下方式进行自动化: - name: 启用SSH凭据传递 lineinfile: dest=/etc/sudoers regexp='^#?Defaults\Wenv_keep[^$]' line='Defaults env_keep += "SSH_AUTH_SOCK"' - Andrej Kyselica

54

这里有一些非常有帮助的部分回答,但经过多次遇到此问题后,我认为一个概述会很有帮助。

首先,您需要确保当从运行Ansible的客户端连接到目标机器时,启用SSH代理转发。即使使用 transport=smart,根据客户端的SSH配置,SSH代理转发可能不会自动启用。要确保它已启用,您可以更新您的~/.ansible.cfg 包含以下内容:

[ssh_connection]
ssh_args=-o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r -o ForwardAgent=yes

接下来,你可能需要应对这个事实:become: yes(和become_user: root)通常会禁用代理转发,因为SSH_AUTH_SOCK环境变量会被重置。(我觉得令人震惊的是,Ansible似乎假定人们将以root用户身份进行SSH操作,因为这使得任何有用的审计都不可能。)有几种方法可以解决这个问题。自 Ansible 2.2 开始,最简单的方法是通过指定-E标志在使用sudo时保留(整个)环境:

become_flags: "-E"

然而,这样做可能会保留像PATH这样的变量,产生不必要的副作用。最干净的方法是只保留SSH_AUTH_SOCK,并将其包含在您的/etc/sudoers文件中的env_keep之中:

Defaults    env_keep += "SSH_AUTH_SOCK"

要使用Ansible完成此操作:

- name: enable SSH forwarding for sudo
  lineinfile:
    dest: /etc/sudoers
    insertafter: '^#?\s*Defaults\s+env_keep\b'
    line: 'Defaults    env_keep += "SSH_AUTH_SOCK"'

这本操作手册的任务相对其他一些建议更加保守,因为它将此添加到任何其他默认的env_keep设置之后(如果没有找到,则在文件末尾),而不会更改任何现有的env_keep设置或假定SSH_AUTH_SOCK已经存在。


2
@AlouaniYounes 当我升级到Ansible 2.4时,它仍然对我有效。 - Trevor Robinson
@trevor-robison 噢,你让我感到开心。将ssh_connection设置添加到我的ansible.cfg中非常有效,所以谢谢你! :) - Justin Finkelstein
6
Sudo也允许通过标志位保留特定的环境变量。因此,在become_flags Ansible设置中,-E可以替换为更具体的--preserve-env=SSH_AUTH_SOCK。这有助于减少保留整个环境所产生的副作用。 - Septatrix
你能解释一下为什么在 ansible.cfg 中添加的每个部分都是必需的吗? - Josh K
不要忘记常见的/etc/sudoers.d扩展,这在某种程度上比黑客攻击发行版提供的/etc/sudoers文件更好。 - undefined
这里有个问题。还是不起作用,因为SSH_AUTH_SOCK指向的套接字很可能对sudo用户不可访问。最好的做法是一开始就直接以该用户身份ssh到目标主机。 - undefined

30

对于你的问题,我另外一个答案是(唯一的例外是我使用的是Ansible 1.9):

你可能想要检查你的/etc/ansible/ansible.cfg文件(或其他三个可能的位置,其中配置设置可以被覆盖),是否包含了推荐在ansible文档中建议的transport=smart。我的默认设置在之前的安装尝试中有一段时间变成了transport=paramiko,阻止了我的控制机器使用OpenSSH,因此阻止了代理转发。这可能是一个非常罕见的情况,但谁知道呢?也可能是你遇到了相同的问题!

虽然我没有发现在我的配置中需要它,但是我应该注意到其他人已经提到你应该像下面这样在同样的文件中添加-o ForwardAgent=yes到你的ssh_args设置中:

[ssh_connection]
ssh_args=-o ForwardAgent=yes

我只是为了完整性而在这里提到它。


4
为了让SSH代理转发正常工作,我不得不在我的ansible.cfg中添加ssh_args。感谢您是唯一一个建议这样做的人!我使用的是OSX 10.10,运行的是Ansible 1.9.1版本。 - staticfloat
7
如果您指定了 ssh_args 参数,那么Ansible将不会提供它自己的参数,包括设置持久连接所需的参数。这可能会导致非常大的减速。相关参数将被添加为-o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r - qqx
1
有时候 sudo_flags 的设置也会出现问题,默认情况下,sudo_flags 被设置为 sudo_flags = -H -S -n,但是可能会出现 "sudo: a password is required" 的错误。这种情况下,你需要将 sudo_flags 设置为 sudo_flags = -H -S,去掉 -n 选项。 - Michał Zalewski
2
我理解使用ssh_extra_args=-o ForwardAgent=yes可以防止 qqx 提到的减速问题。 - simohe

16

扩展 @j.freckle 的答案,更改sudoers文件的ansible方法是:

- name: Add ssh agent line to sudoers
  lineinfile: 
    dest: /etc/sudoers
    state: present
    regexp: SSH_AUTH_SOCK
    line: Defaults env_keep += "SSH_AUTH_SOCK"

1
但是我们不需要运行两次ansible吗?一次用于设置ssh fwding,另一次用于实际使用此环境变量建立连接? - alfetopito
听起来不错。我总是不得不多次运行和注释playbooks,ssh进入服务器并手动检查事情。从来没有一帆风顺过。 - AJcodez
为了尽量避免多次运行,我最终将此步骤放入脚本中,在新的服务器安装中运行。毕竟在使用ansible设置我的服务器之前还有一些要设置的东西... - alfetopito

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接