[その4] HashiCorp Vault Secrets で マルチプロバイダー下での統合シークレット管理について

## これは何？
Vault Secrets + Terraform Cloud でシークレット管理してみました。

## Vault Secrets とは?
[Vault Secrets](https://developer.hashicorp.com/hcp/docs/vault-secrets) とは、マルチプロバイダーにおけるシークレットを統合管理する機能になります。
以下の画像のように複数のプロバイダーをVault Secretsで統合的に管理することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/2099e46b-7fd5-fdb9-0f2a-9c3579096955.png)

また、登録するシークレットの種類として、
- パスワード
- API トークン
- アクセスキー

が挙げられます。

## AWS + Vault でシークレット同期
最初にHashicorp Cloud からVault Secretsアプリケーションを作成します。
[Create new app]からアプリケーションを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/c7ab70bb-9a0b-ff3b-d2b8-bcafe63abd9a.png)

アプリケーション作成後、Integrationsタブを押下し、シークレットを同期したいプロバイダーを指定します。今回はVault -> AWSへシークレットを同期したいのでAWS を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/daa2dd76-d429-2779-6889-4824a7656b48.png)

その後、インテグレーションの詳細を設定します。ExternalIDが記載されているのでこちらの値をコピーします。
また、シークレット同期のため、[AWS Secrets Manager](https://aws.amazon.com/jp/secrets-manager/)の書き込み権限を持っているIAMロールのArnを指定します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/f32b8227-bddd-8549-fabb-dd062e745f17.png)

次に、上記で設定したRole Arnで設定したIAMロールを設定します。

https://developer.hashicorp.com/hcp/docs/vault-secrets/integrations/aws-secrets-manager

上記でコピーしたExternalIDをAWS_EXTERNAL_IDに代入してIAMロールを作成します。
以下の内容はIAMロールの信頼関係になります。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::879554817125:role/HCPVaultSecrets_Sync"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "sts:ExternalId": "<AWS_EXTERNAL_ID>"
                }
            }
        }
    ]
}

```

こちらの方は、ポリシーになります。IAMロールの下に以下のようなインラインポリシーを作成します。
```json
{
   "Version": "2012-10-17",
   "Statement": [
      {
            "Sid": "HCPVaultSecretsAccess",
            "Effect": "Allow",
            "Action": [
               "secretsmanager:DescribeSecret",
               "secretsmanager:GetSecretValue",
               "secretsmanager:CreateSecret",
               "secretsmanager:PutSecretValue",
               "secretsmanager:UpdateSecret",
               "secretsmanager:UpdateSecretVersionStage",
               "secretsmanager:DeleteSecret",
               "secretsmanager:RestoreSecret",
               "secretsmanager:TagResource",
               "secretsmanager:UntagResource"
            ],
            "Resource": "*"
      }
   ]
}

```
以上で下準備が完了しました。

最後に、Vault Secrets で作成したアプリケーション内でシークレットを登録していきます。
以下はRDSを作成する際のDBユーザー/パスワードを登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/9bcec04c-fbc1-e073-4e0d-9af75631ebf3.png)

上記で登録した結果、AWS Screts Managerコンソールにアクセスします。
その結果`<Vault Application Name>/<シークレットキー>`としてシークレットが登録されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/61d6a221-e18d-f44b-54f6-71cb826b0d2a.png)

シークレットの中身も確認することができます。但し内容としては
- ローテーションなし
- KMSキー暗号化なし
のデフォルトの設定になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/64a610b2-ece3-9bb8-bc9b-b61542d0d2f5.png)


注意して欲しい点として、このシークレットですが、Secrets Manager上でローテーションなどで値が変更された場合、 **Secrets Manager → Vault Secrets に同期されない**という注意書きがあります。

> このシークレットはサードパーティのサービスプロバイダー (HCP Vault Secrets) によって管理されています。
AWS Secrets Manager で直接行われた変更は、HCP Vault Secrets と同期されません。このシークレットの管理の詳細については、HCP Vault Secrets ドキュメントを参照してください。
詳細は[こちら](https://developer.hashicorp.com/hcp/docs/vault-secrets/integrations/aws-secrets-manager)

そのため、ローテーションなしで複数プロバイダーのシークレットを管理する目的であるならVault Secrets を利用できるということになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/dd1c4152-3b9b-23e1-6fdf-16d32abd6b20.png)


## Vault Secrets + HCP Terraform とシークレット同期
次にVault Secrets + HCP Terraform でシークレットの同期を実施します。

イメージとしては以下の通りです。
Vault Secretsで登録したシークレット情報をTerraform Cloud上のWorkspace Variablesとして同期します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/02c5abc4-6499-eafb-733f-e929da512547.png)


まず初めにVault がTerraform Cloudへのアクセスを許可するためのトークンを生成します、
Terraform Cloud を開き API トークンを作成します。Teamの管理は[Standard Edition](https://www.hashicorp.com/products/terraform/pricing?ajs_aid=38275c4d-4896-493e-b0d9-9cf3b28ca0d2&product_intent=terraform)以降で利用可能なのでFree Planでは、ownersチームのteam tokenを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/36964811-0dda-df2d-48a4-60e86145961d.png)

アプリケーション作成後、Integrationsタブを押下し、シークレットを同期したいプロバイダーを指定します。今回はVault -> HCP Terraformへシークレットを同期したいのでHCP Terraformを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/daa2dd76-d429-2779-6889-4824a7656b48.png)

次にインテグレーションの詳細を設定します。
先ほど作成したトークンをメモして、インテグレーション設定を実施します。
以下のように同期したいワークスペースを選択し、変数の種類についても以下のように選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/f9bb873e-9af7-c770-abd5-157958b62042.png)

これでインテグレーションの設定が完了しました。

動作確認としてシークレットを登録してみましょう。
以下のようにVault Secrets上のAppからシークレットを登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/cb1b8abf-6ed9-5bec-4f5c-22396caae651.png)


Terraform Cloud についてワークスペース内のworkspace変数を確認します。
その結果、Vault Secrets で作成したパスワードがsensitive variableとして登録されていることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/9c707745-824a-a4b7-cbfb-18505f800dd9.png)


## 実践 RDS作成
Vault Secretsに登録したシークレットをHCP Terraform のWorkspace変数に同期し、その値を参照してインスタンスを作成します。
今回はRDSのDBユーザー/パスワードをシークレットとして登録しますします。

### Vault Secrets 登録

今回はRDSを作成するとうい想定で、DBユーザー/パスワード名などのシークレットの管理をGit上で管理することなく実施したいと思います。
まず、Vault Secrets 上にDBユーザー名`rds_username`とDBパスワード`rds_password`に登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/d6508d9a-7679-eeef-b4c3-10b807ec8d03.png)

登録後、Terraform Cloud に切り替えVaultで登録したシークレットがワークスペース変数として定義されていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/7fa08ac5-fcad-2061-ab5d-5f056460c454.png)


###  Terraform ワークスペース作成
以前実施した[手順](https://qiita.com/atw0_0w/items/58812c0baf1a0000b757#%E4%BD%9C%E6%A5%AD%E6%89%8B%E9%A0%86)を基にTerraform Workspaceを作成します。
ワーキングディレクトリについては、03_vault_secretsを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/e4d240a1-cd73-35ce-ed3f-55db3ac0eb18.png)


Terraform ワークスペースと紐づけるリポジトリは、[こちら](https://github.com/atsw0q0/test-terraform-cloud/tree/main/03_vault_secrets)のように、Vault Secretsを参照するようにします。

https://github.com/atsw0q0/test-terraform-cloud/tree/main/03_vault_secrets

```hcl:variables.tf
variable "rds_password" {
  type = string
}

variable "rds_username" {
  type = string
}
```

```hcl:main.tf
module "rds-mysql" {
  source  = "app.terraform.io/atsuw0w-test-terraform/webapp-templates/aws//modules/rds_instance"
  version = "1.0.0"

  pj_tags = var.pj_tags

  rds = {
    prefix           = "app"
    subnet_group_ids = [for k, v in module.network-templates.subnet_pri_ids : v] #["subnet-xxx", "subnet-yyy"]

    security_group_ids    = [module.mariadb-sg.sg_id]
    rds_instance_class    = "db.t4g.micro"
    rds_allocated_storage = 20
    db_engine             = "mysql"
    db_engine_version     = "8.0"
    db_name               = "fuga"
    db_username           = var.rds_username
    db_password           = var.rds_password
    az                    = "a"
    is_multi_az           = false
    is_ops                = false
  }
}

```

上記のように登録しプルリクエストを投げると、以下のようにPlanが実行されMergeするとApplyが実行されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/039b7bfe-df26-6a67-24b8-1d1864500840.png)

これでVault Secrets + HCP Terraform でシークレットを管理しつつリソースを構築することができました。