エラーの内容
センシティブなリソース属性(データベースのパスワード、APIキー、生成されたシークレットなど)を参照する出力ブロックを書くと、terraform plan や terraform apply が即座に以下のエラーで停止します:
Error: Output refers to sensitive value
on outputs.tf line 3, in output "db_password":
3: value = aws_db_instance.main.password
To allow this, the output must be marked with sensitive = true.
To expose the value, set the "sensitive" argument.
Terraformは、出力ブロックを通じてシークレットが外部に公開されようとしていることを検知します。どう扱うかを明示的に指定するまで、処理を続行しません。
発生する原因
Terraform 0.14 から、センシティブ値の自動追跡機能が導入されました。プロバイダーはスキーマ内の特定の属性をセンシティブとしてマークします。たとえば aws_db_instance.password、random_password.result などがその例です。このセンシティブフラグは、タグのように設定全体に伝播します。
センシティブな値が出力ブロックに到達すると、Terraformはそれを明示的に認識することを要求します。出力をセンシティブとしてマークするか、意図的に値を変換・マスクするかのどちらかです。何もしないという選択肢はありません。
このエラーを引き起こす主な原因:
aws_db_instance.*.passwordrandom_password.*.resultaws_secretsmanager_secret_version.*.secret_stringazurerm_key_vault_secret.*.valuesensitive = trueで宣言された変数
修正方法1 — 出力をセンシティブとしてマークする(最も一般的)
別のモジュールがこの値を必要としている場合や、CI/CDパイプラインがステートから値を取得する場合は、出力ブロックに sensitive = true を追加します:
# outputs.tf
output "db_password" {
value = aws_db_instance.main.password
sensitive = true
}
Terraformは引き続きステートに値を書き込みます。ただし、ターミナルには実際のシークレットの代わりに (sensitive value) と表示されます。パイプラインからは引き続き値を読み取れます:
terraform output -raw db_password
このコマンドは生の値を標準出力に出力します。Terraform自身の出力に表示させることなく、スクリプトにシークレットを渡す際に便利です。
修正方法2 — シークレット自体を出力しない
実のところ、最も堅牢な解決策は、Terraformからシークレットをエクスポートすること自体をやめることです。代わりにARNやパスを出力し、利用側のサービスが実行時にシークレットを取得するようにします。
# シークレット自体ではなく、参照先を出力する
output "db_secret_arn" {
value = aws_secretsmanager_secret.db.arn
}
# アプリはARNを使って実行時にシークレットを取得する
# センシティブな値がTerraformの出力を通じて流れることは一切ない
このパターンにより、CIのログ、Terraformの出力、および人間が誤って読んでしまう可能性のある場所からシークレットを排除できます。本番環境では、この方法を目指す価値があります。
修正方法3 — nonsensitive() を使って明示的にセンシティブフラグを解除する
出力でプレーンテキストの値が本当に必要な場合もあります。使い捨ての開発環境、すでに公開されている値、トレードオフを承知の上でのマイグレーションなどです。nonsensitive() 関数はセンシティブフラグを取り除きます:
# outputs.tf — 値を意図的に公開する場合のみ使用
output "db_password" {
value = nonsensitive(aws_db_instance.main.password)
}
確認ダイアログは表示されません。Terraformはあなたの判断を信頼します。値はターミナルにプレーンテキストで表示され、ステートにもマスクされずに保存されます。だからこそ、この関数は慎重に使用すべきです。
nonsensitive() を使う前に自問してください:このステートファイルは5人のエンジニアがアクセスできるS3バケットに保存されているか?この値はCIのログに表示される可能性があるか?どちらかの答えが「はい」であれば、再考してください。
修正方法4 — 出力に渡されるセンシティブな変数
センシティブ性の起源が sensitive = true で宣言した入力変数にある場合も、同じルールが適用されます。出力にもセンシティブとしてマークして、その契約を守りましょう:
# variables.tf
variable "api_key" {
type = string
sensitive = true
}
# outputs.tf
output "configured_api_key" {
value = var.api_key
sensitive = true # 必須 — ソースがセンシティブのため
}
修正方法5 — 複合型の中にあるセンシティブな値
センシティブでないフィールドと一緒に、マップやオブジェクトの中にシークレットが埋め込まれている場合があります。この場合、2つの選択肢があります。
出力全体をセンシティブとしてマークする:
output "db_config" {
value = {
host = aws_db_instance.main.address
port = aws_db_instance.main.port
password = aws_db_instance.main.password
}
sensitive = true
}
または分割する — センシティブでないフィールドを別の出力に保持し、パスワードは完全に除外します:
output "db_connection_info" {
value = {
host = aws_db_instance.main.address
port = aws_db_instance.main.port
# password は省略 — 利用側は Secrets Manager から取得する
}
}
呼び出し元が認証情報ではなく接続情報だけを必要とする場合は、2番目のアプローチの方がすっきりしています。
確認方法
terraform plan を実行してエラーが出なければ修正完了です。次に適用します:
terraform apply
センシティブな出力は、適用結果に次のように表示されます:
Outputs:
db_password = <sensitive>
値が実際に保存されており、必要なときにアクセスできることを確認するには:
# すべての出力を一覧表示(センシティブなものは "<sensitive>" として表示)
terraform output
# 特定のセンシティブな出力を読み取る — 生の値を標準出力に出力
terraform output -raw db_password
# すべてをJSONとして読み取る(センシティブな値も含まれる)
terraform output -json
CIパイプラインでは、次のように取得します:
DB_PASS=$(terraform output -raw db_password)
# $DB_PASS はTerraformのログに表示されることなくスクリプトで利用可能
リモートステートのセンシティブな値
terraform_remote_state を使って別の設定から出力を読み取る場合も、センシティブ性はステートの境界を越えて値と共に伝播します:
data "terraform_remote_state" "db" {
backend = "s3"
config = {
bucket = "my-tfstate"
key = "db/terraform.tfstate"
region = "us-east-1"
}
}
# この設定内でも引き続きセンシティブとして扱われる — 再マークは不要
locals {
db_pass = data.terraform_remote_state.db.outputs.db_password
}
再度アノテーションを付ける必要はありません。Terraformが自動的に追跡します。
判断の早見表
- 別のモジュールやパイプラインが実際の値を必要としている場合 →
sensitive = true - 利用側のサービスが自分でシークレットを取得できる場合 → ARNやパスを出力し、シークレット自体は渡さない
- 非本番環境、使い捨て、または本当に公開されている値の場合 →
nonsensitive()(リスクを理解した上で) - センシティブなフィールドとそうでないフィールドが混在するオブジェクトの場合 → 2つの出力に分割するか、ブロック全体をセンシティブとしてマーク

