ansible-vaultで暗号化しよう。

## 導入

以前「暗号化パスワードでユーザーを生成する。」という記事を書いたことがある。
当時はファイル全体ではなくvariableを1項目を暗号化したかったので、ansible-vaultを使わなかった。
ユーザーを生成する時のパスワードをとにかく平文で表示したくなかったので、pythonで暗号化したパスワードをそのままプレイブックで貼っておいて使った。
それでうまく行ったので、当時は良かったと思うが、暗号化したい項目がどんどん増えていく。
pythonで暗号化したものでは対応できる場面が上記のケースだけに限られている。
だいぶバージョンが上がったからvariableを1項目だけ暗号化するのができるんでは？と思い検索したら〜

あった。

https://docs.ansible.com/ansible/latest/user_guide/playbooks_vault.html#single-encrypted-variable

Ansible 2.3以降からできるようになったそうだ。

## ansible-vaultのヘルプを確認

一々コマンドを叩いてヘルプを確認するのは面倒なので、記事に貼っておいた。
早速記事の本文を確認したい場合は、飛ばしてもらう。

* ansible-vault -h

```sh
ansible-vault -h
Usage: ansible-vault [create|decrypt|edit|encrypt|encrypt_string|rekey|view] [options] [vaultfile.yml]

encryption/decryption utility for Ansible data files

Options:
  --ask-vault-pass      ask for vault password
  -h, --help            show this help message and exit
  --new-vault-id=NEW_VAULT_ID
                        the new vault identity to use for rekey
  --new-vault-password-file=NEW_VAULT_PASSWORD_FILE
                        new vault password file for rekey
  --vault-id=VAULT_IDS  the vault identity to use
  --vault-password-file=VAULT_PASSWORD_FILES
                        vault password file
  -v, --verbose         verbose mode (-vvv for more, -vvvv to enable
                        connection debugging)
  --version             show program's version number and exit

 See 'ansible-vault <command> --help' for more information on a specific
command.
```

* ansible-vault encrypt_string --help

```sh
ansible-vault encrypt_string --help
Usage: ansible-vault encrypt_string [--prompt] [options] string_to_encrypt

encryption/decryption utility for Ansible data files

Options:
  --ask-vault-pass      ask for vault password
  --encrypt-vault-id=ENCRYPT_VAULT_ID
                        the vault id used to encrypt (required if more than
                        vault-id is provided)
  -h, --help            show this help message and exit
  -n ENCRYPT_STRING_NAMES, --name=ENCRYPT_STRING_NAMES
                        Specify the variable name
  --new-vault-id=NEW_VAULT_ID
                        the new vault identity to use for rekey
  --new-vault-password-file=NEW_VAULT_PASSWORD_FILE
                        new vault password file for rekey
  --output=OUTPUT_FILE  output file name for encrypt or decrypt; use - for
                        stdout
  -p, --prompt          Prompt for the string to encrypt
  --stdin-name=ENCRYPT_STRING_STDIN_NAME
                        Specify the variable name for stdin
  --vault-id=VAULT_IDS  the vault identity to use
  --vault-password-file=VAULT_PASSWORD_FILES
                        vault password file
  -v, --verbose         verbose mode (-vvv for more, -vvvv to enable
                        connection debugging)
  --version             show program's version number and exit

 See 'ansible-vault <command> --help' for more information on a specific
command.
```

--new-vault-idや--new-vault-password-fileなどのオプションがある。
ansible 2.4+から--vault-idを使えるようになって複数のvault-idとvault-passwrodが作られる。
これがなんの話なのかは後ほど分かるようになる。

## variableを1項目だけ暗号化する。

ansible-vaultのパスワードを指定しないまま使うと次のようなエラーが発生する。

```sh
TASK [Gathering Facts] ***********************************************************************************************************************************************
fatal: [redmine]: FAILED! => {"msg": "Attempting to decrypt but no vault secrets found"}
        to retry, use: --limit @/Users/devtopia/.ansible/retry-files/redmine.retry
```

パスワードを指定して使うと通るので、パスワードファイルを先に用意する。

```sh
# 復号化する為のパスワードをgit repositoryではない他のところに保存する。
echo 'PASSWORD' > ~/.vault_pass
```

ここではansible_passwordというvariableを暗号化する。
以前は、hosts.iniファイルに保存しておいて、.gitignoreに指定して使っていた。
ansible_userとansible_passwordをhosts.iniからgroups_var/all.ymlに移す。

```sh
# ansible_passwordというvariableを暗号化する。
echo -n 'PASSWORD' | ansible-vault encrypt_string --vault-id dev@~/.vault_pass --stdin-name 'ansible_password'

Reading plaintext input from stdin. (ctrl-d to end input)
ansible_password: !vault |
          $ANSIBLE_VAULT;1.2;AES256;dev
          38653564306332366561363062643632663834656465366430306139376163386535303539303034
          3335393633333538656534343631336238653063626135320a303834396534366235333030373464
          62336538663566653765646331666130323061373262646166613834343939323938333666303162
          3164303437306662630a646534643661323065373339363166366633363337396330323563656533
          3635
Encryption successful
```

* 'PASSWORD'のところに実際のパスワードを入力する。
* encrypt_stringというのが1項目だけ暗号化する為のサブコマンドである。
* --vault-idで「ラベル名@パスワードファイルのパス」
* --stdin-nameには暗号化したいvariable名（ここではansible_password）を入力する。

ansible-vaultで暗号化した場合、ansibleやansible-playbookのコマンドを実行するときは、
パスワードファイルをオプションで指定しなければならない。
冒頭でも話したが、エラーになる。

```sh
ansible-playbook dev.yml --vault-password-file ~/.vault_pass

# ansible 2.4+
ansible-playbook dev.yml --vault-id ~/.vault_pass
```

毎度「--vault-password-file ~/.vault_pass」を入力するのは面倒なので、
ANSIBLE_VAULT_PASSWORD_FILEという環境変数にパスワードファイルを設定して使う。

```sh
# 環境変数の設定ファイルに追加
vim ~/.bash_profile
... snip ...
export ANSIBLE_VAULT_PASSWORD_FILE = ~/.vault_pass
... snip ...

# 追加したものを適用するために再読込
source ~/.bash_profile

# --vault-idや--vault-password-fileなしで使える。
ansible-playbook dev.yml
```

__環境変数ではなくansible.cfgに記入する方法もあった。__

```sh
... snip ...
vault_password_file = ~/.vault_pass
```

環境変数を消して試したら、うまく行った。

続いて、他のvariableを暗号化しようとしたらエラーが発生した。

```sh
echo -n 'PASSWORD' | ansible-vault encrypt_string --vault-id dev@~/.vault_pass --stdin redmine_password
Usage: ansible-vault encrypt_string [--prompt] [options] string_to_encrypt
... snip ...
command.
ERROR! The vault-ids dev,default are available to encrypt. Specify the vault-id to encrypt with --encrypt-vault-id
```

vault-ids dev、defaultは暗号化に有効です。--encrypt-vault-idを使ってvault-idを指定してください。
言われた通り--encrypt-vault-idで試したら、またエラー

```sh
echo -n 'PASSWORD' | ansible-vault encrypt_string --encrypt-vault-id dev@~/.vault_pass --stdin redmine_password
ERROR! Did not find a match for --encrypt-vault-id=dev@~/.vault_pass in the known vault-ids ['default']
```

vault-idを探せない？先はdevとdefaultが有効だったのに、今はdefaultしかない。
パスワードファイルと一緒に書いたせいかなと思ってdevだけに変更してみたが、同じエラー

```sh
echo -n 'PASSWORD' | ansible-vault encrypt_string --encrypt-vault-id dev --stdin redmine_password
ERROR! Did not find a match for --encrypt-vault-id=dev in the known vault-ids ['default']
```

__ググってみたら、vault_identity_listという設定値もあった。__

```sh
... snip ...
vault_password_file = ~/.vault_pass
vault_identity_list = dev@~/.vault_pass
```

ansible.cfgに追加してもう一度実行したら〜
うまく行った。

```sh
echo -n 'PASSWORD' | ansible-vault encrypt_string --encrypt-vault-id dev --stdin redmine_password
Reading plaintext input from stdin. (ctrl-d to end input)
redmine_password: !vault |
          $ANSIBLE_VAULT;1.2;AES256;dev
          61643061336363643331323437643535356333633439303532646430636534646331373136323234
          3034373631396339306466373966643636353430303235320a646635336539646131343264306433
          65626333643864636639353833326462323166636434393539613663333365383134366635373337
          3866346238313866630a626135663230323462366661653434316361333636353530326231623437
          3736
Encryption successful
```

どうやら、--vault-idと--vault-password-fileはその用途が重なるらしい。
ググってみると「vault-id vs vault-password-file」が検索キーワードとして自動で引っかかる。
--vault-password-fileより機能が拡張されたのが--vault-idで、両方使えるけど--vault-idだけでも行ける。という意味だろう。

__ansible.cfgからvault_password_fileを消して試したら、うまく行った。__

ラベル名devが付いているのは多分vault_identity_listだけでも大丈夫。
vault_identity_listをansible.cfgに記入しないとdefaultだけになるみたい。

https://learn.redhat.com/t5/Automation-Management-Ansible/Vault-IDs-in-Ansible-2-4/td-p/1531

→これが参考になった。

## ファイル全体を暗号化する。

groups_var/db.ymlはデータベースのコネクション情報が書かれている。
ファイルを丸ごと暗号化しよう。

```sh
# 暗号化
ansible-vault create group_vars/db.yml

# 暗号化した後、ファイルの内容
cat group_vars/db.yml
$ANSIBLE_VAULT;1.1;AES256
65656533363866316462313831663032353031626239633333323862323132616239306130303162
3531363266336538376239646430656134363132633339320a636531653933636336306339636666
35373765653935636233353733323538333835316139373632633131326231653838303862346338
3963663332346263340a613932326665303631373932313364623232666535326235383836356336
34373536336139363865633336313762393761386234353830643835376639376662623636363864
37383136396436366231616130376636303039396236343266633930383230363635306332643136
64633865386636636135383363663065396637636435666635653737383061616635616532373865
64343165393335353231363539383635666562653936316264316330373438646564323161303066
34363735323534383461623933333965626634393863386661613030656237346361306336663733
37646531623432336262653030613461653262313831653365323536663034623439363562326365
30356662396231353737346565666230313934343034316333323533313066333130393064323162
31653434383939386164303838623633396665323530633738376262633232346337303661353261
31623463376665383637663466613137313539333366343231303431313434346564366665363062
3034303034653130666531343434346430653030393231373635

# 平文で編集可能
ansible-vault edit group_vars/db.yml --vault-password-file ~/.vault_password

# export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass した場合
ansible-vault edit group_vars/db.yml
```

## 参考

* https://docs.ansible.com/ansible/latest/user_guide/playbooks_vault.html#single-encrypted-variable
* https://qiita.com/yunano/items/86d3f9beb678adbff50d
* https://qiita.com/takuya599/items/2420fb286318c4279a02