💫

Terraform + Claude Codeで既存インフラをサクッとIaC化して幸せになった話

に公開

TL; DR

  • 夏休みの自由研究でClaude Codeに入門した
  • 面倒な既存インフラをIaC化するのがすぐ終わった
  • IAM管理で気を使ったね
  • tips
    • 作業終了時に音を鳴らすと楽だね
    • dotenvやtfenvを使うと、作業が楽にできるね

概要

お盆休み(社会人の夏休み)も終わりますね。

お盆で時間が取れたので、普段、やりたくてもできなかった既存AWS環境をTerraformに落とし込む作業を、Claude Codeへ入門して、AIにサクッと既存インフラをIaC化を依頼したら爆速で対応してくれて幸せになった話でもしようと思います。

想定読者

  1. Claude Code使ったこと
  2. AWSとかインフラ触ってる
  3. Terraformが扱える

1-3が揃ってて、既存インフラをIaCにしたい方向け

どうやるか

ざっくり説明はしますが、細かいことはshellとClaude.mdを公開するので、ご自分のリポジトリに突っ込んで作業してみてください(全部LLMにぶん投げ)

環境準備

  • ReadOnlyAccess権限のみを許可したIAMユーザーを作成し、AWS CLIにProfile設定を行う
  • tfenvでterraformを使う環境を準備する
  • direnvをインストールしておく
  • 以下のMCPをClaudeに追加しておく
    • awslabs-aws-documentation-mcp-server
    • awslabs-terraform-mcp-server

あとは、setup.shをリポジトリに配置して、実行すると全てセットアップしてくれます

setup.sh
#!/bin/bash

# infra_iac セットアップスクリプト
# AWS プロファイルとリージョンの設定を行い、各環境のterraform.tfvarsを作成します

set -e

echo "=== infra_iac セットアップ ==="
echo

# 現在のディレクトリ確認
if [[ ! -f ".terraform-version" ]]; then
    echo "エラー: .terraform-version ファイルが見つかりません。"
    echo "infra_iac のルートディレクトリで実行してください。"
    exit 1
fi

# tfenv の確認
if ! command -v tfenv &> /dev/null; then
    echo "エラー: tfenv がインストールされていません。"
    echo "tfenv をインストールしてから再実行してください。"
    echo "  brew install tfenv"
    exit 1
fi

# Terraform バージョンの確認とインストール
TERRAFORM_VERSION=$(cat .terraform-version)
echo "必要な Terraform バージョン: $TERRAFORM_VERSION"

if ! tfenv list | grep -q "$TERRAFORM_VERSION"; then
    echo "Terraform $TERRAFORM_VERSION をインストールしています..."
    tfenv install "$TERRAFORM_VERSION"
fi

echo "Terraform $TERRAFORM_VERSION を使用します..."
tfenv use "$TERRAFORM_VERSION"

echo
echo "=== AWS プロファイル設定 ==="
echo

# 利用可能なAWSプロファイルを表示
echo "利用可能なAWSプロファイル:"
if [[ -f ~/.aws/config ]]; then
    grep '^\[profile ' ~/.aws/config | sed 's/\[profile \(.*\)\]/  \1/' || echo "  プロファイルが見つかりません"
else
    echo "  ~/.aws/config ファイルが見つかりません"
fi

if [[ -f ~/.aws/credentials ]]; then
    grep '^\[' ~/.aws/credentials | sed 's/\[\(.*\)\]/  \1/' | grep -v default || true
else
    echo "  ~/.aws/credentials ファイルが見つかりません"
fi

echo
read -p "使用するAWSプロファイル名を入力してください: " AWS_PROFILE

if [[ -z "$AWS_PROFILE" ]]; then
    echo "エラー: プロファイル名が入力されていません。"
    exit 1
fi

# プロファイルの存在確認
aws configure list --profile "$AWS_PROFILE" &>/dev/null || {
    echo "エラー: プロファイル '$AWS_PROFILE' が見つかりません。"
    echo "AWS CLI でプロファイルを設定してから再実行してください。"
    exit 1
}

echo
read -p "使用するAWSリージョンを入力してください [ap-northeast-1]: " AWS_REGION
AWS_REGION=${AWS_REGION:-ap-northeast-1}

echo
echo "=== terraform.tfvars ファイルの作成 ==="

# 作業環境の選択
echo "設定する環境を選択してください:"
echo "1) staging"
echo "2) production"
echo "3) 両方"
read -p "選択 [1-3]: " ENV_CHOICE

create_tfvars() {
    local env_dir=$1
    local tfvars_file="$env_dir/terraform.tfvars"

    if [[ ! -d "$env_dir" ]]; then
        echo "警告: $env_dir ディレクトリが見つかりません。スキップします。"
        return
    fi

    echo "  $tfvars_file を作成しています..."

    cat > "$tfvars_file" << EOF
# $(basename $env_dir)環境の設定
# このファイルはgitignoreに含まれています

# AWS CLI プロファイル名
aws_profile = "$AWS_PROFILE"

# AWS リージョン
aws_region = "$AWS_REGION"
EOF
    
    echo "  ✓ $tfvars_file を作成しました"
}

case $ENV_CHOICE in
    1)
        create_tfvars "environments/staging"
        ;;
    2)
        create_tfvars "environments/production"
        ;;
    3)
        create_tfvars "environments/staging"
        create_tfvars "environments/production"
        ;;
    *)
        echo "エラー: 無効な選択です。"
        exit 1
        ;;
esac

echo
echo "=== 環境変数ファイルの作成 ==="

# .envrc ファイルの作成
ENVRC_FILE=".envrc"
echo "  $ENVRC_FILE を作成しています..."

cat > "$ENVRC_FILE" << EOF
# AWS プロファイルと環境変数の自動設定
# direnv を使用して、このディレクトリ配下で自動的に環境変数を設定します
# 使用方法: brew install direnv してから direnv allow を実行

export AWS_PROFILE="$AWS_PROFILE"
export AWS_DEFAULT_REGION="$AWS_REGION"

echo "AWS プロファイル設定完了: \$AWS_PROFILE (\$AWS_DEFAULT_REGION)"
EOF

echo "  ✓ $ENVRC_FILE を作成しました"

# direnv の確認と対話的な許可
if command -v direnv &> /dev/null; then
    echo "  direnv が検出されました。"
    echo
    read -p "direnv allow を実行しますか? [y/N]: " ALLOW_DIRENV
    if [[ "$ALLOW_DIRENV" =~ ^[Yy]$ ]]; then
        direnv allow .
        echo "  ✓ direnv allow を実行しました"
    else
        echo "  手動で 'direnv allow' を実行してください"
    fi
else
    echo "  推奨: direnv をインストールして自動環境変数設定を有効にしてください"
    echo "    brew install direnv"
    echo "    その後シェル設定に direnv の hook を追加してください"
fi

echo
echo "=== セットアップ完了 ==="
echo "設定内容:"
echo "  AWSプロファイル: $AWS_PROFILE"
echo "  AWSリージョン: $AWS_REGION"
echo
echo "次のステップ:"
if command -v direnv &> /dev/null && [[ "$ALLOW_DIRENV" =~ ^[Yy]$ ]]; then
    echo "1. 適切なディレクトリに移動: cd environments/staging または cd environments/production"
    STEP_NUM=2
else
    echo "1. 環境変数の自動設定を有効化: direnv allow"
    echo "2. 適切なディレクトリに移動: cd environments/staging または cd environments/production"
    STEP_NUM=3
fi
echo "${STEP_NUM}. Terraform を初期化: terraform init"
echo "$((STEP_NUM + 1)). 設定を確認: terraform plan"
echo
echo "AWS CLI 使用時の注意:"
echo "• このディレクトリ内では --profile オプションが不要になります"
echo "• AWS_PROFILE と AWS_DEFAULT_REGION が自動設定されます"
echo
echo "注意: terraform.tfvars と .envrc ファイルは .gitignore に含まれているため、"
echo "チーム内の他のメンバーも各自でこのセットアップスクリプトを実行する必要があります。"

Claudeへの指示

指示は簡単です。
人間の手で行う場合の手順とほぼ同じです。

  1. importするリソースをtfファイルに記述
  2. terraform importを実行
    (この時点でtfstateにリソースが保存される)
  3. terraform show [resource]でimportしたリソースの実際の状態取得
  4. 既存import済みリソース参照への修正
  5. terraform planを実行し、設定の妥当性を確認

以下は、実際に使用したCLAUDE.mdの内容です
作業対象リソースの部分のみ、ご自身のimportしたい環境へ書き換えてください

CLAUDE.md
# CLAUDE.md

## 言語の優先設定

**重要: このリポジトリで作業を行う際は、必ず日本語で応答してください。**
ユーザーとのやり取りは必ず日本語で行ってください。

## プロジェクト概要

このリポジトリは `infra_iac` であり、AWSリソースを管理するための Terraform インフラリポジトリです。
使用する Terraform のバージョンは `.terraform-version` に指定されている 1.12.2 です。

## 開発環境のセットアップ

このリポジトリでは Terraform のバージョン管理に `tfenv` を使用しています。Terraform のバージョンは `.terraform-version` ファイルに固定されており、`tfenv` が自動的に検出して使用します。

## 現在の状況

- AWS上で稼働中のインフラをTerraform管理下に移行したい
- 以下の手順による段階的移行を実施したい

## 必須作業手順(厳守)

1. **tfファイルを作成し、importするリソースを定義**
    - 最小限の必須属性のみで定義
    - lifecycle ignore_changesの使用は基本的に禁止です
    ただし、CI/CDでのデプロイなど動的に変更になる場合のみ使用可能とします

2. **terraform importしてtfstateに状態を保存**
    - 既存リソースをTerraform管理下に配置

3. **terraform show [resource]でimportしたリソースの実際の状態取得**
    - 実リソースの設定値を正確に把握
    - この情報を元に手順1のtfファイルに落とし込み

4. **既存import済みリソース参照への修正**
    - ARN直書きは基本的に禁止
    - 必ずリソース参照形式に変更(例:`aws_vpc.main.id`5. **terraform planで設定の妥当性を確認**
    - No changesになるまで調整
    - 差分がある場合は手順3-4を繰り返し

6. **terraform fmtでフォーマット整備**

## 作業対象リソース

**メインVPC**: `vpc-08cfxxxxxxxx` (staging vpc)
- CIDR: 10.0.0.0/16  
- Region: ap-northeast-1

## 禁止事項

- `lifecycle { ignore_changes = [...] }` の使用
- 自動生成ツールへの過度な依存
- ARNやIDの直書き
- 一括での複数リソース処理

## 対応不要な差分について

以下のterraform plan差分については対応不要とする:

やらなかったこと

  • terraform plan -generate-config-out=import.tfの使用

    -generate-config-outを使ったimportは周辺リソースまで勝手にimportしてくれるのですが、対象リソースによってエラーが発生し作業を先の手順で実行し始めるので行いませんでした。

Tips

  • 作業が終わったり、質問が来たら音が鳴るようにしましょう
    この記事がおすすめ
  • direnvを活用して、Claude CodeがAWS CLIを使用する場合のprofileを強制させましょう
    (客先の環境破壊とかし始めたら死ぬのでね…)
GitHubで編集を提案

Discussion