AWS MCP Server × Claude Code 目指せ!人が手を加えず既存AWS環境をTerraform化

AWS MCP Server × Claude Code 目指せ!人が手を加えず既存AWS環境をTerraform化

目次

はじめに

2026年5月に AWS MCP Server が一般提供を開始。
この場をお借りして何か試してみたい!!

というわけで、、
過去にサードパーティ製のツールを使用して挫折した「既存環境のTerraform化」を題材にしたいと思います。

今回の目標

  • AIが生成したTerraformコードで terraform plan の差分0件を目指す
  • AI にどこまで任せられるかをなんとなく理解する

今回の検証対象は、既にTerraformで構築・管理されている環境です。
つまり「答え」がある状態での答え合わせになります。手作業で作られたレガシー環境とは条件が異なる点はご了承ください。

使用するツール

ツール役割
AWS MCP Server既存AWSリソースの情報取得(AWSが提供するマネージドサービス)
Claude CodeAWS MCP Serverへの接続・実行、取得した情報をもとにTerraformコードを生成

AWS MCP Server 単体ではただのAPIの窓口で、それを呼び出して結果を解釈し、コードに落とし込むのが Claude Code という関係です。

AWS MCP Serverについて詳しくはこちら:AWS MCP Server の一般提供開始

前提条件

  • Claude Code がインストール済み
  • AWS CLI v2 がインストール済み(SSO 設定済み)
  • AWS MCP Server のセットアップ済み

AWS MCP Server のセットアップ手順については公式ドキュメントをご参照ください。
AWS Agent Toolkit – Quick Start

権限設計:AI に何を許すか

AWS MCP Serverの権限は、セットアップ時に指定した AWS プロファイルの IAM ロール / ポリシー(SSO の場合は許可セット)がそのまま適用されます。
つまり、そのプロファイルで実行できる操作はすべて AI が実行できてしまいます。

今回の目的は既存リソースの情報取得(読み取り)だけなので、MCP 用の IAM ロール / ポリシーは ReadOnly に制限する ことを強く推奨します。

事前準備:対象リソースの選定

まずは検証アカウント内のリソースを把握するところから始めます。
Claude Code に以下のように依頼しました。

AWS MCP Serverのcall_awsを使って、ap-northeast-1にあるリソースのタグ一覧を取得して。
どんなタグキーとタグ値の組み合わせがあるか整理してほしい。

タグキーを取得した後、各キーの値を並列で取得してくれました。

約2分でアカウント内のタグが整理されました。今回は cloudmake システム(VPC / ALB / RDS / ECS / Lambda など多種のリソースが稼働中)を検証対象に選びました。

cloudmake リソース一覧

続けて、cloudmake に絞ったリソースの棚卸しを依頼しました。

AWS MCP Serverのcall_awsを使って、SystemName=cloudmake または Name に cloudmake を含むリソースを
一覧取得して。リソースタイプごとに整理してほしい。

キャプチャを取り忘れましたが、以下を結果を返してくれました。
またそれぞれのIDなどの詳細な情報も提示してくれていました。

リソースタイプ件数
ACM10
CloudFormation2
EC2 Instance1
EC2 VPC/Network11
EC2 Security Group7
ECR3
ECS (Cluster/Service/Task)5
ECS Task Definition97
ELB8
Lambda2
CloudWatch Logs3
RDS/Aurora7
S31
Secrets Manager1
SQS2
合計160

160 件。これを手動修正 0% で Terraform 化できるか検証していきます。

検証方針

160件のリソースに対して、シンプルなリソースから複雑なリソースへ段階的に検証していきます。

流れとしては、Claude Code に対象リソースを伝えて call_aws で情報取得
→ HCL + import ブロック生成 → terraform plan で差分確認、というアプローチです。

⚠️ 今回の検証の前提条件

  • 単一リージョン(ap-northeast-1)、単一アカウントでの検証です。CloudFront + WAF(us-east-1)のようなマルチリージョン構成や、Organizations 配下のマルチアカウント構成は対象外です。
  • 対象の cloudmake 環境は元々 Terraform で構築された環境です。そのためリソースの命名規則やタグ付けが比較的整っています。コンソールで手作業で作られた「本当のレガシー環境」では、タグなし・命名バラバラ・不要リソース混在により、成功率が下がる可能性があります。

検証①:VPC + セキュリティグループ(21 リソース)

最初のターゲットとして、VPC ネットワーク層とセキュリティグループを選びました。
リソース一覧で抽出したリソースとIDをもとにClaudeに依頼します。

AWS MCP Serverの call_awsを使って、cloudmakeシステムのVPC関連リソース
(VPC、サブネット、ルートテーブル、IGW、NAT GW)とセキュリティグループの
設定情報を取得して、Terraform HCLコードとimportブロックを生成してください。
対象リソース:
- VPC: vpc-0xxxxxxxxxxxxxxxxx
- Subnets: subnet-0xxxxxxxxxxxxxxxxx × 4
- Route Tables: rtb-0xxxxxxxxxxxxxxxxx × 2
- IGW: igw-0xxxxxxxxxxxxxxxxx
- NAT GW: nat-0xxxxxxxxxxxxxxxxx
- Security Groups: sg-0xxxxxxxxxxxxxxxxx × 7
terraform init と terraform plan まで実行して、差分があるか確認してください。

※以降はポイントに絞ってキャプチャを掲載します。

プロンプト1つで、リソース情報の取得からファイル生成まで自動で進みました。
そのままterraform init、terraform planも自動で行われます。

plan結果は以下です。

Plan: 21 to import, 0 to add, 0 to change, 0 to destroy.

差分ゼロ。 21リソースの HCL コードが AWS の実態と一致しました。

ポイント

  • Describe API の呼び出しだけでなく、VPC の DNS 属性や NAT Gateway に紐づく EIP など、追加で必要な情報を Claude が自分で判断して取得していた
  • Route Table Association のように、Describe の結果には直接含まれず暗黙的に導出が必要なリソースも正しく生成された
  • プロンプト1つで、情報取得 → HCL生成 → terraform init → plan まで一気に完了した

検証②:複雑リソース(34 リソース)

VPC + SG で成功したので、より複雑なリソースに挑戦します。

同じ方法で、cloudmakeシステムの以下のリソースもTerraform HCLコードと
importブロックを生成して、terraform planまで実行してください。

対象リソース:
- ALB: cloudmake-dev-alb-private-webapp(リスナー、リスナールール、ターゲットグループ含む)
- ECS: cloudmake-dev-cluster(サービス、タスク定義の最新リビジョン含む)
- RDS/Aurora: cloudmake-dev-rds-app(クラスター、インスタンス、パラメータグループ、サブネットグループ含む)
- ECR / S3 / SQS / Lambda / CloudWatch Logs

1回目の plan

※以降は記事が長くなるのでClaudeのキャプチャは割愛し結果だけをお伝えします。

Plan: 34 to import, 0 to add, 25 to change, 0 to destroy.

25件の差分。しかし Claude は plan の出力を読み取り、自分で原因を分析して即座に修正を始めました。

● plan成功確認。34 import, 25 変更 (主にタグ欠損、ALB削除保護、TGの登録解除遅延、
  RDSパラメータ等)。これらをすべて修正します。

ALB に enable_deletion_protection と access_logs を追加:

● Write(alb.tf)
  ⎿  Added 95 lines, removed 22 lines
      31 +  enable_deletion_protection = true
      
      39 +  access_logs {
      40 +    bucket  = "cloudmake-dev-s3-accesslogs-apn1"
      41 +    prefix  = "alb"
      42 +    enabled = true
      43 +  }

各リソースに欠損していたタグを一括追加:

      75 +  tags = {
      76 +    CmBillingGroup = "cloudmake"
      77 +    Env            = "dev"
      79 +    SystemName     = "cloudmake"
      80 +    Terraform      = "true"
      81 +  }

ECS Service の task_definition を ARN 形式から family:revision 形式に変更:

● Write(ecs.tf)
      116 -  task_definition = aws_ecs_task_definition.backend.arn
      137 +  # family:revision 形式で現在のリビジョンを指定(フォーマット正規化による不要デプロイを防止)
      138 +  task_definition = "${aws_ecs_task_definition.backend.family}:${aws_ecs_task_definition.backend.revision}"

最終結果

● terraform plan は正常に完了しています。残り2件の変更を確認しました:

  変更1: aws_lb_listener.https
  - シンプルな target_group_arn 形式に正規化
  - 機能的な変更なし

  変更2: aws_s3_bucket_lifecycle_configuration.accesslogs
  - 明示的な filter {} を付与
  - 機能的な変更なし

  Plan: 34 to import, 0 to add, 2 to change, 0 to destroy.

✻ Worked for 21m 5s

25件 → 2件 まで自己修正で削減。
残った2件はいずれも AWS API と Terraform の表現差に起因するギャップで、機能的な変更はないとのこと。

検証③:ACM / Secrets Manager / RDS DB Proxy

残りのリソースも追加します。

引き続き、以下のリソースのTerraform HCLコードとimportブロックを追加して、
terraform planまで実行してください。

対象リソース:
- ACM証明書 10件(Env: dev タグ付きのもの全て)
- Secrets Manager: /cloudmake/dev/rds/app/cloudmake
- RDS DB Proxy: cloudmake-dev-rds-proxy-app

エラーからの自己復旧

面白かったのは、最初にエラーが出た場面です。

● aws-mcp - aws___call_aws (MCP)("aws secretsmanager describe-secret --secret-id ...")
  ⎿  "error": "Secrets Manager can't find the specified secret."

● aws-mcp - aws___call_aws (MCP)("aws rds describe-db-proxies --db-proxy-name ...")
  ⎿  "error": "DBProxy 'prx-0xxxxxxxx' not found."

Secret ID と DB Proxy の指定方法が間違っていたのですが、Claude はエラーを見て list-secrets と describe-db-proxies(名前指定なし)で一覧を取得し直し、正しい名前を自分で見つけて再実行しました。

ACM 9件が import 不可

│ Error: Cannot import non-existent remote object

ACM 証明書 10件のうち 9件は VALIDATION_TIMED_OUT ステータスだったため、Terraform プロバイダーが「存在しない」と判断。
Claude はこのエラーも自分で分析し、該当する9件を除外してコメントとして記録しました。

+# 以下の 9 件 (Env: dev) は VALIDATION_TIMED_OUT ステータスのため
+# Terraform AWS プロバイダーが non-existent として扱い import 不可。
+# 該当 ARN (参考):
+#   arn:aws:acm:ap-northeast-1:xxxxxxxxxxxx:certificate/xxxxxxxx-xxxx-...
+#   ...(9件分)

最終結果

terraform plan 成功: 39 to import, 0 to add, 3 to change, 0 to destroy

✻ Brewed for 14m 37s

3件の change は検証②の2件 + Secrets Manager の recovery_window_in_days デフォルト値差異の1件。
いずれも機能的な変更はありません。

ディレクトリ統合と変数化

検証の過程でディレクトリが分かれてしまったため、最終的に 1 つに統合し、変数化も Claude に。

  • ハードコードされたリソース ID → リソース参照(aws_vpc.this.id、aws_security_group.alb.id 等)
  • アカウント ID 入りの ARN → locals で組み立て("arn:aws:iam::${local.account_id}:role/...")
  • 環境依存パラメータ → variables(CPU/メモリ、image URI、RDS エンジンバージョン等)

最終結果

Plan: 60 to import, 0 to add, 3 to change, 0 to destroy.

変数化後も plan 結果は変わらず、60 to import, 0 to add, 3 to change, 0 to destroy を維持しています。

検証リソース数結果
① VPC + SG21差分ゼロ
② 複雑リソース34初回 25 差分 → 自己修正 → 残り 2 件(正規化)
③ ACM / Secrets / Proxy5 (+9 不可)1 件の正規化差分、9 件は import 不可で除外
合計60 import 成功3 件の change(すべて非機能変更)

3 件の change はいずれも機能的な変更を伴わない正規化差分です。
結果、人間が .tf ファイルを手で編集する作業はゼロ でした。

まとめ

今回の検証で分かったこと

AWS MCP Server × Claude Code で、60リソースを人間が .tf ファイルを手で編集することなく terraform plan を通せました。
特に Claude が自律的に plan の差分を分析して自己修正していく動きは印象的でした。

ただし、AWS API と Terraform の表現差に起因する正規化差分(3件)は原理的に回避できず、完全な差分ゼロには至りませんでした。

terraform plan はじめの第一歩

今回の検証は terraform plan までをゴールとしているため、なんだかいい感じの結果に終わりました。
ただ、実際に本番運用へ移行するとなると、まだまだ検証できていない部分で壁があります。

特に私が懸念しているのは、リソースに抜け漏れがないか、という点です。
今回は検証なので AI の回答の通りに進めましたが、本番移行となると現時点では人間の目で確認が必要かなと思っています。
(そもそも Terraform 化したくないリソースを含んでしまう、Terraform化したいリソースが抜けている、など)

Terraform 化は技術的にはほぼ自動化できるが、何を管理下に置くかの判断は人間がやるべき — 現時点でAIを使う上では当然のことですね(用途による・・・)。

私自身、AWS の MCP に触れたのは今回が初めてでしたが、非常に便利と思う反面、やはり恐怖もあります。
権限設定や人間との責任分担をしっかり設計し、業務にも取り入れていければと思います。