Terraformの「Output refers to sensitive value」エラーをシークレットのエクスポート時に修正する方法

intermediate🏗️ Terraform2026-04-02| Terraform 0.14以降、任意のOS(Linux、macOS、Windows)、任意のクラウドプロバイダー

Error Message

Error: Output refers to sensitive value; use 'sensitive = true' to allow this output
#terraform#output#sensitive#セキュリティ

エラーの内容

センシティブなリソース属性(データベースのパスワード、APIキー、生成されたシークレットなど)を参照する出力ブロックを書くと、terraform planterraform 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.passwordrandom_password.result などがその例です。このセンシティブフラグは、タグのように設定全体に伝播します。

センシティブな値が出力ブロックに到達すると、Terraformはそれを明示的に認識することを要求します。出力をセンシティブとしてマークするか、意図的に値を変換・マスクするかのどちらかです。何もしないという選択肢はありません。

このエラーを引き起こす主な原因:

  • aws_db_instance.*.password
  • random_password.*.result
  • aws_secretsmanager_secret_version.*.secret_string
  • azurerm_key_vault_secret.*.value
  • sensitive = 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つの出力に分割するか、ブロック全体をセンシティブとしてマーク

Related Error Notes