我们希望听到您的声音!帮助我们深入了解 Ansible 生态系统的现状。
参与 Ansible 项目 2024 年调查

保护 Tower 安装程序密码

保护 Tower 安装程序密码

Red Hat Ansible Automation Platform 的关键组成部分之一是 Ansible Tower。Ansible Tower 有助于扩展 IT 自动化、管理复杂的部署并加快生产力。Ansible Tower 的优势在于其简单性,这也扩展到安装流程:当以非容器版本安装时,一个简单的脚本用于读取初始配置中的变量以部署 Ansible Tower。相同的脚本和初始配置甚至可以重复使用以扩展设置,例如添加更多集群节点。

但是,此初始配置的一部分是数据库、Ansible Tower 本身等的密码。在许多在线示例中,这些密码通常以明文形式存储。我作为 Red Hat 顾问经常遇到的一个问题是如何保护此信息。一个常见的解决方案是在完成 Ansible Tower 的安装后简单地删除该文件。但是,您可能希望保留该文件的原因有很多。在本文中,我将介绍另一种保护安装文件中的密码的方法。

Ansible Tower 的 setup.sh

简要说明一下背景,setup.sh 是用于安装 Ansible Tower 的脚本,在常规安装程序和捆绑安装程序中都提供。setup.sh 脚本只执行几个任务,例如验证 Ansible 是否安装在本地系统上以及设置安装程序日志;但最重要的是,它启动 Ansible 来处理 Ansible Tower 的安装。可以使用 -i 参数向安装程序指定清单文件,或者,如果未指定,则使用默认提供的清单文件(位于 setup.sh 旁边)。在清单文件的第一个部分,我们有组来指定将安装 Ansible Tower 和数据库的服务器

[tower]
localhost ansible_connection=local

[database]

并且,在这些组规范之后,有一些变量可用于设置连接和密码,并且您通常会在其中输入明文密码,例如

[all:vars]
admin_password='T0w3r123!'

pg_host=''
pg_port=''

pg_database='awx'
pg_username='awx'
pg_password='DB_Pa55w0rd!'

在上面的示例中,这些密码以明文形式显示。我合作过的许多客户出于安全原因,不希望在清单文件中保留其密码的明文。安装 Ansible Tower 后,可以安全地删除此文件,但如果您需要修改安装以向集群添加节点或添加/删除清单组,则需要重新生成此文件。同样,如果您想使用 setup.sh 的备份和恢复功能,您还需要包含所有密码的清单文件,就像最初安装时一样。

Vault 来救援

由于安装程序使用 Ansible 来安装 Ansible Tower,因此我们可以利用一些 Ansible 概念来保护我们的密码。具体来说,我们将使用 Ansible vault 来使用加密密码而不是明文密码。如果您不熟悉 Ansible vault,它是 Red Hat Ansible Automation Platform 自身附带的一个程序,是一种加密和解密数据的机制。它可以用于单个字符串,也可以加密整个文件。在我们的示例中,我们将加密作为密码的单个字符串。如果您最终将清单文件提交到源代码管理工具中,这将非常有用。SCM 将能够显示您在提交中更改的单个密码,而不是只能说加密文件已更改(但无法显示加密文件中更改了哪个密码)。

首先,我们将使用以下命令加密管理员密码(<> 中的字段表示 ansible-vault 的输入)

$ ansible-vault encrypt_string --stdin-name admin_password
New Vault password:
Confirm New Vault password:
Reading plaintext input from stdin. (ctrl-d to end input)
<t0w3r123!>admin_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66663534356430343166356461373464336332343439393731363365303063353032373564623537
          3466663861633936366463346135656130306538376637320a303738653264333737343463613366
          31396336633730323639303436653330386536363838646161653562373631323766346431663461
          6536646264633563660a343163303334336164376339363161373662613137633436393263376631
          3539
Encryption successful
</t0w3r123!>

在此示例中,我们正在运行 ansible-vault 并要求它加密一个字符串。我们已经告诉 ansible-vault 此变量将被称为 admin_password,并且它的值将为 T0w3r123!(我们将输入到清单文件中的内容)。在示例中,我们使用了“password”作为密码来加密这些值。在生产环境中,应使用更强的密码来执行您的 vault 加密。在命令的输出中,在两次 ctrl-d 输入之后,我们的加密变量将显示在屏幕上。我们将获取此输出并将其放入名为 passwords.yml 的文件中,该文件位于我们的清单文件旁边。在加密第二个 pg_password 后,我们的 password.yml 文件如下所示

---
admin_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66663534356430343166356461373464336332343439393731363365303063353032373564623537
          3466663861633936366463346135656130306538376637320a303738653264333737343463613366
          31396336633730323639303436653330386536363838646161653562373631323766346431663461
          6536646264633563660a343163303334336164376339363161373662613137633436393263376631
          3539
pg_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          65633239383761336539313437643733323235366337653164383934303563643464626562633865
          3130313231666531613131633736386134343664373039620a336237393631333532373066343135
          65316431626630633965623134623133353635376236306538653230363038333661623236376330
          3664346237396139610a376536373132313237653239353832623433663230393464343331356561
          3435

现在我们已经完成了 passwords.yml 文件,我们必须告诉安装程序从该文件中加载密码,并提示我们输入 vault 密码以解密该值。为此,我们将向 setup.sh 命令添加三个参数。第一个选项是 -e@passwords.yml,这是告诉 Ansible 从指定的文件名(在本例中为 passwords.yml)加载变量的标准语法。第二个选项将是 --,它将告诉 setup.sh 脚本任何后续选项都应传递给 Ansible,而不是由 setup.sh 处理。最后一个选项将是 --ask-vault-pass,它告诉 Ansible 提示我们输入密码才能解密 vault 机密。我们的设置命令将全部变为

$ ./setup.sh -e@passwords.yml -- --ask-vault-pass

如果您通常向 setup.sh 添加参数,则需要将它们合并到此命令结构中。setup.sh 的参数需要放在 -- 之前,您传递给 Ansible 的任何参数都放在 -- 之后。 

使用这些选项运行 setup.sh 时,现在将提示您在 Ansible 安装程序开始之前输入 vault 密码

$ ./setup.sh -e@passwords.yml -- --ask-vault-pass
Using /etc/ansible/ansible.cfg as config file
Vault <password>:

PLAY [tower:database:instance_group_*:isolated_group_*] ******************************************************************************************

在这里,我必须输入我的弱 vault 密码“password”才能使解密过程正常工作。 

即使您在清单文件中保留空白密码变量,此技术也能正常工作,因为 Ansible 的变量优先级。任何变量可以获得的最高优先级来自 extra_vars(即我们添加到安装程序中的 -e 选项),因此我们 vault 文件中的值将覆盖清单文件中指定的任何值。

使用此方法,您可以将清单文件和密码文件保留在磁盘上或 SCM 中,并且其中不包含明文密码。

另一种解决方案

如果您只想使用单个清单文件,则可以采取的另一个选项是将现有的 ini 清单文件转换为基于 yaml 的清单。这将允许您直接将变量嵌入为 vault 加密值。虽然执行此操作的范围超出了本文的范围,但示例 inventory.yml 文件可能类似于以下内容

all:
  children:
    database: {}
    tower:
      hosts:
        localhost:
  vars:
    admin_password: !vault |
        $ANSIBLE_VAULT;1.1;AES256
        66663534356430343166356461373464336332343439393731363365303063353032373564623537
        3466663861633936366463346135656130306538376637320a303738653264333737343463613366
        31396336633730323639303436653330386536363838646161653562373631323766346431663461
        6536646264633563660a343163303334336164376339363161373662613137633436393263376631
        3539
    ansible_connection: local
    pg_database: awx
    pg_host: ''
    pg_password: !vault |
        $ANSIBLE_VAULT;1.1;AES256
        65633239383761336539313437643733323235366337653164383934303563643464626562633865
        3130313231666531613131633736386134343664373039620a336237393631333532373066343135
        65316431626630633965623134623133353635376236306538653230363038333661623236376330
        3664346237396139610a376536373132313237653239353832623433663230393464343331356561
        3435
    pg_port: ''
    pg_sslmode: prefer
    pg_username: awx
    rabbitmq_cookie: cookiemonster
    rabbitmq_password: ''
    rabbitmq_username: tower
    tower_package_name: ansible-tower
    tower_package_release: '1'
    tower_package_version: 3.6.3

使用此类文件,setup.sh 然后可以调用为

$ ./setup.sh -i inventory.yml -- --ask-vault-pass

使用此方法在升级 Ansible Tower 时需要更多工作,因为提供的清单文件中的任何字段更改都需要反映在您的 yaml 清单中,而之前的方法只需要将清单文件中添加的新密码字段添加到 password.yml 文件中。