
Agent Skillを自作してClaude CodeでCloudFormationリソースインポートを自動化してみた
CloudFormationにリソースをインポートするAgent Skillを作ってみた
以前、HashiCorp Agent Skillsのterraform-search-importを使い、既存リソースをTerraform管理下にインポートする記事を書きました。
今回はその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版はまずアカウント内のリソースを一括スキャンしてから対象を絞り込むアプローチです。
ワークフロー
スキルは以下の流れで動作します。
- サポート確認 — 対象リソースがIaC Generatorに対応しているか確認
- リソーススキャン —
start-resource-scanでアカウント内のリソースを検出 - リソース一覧 —
list-resource-scan-resourcesで対象リソースを絞り込み - テンプレート生成 —
create-generated-templateでCloudFormationテンプレートを自動生成 - クリーンアップ — 読み取り専用属性の除去、パラメータ化、命名整理
- インポート実行 —
create-change-set --change-set-type IMPORT→execute-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-scan → list-resource-scan-resources |
| コード生成 | terraform query -generate-config-out |
create-generated-template → get-generated-template |
| インポート宣言 | importブロックをコードに含める |
--resources-to-importでJSON指定 |
| 実行 | terraform plan → terraform apply |
create-change-set → execute-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での既存リソース管理のハードルが下がります。









