如何安全地使用每个主机密码实现 ansible?

如何安全地使用每个主机密码实现 ansible?

我想使用ansible管理一组现有服务器。我创建了一个文件,并使用仅针对单个主机的命令ansible_hosts成功测试了(使用该选项)-K

ansible -i ansible_hosts host1 --sudo -K # + commands ...

我现在的问题是每个主机上的用户密码不同,但我找不到在 Ansible 中处理这个问题的方法。

使用时-K,系统仅会提示我预先输入一个 sudo 密码,然后似乎会在没有提示的情况下尝试所有后续主机:

host1 | ...
host2 | FAILED => Incorrect sudo password
host3 | FAILED => Incorrect sudo password
host4 | FAILED => Incorrect sudo password
host5 | FAILED => Incorrect sudo password

迄今为止的研究:

  • AStackOverflow 问题有一个错误的答案(“使用-K”)和作者的一个回应说“发现我需要无密码的 sudo”

  • Ansible 文档,其中说“使用无密码 sudo 可以使事情更容易实现自动化,但是这不是必需的“(重点是我的)

  • 这个安全 StackExchange 问题将其视为NOPASSWD必需的已读

  • 文章“可扩展且易于理解的配置……”其中写道:

    “运行 sudo 可能需要输入密码,这是永远阻止 Ansible 的可靠方法。一个简单的解决方法是在目标主机上运行 visudo,并确保 Ansible 用于登录的用户不必输入密码”

  • 文章“基本 Ansible 剧本”,其中表示

    “Ansible 可以以 root 身份登录目标服务器,从而避免使用 sudo,或者让 ansible 用户无需密码即可使用 sudo,但一想到要这样做,我的脾脏就快要跳出食道,堵塞我的气管,所以我不这么做”

    我的想法完全一样,但是如何扩展单个服务器呢?

  • ansible 问题 #1227,“Ansible 应该在剧本中要求所有用户输入 sudo 密码”,该帖子在一年前由 mpdehaan 关闭,评论为“没有看到对此有太多需求,我认为大多数人大部分时间都只从一个用户帐户执行 sudo 或使用密钥。”

那么...人们在这种情况下如何使用 Ansible?设置NOPASSWD/etc/sudoers跨主机重复使用密码或启用 root SSH 登录似乎都会大大降低安全性。

答案1

你肯定已经做过研究了……

从我使用 ansible 的所有经验来看,您想要实现的功能不受支持。正如您所提到的,ansible 声明它不需要无密码 sudo,您说得对,它不需要。但我还没有看到任何在 ansible 中使用多个 sudo 密码的方法,当然不需要运行多个配置。

所以,我无法提供您正在寻找的确切解决方案,但您确实问过......

“那么……人们在这种情况下如何使用 Ansible?在 /etc/sudoers 中设置 NOPASSWD、跨主机重复使用密码或启用 root SSH 登录似乎都会大幅降低安全性。”

我可以给你一个观点。我的用例是多个数据中心的 1000 个节点,为一家全球 SaaS 公司提供支持,由于我们业务的性质,我必须设计/实施一些极其严格的安全控制。安全性始终是一种平衡行为,可用性越高,安全性越低,无论您运行的是 10 台服务器、1,000 台服务器还是 100,000 台服务器,这个过程都没有什么不同。

您绝对正确地避免使用 root 登录(无论是通过密码还是 ssh 密钥)。事实上,如果服务器已插入网线,则应完全禁用 root 登录。

让我们谈谈密码重用问题,在大型企业中,要求系统管理员在每个节点上使用不同的密码是否合理?对于几个节点来说,也许可以,但如果我的管理员/工程师必须在 1000 个节点上使用不同的密码,他们会反抗。实现这一点也几乎是不可能的,每个用户都必须将自己的密码存储在某个地方,最好是密钥密码,而不是电子表格。而且,每次将密码放在可以以纯文本形式提取的位置时,您的安全性都会大大降低。我宁愿让他们记住一两个非常强的密码,也不愿每次需要登录或在机器上调用 sudo 时查阅密钥密码文件。

因此,即使在安全环境中,密码重用和标准化也是完全可以接受的,也是标准的。否则 ldap、keystone 和其他目录服务就不需要存在了。

当我们转向自动用户时,ssh 密钥可以很好地帮助您登录,但您仍然需要通过 sudo。您的选择是为自动用户设置标准化密码(在许多情况下这是可以接受的)或启用 NOPASSWD(正如您所指出的那样)。大多数自动用户只执行几个命令,因此启用 NOPASSWD 是完全可能的,而且肯定是可取的,但仅限于预先批准的命令。我建议使用您的配置管理(在本例中为 ansible)来管理您的 sudoers 文件,以便您可以轻松更新无密码命令列表。

现在,一旦开始扩展,您可以采取一些步骤来进一步隔离风险。虽然我们有 1000 个左右的节点,但并非所有节点都是“生产”服务器,有些是测试环境等。并非所有管理员都可以访问生产服务器,但那些管理员可以使用与其他地方相同的 SSO 用户/密码|密钥。但自动化用户更安全一些,例如非生产管理员可以访问的自动化工具具有不能在生产中使用的用户和凭据。如果您想在所有节点上启动 ansible,则必须分两批进行,一次用于非生产,一次用于生产。

我们也使用 puppet,因为它是一个强制配置管理工具,所以所有环境的大多数更改都会通过它进行。

显然,如果您引用的功能请求重新开放/完成,那么您所希望做的事情将得到完全支持。即便如此,安全性也是一个风险评估和妥协的过程。如果您只有几个节点,您可以记住这些节点的密码而无需使用便签,那么单独的密码会稍微安全一些。但对于我们大多数人来说,这不是一个可行的选择。

答案2

从 Ansible 1.5 开始,可以使用加密保险库对于 host_vars 和其他变量。这至少使您能够ansible_sudo_pass安全地存储每个主机(或每个组)的变量。不幸的是,--ask-vault-pass每次 ansible 调用只会提示一个保险库密码,因此您仍然只能为将一起使用的所有主机使用一个保险库密码。

尽管如此,对于某些用途来说,这可能比在多个主机上使用单个 sudo 密码有所改进,因为无法访问您加密的 host_vars 的攻击者仍然需要为其攻击的每台机器(或机器组)设置单独的 sudo 密码。

答案3

使用 Ansible 1.5,可以设置ansible_sudo_pass变量使用lookup('password', …)

ansible_sudo_pass: "{{ lookup('password', 'passwords/' + inventory_hostname) }}"

我发现这比使用文件更方便,host_vars/原因如下:

  • 我实际上用来with_password: "passwords/{{ inventory_hostname}} encrypt=sha256_crypt" 设置部署远程用户(然后需要须藤),因此它们已经存在于文件中(尽管执行这些纯文本查找会在生成散列值时丢失存储在文件中的盐值)。

  • 这样只会将密码保留在文件中(没有ansible_sudo_pass:已知的明文),从而在一定程度上提高加密安全性。更重要的是,这意味着您不会加密所有其他特定于主机的变量,因此无需密码库密码即可读取它们。

  • 将密码放在单独的目录中,可以更轻松地将文件保留在源代码控制之外,或者使用类似git-crypt以加密形式存储它们(您可以将此功能与缺少保险库功能的早期 Ansible 一起使用)。我使用 git-crypt,由于我只在加密文件系统上以解密形式签出存储库,所以我不必担心保险库,因此不需要输入保险库密码。(当然,同时使用两者会更安全。)

您还可以使用抬头函数ansible_ssh_pass;这甚至可能适用于没有ansible_sudo_pass

答案4

尽管如此,这是一个相当古老的话题:

  • 我们内部使用两种不同的身份验证系统,机器的管理由我的团队的本地工作站完成。
  • vars_plugin为 Ansible 写了一个(一个相当完整的实现可以在https://gist.github.com/mfriedenhagen/e488235d732b7becda81) 区分了几种身份验证系统:
  • 身份验证系统的名称是特定于组的。
  • 使用的登录/sudo 用户是特定于组和管理员的。
  • 因此,我从管理员环境中提取用户,并通过密码保险箱中的 python-keyring 库提取相应的密码(我们使用 Mac OS X 的钥匙串,但从文档来看,kwallet Gnome 和 _win_crypto 也受支持)。
  • 我设置了 Mac OS X 钥匙串中密码的权限,以通知我有关命令行程序安全性请求访问主机使用的每个身份验证系统的密码的事实,因此我运行“ansible -s all -m ping”并得到两个提示(每个身份验证系统一个),我按下空格键,ansible 就会获取密码。

相关内容