取り組みの背景 — IaC 開発における Claude Code の可能性
クラウドインフラを Infrastructure as Code(IaC)で管理することは、今日のエンジニアリング組織において標準的なプラクティスです。しかし Terraform の習得コスト、設定ミスによるセキュリティリスク、膨れ上がるクラウドコストの管理、そして本番環境との差分(ドリフト)への対応は、多くのチームにとって継続的な課題となっています。
Claude Code は、この課題群を根本から変える可能性を持っています。自然言語でインフラ要件を伝えるだけで Terraform コードが生成され、生成されたコードは即座にセキュリティ観点でレビューされ、コスト試算まで自動化される—そのようなワークフローが現実のものとなっています。
対象読者は、Terraform の基本を理解しており Claude Code を本番 DevOps ワークフローに組み込もうとしているエンジニアです。
前提知識・環境準備
本ガイドを最大限に活用するには、以下の環境と知識が必要です。
環境
- Claude Code(最新版)
- Terraform v1.7 以上
- AWS CLI v2(設定済み)
- tfsec または Checkov(セキュリティスキャン)
- Node.js 18 以上(hooks スクリプト用)
必要な知識
- Terraform の基本(provider、resource、variable、output)
- AWS の主要サービス(VPC、EC2、RDS、IAM 等)
- Git の基本操作
- Claude Code の hooks 機能の概念
まず作業ディレクトリとプロジェクト構造を準備します。
mkdir -p ~/projects/infra-with-claude
cd ~/projects/infra-with-claude
# Terraform プロジェクト構造の初期化
mkdir -p {modules/{vpc,ec2,rds,iam},environments/{dev,staging,prod},.claude}
touch CLAUDE.mdCLAUDE.md 設計 — Claude に文脈を与える
Claude Code の品質は、プロジェクトのコンテキストをどれだけ正確に伝えられるかに依存します。Terraform プロジェクトでは特に、使用する provider バージョン、命名規則、セキュリティポリシーを事前に伝える点が肝心です。
# Infra Project — CLAUDE.md
## プロジェクト概要
AWS 上のマルチ環境インフラを Terraform で管理するプロジェクト。
対象環境: dev / staging / prod
## Terraform 規約
- Provider: aws ~> 5.0, terraform ~> 1.7
- バックエンド: S3 + DynamoDB(state lock)
- 命名規則: {env}-{service}-{resource} 例: prod-api-sg
- タグ必須: Environment, Project, ManagedBy=terraform, Owner
## セキュリティポリシー
- S3 バケットは必ず暗号化(SSE-S3 以上)
- セキュリティグループの 0.0.0.0/0 inbound は禁止
- IAM ロールは最小権限の原則を徹底
- RDS はパブリックアクセス禁止、マルチ AZ 必須(prod)
## モジュール設計
- modules/ 以下に再利用可能なモジュールを配置
- 各モジュールに variables.tf / outputs.tf / main.tf を分離
- locals.tf でタグ共通化
## コスト意識
- dev 環境は t3.micro / db.t3.micro を基本
- prod 環境でのスポットインスタンス活用を優先検討
- 不要リソースの定期レビューを実施この CLAUDE.md があることで、Claude Code は「このプロジェクトでは 0.0.0.0/0 は禁止」「タグは必須」といったポリシーを自動的に考慮したコードを生成します。
Terraform コード生成の実践パターン
パターン 1:自然言語からモジュール生成
最も基本的なユースケースから始めましょう。
# Claude Code に対するプロンプト例
claude "CLAUDE.md のポリシーに従い、以下の要件で VPC モジュールを生成してください:
- マルチ AZ(ap-northeast-1a/1c)
- パブリック/プライベートサブネット各 2 つ
- NAT Gateway は prod のみ(dev は不要)
- Flow Logs を CloudWatch に出力
modules/vpc/main.tf, variables.tf, outputs.tf に分けて作成"Claude Code はこの要件を解析し、以下のようなコードを生成します。
# modules/vpc/main.tf(Claude Code 生成例)
locals {
common_tags = merge(var.tags, {
Module = "vpc"
})
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(local.common_tags, {
Name = "${var.env}-vpc"
})
}
# パブリックサブネット(マルチ AZ)
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index)
availability_zone = var.availability_zones[count.index]
# CLAUDE.md ポリシー: パブリック IP の自動割り当ては明示的に制御
map_public_ip_on_launch = false
tags = merge(local.common_tags, {
Name = "${var.env}-public-${var.availability_zones[count.index]}"
Tier = "public"
})
}
# プライベートサブネット(マルチ AZ)
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index + length(var.availability_zones))
availability_zone = var.availability_zones[count.index]
tags = merge(local.common_tags, {
Name = "${var.env}-private-${var.availability_zones[count.index]}"
Tier = "private"
})
}
# NAT Gateway(prod のみ)
resource "aws_eip" "nat" {
count = var.enable_nat_gateway ? length(var.availability_zones) : 0
domain = "vpc"
tags = merge(local.common_tags, {
Name = "${var.env}-nat-eip-${count.index}"
})
}
resource "aws_nat_gateway" "main" {
count = var.enable_nat_gateway ? length(var.availability_zones) : 0
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
tags = merge(local.common_tags, {
Name = "${var.env}-nat-${count.index}"
})
depends_on = [aws_internet_gateway.main]
}
# VPC Flow Logs
resource "aws_flow_log" "main" {
vpc_id = aws_vpc.main.id
traffic_type = "ALL"
iam_role_arn = aws_iam_role.flow_log.arn
log_destination = aws_cloudwatch_log_group.flow_log.arn
tags = local.common_tags
}パターン 2:既存インフラのリファクタリング依頼
既存の Terraform コードに問題がある場合、Claude Code に診断とリファクタリングを依頼できます。
claude "modules/ec2/main.tf を読み込み、以下の観点でリファクタリングしてください:
1. ハードコードされた AMI ID を data source に変更
2. セキュリティグループルールを分離(インラインから aws_security_group_rule へ)
3. CLAUDE.md のタグポリシーに準拠していない箇所を修正
4. 変更の説明コメントを inline で追加"hooks による自動セキュリティスキャン
Claude Code の PostToolUse hooks を活用し、Terraform ファイルが保存されるたびに自動でセキュリティスキャンを実行する仕組みを構築します。
// .claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/terraform-security-scan.js"
}
]
}
]
}
}// .claude/hooks/terraform-security-scan.js
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
// stdin から hook イベントを受け取る
let inputData = '';
process.stdin.on('data', chunk => { inputData += chunk; });
process.stdin.on('end', () => {
const event = JSON.parse(inputData);
const filePath = event.tool_input?.file_path || event.tool_input?.path || '';
// Terraform ファイルのみ処理
if (!filePath.endsWith('.tf') && !filePath.endsWith('.tfvars')) {
process.exit(0);
}
const dir = path.dirname(filePath);
console.error(`🔍 Terraform セキュリティスキャン: ${filePath}`);
try {
// tfsec でスキャン
const result = execSync(
`tfsec ${dir} --format json --no-color 2>/dev/null`,
{ encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
);
const report = JSON.parse(result);
const criticalIssues = report.results?.filter(r =>
r.severity === 'CRITICAL' || r.severity === 'HIGH'
) || [];
if (criticalIssues.length > 0) {
// Claude に問題を通知するため stderr に出力
const issues = criticalIssues.map(issue =>
`[${issue.severity}] ${issue.rule_id}: ${issue.description} (${issue.location?.filename}:${issue.location?.start_line})`
).join('\n');
console.error(`⚠️ セキュリティ問題を検出:\n${issues}`);
// Claude に修正を促す出力
process.stdout.write(JSON.stringify({
decision: 'block',
reason: `Terraform セキュリティ問題を検出しました。修正が必要です:\n${issues}`
}));
process.exit(0);
}
console.error('✅ セキュリティスキャン: 問題なし');
} catch (err) {
// tfsec が未インストールの場合はスキップ
if (err.message.includes('not found') || err.message.includes('command not found')) {
console.error('⚠️ tfsec が未インストールです: npm install -g tfsec でインストール');
}
}
process.exit(0);
});このフックにより、セキュリティポリシー違反のある Terraform コードを書いた瞬間に Claude Code が検知し、自動で修正を提案します。
Checkov との組み合わせ
tfsec に加え Checkov も活用することで、より包括的な IaC スキャンが実現します。
# Checkov でのスキャン(Claude Code から呼び出し)
claude "以下の terraform plan を解析し、Checkov で HIGH 以上の脆弱性を全て修正してください:
$(checkov -d . --framework terraform --compact --output json 2>/dev/null)"terraform plan の AI 解析
terraform plan の出力は人間が読み解くには情報量が多すぎることがあります。Claude Code を使うと、この差分を素早く解析し、リスクを可視化できます。
# terraform plan を実行し Claude Code に解析させる
terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > tfplan.json
claude "tfplan.json を読み込み、以下の観点で解析してください:
1. 破壊的変更(destroy/replace)のリスク評価
2. セキュリティグループ変更のセキュリティ影響
3. データベース変更による downtime リスク
4. コスト増減の概算(追加/削除リソース)
5. 本番適用前に確認すべき項目のチェックリスト
を Markdown 形式でレポートしてください"Claude Code は以下のようなレポートを生成します。
## terraform plan 解析レポート
### 🔴 破壊的変更(要注意)
- `aws_db_instance.main`: **REPLACE** — parameter_group_name の変更により
RDS インスタンスの再起動が必要です。予想ダウンタイム: 約2〜5分
### 🟡 セキュリティ変更
- `aws_security_group_rule.api_ingress`: ポート 443 の許可元を
`10.0.0.0/8` → `10.1.0.0/16` に変更(範囲縮小 = セキュリティ向上)
### 💰 コスト試算(概算)
- 追加: `aws_nat_gateway` × 2 → +約 $64/月
- 削除: `aws_instance.bastion` → -約 $8/月
- 差分: +約 $56/月
### ✅ 適用前チェックリスト
- [ ] RDS のスナップショット取得済み
- [ ] メンテナンスウィンドウ内での適用
- [ ] ロールバック手順の確認コスト最適化の自動化
Claude Code を活用してクラウドコストの最適化提案を自動生成するワークフローです。
# AWS Cost Explorer のデータをエクスポート(aws cli)
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY \
--metrics BlendedCost \
--group-by Type=DIMENSION,Key=SERVICE \
--output json > cost_report.json
# Claude Code で分析
claude "cost_report.json と現在の Terraform コード(terraform/)を照合し:
1. コストの大きい上位 5 サービスの最適化提案
2. 使用率が低いリソースの特定(タグ情報から推測)
3. リザーブドインスタンス・セービングプランの適用候補
4. dev/staging 環境の夜間停止で削減できるコスト
を試算し、Terraform の修正 PR 向けに変更内容を提案してください"スポットインスタンスへの自動移行提案
# Claude Code が提案する EC2 スポットインスタンス化の例
# modules/ec2/main.tf(最適化後)
resource "aws_launch_template" "app" {
name_prefix = "${var.env}-app-"
image_id = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
# スポットインスタンス設定(dev/staging のみ)
dynamic "instance_market_options" {
for_each = var.use_spot ? [1] : []
content {
market_type = "spot"
spot_options {
# 中断耐性の高いワークロード向け設定
instance_interruption_behavior = "terminate"
max_price = var.spot_max_price
}
}
}
lifecycle {
create_before_destroy = true
}
}ドリフト検知と自動修正
本番環境では、手動変更によるインフラドリフトが深刻な問題になります。Claude Code を活用したドリフト検知・修正ワークフローです。
# ドリフト検知スクリプト
cat > .claude/scripts/detect-drift.sh << 'EOF'
#!/bin/bash
echo "🔍 Terraform ドリフト検知開始..."
# terraform refresh で実際の状態を取得
terraform refresh -compact-warnings 2>&1
# plan で差分を確認
terraform plan -detailed-exitcode -out=drift.tfplan 2>&1
EXIT_CODE=$?
if [ $EXIT_CODE -eq 2 ]; then
echo "⚠️ ドリフトを検知しました"
terraform show -json drift.tfplan > drift.json
# Claude Code に修正を依頼
claude "drift.json を解析し:
1. 手動変更された可能性のあるリソースを特定
2. 各変更の意図(緊急対応 or 誤操作)を推測
3. Terraform コードへの反映方法(import or コード修正)を提案
4. 再発防止のための AWS Config ルール設定を提案
してください"
elif [ $EXIT_CODE -eq 0 ]; then
echo "✅ ドリフトなし: インフラは Terraform と一致しています"
fi
rm -f drift.tfplan drift.json
EOF
chmod +x .claude/scripts/detect-drift.shGitHub Actions との統合
# .github/workflows/terraform-drift.yml
name: Terraform Drift Detection
on:
schedule:
- cron: '0 9 * * 1-5' # 平日 9:00 JST
workflow_dispatch:
jobs:
drift-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7.x
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_DRIFT_CHECK_ROLE }}
aws-region: ap-northeast-1
- name: Terraform Init
run: terraform init
working-directory: environments/prod
- name: Detect Drift
id: drift
run: |
terraform plan -detailed-exitcode -out=drift.tfplan 2>&1 || true
echo "exit_code=$?" >> $GITHUB_OUTPUT
working-directory: environments/prod
- name: Notify if Drift Detected
if: steps.drift.outputs.exit_code == '2'
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `[Alert] Terraform Drift Detected - ${new Date().toISOString().split('T')[0]}`,
body: '本番環境で Terraform のドリフトを検知しました。確認と修正が必要です。',
labels: ['infrastructure', 'urgent']
});マルチエージェントによる並列インフラ生成
大規模なインフラ変更が必要な場合、Claude Code のサブエージェント機能を活用して並列処理することで時間を大幅に短縮できます。
claude "以下のインフラコンポーネントをそれぞれサブエージェントで並列生成してください:
【エージェント 1】modules/networking/:
- VPC、サブネット、ルートテーブル、IGW、NAT GW
【エージェント 2】modules/security/:
- WAF、Security Hub、GuardDuty 設定、Security Groups テンプレート
【エージェント 3】modules/compute/:
- ECS Fargate クラスター、ALB、Auto Scaling
【エージェント 4】modules/data/:
- RDS Aurora PostgreSQL、ElastiCache Redis、S3 バケット群
各エージェントが完了したら、整合性チェック(VPC ID 参照、セキュリティグループの cross-module 参照)を実施してください"サブエージェントによる並列実行で、通常 2〜3 時間かかるインフラ設計作業が 20〜30 分に短縮されます。
よくあるエラーと対処法
エラー 1:provider バージョン不整合
Error: Invalid provider configuration
Claude Code に以下のように依頼します。
claude "以下のエラーを修正してください:
$(terraform init 2>&1)
versions.tf のプロバイダー制約を確認し、
全モジュールの provider バージョンを統一してください"エラー 2:state のロック
Error: Error locking state: ConditionalCheckFailedException
claude "terraform state lock が残留しています。
以下を確認して安全に解除してください:
1. 現在実行中の terraform プロセスの確認方法
2. DynamoDB のロックレコード確認コマンド
3. 安全な force-unlock の手順
を step-by-step で案内してください"エラー 3:循環参照
Error: Cycle: module.a.resource, module.b.resource
claude "Terraform の循環参照エラーを解決してください:
$(terraform graph 2>&1 | head -50)
依存関係グラフを整理し、どちらのモジュールを
上位に置くべきかを説明した上で修正してください"まとめ
重要なポイントを整理します。
CLAUDE.md による文脈設計がすべての起点です。セキュリティポリシー・命名規則・コスト方針を事前に記載することで、生成されるコードの品質が劇的に向上します。
hooks による自動セキュリティスキャンで、人間のレビューを補完します。tfsec / Checkov との連携により、脆弱な設定がコードベースに混入するリスクを大幅に低減できます。Claude Code の hooks 機能をさらに深く学びたい方は Claude Code Hooks 完全ガイド — 開発ワークフローを自動化する実践テクニック集 も参考にしてください。
terraform plan の AI 解析により、変更のリスク評価とコスト試算を自動化し、本番適用前の確認漏れを防ぎます。
ドリフト検知 × GitHub Actions の組み合わせで、本番環境の信頼性を継続的に担保します。大規模なインフラ変更で並列エージェントを活用したい場面では Claude Code 並列エージェント開発マスターガイド — ワークツリー × サブエージェント × タスク管理で実現する10倍速開発 が実装の参考になります。
AI とインフラ管理の融合はまだ発展途上ですが、Claude Code + Terraform の組み合わせは、今日から実装できる実践的なスタートポイントです。インフラ管理の自動化