Google Cloud Platform の Secret Manager で Ansible Vault のパスワードを管理する

この記事は [Opt Technologies Advent Calendar 2019](https://qiita.com/advent-calendar/2019/opt-technologies) 14日目の記事です。
もう年も明けてしまい1月ですが埋まっていなかったので仕方ないですね………

Google Cloud Platform の [Secret Manager](https://cloud.google.com/secret-manager/docs/) から Ansible Vault のパスワードを取得してプロビジョニングできるようにするというタイトルそのままの記事です。

Ansible の実行環境の準備などは省略します。

## シークレットの操作

### 登録

```bash
echo -n '!!!!amesome-password!!!!' | \
gcloud beta secrets create vault-password --replication-policy=automatic --data-file=-
```

`vault-password` という名前で `!!!!amesome-password!!!!` というシークレットを登録しています。

`--replication-policy` はシークレットを保存するロケーションを指定したい場合には `user-managed` を指定するようですが、ここでは `automatic` で進めます。

また、 `--data-file` に `-` を指定すると標準入力から値を読んでくれます。
もちろんパスを指定するとファイルから読むことも可能です。

作成に成功すると以下のようなメッセージが出力されます。

```
Created version [1] of the secret [vault-password].
```

### 追加

```bash
echo -n '!!!!amesome-password2!!!!' | \
gcloud beta secrets versions add vault-password --data-file=-
```

バージョンを追加した場合は以下のように出力されるメッセージのバージョンが表示されます。

```
Created version [2] of the secret [vault-password].
```

### 取得

```bash
gcloud beta secret versions access 1 --secret=vault-password
```

上記のコマンドで登録したシークレットを取得できます。

数字部分がシークレットのバージョンなので、適宜変更します。

### その他の操作

バージョンの無効化や削除なども行えますが、今回は必要ないため割愛します。
[ドキュメント](https://cloud.google.com/secret-manager/docs/how-to-use-secret-manager-api?hl=ja#disabling_a_version)を参照してください。

## Ansible Vault

簡易的な Playbook を作成し、復号できることを確かめていきます

### ディレクトリ構成

```
.
├── get_secret.sh
├── roles
│   └── vault_test
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
└── site.yml
```

各ファイルに関して説明していきます。

### シークレット取得用シェルスクリプト

1行だけですが、シークレットを取得するためにシェルスクリプトを用意しておきます。

```bash:get_secret.sh
#!/usr/bin/env bash

gcloud beta secrets versions access 1 --secret=ansible-vault
```

### 暗号化

```bash
echo -n '????sugoi-password????' | \
ansible-vault encrypt_string --vault-password-file ./get_secret.sh
```

適当に `????sugoi-password????` という文字列を暗号化します。
`--vault-password-file` のオプションに上記のシェルスクリプトを指定することでシークレットを取得して Ansible Vault に渡してくれます。

出力を Ansible の変数としてファイルに記載します。

```Yaml:roles/vault_test/defaults/main.yml
---
encrypted_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  66666632656539663339343130393330663134653637376131343866666530336539346136623537
  3830663634343331663638613636646231326663643636350a616164333363356161383232656662
  35623932333333303537306530633537323366356639313431366161653966383736373835613936
  6130633838363930370a353163643561363331303632613438316562653365363566306139303839
  64623233386565643266623464306338626262353235316266336337393664323931
```

### 復号

変数を出力するだけのタスクを作成して問題なく復号できることを確かめます。

```Yaml:roles/vault_test/tasks/main.yml
---
- name: echo encrypted_password
  debug:
    var: encrypted_password
```

```Yaml:site.yml
---
- hosts: localhost
  roles:
    - vault_test
```

これで準備ができたので Playbook を実行します。

```bash
ansible-playbook site.yml --vault-password-file ./get_secret.sh
```

実行すると以下のように出力され、復号された `????sugoi-password????` が表示されています。

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

TASK [Gathering Facts] *************************************************************************************************************************************************************
ok: [localhost]

TASK [vault_test : echo encrypted_password] ****************************************************************************************************************************************
ok: [localhost] => {
    "encrypted_password": "????sugoi-password????"
}

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

問題なく復号できることがわかりました。

Google Cloud Platform でこのようなシークレット管理ができるようになっていたので、Ansible Vault 自体のパスワード管理問題もあり試してみました。
Vault のパスワードは README に書いてあるなどは本末転倒なので…。

今までは HashiCorp Vault を使えなどと GCP は言っていた気がしますが、準備するのも少し面倒なので手っ取り早く使えて良いのではないかと思います。

## おまけ

以下のように記載しておけば、Playbook の実行時に毎回 `--vault-password-file` を付ける必要がなくなります。

```ansible.cfg
[defaults]
vault_password_file=./get_secret.sh
```