継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

Terraform で Secrets Manager に登録するレコードをコード内に直書きせず保存する

タダです.

プログラムで使うトークンや DB 接続情報,鍵情報といった秘匿情報を Secrets Manager に入れています.Secrets Manager に保管してる情報を Terraform で管理しようとした時コードで直書きし,GitHub などで管理するのはリスキーなので別の方法を探していた時に以下のブログを見つけ,参照しつつ試したことをこの記事にまとめていきます.

blog.gruntwork.io

ブログで紹介されていた秘匿情報の取り扱い方法

冒頭のブログで紹介されていた方法として以下の3つがあります.

  1. 変数にして外出しする
  2. ファイルを暗号化してバージョン管理する
  3. Secrets Manager や Hashicorp Vault などに格納する

一つ目は毎回任意のコマンドを打てる環境ならいいのですが,自動デプロイ を仕組んでいる場合にその運用コストが高そうだなと思ったのと,三つ目は現状やっていることでやりたいことに当たらなかったので,二つ目の手法を使ってアプローチを試みることにしました.

大まかな作業の流れ

二つ目の手法の大まかな流れとして,まず Secrets Manager で扱う情報群を YAML ファイルに書き出します.その後,YAML ファイルを KMS を使って暗号化し,そのファイルを Terraform のコードで復号化 -> パラメーターごとにマッピングするといった作業を行います.

秘匿情報を格納する YAML ファイルの作成

secrets.yaml というファイルを作成し,その中に Secrets Manager に格納したい キー:バリュー の順番で転記します.そして,secrets.yamlリポジトリで管理しないように .gitignore で除外しておきます.

hoge_token: hogehoge
dbhost: hoge.cluster-xxxx.ap-northeast-1.rds.amazonaws.com
dbhost_replica: hogecluster-ro-xxxx.ap-northeast-1.rds.amazonaws.com
dbname: hogedb
password: hogehoge
username: hoge

KMS での暗号化処理

次に,KMS で secrets.yaml を暗号化します.AWS CLI で次のようなコマンドを実行して secrets.yaml.encrypted が生成されることを確認します.また,このファイルはリポジトリで管理するようにします.

aws kms encrypt \
  --key-id xxxx-xxxx-xxxx-xxxx-xxxx(個別に発行した CMK) \
  --region ap-northeast-1 \
  --plaintext fileb://secrets.yaml \
  --output text \
  --query CiphertextBlob \
  > secrets.yaml.encrypted

なお,生成された secrets.yaml.encrypted の中身は見てもらうとわかりますが,全然何が書いているか当然わからないようになっています.

Terraform での復号化と秘匿情報のマッピング

secrets.yaml.encrypted の生成が終わったら Terraform のコードを書いていきます.復号化の処理は data.aws_kms_secretsyamldecode(data.aws_kms_secrets.secrets.plaintext["secrets"]) で行います. hoge_secrets の中に復号化した秘匿情報が入っているのですが,そのデータを aws_secretsmanager_secret_versionsecret_stringマッピングしていきます.local.hoge_secrets.[YAML ファイルで定義したキー] といった具合です.

コード例

data "aws_kms_secrets" "secrets" {
    secret {
        name = "secrets"
        payload = file("./secrets.yaml.encrypted")
    }
}

resource "aws_secretsmanager_secret" "hoge_secrets" {
    name = "hoge-secrets"
    recovery_window_in_days = 30
}

locals {
    hoge_secrets = yamldecode(data.aws_kms_secrets.secrets.plaintext["secrets"])
}


resource "aws_secretsmanager_secret_version" "hoge_secrets_detail" {
    secret_id = aws_secretsmanager_secret.hoge_secrets.id
    version_stages = ["AWSCURRENT"]
    secret_string = jsonencode({
        username = local.hoge_secrets.username
        password = local.hoge_secrets.password
        dbhost = local.hoge_secrets.dbhost
        dbname  = local.hoge_secrets.dbname
        dbhost_replica = local.hoge_secrets.dbhost_replica
        hoge_token = local.hoge_secrets.hoge_token
    })
}

関連情報

Terraform の適用と結果確認

Terraform の適用と結果確認していきます.secret_stringの中身は(sensitive value)という形で見えないようになっているので,どの秘匿情報を Secrets Manager に保存しようとしているかはわからないです.

Terraform will perform the following actions:

  # aws_secretsmanager_secret.hoge_secrets will be created
  + resource "aws_secretsmanager_secret" "hoge_secrets" {
      + arn                     = (known after apply)
      + id                      = (known after apply)
      + name                    = "hoge-secrets"
      + name_prefix             = (known after apply)
      + policy                  = (known after apply)
      + recovery_window_in_days = 30
      + rotation_enabled        = (known after apply)
      + rotation_lambda_arn     = (known after apply)
      + tags_all                = (known after apply)

      + rotation_rules {
          + automatically_after_days = (known after apply)
        }
    }

  # aws_secretsmanager_secret_version.hoge_secrets_detail will be created
  + resource "aws_secretsmanager_secret_version" "hoge_secrets_detail" {
      + arn            = (known after apply)
      + id             = (known after apply)
      + secret_id      = (known after apply)
      + secret_string  = (sensitive value)
      + version_id     = (known after apply)
      + version_stages = [
          + "AWSCURRENT",
        ]
    }

適用の結果を見ると,意図通りの設定値が入っていました.

f:id:sadayoshi_tada:20210828175644p:plain f:id:sadayoshi_tada:20210828175651p:plain

まとめ

Secrets Manager にいれる秘匿情報を Terraform で管理する時どうするかを悩んでいたので,冒頭のブログを参考に KMS を使いつつ試してみました.Terraform のコードに秘匿情報は載らないし,暗号化して管理できかつTerraform の適用時にも秘匿情報がターミナル上にも出てこないため運用上も良さそうに思います.何か参考になれば嬉しいです!