Terraformとシークレット管理の深淵:ハードコードを撲滅し、Stateの「汚染」を極限まで防ぐアーキテクチャ
IaCの世界において、シークレットの扱いは「最後の聖域」だ。多くのエンジニアが `tfvars` を暗号化してGitに投げ込むという初歩的な罠に足を取られる中、我々は「Stateファイルという名の時限爆弾」をいかに解体するかを考えなければならない。
今日は、TerraformとAWS Secrets Manager / SSM Parameter Storeを統合し、「運用担当者の目にも、Stateファイルにも、CIのログにも、生のシークレットを一切触れさせない」ための極限の設計思想を伝授する。
—
1. 原則:Stateファイルに「機密」を書き込ませない執念
Terraformの `data` ソースでシークレットを読み込み、リソースの引数に渡すと、その値は必ず平文のまま `terraform.tfstate` に記録される。これは致命的だ。StateファイルがS3等に保存されている場合、暗号化はしているだろうが、アクセス権を持つ人間やCI/CDパイプラインには生のパスワードが見えてしまう。
極限の回避策:参照の「遅延評価」
リソース構築の最終段階まで値を展開せず、「リソースIDやARNのみ」を保持し、実行環境で動的に解決させるのがプロの流儀だ。RDSのパスワードなどは、可能な限り `random_password` で生成し、SSMに直接書き込むフローを徹底せよ。
シークレット生成とSSMへの書き込みを分離する設計
resource “random_password” “db_master_password” {
length = 32
special = true
}
resource “aws_ssm_parameter” “db_password” {
name = “/prod/db/master_password”
type = “SecureString”
value = random_password.db_master_password.result
# Stateに平文を残さないためのトリッキーな手法
lifecycle {
ignore_changes = [value]
}
}
—
2. 実践:Data Sourceを排した「ランタイム・バインディング」
`data “aws_ssm_parameter”` を多用すると、`terraform plan` のたびにAPIコールが発生し、レート制限に引っかかる。また、Stateに値がキャッシュされるリスクがある。
高負荷な環境や大規模なモノリス構成では、「Terraformが値を直接知る必要はない」という事実を逆手に取る。IAMポリシーを用いて、実行主体(ECSタスクやLambda)に直接Secrets Managerを読み込ませる「権限の委譲」に徹するのだ。
Terraformは「シークレットの中身」ではなく「シークレットへのアクセス権」のみを定義する
resource “aws_iam_policy” “secrets_access” {
name = “app-secrets-read-policy”
policy = jsonencode({
Version = “2012-10-17”
Statement = [{
Action = [“secretsmanager:GetSecretValue”]
Effect = “Allow”
Resource = [aws_secretsmanager_secret.db_cred.arn]
}]
})
}
—
3. パフォーマンスと信頼性のハック:Providerの最適化
大規模なインフラでは、`terraform plan` のオーバーヘッドを削ることがSREの命題だ。特にシークレットストアとの通信がボトルネックになる場合、以下の手法を検討せよ。
独自プロバイダラッパーとキャッシュ戦略
CIパイプラインのメモリ消費を抑え、API実行回数を劇的に減らすには、「Terraform実行前に必要な値をCLIで取得し、環境変数として注入する」手法がある。
Makefileによる実行時の動的注入(Stateを汚さない)
export TF_VAR_db_password=$(aws secretsmanager get-secret-value –secret-id prod/db –query SecretString –output text)
terraform apply -auto-approve
この手法の利点は、Terraform自体がシークレットの存在をStateに記録しないことにある。Terraformを「宣言的なIaCツール」としてのみ使い、シークレット管理という責務を切り離す「責任の分離(Separation of Concerns)」だ。
—
4. 現場で震えるほど役立つ「破壊的デバッグ」の回避
シークレット更新時に `terraform apply` で意図せずパスワードがローテーション(再生成)されてしまう事故は、SREの現場で最も多い。
これを防ぐための「最強の防御線」を貼れ:
resource “aws_secretsmanager_secret” “app_secret” {
name = “app/api-key”
# 誤操作による破滅を防ぐ
lifecycle {
prevent_destroy = true
# 更新時でも、一度定義したらTerraform側からは変更させない
ignore_changes = [kms_key_id]
}
}
—
伝説的エンジニアからの提言
シークレット管理において「ツールを信頼するな」。
1. Stateファイルは、常に「漏洩するもの」と仮定せよ。
2. IaCは「値の搬送」ではなく「アクセス制御の定義」に徹せよ。
3. シークレットの生存期間管理(ローテーション)は、Terraformの外(AWS LambdaやEventBridge)に追い出せ。
Terraformは強力だが、すべてを管理させようとすると破綻する。シークレットという「極めて機密性の高い情報」に関しては、Terraformを「鍵を渡す門番」として使い、実際の「鍵の管理」はシークレットストアのネイティブ機能に任せる。これこそが、数千ノードを運用する現場で生き残るための、唯一無二の解である。
もし君が今日、`tfvars` にシークレットを書こうとしているなら、今すぐその手を止めろ。IaCのコードは美しい論理構造であるべきで、泥臭い秘密のゴミ箱であってはならないのだから。