devops
A
信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
Terraformベストプラクティス2026
Terraform を本番で運用するためのベストプラクティスを解説。state 管理・モジュール設計・drift 検出・セキュリティスキャン・CI/CD 統合まで、現場で使える実践知識をまとめます。
一言結論
TerraformをチームでSafely運用するにはS3+DynamoDBによるリモートstate管理と環境別ディレクトリ構成が土台であり、CI/CDでのplan結果レビューとtfsecによるセキュリティスキャンを組み込むことで初めて本番grade のIaCになる。
1. State をリモートに保存する
ローカルの .tfstate は共同作業では即座に問題になります。
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
dynamodb_table = "terraform-lock" # 同時実行ロック
}
}
2. ディレクトリ構成
terraform/
├── modules/ # 再利用可能なモジュール
│ ├── vpc/
│ ├── eks/
│ └── rds/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ └── prod/
└── _global/ # 全環境共通(IAM等)
3. モジュールで再利用する
# modules/rds/main.tf
resource "aws_db_instance" "main" {
identifier = var.identifier
engine = "postgres"
engine_version = var.engine_version
instance_class = var.instance_class
allocated_storage = var.allocated_storage
multi_az = var.multi_az
backup_retention_period = 7
deletion_protection = var.deletion_protection
skip_final_snapshot = !var.deletion_protection
}
# environments/prod/main.tf
module "database" {
source = "../../modules/rds"
identifier = "prod-db"
instance_class = "db.t4g.medium"
multi_az = true
deletion_protection = true
}
4. 変数と tfvars の管理
# variables.tf
variable "instance_type" {
type = string
description = "EC2インスタンスタイプ"
default = "t3.micro"
validation {
condition = can(regex("^t3\\.", var.instance_type))
error_message = "t3 系インスタンスのみ使用可"
}
}
# dev.tfvars
instance_type = "t3.micro"
replica_count = 1
# prod.tfvars
instance_type = "t3.large"
replica_count = 3
terraform apply -var-file="prod.tfvars"
5. secrets を tfvars に書かない
# ❌ tfvars にシークレットを書く(git に入る危険)
db_password = "mysecretpassword"
# ✅ AWS Secrets Manager or Parameter Store から取得
data "aws_ssm_parameter" "db_password" {
name = "/prod/db/password"
}
resource "aws_db_instance" "main" {
password = data.aws_ssm_parameter.db_password.value
}
6. Plan を必ずレビューする
# CI で plan 結果を PR に投稿
terraform plan -out=tfplan
terraform show -json tfplan | jq '.resource_changes[] | select(.change.actions != ["no-op"])'
破壊的変更(destroy/replace) を含む場合は追加承認を必須にする。
7. import で既存リソースを取り込む
# 既存の AWS リソースを state に取り込む
terraform import aws_s3_bucket.main my-existing-bucket
# Terraform 1.5+ からは import ブロックも使える
import {
to = aws_s3_bucket.main
id = "my-existing-bucket"
}
8. tflint・tfsec でセキュリティチェック
# tflint: Terraform の構文・ベストプラクティスチェック
tflint
# tfsec: セキュリティ脆弱性スキャン
tfsec .
# Checkov: コンプライアンスチェック
checkov -d .
# .github/workflows/terraform.yml
- name: tfsec scan
uses: aquasecurity/tfsec-action@v1.0.0
with:
working_directory: terraform/
9. Drift 検出
コンソールで手動変更されたリソースを検出します。
# plan で差分を確認(差分があれば drift)
terraform plan -refresh-only
# 定期的に CI で実行してアラートを送る
10. 命名規則の統一
locals {
prefix = "${var.project}-${var.environment}"
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
tags = merge(local.common_tags, {
Name = "${local.prefix}-vpc"
})
}
まとめ
| 優先度 | プラクティス |
|---|---|
| 必須 | Remote State + DynamoDB Lock |
| 必須 | シークレットを tfvars に書かない |
| 推奨 | モジュール化 + 環境ディレクトリ分離 |
| 推奨 | CI で plan → 手動承認 → apply |
| 推奨 | tfsec / Checkov でセキュリティスキャン |
参考: Terraform 公式ドキュメント / tfsec