Ansible Vault是一项允许用户加密Ansible项目中的值和数据结构的功能。这提供了保证Ansible成功运行敏感数据所必备的能力。
在本教程中,我们将演示如何使用Ansible Vault,并开发一些推荐操作以简化其使用。我们将使用Ubuntu 16.04服务器作为Ansible控制机器。不需要远程主机。
您将需要一个具有sudo
权限的非root用户的Ubuntu 16.04服务器。在服务器上,您需要安装和配置Ansible。
Vault是一种允许将加密内容透明地并入Ansible工作流程的机制。所谓的ansible-vault
的实用程序通过在磁盘上加密来保护机密数据。为了将这些密钥
与常规的Ansible数据整理在一起,ansible
和ansible-playbook
命令分别用于执行adhoc任务和结构化playbook的命令,都支持在运行时解密加密vault的内容。
Vault是以文件级粒度实现,这意味着文件是完全加密或未加密的。它使用AES256
算法提供与用户提供的密码相符合的加密。这意味着使用相同的密码才能加密和解密内容,这从可用性的角度来看是有用的。Ansible能够识别和解密在执行文本或任务时找到的任何加密文件。
在撰写本文时,用户只能将一个密码传递给Ansible。这意味着所涉及的每个加密文件都必须共享密码。
了解Vault的内容,我们就可以开始讨论Ansible提供的工具以及如何将Vault与现有工作流程结合使用。
在使用ansible-vault
命令之前,最好指定首选的文本编辑器。Vault的一些命令会涉及打开编辑器来操作加密文件的内容。Ansible会查看EDITOR
环境变量以查找首选编辑器。如果未设置,则默认为vi
。
如果您不想使用vi
进行编辑,则应在EDITOR
环境中设置变量。
注意:如果您发现自己在
vi
会话中发生异常,可以通过按Esc键,键入:q!
,然后按Enter键退出。如果您不熟悉vi
编辑器,则您所做的任何更改都可能是无意的,因此该命令会在不保存的情况下退出。
要为单个命令设置编辑器,请在命令前加上环境变量赋值,如下所示:
$ EDITOR=nano ansible-vault . . .
要使其持久化,请打开您的~/.bashrc
文件:
$ nano ~/.bashrc
通过在文件末尾添加EDITOR
分配来指定首选编辑器:
~/.bashrc
~/.bashrc
export EDITOR=nano
完成后保存并关闭文件。
再次获取文件以读取当前会话的更改:
$ . ~/.bashrc
显示EDITOR
变量以检查您的设置是否已应用:
$ echo $EDITOR
nano
现在您已经建立了首选编辑器,我们可以使用ansible-vault
命令讨论操作。
ansible-vault
命令是用于管理Ansible中的加密内容的主界面。此命令用于初始加密文件,随后用于查看,编辑或解密数据。
要创建使用Vault加密的新文件,请使用ansible-vault create
命令。传入您要创建的文件的名称。例如,要创建一个名为vault.yml
存储敏感变量的加密YAML文件,可以键入:
$ 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用来知道如何处理文件的一些头信息,然后是加密内容,显示为数字。
如果您已经拥有要使用Vault加密的文件,请改用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
命令将文件的内容提供给标准输出。默认情况下,这意味着内容显示在终端中。
将vault加密文件传递给命令:
$ 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 view
或ansible-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 password:
New Vault password:
Confirm New Vault password:
成功确认新密码后,您将收到一条消息,指示重新加密过程成功:
Rekey successful
现在可以使用新密码访问该文件。旧密码将不再有效。
使用Vault加密敏感信息后,您可以开始使用Ansible传统工具的文件。在命令密码正确的情况下,ansible
和ansible-playbook
命令都知道如何解密受保护文件的文件。根据您的需要,有几种不同的方法可以为这些命令提供密码。
您需要一个保险库加密的文件。您可以输入以下内容创建一个:
$ ansible-vault create secret_key
选择并确认密码。填写您想要的任何内容:
secret_key
confidential data
保存并关闭文件。
我们还可以创建一个临时hosts
文件作为库存:
$ nano hosts
我们将只添加Ansible localhost。为了准备以后的步骤,我们将把它放在[database]
组中:
hosts
[database]
localhost ansible_connection=local
完成后保存并关闭文件。
接下来,ansible.cfg
如果尚不存在,则在当前目录中创建一个文件:
$ nano ansible.cfg
现在,只需添加一个[defaults]
部分并将Ansible指向我们刚刚创建的库存:
ansible.cfg
[defaults]
inventory = ./hosts
准备好后,继续。
在运行解密内容的最直接方法是让Ansible
提示您输入相应的凭据。您可以通过添加--ask-vault-pass
到任何一个ansible
或ansible-playbook
命令来完成此操作。Ansible将提示您输入密码,该密码将用于尝试解密其找到的任何受保管库保护的内容。
例如,如果我们需要将vault加密文件的内容复制到主机,我们可以使用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
}
提示输入密码是安全的,但可能很繁琐,特别是在重复运行时,也会妨碍自动化。好在这些情况有一些替代方案。
如果您不希望每次执行任务时都输入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
现在,当您运行需要解密的命令时,将不再提示您输入保管库密码。ansible-vault
不仅会使用文件中的密码来解密任何文件,而且在使用ansible-vault create
和创建新文件时也会应用密码ansible-vault encrypt
。
您可能担心不小心将密码文件上传到存储库。不幸的是,虽然Ansible有一个环境变量指向密码文件的位置,但它没有一个用于设置密码。
但是,如果您的密码文件是可执行文件,Ansible将把它作为脚本运行并使用生成的输出作为密码。在GitHub问题中,Brian Schwind建议使用以下脚本从环境变量中提取密码。
在编辑器中打开文件.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加密密码。
虽然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变量文件,以便从多个文件应用变量。我们可以重构以利用这种能力。首先,将现有文件重命名database为vars。这将是我们未加密的变量文件:
$ 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)添加回未加密的文件中。我们可以使用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_*
仍使用与上次相同的正确方法应用。
注意:如果未使用密码文件自动应用Vault密码,请将--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_password
和mysql_password
都可访问。
在教程中,我们演示了Ansible Vault如何加密信息,以便您可以将所有配置数据保存在一个位置而不会影响安全性。
参考文献:《How To Use Vault to Protect Sensitive Ansible Data on Ubuntu 16.04》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。