HashiCorp Vault でGCPシークレットエンジンを試してみた

HashiCorp VaultのGCPシークレットエンジンを試してみたので導入方法とサービスアカウント作るところまでを備忘録としてメモ。

# TL;DR
- [Terraform module registry](https://github.com/hashicorp/vault-plugin-secrets-gcp)を使えばTerraformで一瞬でGCP上にVault環境が作成できる。
- GCP シークレットエンジンを使えばVault経由でコマンド一発で一時的なサービスアカウントを作成できる。




# 事前準備
VaultではCloud KMSを使用してシークレットを暗号化する。
シークレット保管方法について詳細は[こちら](https://cloud.google.com/kms/docs/store-secrets?hl=ja)を参照。

> 
シークレットを使用するユーザーとサービス、シークレットを管理するユーザーとサービスは、2 つのプロジェクトと 2 人のユーザーに分けて確実に職掌分散することをおすすめします。あるプロジェクトは Cloud KMS を使用して鍵を管理し、もう 1 つのプロジェクトは Cloud Storage バケットを使用してシークレットを保存します。

事前準備としてVault専用プロジェクト、サービスアカウントを作成しておく。


IAMサービス有効化

```
$ export GOOGLE_CLOUD_PROJECT='dkuji-vault'
     cloudresourcemanager.googleapis.com \
     iam.googleapis.com
```

サービスアカウント作成

```
$ gcloud iam service-accounts create vault-tester \
     --display-name vault-tester \
     --project "${GOOGLE_CLOUD_PROJECT}"
Created service account [vault-tester].
```

IAMポリシー適用

```
$ gcloud projects add-iam-policy-binding "${GOOGLE_CLOUD_PROJECT}" \
     --member "serviceAccount:vault-tester@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
     --role "roles/owner"

```

キー作成

```
$ gcloud iam service-accounts keys create credential.json \
    --iam-account "vault-tester@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com"
```

# TerraformでGCE、KMS、GCS、NAT、GCLBを作成
[こちら](https://github.com/hashicorp/vault-plugin-secrets-gcp)のTerraform module registryを使用し作成する。


```
module "vault" {
  source = "terraform-google-modules/vault/google"

  version     = "1.0.0"
  project_id  = "dkuji-vault"
  region      = "us-central1"
  kms_keyring = "vault"

  #kms_keyring          = "${var.kms_keyring}"
  kms_crypto_key     = "vault-init"
  vault_machine_type = "g1-small"
}

provider "google" {
  project     = "dkuji-vault"
  credentials = "${file("credential.json")}"
}
```


```
$ terraform  init

$ terraform apply
```

# Vaultサーバに接続
vaultアドレス、証明書を環境変数で指定。
アドレスはoutputから、証明書はterraform apply実行時にカレントディレクトリに作成されたものを指定。

```
$ export VAULT_ADDR="`terraform output --module=vault vault_addr`

$ export VAULT_CACERT="$(pwd)/ca.crt"
```

正常にvaultサーバに接続できることを確認。

```
$ vault status
Key                      Value
---                      -----
Recovery Seal Type       gcpckms
Initialized              false
Sealed                   true
Total Recovery Shares    0
Threshold                0
Unseal Progress          0/0
Unseal Nonce             n/a
Version                  n/a
HA Enabled               true
```

# アンシール

Vaultサーバを初期化。標準出力にトークンが出力されるので必ずメモしておく。
5つのリカバリキーを発行し、アンシールのしきい値を3で設定。

```
$ vault operator init \
     -recovery-shares 5 \
     -recovery-threshold 3

Recovery Key 1: **********
Recovery Key 2: **********
Recovery Key 3: **********
Recovery Key 4: **********
Recovery Key 5: **********

Initial Root Token: **********

Success! Vault is initialized

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

Vaultサーバにログイン。先程発行されたRootトークンを指定。

```
$ 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.
```

```
$ vault status
Key                      Value
---                      -----
Recovery Seal Type       shamir
Initialized              true
Sealed                   false
Total Recovery Shares    5
Threshold                3
Version                  1.0.3
Cluster Name             vault-cluster-4936f388
Cluster ID               b00b993f-4571-cc02-06da-31e24767d0e4
HA Enabled               true
HA Cluster               https://xx.xx.xx.xx:8201
HA Mode                  active
```

# GCPシークレットエンジンを有効化

```
$ vault secrets enable gcp

$ vault secrets list
Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_919d48c5    per-token private secret storage
gcp/          gcp          gcp_45cb8da8          n/a
identity/     identity     identity_b29994dd     identity store
secret/       kv           kv_ee02181a           key/value secret storage
sys/          system       system_08a62e9a       system endpoints used for control, policy and debugging
```

パス`gcp/config`に最初に作成したサービスアカウントキーを指定。このIAMアカウントを使用してこれ以降のアカウントが作成される。

```
$ vault write gcp/config credentials=@credential.json  
```

サービスアカウントを作成してみる。

```
$ vault write gcp/roleset/token-test \
  project="${GOOGLE_CLOUD_PROJECT}" \
  secret_type="access_token"  \
  token_scopes="https://www.googleapis.com/auth/cloud-platform" \
  bindings=-<<EOF
    resource "//cloudresourcemanager.googleapis.com/projects/${GOOGLE_CLOUD_PROJECT}" {
      roles = ["roles/viewer"]
    }
EOF



$ vault write gcp/roleset/key-test \
  project="${GOOGLE_CLOUD_PROJECT}" \
  secret_type="service_account_key"  \
  bindings=-<<EOF
    resource "//cloudresourcemanager.googleapis.com/projects/${GOOGLE_CLOUD_PROJECT}" {
      roles = ["roles/viewer"]
    }
EOF

```

WebコンソールからIAMを確認してみると、作成された。

<img width="1128" alt="screenshot 2019-06-02 22.20.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250010/f0aae6b6-7938-8d2e-33ec-936bafeb482c.png">
<img width="1124" alt="screenshot 2019-06-02 22.20.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250010/f1b79609-994f-258d-25d0-587bc3cd5588.png">


# サービスアカウントキーを作成

先程作成したアカウントをreadすると、サービスアカウントキー、トークンが作成される。
ちなみにこれで作成したアカウントは一時的なものであり、一定期間で自動的にクリーンアップされる。


```
$ vault read gcp/token/token-test
Key                   Value
---                   -----
expires_at_seconds    1559478504
token                 ***********************************************
token_ttl             59m59s


$ vault read gcp/key/key-test
Key                 Value
---                 -----
lease_id            gcp/key/key-test/ahigW7iLat8RDEmY9qtCDChe
lease_duration      767h59m59s
lease_renewable     true
key_algorithm       KEY_ALG_RSA_2048
key_type            TYPE_GOOGLE_CREDENTIALS_FILE
private_key_data    ***********************************************

```

# おわりに
VaultのGCPシークレットエンジンを使ってサービスアカウントを作成まで特に問題なくできた。
サービスアカウントは基本的にはTerraformで管理するが、検証等で一時的にしようするアカウントに限りVaultから作成して終わったらそのまま放置し自動的に破棄(Terraformでも管理しない)みたいな使い方になるのかなと思った。



# 参考
https://www.vaultproject.io/docs/secrets/gcp/index.html
https://github.com/hashicorp/vault-plugin-secrets-gcp