Hashicorp Vault 1.0で追加されるauto-unsealを試してみた

# はじめに

[Ateam Lifestyle x cyma Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ateam-lifestyle-cyma) の3日目は [株式会社エイチームライフスタイル](http://life.a-tm.co.jp/) 技術開発部 / 名古屋開発部 部長 の @tsutorm が担当します！

**エンジニアマネージャーとして学んできたこと** とか書こうかなーと思ってたんですが、@ihsiek からマイナーネタ好きを振られたので、マイナーネタでお送りします！！！

# お品書き

- Hashicorp Vault 1.0.0で搭載されるauto-unsealを試す
- AWS KMSをつかうよ

## Hashicorp Vaultとは

詳しい説明は以下におまかせしますが、簡単にいうと秘密管理/データ暗号化サーバーです。

- [Hashicorp Vault (オフィシャル)](https://www.hashicorp.com/products/vault/)
- [Vault を使ってチーム内のセンシティブな情報を安全に管理する](https://qiita.com/munisystem/items/5fe1eead92b946bc5946)
- [やわらかVault](https://tech.pepabo.com/2018/09/06/vault-workshop/)
- [HashiCorp Vaultを機密情報データベースとして検証する](https://qiita.com/chroju/items/5f982bafecd3a1c36a9b)

`Response Wrapping` など、より安全性を高める仕組みが搭載されており、同社の 構成管理ツール [Terraform](https://www.terraform.io/) や サービスメッシュの[Consul](https://www.consul.io/)と組み合わせて利用することで、アプリケーションの秘密情報を安全に管理することができるスグレモノです。

- [Vault: CubbyholeとResponse Wrapping](https://qiita.com/tkusumi/items/04a99d21dea0a0365239)

大きな特徴として、[シャミアの秘密分散法](http://tattsun.hateblo.jp/entry/2018/07/18/205609) というアルゴリズムを用いてVault内部で利用する秘密鍵を複数の鍵に分散して管理しておくことで、マスターキー管理における安全性を高めています。

そのため、サーバー起動時は `Seal(封印)` 状態になっており、分散した鍵情報を一定閾値数入力しなければ `Unseal(封印解除)` せず、サービスを利用することはできません。

~~核ミサイル発射スイッチの解除みたいで、中二病満載な感じしませんか？こういうの大好きです。~~
 
反面、予期しないサーバーダウンなど発生した場合、プロセス自動起動は用意したものの、`Seal`状態の解除が出来ず、サービス利用に問題がでる懸念があります。

Vault 0.x 系においては Enterprise Edition で 自動的にunsealを行う `auto-unseal` 機能がありましたが、Opensource Editionでは提供されておりませんでした。

しかし、Vault 1.0 からは Opensource版でもこの `auto-unseal` が利用できるとのこと。

早速試してみましょう！！

## 手順の概要

- AWS KMS側の設定を行い、KMSとそれを利用するためのIAMをセットアップします。
- Hashicorp Vault 1.0.0-beta2 側に `awskms seal` 設定を追加します。
- Vaultを初期化してKMS経由でのauto-unsealができることを確認します。

## 免責

- もうすぐVault 1.0が出るっぽいのでほぼ仕様変わらないと思いますが、変わった際の本コンテンツの連動はベストエフォートです
- ハンズオンなどで色々お試しする際は、tokenやkeyの情報をうっかりgithubに上げないように。

### 準備

公式のデモ/ハンズオンでは `terraform` を使ってガッと作ってしまいますが、どうも中身がわからないと気持ち悪いので、私の方でdocker/docker-composeベースのもう少し簡単なお試し環境を用意しました。

```shell
$ git pull https://github.com/tsutorm/demo-vault_auto_unseal.git
$ cd demo-vault_auto_unseal
```

`docker-compose up`でvaultサーバーが立ち上がります。`./scripts/attach_vault.sh` でアタッチして、`vault status` などのコマンドをお試しできます。

基本的には公式の以下ドキュメントに準拠しています。

- [Auto-unseal using AWS KMS](https://learn.hashicorp.com/vault/operations/ops-autounseal-aws-kms)
- [Configration > Seal > awskms Seal](https://www.vaultproject.io/docs/configuration/seal/awskms.html) 

**AWSを利用しますので、アカウント無い方は適当に作っておいてください。**

### IAMの作成とアクセスキーの振り出し

IAMで適当なユーザーを追加しておきます。
![Screenshot 2018-12-02 at 13.36.22.png](https://qiita-image-store.s3.amazonaws.com/0/76630/72dd707f-5c84-e145-0a2c-845dc4bf6cfd.png)

ポリシーは`kms:Encrypt`, `kms:Decrypt`, `kms:DescribeKey` の 3つのみで良いので、以下で作成して、アタッチしておきます。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        }
    ]
}
``` 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/76630/33399edd-a4d0-a614-09f0-46f3d6592ef6.png)

アクセスキーとシークレットキーを控えておきましょう。

### KMSの有効化

KMSコンソールで CreateKey を実施します
![Screenshot 2018-12-02 at 13.50.40.png](https://qiita-image-store.s3.amazonaws.com/0/76630/ba089df4-1e29-560b-3b04-35fdd38f99a9.png)

`Define key administrative permissions` は追加したIAMではなく、管理者のIAMを選択しておきます。概ね、ご自身のIAMを登録しておけばよいです。
`Define key usage permissions` では先程追加したIAMを選択してください。
ま、適当にnextしちゃってください。大丈夫。

こんな感じでKeyIDが発行されます。
*(以下 key-id は記事公開のタイミングで削除してあります)*
![Screenshot 2018-12-02 at 13.55.14.png](https://qiita-image-store.s3.amazonaws.com/0/76630/94f2423d-b36c-7a57-4958-59d16a9cc15f.png)

### demo.hclを編集してauto-unsealの設定を追加

以下を `demo.hcl` へ追加して、auto-unsealできるようにします。
今回はデモなんでvpc endpointは使ってませんが、本運用ではendpointを指定するようにしてください。

```
seal "awskms" {
  region     = "ap-northeast-1"
  access_key = "{発行したIAMのAccessKey}"
  secret_key = "{発行したIAMのSecretKey}"
  kms_key_id = "642b1b91-d1bc-45ca-a7cb-10da40b51b23"
  endpoint   = ""
}
```

## `vault operator init` を実行してKMS経由で鍵を発行する

では早速vaultを起動してみましょう。

```shell
$ docker-compose up
Creating network "demo-vault_auto_unseal_default" with the default driver
Creating demo-vault_auto_unseal_vault_1 ... done
Attaching to demo-vault_auto_unseal_vault_1
vault_1  | Couldn't start vault with IPC_LOCK. Disabling IPC_LOCK, please use --privileged or --cap-add IPC_LOCK
vault_1  | ==> Vault server configuration:
vault_1  | 
vault_1  |            AWS KMS KeyID: 642b1b91-d1bc-45ca-a7cb-10da40b51b23
vault_1  |           AWS KMS Region: ap-northeast-1
vault_1  |                Seal Type: awskms
```
`Seal Type`が`awskms`に変わってますね。

`vault operator init` してみましょう。KMSで管理する都合、鍵は分散させず1本となります。引数に`-stored-shares=1 -recovery-shares=1 -recovery-threshold=1 -key-shares=1 -key-threshold=1` とあるので、追加忘れにご注意ください。
*tokenは*****としてあります。*

```shell
# vault operator init -stored-shares=1 -recovery-shares=1 -recovery-threshold=1 -key-shares=1 -key-threshold=1
Recovery Key 1: *****

Initial Root Token: *****

Success! Vault is initialized

Recovery key initialized with 1 key shares and a key threshold of 1. Please
securely distribute the key shares printed above.
```

`vault status`すると...

```shell
# vault status
Key                      Value
---                      -----
Recovery Seal Type       shamir
Initialized              true
Sealed                   false
Total Recovery Shares    1
Threshold                1
Version                  1.0.0-beta2
Cluster Name             vault-cluster-ce6d42aa
Cluster ID               a4231c7f-9601-e404-814e-5947da0a8ce9
HA Enabled               false
```
むむ!!! `Recovery Seal Type`が`shamir`に戻っている...んですが、気にしないでください。これで大丈夫。

この時点で Valutサーバーを再起動します。

```shell
$ docker-compose up
Starting demo-vault_auto_unseal_vault_1 ... done
Attaching to demo-vault_auto_unseal_vault_1
vault_1  | Couldn't start vault with IPC_LOCK. Disabling IPC_LOCK, please use --privileged or --cap-add IPC_LOCK
vault_1  | ==> Vault server configuration:
vault_1  | 
vault_1  |            AWS KMS KeyID: 642b1b91-d1bc-45ca-a7cb-10da40b51b23
vault_1  |           AWS KMS Region: ap-northeast-1
vault_1  |                Seal Type: awskms
vault_1  |                      Cgo: disabled
vault_1  |               Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: $
33554432", tls: "disabled")
vault_1  |                Log Level: (not set)
vault_1  |                    Mlock: supported: true, enabled: false
vault_1  |                  Storage: file
vault_1  |                  Version: Vault v1.0.0-beta2
vault_1  |              Version Sha: 8f61c4953620801477ad40f9d75063659acb5d84
vault_1  | 
vault_1  | ==> Vault server started! Log data will stream in below:
vault_1  | 
vault_1  | 2018-12-02T05:16:32.956Z [WARN]  no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set
vault_1  | 2018-12-02T05:16:32.958Z [INFO]  core: stored unseal keys supported, attempting fetch
vault_1  | 2018-12-02T05:16:33.099Z [INFO]  core: vault is unsealed
vault_1  | 2018-12-02T05:16:33.099Z [INFO]  core: post-unseal setup starting
vault_1  | 2018-12-02T05:16:33.099Z [INFO]  core: loaded wrapping token key
vault_1  | 2018-12-02T05:16:33.099Z [INFO]  core: successfully setup plugin catalog: plugin-directory=
vault_1  | 2018-12-02T05:16:33.100Z [INFO]  core: successfully mounted backend: type=kv path=secret/
vault_1  | 2018-12-02T05:16:33.101Z [INFO]  core: successfully mounted backend: type=system path=sys/
vault_1  | 2018-12-02T05:16:33.101Z [INFO]  core: successfully mounted backend: type=identity path=identity/
vault_1  | 2018-12-02T05:16:33.101Z [INFO]  core: successfully mounted backend: type=cubbyhole path=cubbyhole/
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  core: successfully enabled credential backend: type=token path=token/
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  core: restoring leases
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  rollback: starting rollback manager
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  identity: entities restored
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  expiration: lease restore complete
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  identity: groups restored
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  core: post-unseal setup complete
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  core: starting listener: listener_address=127.0.0.1:8201
vault_1  | 2018-12-02T05:16:33.104Z [INFO]  core: serving cluster requests: cluster_listen_address=127.0.0.1:8201
vault_1  | 2018-12-02T05:16:33.103Z [INFO]  core: successfully unsealed with stored key(s): stored_keys_used=1
```

`successfully unsealed` ってなってますね!! 試しに `vault status` を見てみましょう。

```shell
# vault status
Key                      Value
---                      -----
Recovery Seal Type       shamir
Initialized              true
Sealed                   false
Total Recovery Shares    1
Threshold                1
Version                  1.0.0-beta2
Cluster Name             vault-cluster-bedd5d4f
Cluster ID               df5a9ba2-511b-e0f1-cbe3-0724ec33c455
HA Enabled               false
```

`Sealed false` でちゃんと auto-unseal が成功しています。`login`も試してみましょう。

```shell
/ # vault login
Token (will be hidden): 
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                *****
token_accessor       3q5pBW2RPR8rcoEyIkHGtvqa
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]
```

大丈夫ですね。

## まとめ

- Vault 1.0.0-beta2とAWS KMSを使った`auto-unseal`はOSS版でも簡単にできました。
- Seal-Keyのローテーションなどもできそうなので、よりVaultサーバーを安全に可用性も担保しながら使えそう。

# おわりに

エイチームライフスタイルでは、[ナビクル](https://www.navikuru.jp/) などのWebサービス運営を行っています。これらのサービスでは個人情報などの機密情報を取り扱っており、セキュリティの担保はサービス運営で重要な要素となっています。

今回取り上げたVaultは機能が豊富な反面、マネージドサービスではない事、自分で可用性担保などの構成の面倒を見ないといけないところ、そもそもそんな高度な暗号化機構が必要なの？というところから、[Redditでも議論(Hashicorp Vault vs KMS)](https://www.reddit.com/r/googlecloud/comments/8jvqkm/hashicorp_vault_vs_kms/) になっています。

しかし、使ってみて**自分たちがどう評価するか。** が大事ではないでしょうか。
今後も色々挑戦して行きたいと思います！

---

[Ateam Lifestyle x cyma Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ateam-lifestyle-cyma) の4日目は、@matsu06 がお送りします！！どんなネタを用意してくるのか楽しみです！！

---

そんな"挑戦"を大事にするエイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
https://www.a-tm.co.jp/recruit/