sensitive = true を付けたから秘密情報は安全」と思っていたら、tfstateファイルを開いた瞬間にDBパスワードが平文で丸見えだった ── そんな落とし穴にはまるチームは少なくありません。sensitive = true はTerraformのターミナル出力から値を隠す機能であり、シークレットの「保存」や「管理」の問題を解決するわけではありません。設計レベルでのシークレット管理が別途必要です。この記事では、
sensitive = true の正確な動作と限界を整理したうえで、AWS SSM Parameter Store(SecureString)をdata sourceで参照してシークレットをTerraformコードの外に切り出す設計を、実装例と実行結果を交えて解説します。動作確認環境: Terraform 1.6 / AWS Provider 5.x
この記事のポイント
・sensitive = true はログ隠蔽のみ。tfstateには平文でシークレットが残る
・SSM Parameter Store(SecureString)でシークレットをコード外で管理する
・outputにsensitive指定を忘れるとCI/CDログに平文が流れる
・リモートバックエンドのSSE-KMS暗号化が最低限の対策
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
Terraformのsensitive変数とは何か
Terraformでは、variable・リソース属性・data sourceの値に sensitive = true を指定することで、terraform plan や terraform apply の出力でその値が (sensitive value) と表示されるようになります。
1. sensitive = true の基本的な書き方
variableブロックにsensitiveを設定する場合は次のように書きます。
variable "db_password" { type = string sensitive = true description = "RDSインスタンスのマスターパスワード" } resource "aws_db_instance" "main" { identifier = "myapp-prod" username = "admin" password = var.db_password # ... }
この設定で terraform plan を実行すると、ターミナルの出力は次のようになります。
# terraform plan の出力例(sensitive = true を設定した場合) Terraform will perform the following actions: # aws_db_instance.main will be created + resource "aws_db_instance" "main" { + identifier = "myapp-prod" + password = (sensitive value) + username = "admin" } Plan: 1 to add, 0 to change, 0 to destroy.
パスワードがターミナルに表示されないため、画面共有やペアプロ中の意図しない露出を防ぐ効果があります。
2. sensitive = true が解決しないこと
ここが多くのエンジニアが勘違いするポイントです。sensitive = true は「表示を隠すだけ」であり、以下の問題は解決しません。
・変数ファイル(terraform.tfvars)への平文記述
・Gitリポジトリへのシークレットのコミット
・CI/CDのビルドログへの漏洩(output経由の場合)
sensitive = true はあくまで可視性の最低限対策であり、シークレット管理の根本的な解決策にはなりません。
tfstateに秘密情報が残る問題とリモートバックエンドの暗号化対策
TerraformのtfstateはJSON形式で管理リソースの全属性値を記録します。sensitive = true の設定にかかわらず、シークレット値はtfstateにそのまま書き込まれます。
1. tfstateの平文残存を確認する
ローカル環境でRDSインスタンスを作成した直後にterraform.tfstateを確認すると、次のような構造になっています(パスワード部分は伏字)。
# terraform.tfstate の抜粋(JSON形式 / パスワード部分を伏字) { "resources": [ { "type": "aws_db_instance", "name": "main", "instances": [ { "attributes": { "password": "P@ssw0rd!****", "username": "admin", "endpoint": "myapp-prod.xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com" } } ] } ] }
このJSONファイルが外部に持ち出されたり、パブリックなGitリポジトリにコミットされたりすると、DBパスワードが即座に漏洩します。sensitive = true はこの問題を防ぎません。
2. S3リモートバックエンドとKMS暗号化
本番環境ではtfstateをローカルに置くことは絶対に避けてください。S3リモートバックエンドを使い、KMSによるサーバーサイド暗号化(SSE-KMS)を有効化します。
# backend.tf terraform { backend "s3" { bucket = "myapp-terraform-state" key = "prod/terraform.tfstate" region = "ap-northeast-1" encrypt = true kms_key_id = "arn:aws:kms:ap-northeast-1:123456789012:key/mrk-xxxx" dynamodb_table = "terraform-state-lock" } }
S3バックエンドの詳細な設定手順とDynamoDB State Lockingの組み合わせは、Terraformのtfstate管理とS3バックエンド設定で解説しています。
3. tfstate保護のチェックポイント
・S3バケットのSSE-KMS暗号化を有効化する(encrypt = true)・DynamoDB State Lockingで同時書き込みを防ぐ
・S3バケットのパブリックアクセスブロックを有効化する
・terraform.tfstateとterraform.tfstate.backupを.gitignoreに追加する
・ローカルバックエンドは開発者個人の検証環境のみに限定する
これらの設定を組み合わせることで、tfstateに含まれる秘密情報の露出リスクを最小化できます。
Terraformマニュアルを無料で受け取る >>
AWS SSM Parameter Storeとの連携でシークレットをコード外に出す
tfstateの暗号化と並行して、「そもそもTerraformコードにシークレットを渡さない」設計が重要です。AWS SSM Parameter Store(SecureString)を使うと、シークレット値をAWS管理に置き、Terraformはdata sourceで参照するだけという構成が実現できます。
1. SSM Parameter StoreにSecureStringを登録する
あらかじめAWS CLIでSecureStringタイプのパラメータを登録します。SecureStringはKMSキーで自動暗号化されます。
# AWS CLIでSecureStringを登録する(事前作業) aws ssm put-parameter --name "/myapp/prod/db_password" --value "P@ssw0rd!2024" --type SecureString --key-id "alias/myapp-kms-key" --region ap-northeast-1 # 登録確認(--with-decryptionを付けないと暗号化されたまま返る) aws ssm get-parameter --name "/myapp/prod/db_password" --with-decryption --region ap-northeast-1
2. Terraformでdata sourceとして参照する
aws_ssm_parameter data sourceでSSMパラメータを参照し、RDSリソースにパスワードとして渡します。
# data.tf data "aws_ssm_parameter" "db_password" { name = "/myapp/prod/db_password" with_decryption = true } # rds.tf resource "aws_db_instance" "main" { identifier = "myapp-prod" engine = "mysql" engine_version = "8.0" instance_class = "db.t3.medium" allocated_storage = 20 db_name = "myapp" username = "admin" password = data.aws_ssm_parameter.db_password.value skip_final_snapshot = false final_snapshot_identifier = "myapp-prod-final" }
この設計の最大のポイントは、Terraformのコード中にパスワードの実値が一切現れないことです。terraform plan を実行すると次のようになります。
# terraform plan の出力(SSMから取得した値はsensitiveとして自動隠蔽される) Terraform will perform the following actions: # aws_db_instance.main will be created + resource "aws_db_instance" "main" { + identifier = "myapp-prod" + password = (sensitive value) + username = "admin" + endpoint = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy.
SSM SecureStringから取得した値はTerraformが自動的にsensitiveとして扱うため、明示的に sensitive = true を付けなくても出力が隠蔽されます。
3. variableとdata sourceの使い分け
Terraformのvariable設計の基礎はTerraformのHCL変数設計で解説しています。シークレットのみSSMに外出しし、それ以外の設定値(リージョン、インスタンスタイプ等)は通常のvariableで管理するのが実務上のベストプラクティスです。
sensitive変数をoutputに渡す際のリスクと安全な設計パターン
シークレット値をoutputブロックで出力すると、後続のモジュールやCI/CDステップに値が漏洩するリスクがあります。
1. outputにsensitive指定がないとエラーになる
sensitiveとして扱われる値(SSM SecureStringの参照値を含む)をそのままoutputに渡すと、Terraformがエラーを出します。
# output.tf(NG例 - sensitive指定なし) output "db_password" { value = data.aws_ssm_parameter.db_password.value } # terraform plan 実行時のエラー Error: Output refers to sensitive values on output.tf line 2: 2: value = data.aws_ssm_parameter.db_password.value To reduce the risk of accidentally exporting sensitive data that was not intended to be exported, Terraform requires that any root module output containing sensitive data be explicitly marked as sensitive, to confirm your intent.
エラーを解消するには、outputブロックに sensitive = true を追加します。
# output.tf(OK例 - sensitive指定あり) output "db_password" { value = data.aws_ssm_parameter.db_password.value sensitive = true }
2. terraform output は実値が表示される
outputブロックに sensitive = true を付けても、ターミナルから terraform output db_password を実行すると実値が表示されます。
# sensitive = true でもターミナルでは実値が取得できる $ terraform output db_password "P@ssw0rd!****" # -json フラグでも同様 $ terraform output -json { "db_password": { "sensitive": true, "type": "string", "value": "P@ssw0rd!****" } }
これはTerraformの設計上の仕様です。CI/CDジョブで terraform output の結果をそのままログに流すと、ビルドログに平文で残ります。注意: sensitiveなoutputはCI/CDのジョブログに絶対に出力しないというルールをチームで必ず徹底してください。
3. outputを最小限にする設計原則
・シークレット値そのものをoutputとして出力しない設計を基本とする・後続リソースが値を必要とする場合は直接data sourceを参照させる
・どうしてもoutputが必要な場合はsensitive = trueを付けて最小限にとどめる
・terraform outputコマンドはオペレーターが手動で参照する場面のみに限定する
CI/CD環境でのシークレット漏洩防止チェックリスト
GitHub ActionsなどのCI/CDでTerraformを実行する場合は、シークレット管理の観点で以下を確認してください。詳細なパイプライン構築はGitHub ActionsでTerraformのCI/CDパイプラインを構築する方法と合わせて参照してください。
・AWSの認証はIAMアクセスキーではなくOIDC(OpenID Connect)による一時認証を使う・AWS_ACCESS_KEY_IDなどの認証情報はGitHub ActionsのSecretsで管理する
・terraform planの出力をartifactsとして保存する場合はsensitive値が含まれないか確認する
・ジョブ定義でterraform output db_passwordをechoしない
・terraform.tfvarsに実値を書いたファイルをリポジトリにコミットしない
・.gitignoreにterraform.tfvars、*.tfstate、*.tfstate.backupを必ず追加する
・SSM Parameter Storeのシークレット更新はTerraformパイプラインから分離して管理する
Ansible Vaultとの違い:用途・管理層による使い分け
シークレット管理のトピックで、Ansible Vaultと比較されることがあります。ただし、両者はそもそも解決する問題の層が異なります。詳細な使い分けはTerraformとAnsibleの違いと使い分けで解説しています。シークレット管理の観点で両者を比較します。
| 項目 | Terraform + SSM | Ansible Vault |
|---|---|---|
| 主な用途 | インフラプロビジョニング | 設定管理・アプリデプロイ |
| シークレットの保存先 | SSM / AWS Secrets Manager | 暗号化ファイルをリポジトリ管理 |
| 暗号化方式 | KMSによるサーバーサイド暗号化 | AES-256(Vaultパスワードで管理) |
| Gitとの関係 | シークレットはGitに含めない | 暗号化ファイルをGitに含める |
| 得意なシーン | AWSリソース作成時のシークレット受け渡し | OSユーザーパスワード・設定ファイルの暗号化 |
Ansible VaultはプレイブックやYAML変数ファイルを暗号化してリポジトリに含める設計で、設定管理・デプロイフェーズのシークレット管理に向いています。一方、TerraformのSSM連携はインフラプロビジョニング段階でのシークレット外部管理です。両ツールを組み合わせる場合は、SSM Parameter Storeを「シークレットの単一管理場所」として位置づけ、TerraformもAnsibleも同じSSMパラメータを参照する設計が整合的です。
本記事のまとめ
Terraformのシークレット管理は、sensitive = true の設定だけでは不十分です。設計レベルで複数の対策を組み合わせる必要があります。
| やること | 具体的な対策 |
|---|---|
| ターミナル露出を防ぐ | variable / outputにsensitive = trueを設定する |
| tfstate暗号化 | S3バックエンド + SSE-KMS + DynamoDB State Lock |
| シークレットをコード外に出す | SSM Parameter Store(SecureString)をdata sourceで参照 |
| CI/CD漏洩防止 | OIDC認証の採用、terraform outputをジョブログに流さない |
| Gitリポジトリ保護 | .gitignoreにtfstateとtfvarsを追加 |
Terraformマニュアルを無料で受け取る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます