Skip to content

Files

Latest commit

f87fb9e · Dec 29, 2021

History

History
376 lines (254 loc) · 16.4 KB

File metadata and controls

376 lines (254 loc) · 16.4 KB

八、使用保管库加密数据

使用变量,我们看到了如何分离数据和代码。通常,提供的数据是敏感的,例如用户密码、数据库凭证、应用编程接口密钥和其他特定于组织的信息。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 写的几乎所有东西都符合这个标准。以下是关于可以使用保管库加密的内容的指针:

  • 最常见的是,我们加密变量,如下所示:
    • 角色中的变量文件,例如varsdefaults
    • 库存变量,例如host_varsgroup_vars
    • include_varsvars_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 用户凭据。然后,这些键被用来对亚马逊网络服务云平台进行应用编程接口调用。保存此文件并退出编辑器将生成一个加密文件:

Encrypting the data

您可以通过运行以下命令来检查创建的文件类型及其内容:

# 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命令执行以下操作:

  1. 提示输入密码
  2. 使用 AES 对称密码动态解密文件
  3. 打开编辑器界面,允许您更改文件的内容
  4. 文件保存后再次加密

还有另一种更新文件内容的方法。您可以按如下方式解密文件:

$ 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文件左侧的纯文本内容和右侧的等效加密内容:

Encrypting the database credentials

该文件现在可以安全地签入版本控制系统并共享。然而,以下是用户应该注意的注意事项:

  • 与纯文本不同,生成的文件是加密格式。在提交版本控制时,不可能获得不同的文件格式,例如git diff,来比较更改。
  • 不能直接在这个文件上使用grepsed或者任何文本搜索或操作程序。唯一的方法是先解密它,运行文本操作实用程序,然后再加密回来。

类型

确保您要用一次 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 添加 SSL 支持

我们已经设置了一个 Nginx web 服务器,现在让我们按照以下步骤为默认站点添加 SSL 支持:

  1. 我们从添加变量开始,如下所示:

    #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
    
  2. Let's also create self-signed SSL certificates:

    $ openssl req -x509 -nodes -newkey rsa:2048 -keyout nginx.key -out nginx.crt
    
    

    前面的命令将生成两个文件,nginx.keynginx.crt。这些是我们将要复制到网络服务器上的文件。

  3. 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-----
    

    在前面的示例中,我们只是添加了占位符,这些占位符将被密钥和证书的实际内容替换。这些密钥和证书不应在版本控制系统中公开。

  4. Let's encrypt this file using the vault:

    $ ansible-vault encrypt group_vars/www
    Encryption successful
    
    

    因为我们已经在配置中提供了存储库密码的路径,所以 Ansible-vault 不会要求输入密码。

  5. 现在让我们创建模板,添加这些键:

    # filename: roles/nginx/templates/nginx.crt.j2
    {{ nginx_ssl_cert_content }}
    
    # filename: roles/nginx/templates/nginx.key.j2
    {{ nginx_ssl_key_content }}
    
  6. 另外,让我们向 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 }};
      }
    }
    
  7. 我们还需要创建一个任务文件来配置 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
    
  8. 最后,让我们根据nginx_ssl var参数是否设置为真来有选择地调用这个任务:

    # filename: roles/nginx/tasks/main.yml
     - include: configure_ssl.yml
        when: nginx_ssl
    
  9. 现在,运行剧本如下:

    $ ansible-playbook -i customhosts  site.yml
    
    

这应该使用自签名证书配置在端口443运行的默认 SSL 站点。现在,您应该可以使用https 安全协议打开网络服务器地址,如下所示:

Adding SSL support to Nginx

当然,它应该显示警告,因为我们的证书是自签名的,不是由指定的证书颁发机构提供的。

复习问题

你认为你已经很好地理解这一章了吗?试着回答以下问题来测试你的理解能力:

  1. 为什么需要加密提供给 Ansible 行动手册的数据?
  2. 什么是 AES,什么是对称密钥密码?
  3. 更新以前用 vault 加密的文件的两种方法是什么?
  4. 添加到 Ansible 配置文件中以使其知道保管库密码文件位置的参数是什么?

总结

在本章中,您学习了如何使用 Ansible-vault 保护传递给行动手册的数据。我们从加密数据的需求、保险库的工作方式以及它使用的密码开始。然后,我们开始深入研究 Ansible-vault 实用程序和基本操作,如创建加密文件、解密、密钥更新等。您还学习了如何通过在保存数据库凭证的vars文件上运行 Ansible-vault 来加密现有文件。最后,我们向 Nginx 添加了 SSL 支持,您学习了如何使用 vault 安全地存储 web 服务器的私钥和证书,并使用模板复制它们。请注意,Ansible vault 提供了一种安全地向 Ansible 模块提供数据的方法。除了使用保险库之外,建议采取不在本文范围内的其他系统安全措施。

了解了 vault 之后,在下一章中,我们将开始学习使用 Ansible 管理多个环境的各种方法,例如开发、试运行和生产。这些环境通常映射到软件开发工作流。