如何在Ubuntu 16.04使用Vault来保护敏感的Ansible数据

Ansible Vault是一种允许用户加密Ansible项目中的值和数据结构的功能。这提供了保护成功运行Ansible播放所必需的敏感数据的能力,但不应公开可见。

介绍

Ansible Vault是一种允许用户加密Ansible项目中的值和数据结构的功能。这提供了保护成功运行Ansible播放所需的任何敏感数据的能力,但不应公开可见,例如密码或私钥。 Ansible会在提供密钥时在运行时自动解密文件库加密的内容。 在本指南中,我们将演示如何使用Ansible Vault并探索一些推荐的做法,以简化其使用。我们将使用Ubuntu 16.04服务器用于Ansible控制机器。不需要远程主机。

先决条件

跟着一起,你将需要一个Ubuntu 16.04服务器与非root用户sudo权限。 您可以按照我们的Ubuntu 16.04服务器初始设置向导来创建具有相应权限的用户。 在服务器上,您需要安装和配置Ansible。您可以按照我们的教程在Ubuntu 16.04安装Ansible安装相应的软件包。 当您的服务器配置了上述要求时,请继续阅读本指南。

什么是Ansible Vault?

保险库是一种允许将加密内容透明地并入Ansible工作流程的机制。所谓的实用ansible-vault由磁盘加密来保证机密数据。 要定期Ansible数据整合这些秘密,无论是ansibleansible-playbook命令,分别执行临时任务和结构化的剧本,对在运行时库解密加密内容的支持。 Vault是以文件级粒度实现的,这意味着文件是完全加密的或未加密的。它使用AES256算法来提供键固定到一个用户提供的密码的对称加密。这意味着相同的密码用于加密和解密内容,这从可用性的角度是有帮助的。 Ansible能够识别和解密执行剧本或任务时找到的任何文件库加密文件。 尽管有人提出要改变这种 ,在写这篇文章的时候,用户只能通过在一个单一的密码Ansible。这意味着每个涉及的加密文件必须共享密码。 现在,您了解了有关Vault是什么,我们可以开始讨论Ansible提供的工具以及如何在现有工作流中使用Vault。

设置Ansible Vault编辑器

使用前ansible-vault命令,它是指定您的首选文本编辑器是个好主意。 Vault的一些命令涉及打开编辑器来操纵加密文件的内容。 Ansible会看EDITOR环境变量来找到你喜欢的编辑器。 如果没有设置,则默认为vi 。 如果你不想编辑vi编辑器,你应该设置EDITOR变量在您的环境。 注意:如果一个内发现自己vi届一不小心,你可以通过按Esc键,键入exit :q!,然后按Enter键 。如果你不熟悉的vi编辑器,你所做的任何更改将可能是无意的,所以这个命令退出而不保存。 要为单个命令设置编辑器,请在命令前加上环境变量赋值,如下所示:
EDITOR=nano ansible-vault . . .
为了使这个执着,打开你~/.bashrc文件中:
nano ~/.bashrc
通过添加指定首选的编辑器EDITOR分配到文件的末尾:
〜/ .bashrc
export EDITOR=nano
保存并在完成后关闭文件。 再次来源文件以读取当前会话的更改:
. ~/.bashrc
显示EDITOR变量来检查所应用的设置:
echo $EDITOR
nano
现在,你已经建立了自己喜欢的编辑器,我们可以讨论可用的操作ansible-vault命令。

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

ansible-vault的命令是在Ansible管理加密内容的主界面。此命令用于初始加密文件,并随后用于查看,编辑或解密数据。

创建新的加密文件

要创建库加密的新文件,请使用ansible-vault create命令。 传入您要创建的文件的名称。 例如,要创建一个名为加密YAML文件vault.yml存储敏感的变量,你可以输入:
ansible-vault create vault.yml
系统将提示您输入并确认密码:
New Vault password: 
Confirm New Vault password:
当您确认密码后,Ansible会立即打开一个编辑窗口,您可以在其中输入所需的内容。 要测试加密功能,请输入一些测试文本:
vault.yml
Secret information
Ansible将在您关闭文件时加密内容。如果您检查文件,而不是看到您键入的单词,您会看到一个加密块:
cat vault.yml
$ANSIBLE_VAULT;1.1;AES256
65316332393532313030636134643235316439336133363531303838376235376635373430336333
3963353630373161356638376361646338353763363434360a363138376163666265336433633664
30336233323664306434626363643731626536643833336638356661396364313666366231616261
3764656365313263620a383666383233626665376364323062393462373266663066366536306163
31643731343666353761633563633634326139396230313734333034653238303166
我们可以看到Ansible用来知道如何处理文件的一些标题信息,后面是加密的内容,显示为数字。

加密现有文件

如果你已经有了,你希望与库加密一个文件,请使用ansible-vault encrypt命令。 对于测试,我们可以通过键入以下内容创建示例文件:
echo 'unencrypted stuff' > encrypt_me.txt
现在,您可以通过键入以下内容加密现有文件:
ansible-vault encrypt encrypt_me.txt
同样,系统将提示您提供并确认密码。然后,一条消息将确认加密:
New Vault password: 
Confirm New Vault password:
Encryption successful
而不是打开一个编辑窗口, ansible-vault将加密文件的内容并把它写回磁盘,更换未加密版本。 如果我们检查文件,我们应该看到类似的加密模式:
cat encrypt_me.txt
$ANSIBLE_VAULT;1.1;AES256
66633936653834616130346436353865303665396430383430353366616263323161393639393136
3737316539353434666438373035653132383434303338640a396635313062386464306132313834
34313336313338623537333332356231386438666565616537616538653465333431306638643961
3636663633363562320a613661313966376361396336383864656632376134353039663662666437
39393639343966363565636161316339643033393132626639303332373339376664
如您所见,Ansible以与加密新文件相同的方式加密现有内容。

查看加密文件

有时,您可能需要引用文件库加密文件的内容,而无需编辑它或将其写入未加密的文件系统。该ansible-vault view命令提要文件到标准输出的内容。默认情况下,这意味着内容显示在终端中。 将文件库加密文件传递到命令:
ansible-vault view vault.yml
系统将要求您输入文件的密码。成功输入后,将显示内容:
Vault password:
Secret information
如您所见,密码提示混入到文件内容的输出中。使用时,请记住这一点ansible-vault view中的自动化流程。

编辑加密文件

当你需要编辑加密的文件,请使用ansible-vault edit命令:
ansible-vault edit vault.yml
系统将提示您输入文件的密码。输入后,Ansible会打开文件的编辑窗口,您可以在其中进行任何必要的更改。 保存后,新内容将再次使用文件的加密密码进行加密并写入磁盘。

手动解密加密文件

要解密保管库的加密文件,请使用ansible-vault decrypt命令。 注:由于意外敏感数据提交到项目库中的可能性增加时, ansible-vault decrypt命令只是建议,当你想永久地从文件中删除加密。如果您需要查看或编辑保管库加密文件,通常最好使用ansible-vault viewansible-vault edit分别命令。 传入加密文件的名称:
ansible-vault decrypt vault.yml
系统将提示您输入文件的加密密码。一旦输入正确的密码,文件将被解密:
Vault password:
Decryption successful
如果再次查看文件,而不是文件库加密,您应该会看到文件的实际内容:
cat vault.yml
Secret information
您的文件现在在磁盘上未加密。完成后,请确保删除任何敏感信息或重新加密文件。

更改加密文件的密码

如果您需要更改加密文件的密码,请使用ansible-vault rekey命令:
ansible-vault rekey encrypt_me.txt
当您输入命令时,将首先提示文件的当前密码:
Vault password:
输入后,系统将要求您选择并确认新的Vault密码:
Vault password:
New Vault password:
Confirm New Vault password:
当您成功确认新密码后,您将收到一条指示重新加密过程成功的消息:
Rekey successful
现在应该可以使用新密码访问该文件。旧密码将不再工作。

使用Vault加密的文件运行Ansible

在使用Vault加密敏感信息后,您可以使用Ansible的常规工具开始使用这些文件。该ansibleansible-playbook命令都知道如何给出正确的密码解密跳马保护的文件。根据您的需要,有几种不同的方式为这些命令提供密码。 要继续操作,您需要一个文件库加密的文件。您可以通过键入以下内容创建一个:
ansible-vault create secret_key
选择并确认密码。填写任何你想要的虚拟内容:
secret_key
confidential data
保存并关闭文件。 我们也可以创建一个临时hosts文件的清单:
nano hosts
我们将只添加Ansible localhost。要为后面的步骤做准备,我们将会把它在[database]组:
主机
[database]
localhost ansible_connection=local
保存并在完成后关闭文件。 接下来,创建一个ansible.cfg在当前目录下的文件,如果不存在:
nano ansible.cfg
现在,只需添加一个[defaults]部分,并指出Ansible到我们刚创建的盘点:
ansible.cfg
[defaults]
inventory = ./hosts
当你准备好,继续。

使用交互式提示

在运行时解密内容的最直接的方法是让Ansible提示您输入相应的凭证。您可以通过添加为此--ask-vault-pass任何ansibleansible-playbook命令。 Ansible将提示您输入一个密码,它将用于尝试解密找到的任何受保护的内容。 例如,如果我们需要一个金库加密文件的内容复制到一台主机,我们可以用这样做的copy模块和--ask-vault-pass标志。如果文件实际上包含敏感数据,您很可能希望锁定在远程主机上的访问权限和权限和所有权限制。 注意:我们使用localhost作为目标主机在本实施例,以减少所需的服务器的数量,但由于如果主机是真正的远程的结果应该是相同的:
ansible --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密码。然后系统会要求您输入Vault密码:
SUDO password:
Vault password:
当提供密码时,Ansible将尝试使用所找到的任何加密文件的Vault密码执行任务。请记住,执行期间引用的所有文件必须使用相同的密码:
localhost | SUCCESS => {
    "changed": true, 
    "checksum": "7a2eb5528c44877da9b0250710cba321bc6dac2d", 
    "dest": "/tmp/secret_key", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "270ac7da333dd1db7d5f7d8307bd6b41", 
    "mode": "0600", 
    "owner": "root", 
    "size": 18, 
    "src": "/home/sammy/.ansible/tmp/ansible-tmp-1480978964.81-196645606972905/source", 
    "state": "file", 
    "uid": 0
}
提示输入密码是安全的,但可能很冗长,尤其是在重复运行时,也会妨碍自动化。幸运的是,这些情况有一些替代方案。

使用带有密码文件的Ansible Vault

如果不希望在每次执行任务时键入Vault密码,则可以将Vault密码添加到文件,并在执行期间引用该文件。 例如,你可以把你的密码在.vault_pass像这样的文件:
echo 'my_vault_password' > .vault_pass
如果使用版本控制,请确保将密码文件添加到版本控制软件的忽略文件,以避免意外提交:
echo '.vault_pass' >> .gitignore
现在,您可以引用该文件。该--vault-password-file标志可以在命令行上。我们可以通过键入以下内容完成上一节中的相同任务:
ansible --vault-password-file=.vault_pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost
此次不会提示您输入Vault密码。

自动读取密码文件

为了避免提供一个标志可言,你可以设置ANSIBLE_VAULT_PASSWORD_FILE与路径密码文件环境变量:
export ANSIBLE_VAULT_PASSWORD_FILE=./.vault_pass
你现在应该能在没有执行命令--vault-password-file为当前会话标志:
ansible -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost
为了使Ansible意识到跨会话密码文件的位置,你可以编辑你ansible.cfg文件。 打开本地ansible.cfg我们之前创建的文件:
nano ansible.cfg
[defaults]部分,设置vault_password_file设置。指向密码文件的位置。这可以是相对路径或绝对路径,具体取决于哪个对您最有用:
ansible.cfg
[defaults]
. . .
vault_password_file = ./.vault_pass
现在,当您运行需要解密的命令时,将不再提示您输入Vault密码。作为奖励, ansible-vault不仅会使用密码文件中解密的文件,但与创建新文件时,它将应用密码ansible-vault createansible-vault encrypt

从环境变量读取密码

您可能担心不小心将密码文件提交到您的存储库。不幸的是,虽然Ansible具有环境变量指向一个密码文件的位置,它具有一个用于设置密码本身。 但是,如果您的密码文件是可执行的,Ansible将作为脚本运行它,并使用结果输出作为密码。在GitHub上的问题布赖恩·施温德提出下面的脚本可以用来从一个环境变量拉密码。 打开你的.vault_pass在编辑器中的文件:
nano .vault_pass
使用以下脚本替换内容:
.vault_pass
#!/usr/bin/env python

import os
print os.environ['VAULT_PASSWORD']
输入以下命令以使文件可执行:
chmod +x .vault_pass
然后,您可以设置和导出VAULT_PASSWORD环境变量,将可用于当前会话:
export VAULT_PASSWORD=my_vault_password
你必须在每个Ansible会话开始时这样做,这可能听起来不方便。但是,这有效地防止意外提交您的Vault加密密码,这可能有严重的缺点。

将Vault加密变量与常规变量配合使用

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

设置示例

假设您正在配置数据库服务器。当您创建的hosts早期文件,您放置在localhost名为组进入database ,为这一步做准备。 数据库通常需要混合使用敏感和非敏感变量。这些都可以在一个被分配group_vars在群命名的文件目录:
mkdir -p group_vars
nano group_vars/database
里面的group_vars/database文件,设置一些变量。一些变量,如MySQL端口号,不是秘密,可以自由共享。其他变量,如数据库密码,将保密:
group_vars / database
---
# nonsensitive data
mysql_port: 3306
mysql_host: 10.0.0.3
mysql_user: fred

# sensitive data
mysql_password: supersecretpassword
我们可以测试,所有的变量可用于我们的Ansible的主机debug模块和hostvars变量:
ansible -m debug -a 'var=hostvars[inventory_hostname]' database
localhost | SUCCESS => {
    "hostvars[inventory_hostname]": {
        "ansible_check_mode": false, 
        "ansible_version": {
            "full": "2.2.0.0", 
            "major": 2, 
            "minor": 2, 
            "revision": 0, 
            "string": "2.2.0.0"
        }, 
        "group_names": [
            "database"
        ], 
        "groups": {
            "all": [
                "localhost"
            ], 
            "database": [
                "localhost"
            ], 
            "ungrouped": []
        }, 
        "inventory_dir": "/home/sammy", 
        "inventory_file": "hosts", 
        "inventory_hostname": "localhost", 
        "inventory_hostname_short": "localhost", 
        "mysql_host": "10.0.0.3",
        "mysql_password": "supersecretpassword",
        "mysql_port": 3306,
        "mysql_user": "fred",
        "omit": "__omit_place_holder__1c934a5a224ca1d235ff05eb9bda22044a6fb400", 
        "playbook_dir": "."
    }
}
输出确认我们设置的所有变量都应用于主机。然而,我们的group_vars/database文件目前持有我们所有的变量。这意味着我们可以保持不加密,这是一个安全问题,因为数据库密码变量,或者我们加密所有的变量,这会产生可用性和协作问题。

将敏感变量移动到Ansible Vault中

为了解决这个问题,我们需要区分敏感和非敏感变量。我们应该能够加密机密值,同时容易共享我们的非敏感变量。为此,我们将在两个文件之间分割变量。 有可能在以从多个文件应用变量使用可变目录代替一个Ansible变量文件 。 我们可以重构利用这种能力。 首先,重命名现有的文件databasevars 。这将是我们未加密的变量文件:
mv group_vars/database group_vars/vars
接下来,创建一个与旧变量文件同名的目录。移动vars内部文件:
mkdir group_vars/database
mv group_vars/vars group_vars/database/
我们现在有用于可变目录database基,而不是一个单一的文件,我们有一个未加密的可变文件。 由于我们将加密我们的敏感变量,因此我们应该从未加密的文件中删除它们。 编辑group_vars/database/vars文件,删除机密数据:
nano group_vars/database/vars
在这种情况下,我们要删除的mysql_password变量。该文件现在应该看起来像这样:
group_vars / database / vars
---
# nonsensitive data
mysql_port: 3306
mysql_host: 10.0.0.3
mysql_user: fred
接下来,创建将居住在旁边的未加密目录中的保管库加密的文件vars文件:
ansible-vault create group_vars/database/vault
在这个文件中,定义以前是在敏感的变量vars文件。 使用相同的变量名称,但前面加上字符串vault_表明这些变量在跳马保护的文件中定义:
group_vars / database / vault
---
vault_mysql_password: supersecretpassword
保存并在完成后关闭文件。 生成的目录结构如下:
.
├── . . .
├── group_vars/
│   └── database/
│       ├── vars
│       └── vault
└── . . .
在这一点上,变量是分开的,并且只有机密数据被加密。这是安全的,但我们的实施已经影响了我们的可用性。虽然我们的目标是保护敏感的价值观 ,我们也无意可视性降低到实际的变量名。不清楚在不引用多个文件的情况下分配哪些变量,虽然您可能希望在协作期间限制对机密数据的访问,但您可能仍希望共享变量名称。 为了解决这个问题,Ansible项目通常建议一个稍微不同的方法。

从未加密的变量引用库变量

当我们转移到金库保护的文件移到我们的敏感数据,我们用开头的变量名vault_mysql_password成为vault_mysql_password )。 我们可以在原变量名( mysql_password回)到未加密的文件。我们可以使用Jinja2模板语句来引用来自未加密变量文件中的加密变量名称,而不是直接将它们设置为敏感值。这样,您可以通过引用单个文件来查看所有定义的变量,但机密值将保留在加密文件中。 要演示,请再次打开未加密的变量文件:
nano group_vars/database/vars
添加mysql_password再次变量。这次,使用Jinja2模板引用在保险库文件中定义的变量:
group_vars / database / vars
---
# nonsensitive data
mysql_port: 3306
mysql_host: 10.0.0.3
mysql_user: fred

# sensitive data
mysql_password: "{{ vault_mysql_password }}"
mysql_password变量将被设置为的值vault_mysql_password变量,这是在保管库文件中定义。 使用这种方法,你可以明白这一切将被应用到主机中的变量database通过查看组group_vars/database/vars文件。 敏感部分将被Jinja2模板遮挡。 该group_vars/database/vault只需要打开时,值本身需要进行查看或更改。 你可以检查,以确保所有的mysql_*变数仍然正确使用相同的方法最后一次应用。 注意:如果您存储库密码不被自动密码文件应用,添加--ask-vault-pass标志下面的命令。
ansible -m debug -a 'var=hostvars[inventory_hostname]' database
localhost | SUCCESS => {
    "hostvars[inventory_hostname]": {
        "ansible_check_mode": false, 
        "ansible_version": {
            "full": "2.2.0.0", 
            "major": 2, 
            "minor": 2, 
            "revision": 0, 
            "string": "2.2.0.0"
        }, 
        "group_names": [
            "database"
        ], 
        "groups": {
            "all": [
                "localhost"
            ], 
            "database": [
                "localhost"
            ], 
            "ungrouped": []
        }, 
        "inventory_dir": "/home/sammy/vault", 
        "inventory_file": "./hosts", 
        "inventory_hostname": "localhost", 
        "inventory_hostname_short": "localhost", 
        "mysql_host": "10.0.0.3",
        "mysql_password": "supersecretpassword",
        "mysql_port": 3306,
        "mysql_user": "fred",
        "omit": "__omit_place_holder__6dd15dda7eddafe98b6226226c7298934f666fc8", 
        "playbook_dir": ".", 
        "vault_mysql_password": "supersecretpassword"
    }
}
两者vault_mysql_passwordmysql_password可访问。这种重复是无害的,不会影响您对本系统的使用。

结论

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