zaki work log

作業ログやら生活ログやらなんやら

ansible-vaultで暗号化

ansible-vaultを使ったインベントリの暗号化について、ざっくりとお試し。

初期状態

include.ymlファイルを作成。
これはプレイブックからvars_filesで読み込む。

username: www-user
password: my-passwd

プレイブックのplaybook.yml

---
- hosts: nodes
  gather_facts: False
  vars_files:
    - included.yml
  tasks:
    - ping:
    - debug:
        msg: "username:{{ username }} password:{{ password }}"
[zaki@control-node vault]$ ansible-playbook -i inventory.ini playbook.yml

PLAY [nodes] ******************************************************************************

TASK [ping] *******************************************************************************
ok: [192.168.0.142]
ok: [192.168.0.140]
ok: [192.168.0.141]

TASK [debug] ******************************************************************************
ok: [192.168.0.141] =>
  msg: username:www-user password:my-passwd
ok: [192.168.0.142] =>
  msg: username:www-user password:my-passwd
ok: [192.168.0.140] =>
  msg: username:www-user password:my-passwd

PLAY RECAP ********************************************************************************
192.168.0.140              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.0.141              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.0.142              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[zaki@control-node vault]$

ファイルの暗号化と復号

暗号化ファイルの新規作成

[zaki@control-node vault]$ ansible-vault create encrypted.yml
New Vault password:
Confirm New Vault password:
[zaki@control-node vault]$

ansible-vault create <filename>で、エディタが起動し、filenameの暗号化ファイルを作成できる。 エディタで以下の内容を記入すればencrypted.ymlが生成される。

username: www-user
password: my-passwd
[zaki@control-node vault]$ ls
ansible.cfg  encrypted.yml  included.yml  inventory.ini  playbook.yml
[zaki@control-node vault]$ cat encrypted.yml
$ANSIBLE_VAULT;1.1;AES256
37303361636633663039323363643463646162343532663938633130306231353537666538613966
3762613265303737353031343936343435633861636434620a343331343638336536383230303437
39646261363261636664653739323637343161616332313932303362643661313535373361323331
6566323235656434330a386661303532363831613232363737613336323761323865343132666434
64623131633038353263326465343239343436626133353038303764623532323865653835396636
3335653330356536303330383132303566633262323734313733
[zaki@control-node vault]$

こんなプレイブックを用意

[zaki@control-node vault]$ cat playbook-enc.yml
---
- hosts: localhost
  gather_facts: False
  vars_files:
  - encrypted.yml
  tasks:
  - debug:
      msg: "{{username}}"
[zaki@control-node vault]$ ansible-playbook -i inventory.ini playbook-enc.yml
ERROR! Attempting to decrypt but no vault secrets found
[zaki@control-node vault]$

普通にやってもエラーになる。

Vaultによる暗号化データを含む場合は--ask-vault-passを付加して実行する。

[zaki@control-node vault]$ ansible-playbook -i inventory.ini playbook-enc.yml --ask-vault-pass
Vault password:

PLAY [localhost] **************************************************************************

TASK [debug] ******************************************************************************
ok: [localhost] =>
  msg: www-user

PLAY RECAP ********************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[zaki@control-node vault]$

復号される。

既存ファイルの暗号化

Encrypting Unencrypted Files

[zaki@control-node vault]$ ansible-vault encrypt included.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[zaki@control-node vault]$ cat included.yml
$ANSIBLE_VAULT;1.1;AES256
62313233666265373965656666636166363334303231313836313562636363663563343031663738
6337653333663563663662656665613930333839323461310a396431653933666361393536306231
35336635323737636531313436363238646661323330393764333638393662353232336138386562
3430653132363361330a373334613131633631343635633463653332356464643433353364663633
35376462633061373638386635306530636532636163663363376462653631613865636334386165
6232313264353234343733396566623731663339366133623132
[zaki@control-node vault]$

暗号化された。

ansible-playbookを実行しても

[zaki@control-node vault]$ ansible-playbook -i inventory.ini playbook.yml
ERROR! Attempting to decrypt but no vault secrets found
[zaki@control-node vault]$

--ask-vault-passを付けて実行

[zaki@control-node vault]$ ansible-playbook -i inventory.ini playbook.yml --ask-vault-pass
Vault password:

PLAY [nodes] ******************************************************************************

TASK [ping] *******************************************************************************
ok: [192.168.0.141]
ok: [192.168.0.142]
ok: [192.168.0.140]

TASK [debug] ******************************************************************************
ok: [192.168.0.140] =>
  msg: username:www-user password:my-passwd
ok: [192.168.0.141] =>
  msg: username:www-user password:my-passwd
ok: [192.168.0.142] =>
  msg: username:www-user password:my-passwd

PLAY RECAP ********************************************************************************
192.168.0.140              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.0.141              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.0.142              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[zaki@control-node vault]$

暗号化されたファイルの中身を確認する

viewサブコマンドを使用する。

[zaki@control-node vault]$ ansible-vault view included.yml
Vault password:
username: www-user
password: my-passwd

暗号化されたファイルを編集する

editサブコマンドでviなどのエディタが起動する。

[zaki@control-node vault]$ ansible-vault edit included.yml
Vault password:

ファイルを復号する

Decrypting Encrypted Files

[zaki@control-node vault]$ cat included.yml
$ANSIBLE_VAULT;1.1;AES256
62313233666265373965656666636166363334303231313836313562636363663563343031663738
6337653333663563663662656665613930333839323461310a396431653933666361393536306231
35336635323737636531313436363238646661323330393764333638393662353232336138386562
3430653132363361330a373334613131633631343635633463653332356464643433353364663633
35376462633061373638386635306530636532636163663363376462653631613865636334386165
6232313264353234343733396566623731663339366133623132
[zaki@control-node vault]$ ansible-vault decrypt included.yml
Vault password:
Decryption successful
[zaki@control-node vault]$ cat included.yml
username: www-user
password: my-passwd
[zaki@control-node vault]$

値の暗号化

Use encrypt_string to create encrypted variables to embed in yaml

前述のencrypt/decryptだと、ファイルを丸ごと暗号化してしまうため、ファイル名以外に(復号しない限りは)何の値が保存されているか(何のキーでアクセスできるのか)全くわからない。 それに対してencrypt_stringを使うと、値のみを暗号化し、キーはtext/plainで記述できるので、必要最小限の箇所のみ暗号化できる。 ただし現状では作成は手作業になり、部分的に復号することも(多分)できない。

標準入力から暗号化

ファイルを指定

[zaki@control-node vault]$ ansible-vault encrypt_string --stdin-name password < password.txt
New Vault password:
Confirm New Vault password:
Reading plaintext input from stdin. (ctrl-d to end input)
password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          30376662633136666664616264633562373739333739393331633732623763323632646136656134
          3035393837366363623462376535333661346339633461610a656437393063633164303833336338
          65336165343333353364336237316632386137353833623531383666313165656664366132626535
          3361373038336134320a643636363938666565326263326464363230653661633430366464336663
          3631
Encryption successful

指定がない場合は次のようにCtrl-dされるまで手入力できる状態になるが、入力文字列がエコーバックされるので微妙。

[zaki@control-node vault]$ ansible-vault encrypt_string --stdin-name password
New Vault password:
Confirm New Vault password:
Reading plaintext input from stdin. (ctrl-d to end input)
my-passwd
password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          33613739656135656461303938303061323030353035633439663833313830393166383335353738
          6665643136613763306338363766323263663630373237350a303539623334666665623563303763
          34626161633965633461336565313338303266633065333631323535386531623630363563383164
          3533666235616330370a636435323133303164376663636463323666343334336530363837303363
          6533
Encryption successful

実行

ansible-vault encrypt_stringで作成した暗号化文字列を既存のインベントリに追加する。
更新するのはvars_filesで読み込むincluded.yml

username: www-user
password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          33613739656135656461303938303061323030353035633439663833313830393166383335353738
          6665643136613763306338363766323263663630373237350a303539623334666665623563303763
          34626161633965633461336565313338303266633065333631323535386531623630363563383164
          3533666235616330370a636435323133303164376663636463323666343334336530363837303363
          6533

playbook(変更なし)

- hosts: nodes
  gather_facts: False
  vars_files:
    - included.yml
  tasks:
    - ping:
    - debug:
        msg: "username:{{ username }} password:{{ password }}"

オプション無しで実行

[zaki@control-node vault]$ ansible-playbook -i inventory.ini playbook.yml

PLAY [nodes] ******************************************************************************

TASK [ping] *******************************************************************************
ok: [192.168.0.141]
ok: [192.168.0.140]
ok: [192.168.0.142]

TASK [debug] ******************************************************************************
fatal: [192.168.0.140]: FAILED! =>
  msg: Attempting to decrypt but no vault secrets found
fatal: [192.168.0.141]: FAILED! =>
  msg: Attempting to decrypt but no vault secrets found
fatal: [192.168.0.142]: FAILED! =>
  msg: Attempting to decrypt but no vault secrets found

PLAY RECAP ********************************************************************************
192.168.0.140              : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
192.168.0.141              : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
192.168.0.142              : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

オプションなしだと復号できずにエラーになる。 --ask-vault-passを付与して実行。

[zaki@control-node vault]$ ansible-playbook -i inventory.ini playbook.yml --ask-vault-pass
Vault password:

PLAY [nodes] ******************************************************************************

TASK [ping] *******************************************************************************
ok: [192.168.0.141]
ok: [192.168.0.142]
ok: [192.168.0.140]

TASK [debug] ******************************************************************************
ok: [192.168.0.141] =>
  msg: |-
    username:www-user password:my-passwd
ok: [192.168.0.142] =>
  msg: |-
    username:www-user password:my-passwd
ok: [192.168.0.140] =>
  msg: |-
    username:www-user password:my-passwd

PLAY RECAP ********************************************************************************
192.168.0.140              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.0.141              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.0.142              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

素のインベントリファイルでも確認

素というか、vars_filesとかで読み込む外部ファイルでなく、実行時に-iで指定するターゲットホストが書かれているファイル。
呼称とかあるのかな…?

インベントリファイルを暗号化

元ファイル。

[zaki@control-node vault]$ cat inventory.ini
[nodes]
192.168.0.141
192.168.0.142
192.168.0.140

インベントリファイルを暗号化する。

[zaki@control-node vault]$ ansible-vault encrypt inventory.ini
New Vault password:
Confirm New Vault password:
Encryption successful

インベントリファイルが暗号化されていることの確認。

[zaki@control-node vault]$ cat inventory.ini
$ANSIBLE_VAULT;1.1;AES256
35386263396533363163393562353239306133306238656166316164333832313265383639616232
6163663339383333356634386332656433316336316430650a336230306230343065353234643062
66346438623862316162633538393063323563333366383064326664393164346363363163643564
3135333561653831330a373235626335386563663464333565383936633932636163303138313932
66663635633439643262376130383233653835633166303465336362383031393866616130643764
38333364353233363663316536643130363432643363613938376637613064383135636465366264
633464623431383866633262353661616235

暗号化されたインベントリファイルの中身の確認。

[zaki@control-node vault]$ ansible-vault view inventory.ini
Vault password:
[nodes]
192.168.0.141
192.168.0.142
192.168.0.140

実行

--ask-vault-pass無しで実行

[zaki@control-node vault]$ ansible all -i inventory.ini -m ping
[WARNING]:  * Failed to parse /home/zaki/ansible/vault/inventory.ini with ini plugin: Attempting to decrypt but no vault secrets found

[WARNING]: Unable to parse /home/zaki/ansible/vault/inventory.ini as an inventory source

[WARNING]: No inventory was parsed, only implicit localhost is available

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

[zaki@control-node vault]$

動作しない。 --ask-vault-passを付けて実行。

[zaki@control-node vault]$ ansible all -i inventory.ini -m ping --ask-vault-pass
Vault password:
192.168.0.140 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
192.168.0.142 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
192.168.0.141 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

インベントリファイルが復号されてちゃんと実行できる。