如何使用 Ansible Vault 保护敏感的游戏本数据

介绍

Ansible Vault 是一个功能,允许用户在 Ansible 项目中加密值和数据结构,这提供了安全的能力,以确保成功运行 Ansible 播放所需的任何敏感数据,但不应该公开可见,如密码或私钥。

在本指南中,我们将展示如何使用Ansible Vault,并探索一些建议的做法来简化其使用,我们将使用Ubuntu 20.04服务器用于Ansible控制机器,无需远程主机。

前提条件

要继续下去,你需要一个 Ubuntu 20.04 服务器,具有sudo特权的非根用户,你可以遵循我们的 Ubuntu 20.04 初始服务器设置指南以创建具有相应权限的用户。

在服务器上,您需要安装和配置 Ansible. 您可以遵循我们在 安装在Ubuntu 20.04上的 Ansible上的教程来安装相应的包。

当您的服务器配置符合上述要求时,继续使用本指南。

什么是 Ansible Vault?

Ansible Vault 是一种机制,允许加密内容透明地嵌入 Ansible 工作流程中.一个名为ansible-vault的实用程序通过在磁盘上加密保护机密数据,称为 secrets

Vault 以文件级细微性实现,这意味着单个文件是加密或未加密的。它使用AES256算法提供对称的加密,以用户提供的密码。这意味着使用相同的密码来加密和解密内容,这从可用性角度来看是有用的。

现在您已经了解了 Vault 是什么,我们可以开始讨论 Ansible 提供的工具以及如何在现有工作流中使用 Vault。

使用 Ansible Vault 编辑器

在使用ansible-vault命令之前,最好指定您喜爱的文本编辑器。 Vault 的一些命令包括打开编辑器来操纵加密文件的内容。 Ansible 会查看EDITOR环境变量以找到您喜爱的编辑器。

如果您不希望使用vi编辑器进行编辑,您应该在环境中设置EDITOR变量。

<$>[注] 注: 如果您偶然发现自己处于vi会话中,您可以通过打击 Esc键,键入 :q!,然后按 Enter

若要将编辑器设置为单个命令,请将命令预定为环境变量分配,如下:

1EDITOR=nano ansible-vault . . .

要保持这种状态,请打开您的 ~/.bashrc 文件:

1nano ~/.bashrc

通过在文件末尾添加一个EDITOR分配来指定您最喜欢的编辑器:

1[label ~/.bashrc]
2export EDITOR=nano

保存并关闭文件,当你完成。

重新來源檔案,以閱讀變更到目前的會議:

1. ~/.bashrc

显示编辑器变量,以检查您的设置是否被应用:

1echo $EDITOR
1[secondary_label Output]
2nano

现在你已经建立了你喜欢的编辑器,我们可以用ansible-vault命令讨论可用的操作。

如何使用 ansible-vault 管理敏感文件

ansible-vault命令是管理 Ansible 中的加密内容的主要界面,该命令最初用于加密文件,然后用于查看、编辑或解密数据。

创建新的加密文件

要创建一个用 Vault 加密的新文件,请使用ansible-vault create命令. 请输入您想要创建的文件的名称. 例如,要创建一个加密的 YAML 文件,名为vault.yml,以存储敏感变量,您可以键入:

1ansible-vault create vault.yml

您将被要求输入并确认密码:

1[secondary_label Output]
2New Vault password: 
3Confirm New Vault password:

当您确认密码后,Ansible将立即打开一个编辑窗口,您可以输入您想要的内容。

要测试加密功能,请输入一些测试文本:

1[label vault.yml]
2Secret information

Ansible 在关闭文件时会加密内容. 如果你检查文件,而不是看到你输入的单词,你会看到一个加密的块:

1cat vault.yml
1[secondary_label Output]
2$ANSIBLE_VAULT;1.1;AES256
365316332393532313030636134643235316439336133363531303838376235376635373430336333
43963353630373161356638376361646338353763363434360a363138376163666265336433633664
530336233323664306434626363643731626536643833336638356661396364313666366231616261
63764656365313263620a383666383233626665376364323062393462373266663066366536306163
731643731343666353761633563633634326139396230313734333034653238303166

我们可以看到一些 Ansible 使用的标题信息,以了解如何处理文件,然后是加密的内容,这些内容显示为数字。

加密现有文件

如果您已经有要使用 Vault 加密的文件,请使用ansible-vault encrypt命令。

为了测试,我们可以通过键入创建一个示例文件:

1echo 'unencrypted stuff' > encrypt_me.txt

现在,您可以通过键入来加密现有文件:

1ansible-vault encrypt encrypt_me.txt

再次,您将被要求提供并确认密码. 之后,一个消息将确认加密:

1[secondary_label Output]
2New Vault password: 
3Confirm New Vault password:
4Encryption successful

而不是打开编辑窗口,ansible-vault会加密文件的内容,并将其写回磁盘,取代未加密的版本。

如果我们检查文件,我们应该看到类似的加密模式:

1cat encrypt_me.txt
1[secondary_label Output]
2$ANSIBLE_VAULT;1.1;AES256
366633936653834616130346436353865303665396430383430353366616263323161393639393136
43737316539353434666438373035653132383434303338640a396635313062386464306132313834
534313336313338623537333332356231386438666565616537616538653465333431306638643961
63636663633363562320a613661313966376361396336383864656632376134353039663662666437
739393639343966363565636161316339643033393132626639303332373339376664

正如你所看到的,Ansible以与新文件一样,对现有内容进行加密。

查看加密文件

有时,您可能需要引用密封文件的内容,而无需编辑或写入未加密的文件系统。ansible-vault view命令将文件的内容提供标准化。

将 vault 加密文件传输到命令:

1ansible-vault view vault.yml

您将被要求提供文件的密码. 成功输入后,内容将显示:

1[secondary_label Output]
2Vault password:
3Secret information

正如你所看到的,密码提示被混合到文件内容的输出中,在自动化流程中使用ansible-vault view时要记住这一点。

编辑加密文件

当您需要编辑加密文件时,请使用ansible-vault edit命令:

1ansible-vault edit vault.yml

在输入后,Ansible将打开文件编辑窗口,在那里你可以做任何必要的更改。

保存后,新内容将使用文件的加密密码再次加密并写入磁盘。

手动解密加密文件

若要解密密码文件,请使用ansible-vault decrypt命令。

<$>[注] **注:**由于意外将敏感数据泄露到您的项目存储库的可能性增加,因此只建议使用ansible-vault decrypt命令,当您希望从文件中永久删除加密时。

输入加密文件的名称:

1ansible-vault decrypt vault.yml

您将被要求为文件的加密密码. 一旦您输入正确的密码,文件将被解密:

1[secondary_label Output]
2Vault password:
3Decryption successful

如果您再次查看文件,而不是保险箱加密,您应该看到文件的实际内容:

1cat vault.yml
1[secondary_label Output]
2Secret information

您的文件现在在磁盘上没有加密,请确保在完成后删除任何敏感信息或重新加密文件。

更改加密文件的密码

如果您需要更改加密文件的密码,请使用ansible-vault rekey命令:

1ansible-vault rekey encrypt_me.txt

当您输入命令时,您将首先被提示使用该文件的当前密码:

1[secondary_label Output]
2Vault password:

输入后,您将被要求选择并确认一个新的保险箱密码:

1[secondary_label Output]
2Vault password:
3New Vault password:
4Confirm New Vault password:

当您成功确认新的密码时,您将收到一个消息,说明重加密过程的成功:

1[secondary_label Output]
2Rekey successful

现在应该使用新密码访问该文件,旧密码将不再工作。

使用 Vault-Encrypted 文件运行 Ansible

在您使用 Vault 加密敏感信息后,您可以开始使用 Ansible 的常规工具来使用这些文件。ansibleansible-playbook命令都知道如何解密安全箱保护的文件,以正确的密码。

要跟上,你需要一个密码文件,你可以通过键入创建一个:

1ansible-vault create secret_key

选择并确认密码. 填写您想要的任何愚蠢内容:

1[label secret_key]
2confidential data

保存并关闭文件。

我们还可以创建一个临时的主机文件作为库存:

1nano hosts

我们只会添加Ansible localhost,以便为下一步做好准备,我们会将其放入[数据库]组:

1[label hosts]
2[database]
3localhost ansible_connection=local

保存并关闭文件,当你完成。

接下来,在当前目录中创建一个ansible.cfg文件,如果其中一个文件尚未存在:

1nano ansible.cfg

目前,只需添加一个[默认]部分,并指向我们刚刚创建的库存:

1[label ansible.cfg]
2[defaults]
3inventory = ./hosts

当你准备好了,继续。

使用互动提示

在运行时解密内容的最简单方法是让Ansible提示您获得相应的身份证件。您可以通过将--ask-vault-pass添加到任何ansibleansible-playbook命令中来做到这一点。

例如,如果我们需要将保险箱加密文件的内容复制到主机,我们可以使用复制模块和--ask-vault-pass旗帜这样做。

<$>[注] **注:**我们在本示例中使用本地主机作为目标主机,以尽量减少所需的服务器数量,但结果应该是相同的,如果主机是真正的远程: <$>

1ansible --ask-vault-pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost

我们的任务规定,该文件的所有权应该被更改为root,因此需要管理权限。-bK旗告诉Ansible为目标主机请求sudo密码,因此您将被要求提供您的sudo密码。

1[secondary_label Output]
2BECOME password:
3Vault password:

提供密码后,Ansible 将尝试执行任务,使用 Vault 密码来查找所发现的任何加密文件. 请记住,执行过程中引用的所有文件都必须使用相同的密码:

 1[secondary_label Output]
 2localhost | SUCCESS => {
 3    "changed": true, 
 4    "checksum": "7a2eb5528c44877da9b0250710cba321bc6dac2d", 
 5    "dest": "/tmp/secret_key", 
 6    "gid": 0, 
 7    "group": "root", 
 8    "md5sum": "270ac7da333dd1db7d5f7d8307bd6b41", 
 9    "mode": "0600", 
10    "owner": "root", 
11    "size": 18, 
12    "src": "/home/sammy/.ansible/tmp/ansible-tmp-1480978964.81-196645606972905/source", 
13    "state": "file", 
14    "uid": 0
15}

请求密码是安全的,但可能很无聊,特别是在重复运行时,并且也妨碍了自动化。

使用 Ansible Vault 与密码文件

如果您不希望每次执行任务时输入 Vault 密码,则可以将 Vault 密码添加到文件中,并在执行过程中引用该文件。

例如,您可以将密码放到一个 .vault_pass 文件中,如下:

1echo 'my_vault_password' > .vault_pass

如果您正在使用版本控制,请确保将密码文件添加到您的版本控制软件的忽略文件,以避免意外执行:

1echo '.vault_pass' >> .gitignore

现在,你可以引用该文件,而不是它。在命令行上可用的是 --vault-password-file 旗帜.我们可以通过键入最后一节完成相同的任务:

1ansible --vault-password-file=.vault_pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost

这一次,您将不会被要求使用 Vault 密码。

 1[secondary_label Output]
 2localhost | SUCCESS => {
 3    "changed": false,
 4    "checksum": "52d7a243aea83e6b0e478db55a2554a8530358b0",
 5    "dest": "/tmp/secret_key",
 6    "gid": 80,
 7    "group": "root",
 8    "mode": "0600",
 9    "owner": "root",
10    "path": "/tmp/secret_key",
11    "size": 8,
12    "state": "file",
13    "uid": 0
14}

自动阅读密码文件

要避免提供旗帜,您可以设置环境变量ANSIBLE_VAULT_PASSWORD_FILE与通往密码文件的路径:

1export ANSIBLE_VAULT_PASSWORD_FILE=./.vault_pass

您现在应该能够在没有当前会话的--vault-password-file旗帜的情况下执行该命令:

1ansible -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost

若要让 Ansible 在各个会话中了解密码文件的位置,您可以编辑您的ansible.cfg文件。

打开我们之前创建的本地 ansible.cfg 文件:

1nano ansible.cfg

[默认]部分中,设置vault_password_file设置,指向您的密码文件的位置,这可以是相对的或绝对的路径,取决于哪个是最有用的:

1[label ansible.cfg]
2[defaults]
3. . .
4vault_password_file = ./.vault_pass

现在,当您运行需要解密的命令时,您将不再被要求使用保险箱密码. 作为奖励,ansible-vault 不仅会使用文件中的密码来解密任何文件,而且会在创建新文件时使用ansible-vault 创建ansible-vault 加密来执行密码。

从环境变量读取密码

您可能担心意外将您的密码文件发送到您的存储库,而Ansible有一个环境变量来指向密码文件的位置,但它没有一个来设置密码本身。

但是,如果您的密码文件是可执行的,则 Ansible 会将其运行为脚本,并将结果输出作为密码。 在 GitHub 问题, Brian Schwind 建议下面的脚本可以用来从环境变量中提取密码。

在您的编辑器中打开您的 .vault_pass 文件:

1nano .vault_pass

用以下脚本取代内容:

1[label .vault_pass]
2#!/usr/bin/env python3
3
4import os
5print os.environ['VAULT_PASSWORD']

通过键入使文件可执行:

1chmod +x .vault_pass

然后,您可以设置和导出当前会话中可用的VAULT_PASSWORD环境变量:

1export VAULT_PASSWORD=my_vault_password

您将不得不在每个 Ansible 会话开始时这样做,这可能听起来很不方便,但是,这有效地防止您意外使用 Vault 加密密码,这可能会导致严重的缺陷。

使用 Vault 加密变量与常规变量

虽然 Ansible Vault 可用于任意文件,但它最常用于保护敏感变量,我们将通过一个示例来向您展示如何将常规变量文件转换为平衡安全性和可用性的配置。

树立榜样

对于这个例子,我们会假装我们正在配置数据库服务器,而实际上不需要安装数据库作为先决条件。

当您早些时候创建了主机文件时,您将本地主机列入名为数据库的组中,以便为此步骤做好准备。

1mkdir -p group_vars
2nano group_vars/database

group_vars/database文件中,我们将添加一些典型的变量。一些变量,如MySQL端口号,不是秘密的,可以自由共享。

1[label group_vars/database]
2---
3# nonsensitive data
4mysql_port: 3306
5mysql_host: 10.0.0.3
6mysql_user: fred
7
8# sensitive data
9mysql_password: supersecretpassword

我们可以测试所有变量是否可用于我们的主机,使用Ansible的debug模块和hostvars变量:

1ansible -m debug -a 'var=hostvars[inventory_hostname]' database
 1[secondary_label Output]
 2localhost | SUCCESS => {
 3    "hostvars[inventory_hostname]": {
 4        "ansible_check_mode": false, 
 5        "ansible_version": {
 6            "full": "2.2.0.0", 
 7            "major": 2, 
 8            "minor": 2, 
 9            "revision": 0, 
10            "string": "2.2.0.0"
11        }, 
12        "group_names": [
13            "database"
14        ], 
15        "groups": {
16            "all": [
17                "localhost"
18            ], 
19            "database": [
20                "localhost"
21            ], 
22            "ungrouped": []
23        }, 
24        "inventory_dir": "/home/sammy", 
25        "inventory_file": "hosts", 
26        "inventory_hostname": "localhost", 
27        "inventory_hostname_short": "localhost", 
28        "mysql_host": "10.0.0.3",
29        "mysql_password": "supersecretpassword",
30        "mysql_port": 3306,
31        "mysql_user": "fred",
32        "omit": "__omit_place_holder__1c934a5a224ca1d235ff05eb9bda22044a6fb400", 
33        "playbook_dir": "."
34    }
35}

输出确认我们设置的所有变量都应用于主机,然而,我们的group_vars/database文件目前包含我们所有的变量,这意味着我们可以不加密,这是一个安全问题,因为数据库密码变量,或者我们加密所有变量,从而产生可用性和协作问题。

将敏感变量移动到Ansible Vault

要解决这个问题,我们需要区分敏感变量和非敏感变量,我们应该能够加密机密值,同时轻松共享我们的非敏感变量。

可以使用变量 directory 代替 Ansible 变量 file 来应用来自多个文件的变量. 我们可以重塑我们的配置以利用这种能力。

1mv group_vars/database group_vars/vars

接下来,创建一个与旧变量文件相同的目录。

1mkdir group_vars/database
2mv group_vars/vars group_vars/database/

我们现在有一个数据库组的变量目录,而不是单个文件,我们有一个单个未加密的变量文件. 因为我们将加密我们的敏感变量,我们应该从我们的未加密文件中删除它们。

1nano group_vars/database/vars

在这种情况下,我们要删除mysql_password变量,该文件现在应该是这样的:

1[label group_vars/database/vars]
2---
3# nonsensitive data
4mysql_port: 3306
5mysql_host: 10.0.0.3
6mysql_user: fred

接下来,在目录中创建一个保管加密文件,它将与未加密的vars文件一起生活:

1ansible-vault create group_vars/database/vault

在此文件中,定义以前在vars文件中存在的敏感变量. 使用相同的变量名称,但预先使用vault_字符串,以表示这些变量在保险箱保护的文件中定义:

1[label group_vars/database/vault]
2---
3vault_mysql_password: supersecretpassword

保存并关闭文件,当你完成。

由此产生的目录结构看起来如下:

1.
2├── . . .
3├── group_vars/
4   └── database/
5       ├── vars
6       └── vault
7└── . . .

此时,变量是分开的,只有机密数据被加密,这是安全的,但我们的实现影响了我们的可用性. 虽然我们的目标是保护敏感的 values,但我们还无意间将可见性减少到实际的变量名称。

为了解决这一问题,Ansible项目通常建议采取稍微不同的方法。

引用未加密变量中的 Vault 变量

当我们将敏感数据迁移到保护保险箱的文件中时,我们将变量名设置为vault_(mysql_password变成了vault_mysql_password).我们可以将原始变量名(mysql_password)添加到未加密的文件中。而不是直接将这些变量名设置为敏感值,我们可以使用Jinja2模板陈述来参考我们未加密的变量文件中的加密变量名。

要演示,请重新打开未加密变量文件:

1nano group_vars/database/vars

再次添加mysql_password变量. 此时,使用 Jinja2 模板来引用保险箱保护文件中定义的变量:

1[label group_vars/database/vars]
2---
3# nonsensitive data
4mysql_port: 3306
5mysql_host: 10.0.0.3
6mysql_user: fred
7
8# sensitive data
9mysql_password: "{{ vault_mysql_password }}"

mysql_password变量设置为vault_mysql_password变量的值,该变量在保险箱文件中定义。

使用此方法,您可以通过查看group_vars/database/vars文件来理解将应用于数据库组中的所有变量。敏感部分将被Jinja2模板掩盖。

您可以检查,以确保所有mysql_*变量仍然使用与上次相同的方法正确应用。

<$>[注] 注: 如果您的 Vault 密码不会自动应用到密码文件中,请在下面的命令中添加 --ask-vault-pass 旗帜。

1ansible -m debug -a 'var=hostvars[inventory_hostname]' database
 1[secondary_label Output]
 2localhost | SUCCESS => {
 3    "hostvars[inventory_hostname]": {
 4        "ansible_check_mode": false, 
 5        "ansible_version": {
 6            "full": "2.2.0.0", 
 7            "major": 2, 
 8            "minor": 2, 
 9            "revision": 0, 
10            "string": "2.2.0.0"
11        }, 
12        "group_names": [
13            "database"
14        ], 
15        "groups": {
16            "all": [
17                "localhost"
18            ], 
19            "database": [
20                "localhost"
21            ], 
22            "ungrouped": []
23        }, 
24        "inventory_dir": "/home/sammy/vault", 
25        "inventory_file": "./hosts", 
26        "inventory_hostname": "localhost", 
27        "inventory_hostname_short": "localhost", 
28        "mysql_host": "10.0.0.3",
29        "mysql_password": "supersecretpassword",
30        "mysql_port": 3306,
31        "mysql_user": "fred",
32        "omit": "__omit_place_holder__6dd15dda7eddafe98b6226226c7298934f666fc8", 
33        "playbook_dir": ".", 
34        "vault_mysql_password": "supersecretpassword"
35    }
36}

vault_mysql_passwordmysql_password都是可访问的,这种重复是无害的,不会影响您使用该系统。

结论

您的项目应该拥有成功安装和配置复杂系统所需的所有信息,但某些配置数据定义上是敏感的,不应公开披露。 在本指南中,我们展示了 Ansible Vault 如何加密机密信息,以便您可以将所有配置数据保存在一个位置,而不会损害安全。

Published At
Categories with 技术
comments powered by Disqus