Terraformのsensitive変数とシークレット管理|SSMパラメータストア参照で秘密情報を安全に扱う設計

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Terraform > Terraformのsensitive変数とシークレット管理|SSMパラメータストア参照で秘密情報を安全に扱う設計
「Terraformのvariableに 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暗号化が最低限の対策


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

Terraformのsensitive変数とは何か

Terraformでは、variable・リソース属性・data sourceの値に sensitive = true を指定することで、terraform planterraform 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 は「表示を隠すだけ」であり、以下の問題は解決しません。

・tfstateファイルへの平文保存(JSONとして値がそのまま残る)
・変数ファイル(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に含まれる秘密情報の露出リスクを最小化できます。

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。Terraformのシークレット管理からtfstate暗号化設計まで、実務で即使える設計パターンをLinuxマスターの無料マニュアルで解説しています。
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を追加
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。sensitive設計・SSM連携・CI/CDシークレット管理まで、Terraform実務の全体像を図解マニュアルで整理しています。
Terraformマニュアルを無料で受け取る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。