使用变量,我们看到了如何分离数据和代码。通常,提供的数据是敏感的,例如用户密码、数据库凭证、应用编程接口密钥和其他特定于组织的信息。Ansible- 剧本作为源代码,通常存储在版本控制存储库中,例如 git ,这使得在协作环境中保护这些敏感信息变得更加困难。从 1.5 版本开始,Ansible 提供了一个名为 vault 的解决方案,使用成熟的加密技术安全地存储和检索此类敏感信息。使用 vault 的目的是对数据进行加密,然后可以与版本控制系统(如 git)自由存储和共享这些数据,而这些值不会受到损害。
在本章中,我们将了解以下主题:
- 理解易拉罐
- 使用保险库保护数据
- 加密、解密和密钥更新操作
Ansible 提供了一个名为 Ansible-vault 的实用程序,顾名思义,它可以让你安全地管理数据。Ansible-vault 实用程序可以通过启动编辑器界面来创建加密文件,也可以加密现有文件。无论是哪种情况,它都会要求一个保管库密码,然后用 AES 密码对数据进行加密。加密的内容可以存储在版本控制系统中而不会被泄露。由于 AES 是基于共享机密的,所以解密时也需要提供相同的密码。要提供密码,有两个选项,在启动 Ansible 时,运行--ask-vault-pass
选项提示输入密码,运行--vault-password-file
选项提供包含密码的文件路径。
高级 加密标准 ( AES )是一种基于 Rijndael 对称分组密码的加密标准,以两位比利时密码学家——文森特·里曼和琼·代蒙的名字命名,并由他们开发。AES 最初由(美国)国家标准与技术研究所 ( NIST )于 2001 年建立,是美国政府为共享机密信息而采用的一种算法,是最流行的对称密钥加密算法。AES 也是第一个由国家安全局 ( NSA )批准的可公开访问的开放密码。
作为一个开放和流行的标准,Ansible 使用密钥大小为 256 位的 AES 密码来加密存储区中的数据。
Ansible-vault 可以加密任何结构化数据。由于 YAML 本身是一种结构化语言,你为 Ansible 写的几乎所有东西都符合这个标准。以下是关于可以使用保管库加密的内容的指针:
- 最常见的是,我们加密变量,如下所示:
- 角色中的变量文件,例如
vars
和defaults
- 库存变量,例如
host_vars
、group_vars
include_vars
或vars_files
包含的变量文件- 通过
-e
选项传递给 Ansible-playbook 的变量文件,例如-e @vars.yml
或-e @vars.json
- 角色中的变量文件,例如
- 由于任务和处理程序也是 JSON 数据,因此可以用 vault 对它们进行加密。然而,这应该很少实践。建议您加密变量,并在任务和处理程序中引用它们。
以下是关于哪些内容不能用保管库加密的指针:
- 由于保管库的加密单位是文件,因此不能加密部分文件或值。您可以加密整个文件,也可以不加密。
- 文件和模板不能加密,因为它们可能与 JSON 或 YML 不相似。
以下数据非常适合加密:
- 凭证,例如数据库密码和应用凭证
- 应用编程接口密钥,例如,AWS 访问和密钥
- 网络服务器的 SSL 密钥
- 用于部署的私有 SSH 密钥
下表列出了 Ansible-vault 实用程序附带的所有子命令:
|子命令
|
描述
|
| --- | --- |
| create
| 这将使用编辑器从头开始创建加密文件。这需要在启动命令之前设置编辑器环境变量。 |
| edit
| 这将使用编辑器编辑现有的加密文件,而不解密内容。 |
| encrypt
| 这将使用结构化数据加密现有文件。 |
| decrypt
| 这将解密文件。请谨慎使用,不要将解密的文件提交给版本控制。 |
| rekey
| 这将更改用于加密或解密的密钥或密码。 |
让我们使用 Ansible-vault 执行一些操作。我们将从创建一个加密文件开始。要从头开始创建新文件,Ansible-vault 使用create
子命令。在使用此子命令之前,在环境中设置编辑器非常重要,如下所示:
# setting up vi as editor
$ export EDITOR=vi
# Generate a encrypted file
$ ansible-vault create aws_creds.yml
Vault password:
Confirm Vault password:
启动此命令会打开一个用编辑器环境变量指定的编辑器。以下是您可以创建的aws_creds.yml
文件的示例,该文件以访问密钥和密钥的形式存储 AWS 用户凭据。然后,这些键被用来对亚马逊网络服务云平台进行应用编程接口调用。保存此文件并退出编辑器将生成一个加密文件:
您可以通过运行以下命令来检查创建的文件类型及其内容:
# Check file type and content
$ file aws_creds.yml
aws_creds.yml: ASCII text
$ cat aws_creds.yml
$ANSIBLE_VAULT;1.1;AES256
64616236666362376630366435623538336565393331333331663663636237636335313234313134
3337303865323239623436646630336239653864356561640a363966393135316661636562333932
61323932313230383433313735646438623032613635623966646232306433383335326566343333
3136646536316261300a616438643463656263636237316136356163646161313365336239653434
36626135313138343939363635353563373865306266363532386537623463623464376134353863
37646638636231303461343564343232343837356662316262356537653066356465353432396436
31336664313661306630653765356161616266653232316637653132356661343162396331353863
34356632373963663230373866313961386435663463656561373461623830656261636564313464
37383465353665623830623363353161363033613064343932663432653666633538
要更新添加到加密文件中的 AWS 密钥,您可以稍后使用 Ansible-vault 的edit
子命令,如下所示:
$ ansible-vault edit aws_creds.yml
Vault password:
edit
命令执行以下操作:
- 提示输入密码
- 使用 AES 对称密码动态解密文件
- 打开编辑器界面,允许您更改文件的内容
- 文件保存后再次加密
还有另一种更新文件内容的方法。您可以按如下方式解密文件:
$ ansible-vault decrypt aws_creds.yml
Vault password:
Decryption successful
更新后,该文件可以再次加密,如您之前所知。
作为一种良好的安全实践,经常更改 Ansible-vault 使用的加密密钥是一个好主意。当这种情况发生时,使用 vault 重新加密之前加密的所有文件是至关重要的。Ansible vault 提供了rekey
子命令,可以如下使用:
$ ansible-vault rekey aws_creds.yml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful
它会询问当前密码,然后允许您指定并确认新密码。请注意,如果您正在使用版本控制管理该文件,您还需要提交更改。即使实际内容没有改变,更新密钥操作也会更新创建的结果文件,它是我们存储库的一部分。
早些时候创建数据库用户时,我们在group_vars
中以纯文本形式提供了密码。这可能是一个潜在的威胁,尤其是在签入版本控制存储库时。让我们加密它。我们将使用encrypt
子命令,因为我们已经有了一个变量文件。
由于我们使用group_vars
组来提供数据库凭证,我们将对group_vars/all
文件进行如下加密:
$ ansible-vault encrypt group_vars/all
Vault password:
Confirm Vault password:
Encryption successful
对于加密,Ansible-vault 要求用户输入密码或密钥。使用此密钥,保管库对数据进行加密,并用加密的内容替换文件。下图显示了group_vars/all
文件左侧的纯文本内容和右侧的等效加密内容:
该文件现在可以安全地签入版本控制系统并共享。然而,以下是用户应该注意的注意事项:
- 与纯文本不同,生成的文件是加密格式。在提交版本控制时,不可能获得不同的文件格式,例如
git diff
,来比较更改。 - 不能直接在这个文件上使用
grep
、sed
或者任何文本搜索或操作程序。唯一的方法是先解密它,运行文本操作实用程序,然后再加密回来。
确保您要用一次 Ansible-playbook 运行解密的所有文件使用相同的密码。Ansible 一次只能接受一个密码值,如果同一剧本中的文件使用不同的密码加密,将会失败。
现在,让我们使用以下命令运行 Ansible 行动手册:
$ ansible-playbook -i customhosts site.yml
ERROR: A vault password must be specified to decrypt /vagrant/chap8/group_vars/all
失败并出现错误!这是因为我们为剧本提供了加密数据,而没有解密的密钥。保管库的主要用途是在数据位于 Ansible 存储库中时保护数据。最终,这些值需要在运行剧本时解密。解密密码可以用--ask-vault-pass
选项指定,如下所示:
$ ansible-playbook -i customhosts site.yml --ask-vault-pass
这将提示输入“保管库密码”,然后像往常一样继续运行 Ansible 代码。
每次输入密码可能都不理想。通常情况下,您可能还希望自动化启动 Ansible playbook 运行的过程,在这种情况下,交互方式是不可行的。这可以通过将密码存储在文件中并将该文件提供给 Ansible playbook 运行来避免。在此文件中,密码应作为单行字符串提供。
让我们创建一个密码文件,并用正确的权限保护它:
$ echo "password" > ~/.vault_pass
(replace password with your own secret)
$ chmod 600 ~/.vault_pass
当保管库密码以纯文本形式存储时,任何有权访问此文件的人都可以解密数据。请确保密码文件具有适当的权限,并且没有添加到版本控制中。如果您决定对其进行版本控制,请使用 gpg 或等效措施。
现在,该文件可以提供给 Ansible 行动手册,如下所示:
$ ansible-playbook -i customhosts site.yml --vault-password-file ~/.vault_pass
在 1.7 版本中,也可以在【默认】部分的ansible.cfg
文件中添加选项。
请考虑以下几点:
[defaults]
vault_password_file = ~/.vault_pass
上述选项让您可以自由选择不每次都指定加密密码或密码文件。让我们来看看以下命令:
# launch ansible playbook run with encrypted data
# with vault_password_file option set in the config
$ ansible-playbook -i customhosts site.yml
$ ansible-vault encrypt roles/mysql/defaults/main.yml
Encryption successful
$ ansible-vault decrypt roles/mysql/defaults/main.yml
Decryption successful
而且,从 1.7 版本开始,也可以在vault_password_file
选项中提供脚本,而不是在文件中存储纯文本密码。使用脚本时,请确保:
- 脚本上的执行位被启用
- 调用该脚本会在标准输出中输出一个密码
- 如果脚本提示用户输入,它可以被发送到标准错误
您之前了解到由于模板可能不是结构化文件,如 YAML 或 JSON,因此无法加密。但是,有一种方法可以将加密数据添加到模板中。请记住,模板毕竟是动态生成的,动态内容实际上来自变量,可以加密。让我们讨论如何通过为 Nginx 网络服务器添加 SSL 支持来实现这一点。
我们已经设置了一个 Nginx web 服务器,现在让我们按照以下步骤为默认站点添加 SSL 支持:
-
我们从添加变量开始,如下所示:
#file: roles/nginx/defaults/main.yml nginx_ssl: true nginx_port_ssl: 443 nginx_ssl_path: /etc/nginx/ssl nginx_ssl_cert_file: nginx.crt nginx_ssl_key_file: nginx.key
-
Let's also create self-signed SSL certificates:
$ openssl req -x509 -nodes -newkey rsa:2048 -keyout nginx.key -out nginx.crt
前面的命令将生成两个文件,
nginx.key
和nginx.crt
。这些是我们将要复制到网络服务器上的文件。 -
Let's add the contents of these files to the variables, and create the
group_vars/www
file:# file: group_vars/www --- nginx_ssl_cert_content: | -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- nginx_ssl_key_content: | -----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----
在前面的示例中,我们只是添加了占位符,这些占位符将被密钥和证书的实际内容替换。这些密钥和证书不应在版本控制系统中公开。
-
Let's encrypt this file using the vault:
$ ansible-vault encrypt group_vars/www Encryption successful
因为我们已经在配置中提供了存储库密码的路径,所以 Ansible-vault 不会要求输入密码。
-
现在让我们创建模板,添加这些键:
# filename: roles/nginx/templates/nginx.crt.j2 {{ nginx_ssl_cert_content }} # filename: roles/nginx/templates/nginx.key.j2 {{ nginx_ssl_key_content }}
-
另外,让我们向 SSL 添加一个虚拟主机
config
文件:# filename: roles/nginx/templates/nginx.key.j2 server { listen {{ nginx_port_ssl }}; server_name {{ ansible_hostname }}; ssl on; ssl_certificate {{ nginx_ssl_path }}/{{ nginx_ssl_cert_file }}; ssl_certificate_key {{ nginx_ssl_path }}/{{ nginx_ssl_key_file }}; location / { root {{ nginx_root }}; index {{ nginx_index }}; } }
-
我们还需要创建一个任务文件来配置 SSL 站点,这将创建所需的目录、文件和配置:
--- # filename: roles/nginx/tasks/configure_ssl.yml - name: create ssl directory file: path="{{ nginx_ssl_path }}" state=directory owner=root group=root - name: add ssl key template: src=nginx.key.j2 dest="{{ nginx_ssl_path }}/nginx.key" mode=0644 - name: add ssl cert template: src=nginx.crt.j2 dest="{{ nginx_ssl_path }}/nginx.crt" mode=0644 - name: create ssl site configurations template: src=default_ssl.conf.j2 dest="{{ nginx_ssl_path }}/default_ssl.conf" mode=0644 notify: - restart nginx service
-
最后,让我们根据
nginx_ssl var
参数是否设置为真来有选择地调用这个任务:# filename: roles/nginx/tasks/main.yml - include: configure_ssl.yml when: nginx_ssl
-
现在,运行剧本如下:
$ ansible-playbook -i customhosts site.yml
这应该使用自签名证书配置在端口443
运行的默认 SSL 站点。现在,您应该可以使用https
安全协议打开网络服务器地址,如下所示:
当然,它应该显示警告,因为我们的证书是自签名的,不是由指定的证书颁发机构提供的。
你认为你已经很好地理解这一章了吗?试着回答以下问题来测试你的理解能力:
- 为什么需要加密提供给 Ansible 行动手册的数据?
- 什么是 AES,什么是对称密钥密码?
- 更新以前用 vault 加密的文件的两种方法是什么?
- 添加到 Ansible 配置文件中以使其知道保管库密码文件位置的参数是什么?
在本章中,您学习了如何使用 Ansible-vault 保护传递给行动手册的数据。我们从加密数据的需求、保险库的工作方式以及它使用的密码开始。然后,我们开始深入研究 Ansible-vault 实用程序和基本操作,如创建加密文件、解密、密钥更新等。您还学习了如何通过在保存数据库凭证的vars
文件上运行 Ansible-vault 来加密现有文件。最后,我们向 Nginx 添加了 SSL 支持,您学习了如何使用 vault 安全地存储 web 服务器的私钥和证书,并使用模板复制它们。请注意,Ansible vault 提供了一种安全地向 Ansible 模块提供数据的方法。除了使用保险库之外,建议采取不在本文范围内的其他系统安全措施。
了解了 vault 之后,在下一章中,我们将开始学习使用 Ansible 管理多个环境的各种方法,例如开发、试运行和生产。这些环境通常映射到软件开发工作流。