如何将ansible与两因素身份验证一起使用?
Posted
技术标签:
【中文标题】如何将ansible与两因素身份验证一起使用?【英文标题】:How to use ansible with two factor authentication? 【发布时间】:2014-05-31 16:34:25 【问题描述】:我已经使用 duosecurity 为 ssh 启用了两因素身份验证(使用此 playbook https://github.com/CoffeeAndCode/ansible-duo)。
我现在如何使用 ansible 来管理服务器。因此,SSH 调用无法收集事实。我希望运行 playbook 的人在运行 playbook 之前输入两个因素代码。
为部署用户禁用两个因素是一种可能的解决方案,但会产生我希望避免的安全问题。
【问题讨论】:
在我能想到的几乎所有情况下,使用 2 因素身份验证锁定网络中的堡垒主机并允许 Ansible 在该网络中没有它的情况下进行 ssh 是一个更好的设计选择。正如下面的(技术上正确!)答案所说,任何涉及如此繁重的设置的解决方案在规模上都会非常痛苦,它会首先消除使用 Ansible 的大部分优势。 【参考方案1】:这是一个 hack,但您可以通过启用 2fac 的 SSH 连接建立非 2fac Ansible SSH 连接。
概述
我们将设置两个用户:ansible
将是 Ansible 将使用的用户。它应该以 Ansible 支持的方式进行身份验证(即不是 2fac)。此用户将受到限制,因此无法从除127.0.0.1
之外的任何地方连接,因此无法从机器外部访问。
第二个用户ansible_tunnel
将对外界开放,但将通过两个因素进行身份验证,并且只允许通过隧道连接到本地计算机。
您必须能够仅为部分用户(不是全部)配置两因素身份验证。
Some info on SSH tunnels.
在目标机器上:
-
创建两个用户:
ansible
和 ansible_tunnel
将您的公钥放入两个用户的~/.ssh/authorized_keys
将ansible_tunnel
的shell 设置为/bin/false
,或者锁定用户 - 它将用于独占隧道,而不是运行命令
将以下内容添加到/etc/ssh/sshd_config
:
AllowTcpForwarding no
AllowUsers ansible@127.0.0.1 ansible_tunnel
Match User ansible_tunnel
AllowTcpForwarding yes
PermitOpen 127.0.0.1:22
ForceCommand echo 'This account can only be used for tunneling SSH sessions'
为ansible_tunnel
设置两因素身份验证仅
重启sshd
在运行 Ansible 的机器上:
在运行 Ansible 之前,运行以下命令(在 Ansible 机器上,而不是目标上):
ssh -N -L 8022:127.0.0.1:22 ansible_tunnel@<host>
您将通过两个因素进行身份验证。
一旦隧道启动(使用netstat
检查),使用ansible_ssh_user=ansible
、ansible_ssh_port=8022
和ansible_ssh_host=localhost
运行Ansible。
回顾
只有ansible_tunnel
可以从外部连接,它会使用两个因素进行身份验证
隧道建立后,连接到本地机器上的端口8022
与连接到远程机器上的sshd是一样的
我们允许ansible
仅在通过 localhost 完成 SSH 连接时,因此只允许通过隧道连接的连接
规模
这不适用于多台服务器,因为需要为每台机器打开单独的隧道,这需要手动操作。但是,如果您为服务器选择了 2 因素身份验证,则您已经愿意执行一些手动操作来连接到每个服务器,并且此解决方案只会增加一些脚本包装的开销。
[编辑添加]
奖金
为方便起见,我们可能想直接登录维护账户做一些手工工作,而不经过建立隧道的过程。在这种情况下,我们可以将 SSH 配置为需要 2fac 身份验证,同时保持无需 2fac 通过隧道进行连接的能力:
# All users must authenticate using two factors
AuthenticationMethods publickey,keyboard-interactive
# Allow both maintenance user and tunnel user with no restrictions
AllowUsers ansible ansible_tunnel
# The maintenance user is allowed to authenticate using a single factor only
# when connecting from a local address - it should be impossible to connect to
# this user using a single factor from the outside (the only way to do that is
# having an existing access to the machine, or use the two-factor tunnel)
Match User ansible Address 127.0.0.1
AuthenticationMethods publickey
【讨论】:
很好的答案,这是一种 hack,但这似乎比我在 ansible 邮件列表或 github 问题上找到的任何解决方案都更好。拥有单独的用户,ansible_tunnel 用户设置为仅隧道有什么好处?似乎您可以允许每个用户仅使用来自 127.0.0.1 的 publickey auth,然后只涉及一个用户,并且实际的维护命令作为您自己运行。 我认为您可以设置一个用户以允许来自外部的 2fac-only,但来自 127.0.0.1 的 pubkey-only,并将该用户用于隧道和 ansible(即隧道该用户对自己来说,哈哈)。我只是想将角色分开 - 万一我为隧道用户错误配置了 SSH,它仍然不允许运行命令。【参考方案2】:使用堡垒主机的解决方案
即使使用 ssh 堡垒主机,我也花了很长时间才能让它工作。如果它对其他人有帮助,这就是我想出的。它使用ControlMaster
ssh 配置选项,并且由于 ansible 使用常规 ssh,因此可以将其配置为使用相同的 ssh 功能并重新使用与堡垒主机的连接,而不管它与远程主机打开多少连接。我已经看到一般推荐的这些控制选项(如果您有很多主机,可能是出于性能原因),但不是在 2FA 到堡垒主机的上下文中。
使用这种方法,您不需要任何 sshd 配置更改,因此您需要 AuthenticationMethods publickey,keyboard-interactive
作为堡垒服务器上的唯一身份验证方法设置,而 publickey
仅适用于您正在代理的所有其他服务器通过堡垒到达。由于堡垒主机是唯一接受来自 Internet 的外部连接的主机,因此它是唯一需要 2FA 的主机,而内部主机依赖代理转发进行公钥身份验证,但不使用 2FA。
在客户端上,我在名为ssh.config
的顶层目录中为我的ansible 环境创建了一个新的ssh 配置文件(ansible.cfg 的兄弟)。它包含:
Host bastion-persistent-connection
HostName <bastion host>
ForwardAgent yes
IdentityFile ~/.ssh/my-key
ControlMaster auto
ControlPath ~/.ssh/ansible-%r@%h:%p
ControlPersist 10m
Host 10.0.*.*
ProxyCommand ssh -W %h:%p bastion-persistent-connection -F ./ssh.config
IdentityFile ~/.ssh/my-key
然后在 ansible.cfg 我有:
[ssh_connection]
ssh_args = -F ./ssh.config
需要注意的几点:
在这种情况下,我的私有子网是 10.0.0.0/16,它映射到上面的主机通配符选项。堡垒代理到该子网上的服务器的所有 ssh 连接。
这有点脆弱,因为我只能在这个目录中运行我的 ssh 或 ansible 命令,因为 ProxyCommand
将本地路径传递给这个配置文件。不幸的是,我认为没有 ssh 变量映射到当前正在使用的配置文件,因此我可以自动将相同的配置文件传递给 ProxyCommand。根据您的环境,最好使用绝对路径。
唯一的问题是它使运行 ansible 变得更加复杂。不幸的是,据我所知,ansible 不支持 2FA。因此,如果您没有与堡垒的现有 ssh 连接,ansible 将为它连接到的每个私有服务器打印一次 Verification code:
,但它实际上并没有监听输入,因此无论您做什么连接都会失败。
所以我首先运行:ssh -F ssh.config bastion-persistent-connection
这会在~/.ssh/ansible-*
中创建套接字文件,并且本地 ssh 代理将在可配置的时间(我设置为 10m)之后关闭并删除该套接字。
一旦套接字打开,我就可以像正常一样运行 ansible 命令,例如ansible all -m ping
他们成功了。
【讨论】:
小调整:我最终使用了ControlPath ~/.ansible/cp/ansible-ssh-%h-%p-%r
,它对应于 Ansible 的默认 control_path
。 docs.ansible.com/ansible/intro_configuration.html#control-path【参考方案3】:
我可以通过 ssh 和 ansible 的 ControlMaster
功能将 ansible 与 ssh 和 2FA 一起使用。
我的本地 ssh 客户端配置为转储 ControlPath
套接字以进行多路复用连接。 Ansible 配置为使用相同的套接字。
本地 ssh 客户端
此配置为所有连接启用多路复用。我个人将此配置存储在 `~/.ssh/config:
Host *
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p.socket
ControlPersist 1m
建立连接后,$HOME/.ssh
目录中会出现一个套接字。此套接字在断开连接后一分钟内仍然存在。
配置 ansible
Ansible 被配置为重用本地套接字。
将此添加到您的ansible configuration file(例如,~/.ansible.cfg
):
[ssh_connection]
control_path=~/.ssh/master-%%r@%%h:%%p.socket
注意用于变量替换的双 %
。
用法
-
使用 ssh 常规命令 (
ssh user@server
) 连接到您的服务器,并执行 2FA;
照常启动您的 ansible 命令。
第 2 步必须在 ControlPersist
配置中执行,或者在另一个终端中启动 ansible 命令时在终端中保持 ssh 连接。
您也可以在不需要时强制关闭连接,使用:ssh -O exit user@server
。
请注意,如果您打开第三个终端并运行ssh user@server
,则不会要求您提供凭据:在 1. 中建立的连接将被重新使用。
缺点
网络状况不佳时
有时,当您断开连接时,套接字仍然存在。每个进一步的连接都会挂起。您必须使用ssh -O exit user@server
手动断开此连接。这是此方法唯一已知的缺点。
参考资料:
Ansible parameterANSIBLE_SSH_CONTROL_PATH
关于多路复用 ssh(一篇非常古老的博文让我发现了 ssh 多路复用:https://blog.scottlowe.org/2015/12/11/using-ssh-multiplexing/)
【讨论】:
以上是关于如何将ansible与两因素身份验证一起使用?的主要内容,如果未能解决你的问题,请参考以下文章