「真実はいつもひとつ!」
ということで今回はCloudFormationのdriftの犯人をDevOps Agentに特定してもらいました。
この記事で分かること
- AWS ConfigのマネージドルールでCloudFormationのドリフト検知しAWS DevOps Agentに「CloudTrailで変更者を特定しろ」と自動で調査を起票する構成
- 調査完了後、変更を実施したIAMユーザー本人にSESでメールを直接送るところまでの実装
0. 先に...全体アーキテクチャ
1. CloudFormationのドリフト検知を自動化する
CloudFormationで作ったリソースを、誰かがマネジメントコンソールからポチポチっと直接いじってしまう。誰もが若かりし頃、一度はやったと思います。
ドリフトとは
SGにポート開けたり、EC2のタグを書き換えたり——テンプレートには何の変更もないのに、実リソースだけがこっそり書き換わっている状態のことです。
AWS Configのマネージドルール(CLOUDFORMATION_STACK_DRIFT_DETECTION_CHECK)を使えばこれを定期的に実行して「ドリフトしているかどうか」を機械的に検出できます。しかし実務で本当に知りたいのはその先です。
誰が、いつ、何の手段で、そのリソースを変更したのか
これをドリフト検知のたびに手動でCloudTrailを漁って調べるのは正直かなり骨が折れます。
イベント名の絞り込み、時間範囲の指定、userIdentityからのユーザー特定……。
この調査を自動化できないかというのが出発点です。
2. 役割解説
| 工程 | 担当 | 備考 |
|---|---|---|
| ドリフトの定期検査(1時間おき) | AWS Config マネージドルール |
CLOUDFORMATION_STACK_DRIFT_DETECTION_CHECK。間隔はOne_Hour
|
| コンプライアンス遷移イベントの中継 | EventBridge | COMPLIANT / NON_COMPLIANT の遷移時のみlambdaを起動 |
| ドリフト詳細の取得・起票 |
driftwatch-checker(Lambda) |
DescribeStackResourceDriftsで差分を取得して起票するだけ |
| 変更者特定の自律調査 | AWS DevOps Agent | CloudTrailのWrite系イベントを解析 |
| 変更者本人へのメール通知 |
driftwatch-notifier(Lambda) |
SESで送信 |
工夫:Slackではなく本人だけにSESメール通知
AWS DevOps AgentはAgent Space側の設定で、調査完了時にSlackチャンネルへ投稿することができますが、あえてIAMタグからメールアドレスを取得して本人にこっそり通知する方式を取りました。
Slackのチャンネル投稿だけに頼ると、ちょっと気まずい問題が起きます。「◯◯さんがセキュリティグループを勝手に書き換えました」という調査結果が、チームの目に触れるチャンネルにそのまま流れてしまうのです。うっかりミスをした本人からすると、いきなり公開処刑されるような形になってしまいます。
3. DevOps Agent呼び出し
実際にDevOps Agentを呼び出している部分を抜粋します。
cfn = boto3.client("cloudformation")
try:
devops_agent = boto3.client("devops-agent") # boto3 のクライアント名はハイフン付き
except Exception as e:
devops_agent = None
print(f"devopsagent client init failed: {e}")
NON_COMPLIANTへの遷移イベントを受けてドリフト詳細を取得できたら、create_backlog_taskで調査を起票します。
# clientToken は評価イベント由来(スタック名+評価時刻)から生成する
digest = hashlib.sha256(f"{stack}|{ordering_ts}".encode("utf-8")).hexdigest()
client_token = f"driftwatch-{digest[:48]}"
task_id, error = None, None
if devops_agent and AGENT_SPACE_ID:
try:
resp = devops_agent.create_backlog_task(
agentSpaceId=AGENT_SPACE_ID,
taskType="INVESTIGATION",
title=f"[driftwatch] {stack} のドリフト調査(変更者特定)"[:400],
description=build_description(stack, drifts), # ドリフト差分 + INVESTIGATION_PROMPT(5節)
priority="HIGH",
clientToken=client_token, # 重複起票防止(冪等性キー)
)
# CreateBacklogTaskResponse は {"task": Task} 構造(taskId はその中)。
task_id = resp.get("task", {}).get("taskId")
except Exception as e:
error = e
print(f"create_backlog_task failed for {stack}: {e}")
このLambdaの実行ロールに必要なDevOps Agent側の権限は、Agent Spaceのリソースに絞ったaidevops:CreateBacklogTaskのみです。
- Effect: Allow
Action: aidevops:CreateBacklogTask
Resource: !Sub "arn:aws:aidevops:${AWS::Region}:${AWS::AccountId}:agentspace/${AgentSpaceId}"
起票時にcreate_backlog_taskへ渡すdescriptionの末尾には、固定の調査依頼文(INVESTIGATION_PROMPT)を必ず付けています。
INVESTIGATION_PROMPT 全文(infra/lambda/drift_checker.py)
INVESTIGATION_PROMPT = """
## 調査依頼
1. AWS CloudTrail で、上記の物理リソースID(例: sg-xxxx)に対する Write 系イベント
(Authorize*, Revoke*, Modify*, Update*, Create*, Delete*, Put*, Run* など状態を変更する操作)を
過去1時間の範囲で検索してください。Get*/List*/Describe* などの参照系イベントは対象外です。
2. 該当イベントの userIdentity から、変更を実施した IAM ユーザー名またはロール名(Username)、
実行時刻、ソースIPアドレス、実行手段(マネジメントコンソール / CLI / SDK)を特定してください。
3. イベントのリクエスト内容が上記のプロパティ差分と一致するか突き合わせ、
①誰が ②いつ ③どのリソースを ④どう変更したか を調査サマリにまとめてください。
4. この変更が引き起こしうるリスク(セキュリティ・可用性・運用・コストの観点で該当するもの)を
簡潔に評価してください。
5. 調査サマリの末尾に「## 変更実施者(1行)」という見出しを設け、
特定したユーザー名と実行時刻を1行で記載してください。その際、
ユーザー名だけでなく完全な IAM ARN(arn:aws:iam::アカウントID:user/ユーザー名
の形式)も必ず含めてください。
6. 調査サマリの末尾に、通知メール転記用の固定形式ブロックを必ず含めてください。
各行は「キー: 値」形式で値は1行、以下の7行のみを ---NOTIFY-BEGIN--- と ---NOTIFY-END--- の行で囲んでください:
---NOTIFY-BEGIN---
変更者: <IAMユーザー名>
変更者ARN: <arn:aws:iam::アカウントID:user/ユーザー名>
日時: <JSTの日時(UTC併記)>
リソース: <物理リソースID(リソース種別、スタック名)>
変更内容: <何がどう変わったか1行で>
実行手段: <CLI/コンソール等(ソースIP)>
リスク: <この変更に伴うリスクを1〜2行で>
---NOTIFY-END---
"""
「参照系イベントは対象外」と明示しているのがポイントです。CloudTrailにはGet/List/Describeのログも大量に流れてくるので、ここを絞らないとノイズに埋もれて肝心のWrite系イベントを見失います。
そして依頼文の末尾では、通知メールに転記するための固定形式ブロックを出力するよう指示しています。
---NOTIFY-BEGIN---
変更者: <IAMユーザー名>
変更者ARN: <arn:aws:iam::アカウントID:user/ユーザー名>
日時: <JSTの日時(UTC併記)>
リソース: <物理リソースID(リソース種別、スタック名)>
変更内容: <何がどう変わったか1行で>
実行手段: <CLI/コンソール等(ソースIP)>
リスク: <この変更に伴うリスクを1〜2行で>
---NOTIFY-END---
4. やってみよう!
ドラフトを発生させるためマネコンでSGのインバウンドを全開放してみましょう。
(この操作...昔やってしまった覚えがある人も多いのではないでしょうか?)
セキュリティリスクのある行為ですのでくれぐれも真似しないようにお願いします
すぐ検知して欲しいので、コマンドで動かします。
aws configservice start-config-rules-evaluation --config-rule-names driftwatch-stack-drift-detection --region ap-northeast-1
5. まとめ
DevOpsAgentは障害解析等で扱うユースケースが注目されがちですが、コスト分析や監査調査も得意だったりします。
実はAWSConfigを使用して検知したドリフトを自動的に是正する仕組みを作ること自体は可能です。
ただ、今回あえてDevOpsAgentを使ってみたのは変更した本人に変更内容やリスクを通知するアプローチには、本人の気づき・成長につながるという価値があると思ったからです。自動是正は楽ですが、人の成長機会を奪うというリスクも負っていると感じております。私は長期的に見て人の成長を補助してくれるようなAIの使い方を今後も模索していきたいと思います。






