Ansible Valut


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

文章作者: Da
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Da !
  目录