sensitive変数 — 機密値のマスクとstateへの記録

1. 概要

  • sensitive = trueとは何か、なぜ必要か
  • variable・output・localsでのsensitive設定
  • stateファイルへの保存とその注意点
  • nonsensitive()関数の使い方
  • 機密値の安全な管理パターン

Terraformでsensitive = trueを設定すると、パスワード・APIキー・秘密鍵などの機密値がterraform planapplyの出力でマスクされます。ただし、stateファイルには平文で保存されるという点を理解して使うことが重要です。


2. variableでsensitiveを設定する

variableブロックにsensitive = trueを設定することで、その変数を使用する箇所の出力がすべてマスクされます。

terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

variable "environment" {
  description = "環境名"
  type        = string
  default     = "dev"
}

variable "db_password" {
  description = "RDSマスターパスワード"
  type        = string
  sensitive   = true   # ← これでマスク
}

variable "db_username" {
  description = "RDSマスターユーザー名"
  type        = string
  sensitive   = true
}

resource "aws_db_instance" "main" {
  identifier        = "${var.environment}-mysql"
  engine            = "mysql"
  engine_version    = "8.0"
  instance_class    = "db.t3.micro"
  allocated_storage = 20
  storage_encrypted = true

  username = var.db_username
  password = var.db_password

  skip_final_snapshot = true

  tags = {
    Name        = "${var.environment}-mysql"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

terraform plan実行時の出力:

+ resource "aws_db_instance" "main" {
    + identifier = "dev-mysql"
    + username   = (sensitive value)
    + password   = (sensitive value)
    ...
}

3. outputでsensitiveを設定する

出力値に機密情報を含む場合はoutputブロックにもsensitive = trueを設定します。

output "db_endpoint" {
  description = "RDSエンドポイント"
  value       = aws_db_instance.main.endpoint
  # sensitiveではない(エンドポイントは公開してよい情報)
}

output "db_password" {
  description = "RDSパスワード(機密)"
  value       = aws_db_instance.main.password
  sensitive   = true   # ← 出力もマスク
}

sensitive = trueのoutputはterraform outputコマンドでもマスクされます。

$ terraform output
db_endpoint = "dev-mysql.xxx.ap-northeast-1.rds.amazonaws.com:3306"
db_password = <sensitive>

値を確認したい場合は-jsonフラグを使います(アクセスできる人のみ):

$ terraform output -json db_password
"my-secret-password"

4. localsでsensitiveを扱う

local値はsensitiveな変数を参照すると自動的にsensitiveになります。明示的に設定することも可能です(Terraform 1.9以降)。

locals {
  # db_passwordがsensitiveなため、connection_stringも自動的にsensitive
  connection_string = "mysql://${var.db_username}:${var.db_password}@${aws_db_instance.main.endpoint}"

  # Terraform 1.9以降: 明示的にsensitiveを設定
  api_config = sensitive({
    endpoint = "https://api.example.com"
    key      = var.api_key
  })
}

5. stateファイルへの保存

sensitive = trueはplanやapplyの出力をマスクするだけです。stateファイルには平文で保存されます。

# terraform.tfstate の中身(実際は平文)
{
  "resources": [{
    "values": {
      "password": "my-secret-password"  ← 平文で保存される
    }
  }]
}

このため、stateファイルの保護が非常に重要です。

対策方法
stateを暗号化して保存S3バックエンド + SSE-S3/SSE-KMS
stateへのアクセス制限S3バケットポリシーでIAM制限
ローカルのstateを使わないリモートバックエンドを必ず使う
CI/CDでの機密値管理AWS Secrets Manager・GitHub Actions Secretsを活用

6. nonsensitive() — sensitiveを解除する

nonsensitive(value)を使うと、sensitiveフラグを明示的に解除できます。機密値が安全に加工されたと確信できる場合のみ使用します。

variable "api_key" {
  type      = string
  sensitive = true
}

locals {
  # キーをハッシュ化してsensitiveを解除(ハッシュ値は公開してよい)
  api_key_hash = nonsensitive(sha256(var.api_key))
}

output "api_key_hash" {
  value = local.api_key_hash  # sensitiveではない
}

7. 関連記事


8. まとめ

  • sensitive = trueはplan/apply出力のマスクのみで、stateには平文保存される
  • variableoutputlocals(Terraform 1.9以降で明示設定可能)に設定できる
  • sensitiveな変数を参照するlocal値は自動的にsensitiveになる
  • stateファイルは必ずリモートバックエンド + 暗号化で保護する
  • nonsensitive()は加工済みの安全な値にのみ使用する

動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/language/values/variables#suppressing-values-in-cli-output