Ansible Vault
一、什么是 Ansible Vault?
Ansible Vault 用以对明娜数据进行加密,例如:username/password、token 等等
二、快速体验 Ansible Vault
Ansible 使用 ansible-Vault 命令完成 Vault 加解密相关操作,它有很多子命令,比如创建加密文件的 create 子命令、查看加密文件的 view 子命令,等等,这些子命令的选项大多类似。
$ ansible-vault --help
positional arguments:
{create,decrypt,edit,view,encrypt,encrypt_string,rekey}
create 创建新的文件并加密
decrypt 解密已加密的文件
edit 编辑已加密文件的内容
view 查看已加密文件的内容
encrypt 加密已存在的未加密文件
encrypt_string 加密一段字符串
rekey 修改已加密文件的 Vault ID 和凭据密码
2.1 encrypt 加密剧本文件
剧本定义
- hosts: 'ecs[0]'
tasks:
- debug:
msg: "Ansible Vault Demo1"
加密文件
$ ansible-vault encrypt playbook-vault-demo1.yml
New Vault password: # 123
Confirm New Vault password: # 123
Encryption successful
尝试执行
$ ansible-playbook playbook-vault-demo1.yml
ERROR! Attempting to decrypt but no vault secrets found
查看文件
$ cat playbook-vault-demo1.yml
$ANSIBLE_VAULT;1.1;AES256
30666435343130356630646137333436653061363030643633326439336538653966303530353732
3536326563363933663665396663613630313064613862620a623566313631346638336331616261
61303630623461353236373931363466613837653564653138623439313131653934356331386266
3930653535326662360a336363396133643137316564356336633030343533343631646362343262
32613632643234323061313864653463616533366363366261653438643361336565363638393462
65613832326234643030316666353030333263373632613535393438393334653535313737626162
66633438613739663366383832666265626465393431396666343037383435326464313765376537
62346161333633306533
可以看到,剧本文件已经被加密过,所以无法直接执行,我们需要在执行时通过 --ask-vault-pass
提供解密密码,示例如下:
$ ansible-playbook --ask-vault-pass playbook-vault-demo1.yml
Vault password: # 123
PLAY [ecs[0]] ******
TASK [Gathering Facts] ******
ok: [ecs-1.aliyun.sz]
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "Ansible Vault Demo1"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.2 –vault-id 解密执行
Ansible 更推荐通过 --vault-id
执行剧本,它支持通过 “交互式输入”、“读文件”、“脚本执行结果” 三种方式,示例如下:
prompt:prompt 是固定的值,表示以交互式的方式提示用户提供凭据密码
$ ansible-playbook --vault-id prompt playbook-vault-demo1.yml # 用户输入密码 Vault password (default): # 123 PLAY [ecs[0]] ****** TASK [Gathering Facts] ****** ok: [ecs-1.aliyun.sz] TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Ansible Vault Demo1" } PLAY RECAP ****** ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
读文件:从文件中读取解密密码
$ ansible-playbook --vault-id pass.txt playbook-vault-demo1.yml PLAY [ecs[0]] ****** TASK [Gathering Facts] ****** ok: [ecs-1.aliyun.sz] TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Ansible Vault Demo1" } PLAY RECAP ****** ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
脚本执行结果:从脚本执行结果中获取凭据密码
$ cat pass.sh # 确保拥有执行权限 chmod +x pass.sh #!/bin/bash echo 123 $ ansible-playbook --vault-id pass.sh playbook-vault-demo1.yml PLAY [ecs[0]] ****** TASK [Gathering Facts] ****** ok: [ecs-1.aliyun.sz] TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Ansible Vault Demo1" } PLAY RECAP ****** ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.3 decrypt 解密剧本文件
通过 decrypt
解密剧本文件
$ ansible-vault decrypt --vault-id pass.sh playbook-vault-demo1.yml
Decryption successful
查看解密后内容
$ cat playbook-vault-demo1.yml
- hosts: 'ecs[0]'
tasks:
- debug:
msg: "Ansible Vault Demo1"
2.4 edit 解密编辑剧本
有时我们希望直接编辑加密的文件,这时我们就用到了 edit
指令,下面我们看个例子,之前我们是采用交互式的方式创建加密文件,现在通过 --vault-id
可以实现非交互式的方式更简单的操作
$ ansible-vault encrypt --vault-id pass.sh playbook-vault-demo1.yml
Encryption successful
解密编辑
$ ansible-vault edit --vault-id pass.sh playbook-vault-demo1.yml
- hosts: 'ecs[0]'
tasks:
- debug:
msg: "Ansible Vault Demo1"
2.5 view 解密查看剧本
encrypt
加密后剧本文件会以密文方式保存,如下所示,不过我们可以通过 view
指令解密查看到源内容
$ cat playbook-vault-demo1.yml
$ANSIBLE_VAULT;1.1;AES256
63313537393030646131663032613439653334363263643166393862346338373965346534373337
3961643539663866386265373439343930353435633564640a353734356339326331323236653035
61336334376661366338626331626264613266303235626665323531623761396531363961646434
6263326564376563360a653332353838626430383762333238323830613761633833333064333566
66333534666433383635306162353039613631323563333737316161626638303231653437313739
62636330363835326639656131376332356561353135346233373664613033623161613539353632
62356363666332383263343433663466613638333830363161643334346661393931623138653763
38636135393762393433
解密查看
$ ansible-vault view --vault-id pass.sh playbook-vault-demo1.yml
- hosts: 'ecs[0]'
tasks:
- debug:
msg: "Ansible Vault Demo1"
2.6 rekey 修改加密
有时我们希望修改文件密码,当然我们可以通过先解密decrypt
再加密encrypt
的方式操作,但这样有些低效,通过 rekey
可以直接完成
$ echo '456' > pass.txt
# pass.sh 包含旧密码
# pass.txt 包含新密码
$ ansible-vault rekey --vault-id pass.sh --new-vault-id pass.txt playbook-vault-demo1.yml
Rekey successful
执行剧本
$ ansible-playbook --vault-id pass.txt playbook-vault-demo1.yml
PLAY [ecs[0]] ******
TASK [Gathering Facts] ******
ok: [ecs-1.aliyun.sz]
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "Ansible Vault Demo1"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.7 encrypt_string 加密字符串
假如,我们不希望加密整个剧本,只是加密某个私密信息,可以使用 encrypt_string
指令,示例如下:
加密字符串
# Passw0rd 为加密前的字符串
$ ansible-vault encrypt_string --vault-id pass.txt Passw0rd
!vault |
$ANSIBLE_VAULT;1.1;AES256
64396265313737333961383631376631323730396262393464666334623731616236616264313934
6231613064363563663138623462336630623937633037370a303865613537653134613130373563
34373565343065663965353331373431663539353639313337323831306435613334333833386439
3462396337373333300a343630346637353731626238393439396133336332393765326630306232
3934
Encryption successful
剧本定义
- hosts: 'ecs[0]'
gather_facts: no
vars:
username: "admin"
# 此时 password 为密文
password: !vault |
$ANSIBLE_VAULT;1.1;AES256
64396265313737333961383631376631323730396262393464666334623731616236616264313934
6231613064363563663138623462336630623937633037370a303865613537653134613130373563
34373565343065663965353331373431663539353639313337323831306435613334333833386439
3462396337373333300a343630346637353731626238393439396133336332393765326630306232
3934
tasks:
- debug:
msg: "Ansible Vault Demo2"
# 输出解密后的原字符串
- debug:
msg: "{{ username }}---{{ password }}"
执行效果
# 通过 pass.txt 文件内的密码解密获取 原字符串
$ ansible-playbook --vault-id pass.txt playbook-vault-demo2.yml
PLAY [ecs[0]] ******
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "Ansible Vault Demo2"
}
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "admin---Passw0rd"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.8 推荐实践
一般来说,不建议直接加密文件,主要是加密后不方便查看和修改任务文件,所以仅针对私密数据项进行加密即可,如下所示,包含三个文件
- mysql_vars.yml:mysql 服务基础信息,不加密
- mysql_secret.yml:mysql 私密认证信息,单独加密此文件
- playbook-vault-demo7.yml:剧本文件,通过循环包含多个变量定义文件
mysql_vars.yml
---
mysql_port: 3306
mysql_user: root
# 以 vault_ 开头,表示该变量是 Vault 加密的变量
mysql_pass: "{{ vault_mysql_pass }}"
mysql_host: 192.168.1.10
mysql_secret.yml
---
vault_mysql_pass: "MySQLPassW0rd"
playbook-vault-demo7.yml
- hosts: 'ecs[0]'
gather_facts: no
tasks:
- include_vars: "{{ item }}"
loop:
- mysql_vars.yml
- mysql_secret.yml
- debug:
msg: "MySQL Info: IP: {{ mysql_host }} PORT: {{ mysql_port }} USER: {{ mysql_user }} PASSWORD: {{ mysql_pass }}"
只加密 mysql_secret.yml 文件
$ cat pass.txt
123
$ ansible-vault encrypt --vault-id mysql_pass@pass.txt mysql_secret.yml
Encryption successful
$ cat mysql_secret.yml
$ANSIBLE_VAULT;1.2;AES256;mysql_pass
34616237306236373637376362646666393235316664316561346135636138386239386461656538
3136643866306565363331376163626630363932393136660a363432633234373536633034356138
35646363353966613464346133303863636538643434303232333533346438363331363736323561
3563323361643630320a386136306334663538393234636630356365623230303937336666663562
33623537653766356363313838376563616536376561313434333830303135363834616264316333
3436373438376530336366303434383739316433363033343434
执行剧本,通过 --vault-id
传入密码文件,用以解密加密变量
$ ap --vault-id mysql_pass@pass.txt playbook-vault-demo7.yml
PLAY [ecs[0]] ***************
TASK [include_vars] ***************
ok: [ecs-1.aliyun.sz] => (item=mysql_vars.yml)
ok: [ecs-1.aliyun.sz] => (item=mysql_secret.yml)
TASK [debug] ***************
ok: [ecs-1.aliyun.sz] => {
"msg": "MySQL Info: IP: 192.168.1.10 PORT: 3306 USER: root PASSWORD: MySQLPassW0rd"
}
PLAY RECAP ***************
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
三、深入了解 Ansible Vault
3.1 加密协议头
在每个已加密的文件中,都包含了一行头部数据,例如:
$ cat playbook-vault-demo1.yml
$ANSIBLE_VAULT;1.1;AES256
35366664373362363762363338633732383464663261613931333337633136613164323832306332
6663626236353162303262616565333262366338326361350a626630666637383561316330346639
63376361333839363635623636616136303264666630393234346533633031633531303366383166
6633613434386365630a303266376337393266646232326437343531633534653062363734326661
35366330626263376633353435613466373038353437343831326565386331626534666632363663
30373766643761643966366361333666646432643937306464346634623135366434386564666466
61653163613365386166316230663766356262383864333566353765353436353961313065626234
64323864353536626233
基本规则是这样的:<固定标识>;<Vault 版本号>;<加密算法>;<Vault ID 标识>
- 固定标识:目前只能是
$ANSIBLE_VAULT
- Vault 版本号:如果使用默认的 Vault ID,则版本号为
1.1
,如果给定了 Vault ID,则版本号为1.2
- 加密算法:目前只支持
AES256
加密算法 - Vault ID 标识:加密标识,没什么特别意义,主要是用来让管理员管理起来更方便些
3.2 加密标识
一般情况下,当我们通过不同密码加密多个字符串时,为了标识加密数据方面阅读会使用 vault tag
或者 vaule label
,示例如下
$ cat pass.txt
123
$ cat pass2.txt
456
加密 用户名 和 密码
$ ansible-vault encrypt_string --vault-id mysql_user@pass.txt adm1n
!vault |
$ANSIBLE_VAULT;1.2;AES256;mysql_user
64623338303238333566613233373536653931313363616336383566343861356532383162326666
3138353232313635356262316236623639336564363863610a653836653831623239366236366333
32363865363733663939346238383733616566343130633130346339356535313461646364376238
3761353237393365310a633732616531326463366264363064386331386133386536393665313531
3338
Encryption successful
$ ansible-vault encrypt_string --vault-id mysql_pass@pass2.txt Passw0rd
!vault |
$ANSIBLE_VAULT;1.2;AES256;mysql_pass
65306463313965333534346535393861346231323739643339353665633533333536643266613433
3836663964333637346334636361656434336164653736380a343762313561313137636665323237
66663330376633656336616665626531386134643138643833613364663537353031366430313136
3262366534363661370a313332656436643635373539623334383237653338616430646462643730
3665
Encryption successful
将密文存储至剧本中
- hosts: 'ecs[0]'
gather_facts: no
vars:
username: !vault |
$ANSIBLE_VAULT;1.2;AES256;mysql_user
64623338303238333566613233373536653931313363616336383566343861356532383162326666
3138353232313635356262316236623639336564363863610a653836653831623239366236366333
32363865363733663939346238383733616566343130633130346339356535313461646364376238
3761353237393365310a633732616531326463366264363064386331386133386536393665313531
3338
# 此时 password 为密文
password: !vault |
$ANSIBLE_VAULT;1.2;AES256;mysql_pass
65306463313965333534346535393861346231323739643339353665633533333536643266613433
3836663964333637346334636361656434336164653736380a343762313561313137636665323237
66663330376633656336616665626531386134643138643833613364663537353031366430313136
3262366534363661370a313332656436643635373539623334383237653338616430646462643730
3665
tasks:
- debug:
msg: "Ansible Vault Demo2"
# 输出解密后的原字符串
- debug:
msg: "{{ username }}---{{ password }}"
读取多个密码文件,解密执行并输出原始字符串
$ ap --vault-id mysql_user@pass.txt --vault-id mysql_pass@pass2.txt playbook-vault-demo6.yml
PLAY [ecs[0]] ***************
TASK [debug] ***************
ok: [ecs-1.aliyun.sz] => {
"msg": "Ansible Vault Demo2"
}
TASK [debug] ***************
ok: [ecs-1.aliyun.sz] => {
"msg": "adm1n---Passw0rd"
}
PLAY RECAP ***************
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
当然,解密时不添加标识也会可以的,毕竟只是为了提高可读性
$ ap --vault-id pass.txt --vault-id pass2.txt playbook-vault-demo6.yml
PLAY [ecs[0]] ***************
TASK [debug] ***************
ok: [ecs-1.aliyun.sz] => {
"msg": "Ansible Vault Demo2"
}
TASK [debug] ***************
ok: [ecs-1.aliyun.sz] => {
"msg": "adm1n---Passw0rd"
}
PLAY RECAP ***************
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3.3 加/解密包含剧本
在看个类似的,A 加密剧本中引用了 B 加密剧本
剧本定义:playbook-vault-demo3.yml
- hosts: 'ecs[0]'
gather_facts: no
tasks:
- debug:
msg: "Ansible Vault Demo3"
- include_tasks: playbook-vault-demo4.yml
剧本定义:playbook-vault-demo4.yml
---
- debug:
msg: "Ansible Vault Demo4"
创建两个密码文件
$ echo '123' > pass2.txt
$ echo '321' > pass3.txt
分别加密剧本文件
$ ansible-vault encrypt --vault-id pass2.txt playbook-vault-demo3.yml
Encryption successful
$ ansible-vault encrypt --vault-id pass3.txt playbook-vault-demo4.yml
Encryption successful
因为两个剧本依赖不同的密码文件,所以我们需要声明多次 --vault-id
$ ansible-playbook --vault-id pass2.txt --vault-id pass3.txt playbook-vault-demo3.yml
PLAY [ecs[0]] ******
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "Ansible Vault Demo3"
}
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/playbook-vault-demo4.yml for ecs-1.aliyun.sz
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "Ansible Vault Demo4"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3.4 优化加/解密速度
按照官方文档所说,当加解密的文件较多时,可安装 cryptography 包进行优化提速
$ pip install cryptography