Agent Skillを自作してClaude CodeでCloudFormationリソースインポートを自動化してみた

Agent Skillを自作してClaude CodeでCloudFormationリソースインポートを自動化してみた

2026.03.31

CloudFormationにリソースをインポートするAgent Skillを作ってみた

以前、HashiCorp Agent Skillsのterraform-search-importを使い、既存リソースをTerraform管理下にインポートする記事を書きました。

https://dev.classmethod.jp/articles/terraform-search-import-skill-claude-code/

今回はそのCloudFormation版として、IaC Generatorを活用したcfn-resource-importというAgent Skillを自作し、CloudWatch Logsロググループのインポートを試してみます。

なぜCloudFormation版を作ったのか

Terraform版のterraform-search-importは、terraform queryによる検出からインポートまでを一連の流れで自動化してくれる便利なスキルです。一方、CloudFormationにも同様のユースケースがあります。手動で作成したリソースをCloudFormation管理下に取り込みたい場面は多く、特にIaC Generatorの登場で手順は大幅に簡略化されました。

しかし、IaC Generatorのワークフローは複数のAWS CLIコマンドを順番に実行する必要があり、手順を覚えておくのは手間です。これをAgent Skillとしてまとめれば、Claude Codeに「このリソースをCloudFormationにインポートして」と伝えるだけで済みます。

cfn-resource-importスキルの概要

cfn-resource-importは、CloudFormation IaC Generatorを活用し、既存AWSリソースの検出からCloudFormationスタックへのインポートまでを行うスキルです。

主なユースケースは以下です。

  • 手動で作成したリソースをCloudFormation管理下に取り込む
  • 既存クラウドインフラの棚卸し・監査
  • 複数リージョンにまたがるリソースの検出

Terraform版との対比

観点 Terraform (terraform-search-import) CloudFormation (cfn-resource-import)
検出方法 terraform query (.tfquery.hcl) aws cloudformation start-resource-scan
フィルタリング listブロックのconfig.filter --resource-type-prefix
コード生成 -generate-config-out create-generated-template + get-generated-template
インポート importブロック + terraform apply create-change-set --change-set-type IMPORT + execute-change-set
前提条件 Terraform >= 1.14 + プロバイダーサポート AWS CLI v2 + IaC Generatorのリージョンサポート
スキャン範囲 プロバイダーのlist resourceに依存 Cloud Control API対応リソース全般

大きな違いとして、Terraform版はクエリファイル(.tfquery.hcl)で検索条件を宣言的に記述するのに対し、CloudFormation版はまずアカウント内のリソースを一括スキャンしてから対象を絞り込むアプローチです。

ワークフロー

スキルは以下の流れで動作します。

  1. サポート確認 — 対象リソースがIaC Generatorに対応しているか確認
  2. リソーススキャンstart-resource-scanでアカウント内のリソースを検出
  3. リソース一覧list-resource-scan-resourcesで対象リソースを絞り込み
  4. テンプレート生成create-generated-templateでCloudFormationテンプレートを自動生成
  5. クリーンアップ — 読み取り専用属性の除去、パラメータ化、命名整理
  6. インポート実行create-change-set --change-set-type IMPORTexecute-change-set

スキルの構成

cfn-resource-import/
├── SKILL.md                              # メインスキル定義
├── references/
│   └── MANUAL-IMPORT.md                  # IaC Generator非対応時の手動インポート手順
└── scripts/
    └── list_importable_resources.sh      # インポート可能なリソースタイプ一覧取得

Terraform版と同様に、IaC Generatorに対応していないリソースタイプ向けの手動インポート手順もreferences/MANUAL-IMPORT.mdに記載しています。

やってみた

事前準備: CloudWatch Logsロググループの作成

Terraform版と同じ検証用リソースを使います。AWS CLIでロググループを10個作成します。

for i in $(seq 1 5); do
  aws logs create-log-group --log-group-name "demo-prod-$i"
  aws logs create-log-group --log-group-name "demo-dev-$i"
done

作成を確認します。

aws logs describe-log-groups --log-group-name-prefix "demo-" --query 'logGroups[].logGroupName' --output table
---------------------
|DescribeLogGroups  |
+-------------------+
|  demo-dev-1       |
|  demo-dev-2       |
|  demo-dev-3       |
|  demo-dev-4       |
|  demo-dev-5       |
|  demo-prod-1      |
|  demo-prod-2      |
|  demo-prod-3      |
|  demo-prod-4      |
|  demo-prod-5      |
+-------------------+

Claude Codeでスキルを実行

空のディレクトリでClaude Codeに以下のように依頼します。

既存のCloudWatch Logsロググループ(demo-で始まるもの)をCloudFormationにインポートして

以降のセクションでは、スキルが実行する各ステップの内容を確認していきます。

リソーススキャンの実行

スキルはまず、IaC Generatorでアカウント内のリソーススキャンを開始します。

# スキャンの開始
aws cloudformation start-resource-scan
{
    "ResourceScanId": "arn:aws:cloudformation:ap-northeast-1:123456789012:resourceScan/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

スキャンの完了を待ちます。アカウント内のリソース数によりますが、数分かかることがあります。

aws cloudformation describe-resource-scan \
  --resource-scan-id <scan-id> \
  --query '[Status,PercentageCompleted]' \
  --output text
COMPLETE    100.0

Terraform版のterraform queryはクエリファイルで対象を絞り込んで検索するのに対し、CloudFormation版はアカウント全体をスキャンしてから絞り込みます。このため初回スキャンには時間がかかりますが、24時間以内のスキャン結果は再利用できます。

リソースの検出

スキャン完了後、CloudWatch Logsロググループを絞り込みます。

aws cloudformation list-resource-scan-resources \
  --resource-scan-id <scan-id> \
  --resource-type-prefix "AWS::Logs::LogGroup" \
  --query 'Resources[].{Type:ResourceType,Id:ResourceIdentifier}' \
  --output table

ここではTerraform版と異なり、--resource-type-prefixでリソースタイプ単位のフィルタリングのみが可能です。名前による絞り込みはAPI側では対応していないため、取得結果からdemo-で始まるものをスキルが抽出します。

テンプレート生成

対象リソースを指定して、CloudFormationテンプレートを生成します。

aws cloudformation create-generated-template \
  --generated-template-name "demo-log-groups" \
  --resources '[
    {
      "ResourceType": "AWS::Logs::LogGroup",
      "ResourceIdentifier": {"LogGroupName": "demo-dev-1"},
      "LogicalResourceId": "DemoDev1"
    },
    {
      "ResourceType": "AWS::Logs::LogGroup",
      "ResourceIdentifier": {"LogGroupName": "demo-dev-2"},
      "LogicalResourceId": "DemoDev2"
    }
  ]' \
  --template-configuration '{"DeletionPolicy":"RETAIN","UpdateReplacePolicy":"RETAIN"}'

テンプレート生成が完了したらダウンロードします。

aws cloudformation get-generated-template \
  --generated-template-name "demo-log-groups" \
  --format YAML \
  --query 'TemplateBody' \
  --output text > generated-template.yaml

生成されたテンプレート(一部抜粋)です。

AWSTemplateFormatVersion: '2010-09-09'
Description: Generated template for demo log groups

Resources:
  DemoDev1:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      LogGroupName: demo-dev-1
      RetentionInDays: 0
      LogGroupClass: STANDARD

  DemoProd1:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      LogGroupName: demo-prod-1
      RetentionInDays: 0
      LogGroupClass: STANDARD

  # ... 残り8個も同様

Terraform版ではimportブロックがコードに含まれるのに対し、CloudFormation版ではテンプレートとインポート対象リソースの指定が分離されています。また、DeletionPolicy: Retainが設定されるため、スタック削除時に実リソースが消えない安全設計になっています。

インポートの実行

IMPORTタイプのChange Setを作成して、リソースをスタックにインポートします。

aws cloudformation create-change-set \
  --stack-name "demo-log-groups" \
  --change-set-name "initial-import" \
  --change-set-type IMPORT \
  --template-body file://generated-template.yaml \
  --resources-to-import '[
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoDev1","ResourceIdentifier":{"LogGroupName":"demo-dev-1"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoDev2","ResourceIdentifier":{"LogGroupName":"demo-dev-2"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoDev3","ResourceIdentifier":{"LogGroupName":"demo-dev-3"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoDev4","ResourceIdentifier":{"LogGroupName":"demo-dev-4"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoDev5","ResourceIdentifier":{"LogGroupName":"demo-dev-5"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoProd1","ResourceIdentifier":{"LogGroupName":"demo-prod-1"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoProd2","ResourceIdentifier":{"LogGroupName":"demo-prod-2"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoProd3","ResourceIdentifier":{"LogGroupName":"demo-prod-3"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoProd4","ResourceIdentifier":{"LogGroupName":"demo-prod-4"}},
    {"ResourceType":"AWS::Logs::LogGroup","LogicalResourceId":"DemoProd5","ResourceIdentifier":{"LogGroupName":"demo-prod-5"}}
  ]'

Change Setの内容を確認します。

aws cloudformation describe-change-set \
  --stack-name "demo-log-groups" \
  --change-set-name "initial-import"
{
    "Changes": [
        {
            "ResourceChange": {
                "Action": "Import",
                "LogicalResourceId": "DemoDev1",
                "ResourceType": "AWS::Logs::LogGroup"
            }
        }
    ],
    "Status": "CREATE_COMPLETE"
}

すべてのリソースがAction: Importであることを確認し、Change Setを実行します。

aws cloudformation execute-change-set \
  --stack-name "demo-log-groups" \
  --change-set-name "initial-import"

スタックのステータスを確認します。

aws cloudformation describe-stacks \
  --stack-name "demo-log-groups" \
  --query 'Stacks[0].StackStatus' --output text
IMPORT_COMPLETE

10個のロググループがすべてCloudFormation管理下にインポートされました。

Terraform版との手順比較

同じロググループのインポートで手順を比較すると、ワークフローの違いが見えてきます。

ステップ Terraform版 CloudFormation版
環境準備 terraform init なし(AWS CLIのみ)
リソース検出 .tfquery.hcl作成 → terraform query start-resource-scanlist-resource-scan-resources
コード生成 terraform query -generate-config-out create-generated-templateget-generated-template
インポート宣言 importブロックをコードに含める --resources-to-importでJSON指定
実行 terraform planterraform apply create-change-setexecute-change-set

Terraform版はクエリからインポートまでHCLファイルで完結する一方、CloudFormation版はAWS CLIコマンドの連携が中心です。Agent Skillがこの手順をラップしてくれるため、利用者は違いを意識する必要がありません。

後片付け

検証用リソースを削除します。DeletionPolicy: Retainが設定されているため、スタックを削除してもロググループは残ります。

# スタックの削除
aws cloudformation delete-stack --stack-name "demo-log-groups"

# ロググループの削除
for i in $(seq 1 5); do
  aws logs delete-log-group --log-group-name "demo-prod-$i"
  aws logs delete-log-group --log-group-name "demo-dev-$i"
done

おわりに

Terraform版のterraform-search-importをベースに、CloudFormation IaC Generatorを活用したcfn-resource-importスキルを自作し、CloudWatch Logsロググループのインポートを試しました。

Claude Codeにインポートしたい旨を伝えるだけで、リソーススキャンの開始からテンプレート生成、Change Setの作成・実行までを一連の流れで実行してくれます。IaC GeneratorのAPI呼び出し手順を覚えていなくても、スキルが適切なコマンドを組み立ててくれるため、CloudFormationでの既存リソース管理のハードルが下がります。

この記事をシェアする

関連記事