Open8

ECS タスク定義に設定する環境変数をTerraformで楽に管理するには

職人職人

前提

  • 今回はTerraform Cloudを使用する
  • ECS上ではバックエンド(Railsとか)、フロントエンド(ReactとかNext.jsとか)のサービスを分ける
  • AWSのパラメータストアを使って、環境変数を設定する
  • バックエンド、フロントエンドで使用する環境変数はそれぞれ別々に管理したい
  • DBのパスワードなどの秘匿情報はTerraform(tfstate)に含まれないようにする

Terraformのディレクトリ構成

https://tech.smartcamp.co.jp/entry/easy-terraform-later
に大体準拠して書く(おにまるさんに感謝)

職人職人

環境変数の種類って何があったっけ?

  • バックエンドのアプリに必要な環境変数
    • 基本的なもの
      • RailsならRAILS_ENVとか、SECRET_KEY_BASEとか
    • DBへの接続に必要な情報
      • ホスト名とかパスワードとか
    • その他各種サービスに連携するための必要なAPIキー
  • フロントのアプリに必要な環境変数
    • バックエンドと接続するためのエンドポイントURLとかとか

一番気にしたいのは

  • DBへの接続に必要な情報
    • ホスト名とかパスワードとか
職人職人

実行環境でも状況が変わりそう

CLI経由

  • tfstateに秘匿情報が残ってしまうのは辛い
  • そもそも複数人での開発でtfstateをコミットしてしまうと、コンフリクトが多発しそうで辛そう

Terraform Cloud経由

  • Terraform Cloudにログインできないと、tfstateは見れないので神経質になって気にするほどではないかもしれない(Terraformアカウントが何らかの仕組みで制限できている前提)
職人職人

秘匿情報を管理するベストプラクティス

こちらのスライドにある通りなんじゃなかろうかと思ってる
https://speakerdeck.com/harukasakihara/sekiyuanaterraformfalseshi-ifang-ji-mi-qing-bao-wokodonihan-mezuhuan-jing-gou-zhu-surunihadousitaraiifalse?slide=74

要約

  • Terraformのコード上はダミー値でRDSのパスワードをパラメータストアに設定する
  • Secrets ManagerでRDSのパスワードを管理する
  • Lambdaで新しいパスワードを生成し、Secrets Managerの値を更新する
  • Lambdaで新しいパスワードをRDSに設定する

このLambdaに関しては
https://github.com/aws-samples/aws-secrets-manager-rotation-lambdas
にテンプレートが公開されているので、参考にすると良さそう

パラメータストアを使用している場合はこのLambdaの中でパラメータストアの値も更新するようにすると良さそう

職人職人

んで結局、何悩んでたんだっけ

環境変数が多くて、どう一元管理しようか

resource "aws_ssm_parameter" "database_password" {
  name        = "/rds/DATABASE_PASSWORD"
  description = "RDS password"
  type        = "SecureString"
  value       = random_password.database_password.result

  lifecycle {
    ignore_changes = [
      value
    ]
  }
}

こういうのが、RDSのmoduleとかECSのサービスごとのmoduleとかに散らばると、何の環境変数があるのか管理するのが辛い・・・

環境毎のlocals.tfにまとめて書いて、for_eachで一気に作るか・・・

だがしかしignore_changesしとかないと、パラメータストアの値が変更されたときに、差分が出てしまう

しかも今回はサービスが2つ、バックエンド、フロントエンドの環境変数がそれぞれ存在することになる

もっと楽に管理できないものか

職人職人

前述のスライドの本日のまとめの最終行の気になる一言

ローテーションを想定していない機密情報をSecrets ManagersやSSMにセットする作業は、そもそもIaC化するメリットも薄いため、手動やCLIを用いたスクリプトでやるのが望ましいです。

た、たしかに・・・

既に今悩んでいる時点で、Terraformで管理するのがあんまりよろしくないんじゃないかと思った

CLIで作ったほうが楽そうな予感

職人職人

CLIで実装すると考えなきゃいけないこと

  • まずAWS CLIをどこで実行するのか
    • CloudShellとかローカルPCとか?実行できる人を絞らなきゃいけなさそう
  • ステージング、本番環境ごとに異なる環境変数をどう保持しておくか
    • JSON?yaml?
    • ファイルごと分けるのか、それとも一つのファイルにしてキーを分けるか

それなりに考えることは多そう