Terraform CI/CDのシークレット管理

1. 概要

  • Terraform CI/CDにおけるシークレットの種類
  • GitHub Actionsでのシークレット管理
  • AWS Secrets Manager / SSM Parameter Storeとの連携
  • シークレットをコードに埋め込まないためのベストプラクティス

Terraform CI/CDで扱うシークレットには「AWSクレデンシャル」「DBパスワード」「APIキー」などがあります。これらをソースコードやCI設定ファイルに直接書くのは非常に危険です。


2. シークレットの種類と管理場所

シークレット種別管理場所理由
AWS認証情報OIDCで不要化(推奨) / GitHub Secrets長期アクセスキーを排除
Terraform Cloud APIトークンGitHub SecretsCI/CDからTF Cloudを操作する場合
DBパスワードAWS Secrets Manager / SSM Parameter Storeアプリが実行時に取得
APIキーAWS Secrets Managerローテーションが必要な場合
SSH秘密鍵GitHub Secretsプロビジョニング用

3. GitHub SecretsをTerraformに渡す

# .github/workflows/terraform.yml
name: Terraform

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 推奨: OIDCでAWS認証(GitHub Secretsにアクセスキー不要)
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: ap-northeast-1

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.9"

      - name: Terraform Init
        run: terraform init

      # GitHub SecretsをTerraform変数として渡す
      - name: Terraform Apply
        env:
          TF_VAR_db_password: ${{ secrets.DB_PASSWORD }}
          TF_VAR_api_key: ${{ secrets.THIRD_PARTY_API_KEY }}
        run: terraform apply -auto-approve

4. TerraformコードでのSecrets Manager連携

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  # plan/apply出力でマスク
}

# Secrets Managerにシークレットを保存(Terraformで作成する場合)
resource "aws_secretsmanager_secret" "db" {
  name = "/${var.environment}/app/db"

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

resource "aws_secretsmanager_secret_version" "db" {
  secret_id = aws_secretsmanager_secret.db.id
  secret_string = jsonencode({
    username = "admin"
    password = var.db_password  # CI/CDからTF_VAR_db_passwordで渡す
  })
}

# アプリが実行時にSecrets Managerから取得するための参照例
data "aws_secretsmanager_secret_version" "db" {
  secret_id = aws_secretsmanager_secret.db.id
  depends_on = [aws_secretsmanager_secret_version.db]
}

5. SSM Parameter StoreをTerraformで管理する

# SSM Parameter Storeにシークレットを保存
resource "aws_ssm_parameter" "api_key" {
  name  = "/${var.environment}/app/api-key"
  type  = "SecureString"  # KMSで暗号化
  value = var.api_key

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

variable "api_key" {
  description = "サードパーティAPIキー"
  type        = string
  sensitive   = true
}

6. 絶対にやってはいけないこと

# ❌ 絶対NG: シークレットをコードに直書き
resource "aws_db_instance" "bad" {
  password = "SuperSecret123!"  # コードにパスワードを書かない
}

# ❌ 絶対NG: tfvarsファイルをGitにコミット
# terraform.tfvars(Gitignoreに追加すること)
# db_password = "SuperSecret123!"

# ✅ 推奨: 環境変数経由(CI/CDでは自動設定される)
# TF_VAR_db_password=xxxx terraform apply

.gitignoreに必ず追加する:

# Terraform
*.tfvars
*.tfvars.json
.terraform/
terraform.tfstate
terraform.tfstate.backup

7. 関連記事


8. まとめ

  • AWSクレデンシャルはOIDCで不要化するのが最優先。アクセスキーはGitHub Secretsに保存しない
  • DBパスワード等はCI/CD変数(GitHub Secrets)として管理し、TF_VAR_*でTerraformに渡す
  • Secrets Manager / SSM Parameter Storeを活用してアプリが実行時に取得する設計にする
  • .tfvarsファイルは.gitignoreに追加してコミットしない

対象バージョン: Terraform >= 1.9 / GitHub Actions (2024) 公式ドキュメント: https://developer.hashicorp.com/terraform/language/values/variables#environment-variables