請求アラートから始まりました。

AWS billing alert email: estimated charges of $252.61 crossed the $250 threshold on my BillingAlertAbove250 alarm

推定請求額が250ドルを超えました。怖い金額ではありませんでしたが、確認するきっかけになりました。そして実際に気になったのは金額ではなく、アラートそのものでした。以前に設定したもので、しきい値が古くなっていることがわかりました。

そこでアラートがどこにあるかを探しました。

2014年に作成して完全に忘れていた BillingAlerts CloudFormationスタックから来ていました。つまり、忘れていたものが、他の忘れていたすべてについて警告していたのです。

スタック一覧を開くと、それだけではありませんでした。認識できないスタックがずらりと並んでいました。長年の残骸がただそこに存在していました。

忘れ去られたものは何も壊しません。夜中の2時にページングすることもありません。ただ静かに課金し続け、請求書を見てその半分が何のためのものか思い出せないだけです。放置されたまま動作しているリソースは、無駄なクラウド支出の最大の原因の一つで、ある推定では平均的なクラウド予算の4分の1程度を占めています。

1つのアラートを更新しようとしたら、混乱した状態に直面しました。

念のため、これらのスタックはそれほどコストがかかっていたわけではありません。停止したインスタンスや、半分削除された残骸です。もし252ドル相当だったら、毎月アラートが鳴っていたでしょう。しかし、それがポイントです。不要なものをすべて取り除かないと、実際にコストがかかっているものがわからないのです。

だからアラートは後回しにして、まずこれらの古いスタックを削除することにしました。

通常、これは面倒な作業です。コンソールを開いて各スタックを探し、削除をクリックし、待機し、リフレッシュし、成功したかを確認するか、CLIコマンドを書く必要があります。難しいわけではありませんが、退屈です。後回しにし続ける作業です。

そして、これがまさに始まりでした。コンソールでのClickOpsです。ムンバイリージョンで古いDirectory Serviceディレクトリを手作業で削除し、画面をクリックしてスピナーを待機していたところ、ふと気づきました。わずか10分間の手作業クリックで、まだ山積みのスタックが残っていました。これをすべて自分でやる必要はありませんでした。

なぜまだクリックしていたのか?

Kiroを開きました。Agent Toolkit for AWSが搭載されており、やりたいことを説明するだけでよかったのです。以前のブログI Switched to the Agent Toolkit for AWS. Here's Why.でセットアップ方法を説明しています。

コンソールもCLIも不要でした。エージェントとチャットして、残りを任せました。優秀なアシスタントのように!

AWS CLIがインストール済みなら、次のコマンドを実行するだけです:

aws configure agent-toolkit

Enter fullscreen mode Exit fullscreen mode

まず、何があるかを見せる

まず、エージェントにリージョン内のCloudFormationスタックを一覧表示するよう依頼しました。

Kiro chat where the agent lists 12 CloudFormation stacks in my region, showing each stack name and status

12個のスタックが返ってきました。一部は認識できましたが、一部は古いものでした。2014年のbilling-alertsスタック、2021年のパッチ適用・コンプライアンススタック、CDKブートストラップツールキット。そして実際に削除したいものでした。

4つのスタックを選んで削除するようエージェントに指示しました。

削除前に確認を求めた

これは重要なので、まず指摘しておきます。

The agent listing the four stacks it is about to delete and asking me to confirm, warning that removing the resources cannot be easily undone

エージェントは依頼した瞬間に削除を開始しませんでした。何かを実行する前に、4つのスタックを一覧表示し、リソースの削除は簡単に元に戻せないことを明確に伝え、確認を求めました。

インフラストラクチャの削除は元に戻せません。

「実行」と言うと、行動しました。

The agent confirming that the delete requests for the four stacks have been submitted

「ただ処理して」というスピードを、破壊的なアクションのチェックポイントを諦めることなく得られました。

コードで結果を確認、毎秒コンソールをリフレッシュする必要なし

削除リクエストが送信されると、エージェントはスクリプトを作成し、ツールキットのサンドボックスで実行して4つすべてのステータスを一度に確認しました。

A Python script the agent wrote and ran in the toolkit sandbox with boto3, checking the delete status of all four stacks in parallel

4つすべてを並列で確認し、すでに削除されている可能性のあるスタックを処理し、クリーンなステータスマップを返しました。すべてがboto3を備えたリモートサンドボックスで実行されました。私のマシンは何も実行しませんでした。

3つは正常に削除されましたが、1つは拒否されました。

The status result showing three stacks deleted cleanly while aws-sam-cli-managed-default came back DELETE_FAILED

4番目のスタック aws-sam-cli-managed-defaultDELETE_FAILED で返ってきました。

そこでエージェントはスタックイベントを取得して原因を調べました。失敗は1つのリソース、SAMがデプロイ成果物に使用するS3バケット (SamCliSourceBucket) を指していました。メッセージは具体的でした:

削除しようとしたバケットは空ではありません。バケット内のすべてのバージョンを削除する必要があります。

このバケットにはバージョニングが有効になっていました。つまり「バケットを空にする」だけでは不十分です。すべてのオブジェクトバージョンとすべての削除マーカーを削除しないと、CloudFormationはまだバケットを削除できません。そのため、コンソールでのクイック「空にする」操作では修正できない場合があります。

エージェントは原因を説明し、バケットを適切に空にして再試行することを提案しました。私は「はい」と言いました。

この一連の作業、バージョニングされたバケットの問題を思い出し、バケット名を探し、削除マーカーもカウントされることに気づき、手動で空にしてから再試行するという流れは、通常自分で苦労して行う部分です。エージェントは削除失敗とフルバケットを結びつけ、処理しました。

The agent emptying the versioned S3 bucket, deleting every object version and delete marker, then retrying the stack delete so all four stacks are gone

4つすべてが削除されました。

なぜこれが違ったのか

ここで実際に何が変わったのかを明確にしておきます。「AIを使ってスタックを削除した」というのがポイントではありません。

ポイントは、ループ全体が1つの場所に留まったことです。目標を平易な言葉で説明しました。エージェントはアカウントの実際の状態を一覧表示し、破壊的なステップを確認し、それを実行するコードを実行し、壊れたものを私がドキュメントを掘ることなくデバッグ・修正しました。

これを可能にしたいくつかの要因:

実際のコードを安全に実行した。 ツールキットはエージェントにboto3を備えたサンドボックス化されたPythonランタイムを提供します。数行で状態を確認・フィルタリング・アクションを実行でき、ラップトップで何も実行する必要がありません。

リスクのある部分を確認した。 削除は一方通行です。エージェントはそれを認識し、最初に確認しました。

失敗を最初から最後まで処理した。 コンソールではここで詰まっていたでしょう。DELETE_FAILED でポップアップが表示され、再試行を許可しますが、バケットを保持(アカウントに孤立させる)するか、S3コンソールに移動して自分で空にするかのどちらかです。どちらもコンテキストスイッチであり、「保持」はバケットを残すだけです。エージェントはこれらすべてをスキップしました。スタックイベントを読み、バージョニングされたバケットを見つけ、適切に(バージョンと削除マーカーを含めて)空にし、チャットを離れることなく、孤立させることなく再試行しました。

すべてが監査可能。 すべてが管理された AWS MCP Server を通じて行われるため、すべての呼び出しがCloudTrailに記録されます。次で詳しく説明します。

CloudTrailですべての呼び出しを確認できた

これが「エージェントにインフラストラクチャを削除させた」を怖いものから問題ないものに変える部分です。

エージェントが行ったすべてのアクションは管理されたAWS MCP Serverを通じて行われ、それらの呼び出しはすべて CloudTrail に表示されます。確認しました。4つの DeleteStack イベントは私のIDの下にあり、明確な指紋を持っています:

eventName:        DeleteStack
userIdentity:     gaonkarr
sourceIPAddress:  aws-mcp.amazonaws.com
userAgent:        aws-mcp.amazonaws.com

Enter fullscreen mode Exit fullscreen mode

aws-mcp.amazonaws.com の値は、エージェントのアクションと自分のアクションを区別する方法です。同日早い時間にコンソールで手動でスタックを削除しましたが、それらのイベントは完全に異なっていました:実際のブラウザユーザーエージェントと私の実際のIPアドレスです。したがって、監査証跡には実際に誰が何をしたかが表示されます。私のクリックと、エージェントが私の代わりに実行したアクションです。

このクリーンアップからの5つの DeleteStack イベントを、CloudTrailからそのまま示します:

Time (UTC) Stack Identity Source IP User Agent
14:23:18 CdkPipelineStack gaonkarr aws-mcp.amazonaws.com aws-mcp.amazonaws.com
14:23:18 buildon-sam-app gaonkarr aws-mcp.amazonaws.com aws-mcp.amazonaws.com
14:23:18 aws-sam-cli-managed-default (1st attempt) gaonkarr aws-mcp.amazonaws.com aws-mcp.amazonaws.com
14:23:19 sam-app gaonkarr aws-mcp.amazonaws.com aws-mcp.amazonaws.com
14:24:19 aws-sam-cli-managed-default (retry) gaonkarr aws-mcp.amazonaws.com aws-mcp.amazonaws.com

再試行は証跡にそのまま残っています。aws-sam-cli-managed-default の削除は2回表示されます:失敗したときと、バケットを空にした後にエージェントが再試行した約1分後です。失敗から修正までの全シーケンスが保存されています。

正直な注意点: DeleteStack の呼び出しは 管理イベント で、CloudTrailはデフォルトでログに記録します。しかし、バケットを実際に空にしたS3の DeleteObjects の呼び出しは データイベント で、そのバケットのデータイベントログを有効にしない限り記録されません。したがって、スタックの削除は明確に確認できましたが、個々のオブジェクトの削除は確認できませんでした。オブジェクトレベルのアクションを証跡に含めたい場合は、まずS3データイベントを有効にする必要があります。

次に何をするか

4つのスタックを削除して気持ちが良くなりました。そこで好奇心からエージェントに尋ねました:

AWSアカウントをスキャンして、残っているリソースを特定できますか?

The agent scanning common AWS services for leftover resources, starting in the default region and then expanding to the others

アカウントの一般的なサービスをスキャンしました。まずデフォルトのリージョンから開始し、その後他のリージョンに拡大しました。4ページ以上のリストになりました。🫣

ワークショップ、デモ、古いプロジェクトからの残りのリソースをかなりの数見つけ、Cost Impact Summaryを提供しました。

  • 停止したEC2インスタンス3つ、最も古いものは2021年のもの。

  • アタッチされていないEBSボリューム14個、一部は2014年に作成され、何にもアタッチされていないストレージに対して静かに課金され続けている。

  • 関連付けられていないElastic IP 5個、何の作業もしていないアドレスに対して月額約18ドル。

  • S3バケット122個、忘れていたロードバランサー、サポート終了から何年も経過したランタイムで動作しているLambda関数16個。

どれも何も壊していません。それが長く生き残った理由です。

A Cost Impact Summary from the agent listing leftover resources: stopped EC2 instances, unattached EBS volumes, unassociated Elastic IPs, S3 buckets, a load balancer, and old Lambda functions

これらすべてを見つけるのが通常最も難しい部分です。すべてのサービスを、すべてのリージョンで、1つのコンソールずつクリックしていく作業が、1つも削除する前に何時間もかかる理由です。今回は1回尋ねるだけで、エージェントがリスト全体を渡してくれました。

いつも手をつけるのが大変だと思っていた作業が、今では簡単な部分になりました。

そこで、新しいアシスタントの助けを借りてクリーンアップすることにします。

もしあなたのアカウントが私のものと似ているなら、あなたのものでもあるべきでしょう。


そこで何を見つけたか教えてください。私はそれについて忘れていた唯一の人ではないと思います。

Follow along