bcrypt / rsadecrypt — 暗号関数

1. 概要

  • bcrypt — パスワードのBcryptハッシュを生成
  • rsadecrypt — RSA秘密鍵でデータを復号
  • セキュリティ上の注意点

Terraformの暗号関数は、初期パスワードのハッシュ化やEC2インスタンスの初期パスワード取得などの限定的な用途に使います。機密データの扱いには十分な注意が必要です。


2. bcrypt — Bcryptハッシュを生成

bcrypt(string, cost)は文字列のBcryptハッシュを返します。costはハッシュのコスト(デフォルト10)で、高いほど計算が重くなります。

# terraform consoleで確認
> bcrypt("my-password")
"$2a$10$..."  # 実行のたびに異なるソルトが生成される

Grafanaの初期パスワードをBcryptで設定する

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 "grafana_admin_password" {
  description = "Grafana管理者パスワード"
  type        = string
  sensitive   = true
}

locals {
  # パスワードのBcryptハッシュを生成(Grafanaのenv変数に渡す形式)
  grafana_password_hash = bcrypt(var.grafana_admin_password)
}

# ECSタスク定義のenv変数としてBcryptハッシュを渡す
resource "aws_ecs_task_definition" "grafana" {
  family                   = "${var.environment}-grafana"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"
  execution_role_arn       = aws_iam_role.ecs_execution.arn

  container_definitions = jsonencode([{
    name  = "grafana"
    image = "grafana/grafana:latest"
    environment = [
      {
        name  = "GF_SECURITY_ADMIN_PASSWORD__FILE"
        value = "/dev/stdin"
      },
      {
        # Bcryptハッシュ形式で渡す(平文パスワードを避ける)
        name  = "GF_SECURITY_ADMIN_PASSWORD"
        value = local.grafana_password_hash
      }
    ]
    portMappings = [{
      containerPort = 3000
      protocol      = "tcp"
    }]
  }])

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

resource "aws_iam_role" "ecs_execution" {
  name = "${var.environment}-ecs-execution"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "ecs-tasks.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

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

注意: bcrypt()は実行のたびに異なるソルトが生成されるため、planのたびに差分が発生します。lifecycle { ignore_changes = [container_definitions] }で管理するか、外部でハッシュを生成して変数で渡す方法を検討してください。


3. rsadecrypt — RSA秘密鍵で復号

rsadecrypt(ciphertext, privatekey)はRSA秘密鍵でBase64エンコードされた暗号文を復号します。主にEC2 Windowsインスタンスの初期パスワード取得に使います。

data "aws_instance" "windows" {
  instance_id = "i-1234567890abcdef0"
}

# Windowsインスタンスの初期パスワードを取得
data "aws_ec2_instance_password_data" "windows" {
  instance_id = data.aws_instance.windows.id
}

locals {
  # RSA秘密鍵で暗号化されたパスワードを復号
  windows_password = rsadecrypt(
    data.aws_ec2_instance_password_data.windows.encrypted_password,
    file("${path.module}/ec2-key.pem")
  )
}

output "windows_password" {
  value     = local.windows_password
  sensitive = true  # sensitiveで出力を隠す
}

4. セキュリティ上の注意点

bcrypt()rsadecrypt()で扱う値はtfstateに平文で記録されます。

  • tfstateの暗号化を有効にすること(S3バックエンドの場合はSSE)
  • tfstateへのアクセス権限を最小限に制限すること
  • sensitive = trueをoutputやvariableに設定すること

5. 関連記事


6. まとめ

  • bcrypt(str, cost) — Bcryptハッシュを生成。Grafanaなどの初期パスワード設定に使う
  • rsadecrypt(cipher, key) — RSA秘密鍵で復号。WindowsのEC2初期パスワード取得に使う
  • bcrypt()は実行のたびに値が変わるためdriftが発生する。ignore_changesか外部ハッシュを検討
  • 暗号関数で扱う値はtfstateに記録されるためstateの暗号化が必須

動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/language/functions/bcrypt