
AWS HealthのLifecycleイベントをAWS DevOps Agentで自動調査させてみた
はじめに
AWS HealthのLifecycleイベント(ランタイム廃止・インスタンスタイプ廃止など)は、通知を受け取っても対応が必要なリソースの洗い出しや優先順位の判断などが必要です。
リソースが多い環境ではこの調査だけで相応の時間がかかります。
本記事では、AWS HealthのイベントをトリガーにAWS DevOps Agentが自動で影響範囲を調査し、対応計画まで提示する仕組みを紹介します。
構成概要

AWS Health(Lifecycleイベント)
↓ 1. EventBridgeにイベント発行
Amazon EventBridge
↓ 2. ルールにマッチ
AWS Lambda
↓ 3. Webhookペイロードに変換・送信
AWS DevOps Agent
↓ 4. skillをロードして調査開始
調査レポート生成 + Slack通知
構築手順
AWS DevOps Agent Spaceが作成済みであることを前提とします。
作成方法は公式ドキュメントを参照してください。
1. Generic Webhook の設定
- 対象のエージェントスペースを開き、
機能タブからAgent Space ウェブフックの項目でWebhookを追加をクリック

- ウィザードを進行し、ステップ3で
URLとシークレットキーを生成をクリック

- 表示された Webhook URL と Secret をコピーして控え(またはcsvファイルでダウンロード)、
追加をクリック
Secret は生成時に一度しか表示されないので、必ず控えておきましょう。
2. Lambda関数の作成
EventBridgeから受け取るAWS Health イベントを、DevOps Agent Webhookのペイロード形式に変換して送信するLambda関数を作成します。
Lambda以外のサービス(EC2、RDSなど)のLifecycleイベントにも対応できるよう汎用的な設計にしています。
2-1. IAMロールの作成
Lambda の実行ロールを作成します。
今回の Lambda はログ出力のみで他のAWSリソースへのアクセスは不要なため、AWSLambdaBasicExecutionRole のみ付与します。
aws iam create-role \
--role-name health-to-devops-agent-lambda \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
aws iam attach-role-policy \
--role-name health-to-devops-agent-lambda \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
2-2. 関数コードの作成
index.py
import hashlib
import hmac
import json
import os
import urllib.request
from base64 import b64encode
from datetime import datetime, timezone
WEBHOOK_URL = os.environ["DEVOPS_AGENT_WEBHOOK_URL"]
WEBHOOK_SECRET = os.environ["DEVOPS_AGENT_WEBHOOK_SECRET"]
def build_payload(event: dict) -> dict:
detail = event["detail"]
service = detail["service"]
event_type_code = detail["eventTypeCode"]
event_region = detail.get("eventRegion", event["region"])
descriptions = detail.get("eventDescription", [])
description_text = next(
(d["latestDescription"] for d in descriptions if d["language"] == "en_US"),
next((d["latestDescription"] for d in descriptions), ""),
)
# PENDING状態のリソースのみ対象(RESOLVEDは除外)
affected = [
e["entityValue"]
for e in detail.get("affectedEntities", [])
if e.get("status", "PENDING") != "RESOLVED"
] or event.get("resources", [])
affected_str = "\n".join(f"- {e}" for e in affected)
return {
"eventType": "incident",
"incidentId": detail["eventArn"],
"action": "created",
"priority": "HIGH",
"title": f"AWS Health: {service} / {event_type_code}",
"description": (
f"【通知内容】\n{description_text}\n\n"
f"【影響リソース ({len(affected)}件)】\n{affected_str}"
),
"timestamp": event["time"],
"service": "AWSHealth",
"data": {
"metadata": {
"eventArn": detail["eventArn"],
"service": service,
"eventTypeCode": event_type_code,
"eventTypeCategory": detail["eventTypeCategory"],
"statusCode": detail["statusCode"],
"actionability": detail.get("actionability", ""),
"region": event_region,
"accountId": event["account"],
"startTime": detail.get("startTime", ""),
"affectedResources": affected,
}
},
}
def send_webhook(payload: dict) -> int:
body = json.dumps(payload).encode("utf-8")
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z")
sig = hmac.new(
WEBHOOK_SECRET.encode("utf-8"),
f"{timestamp}:{body.decode('utf-8')}".encode("utf-8"),
hashlib.sha256,
).digest()
signature = b64encode(sig).decode("utf-8")
req = urllib.request.Request(
WEBHOOK_URL,
data=body,
headers={
"Content-Type": "application/json",
"x-amzn-event-timestamp": timestamp,
"x-amzn-event-signature": signature,
},
method="POST",
)
with urllib.request.urlopen(req) as resp:
return resp.status
def handler(event, context):
detail = event.get("detail", {})
status = detail.get("statusCode", "")
# closed は調査不要なのでスキップ
if status == "closed":
print(f"Skipped: statusCode={status}")
return {"status": "skipped"}
payload = build_payload(event)
print(f"Sending webhook: eventArn={detail['eventArn']}")
status_code = send_webhook(payload)
print(f"Webhook response: {status_code}")
return {"status": "sent", "httpStatus": status_code}
- 補足
eventDescription[].latestDescriptionにはAWS Health ダッシュボードに表示されるイベントの説明テキストが入る。DevOps Agentにそのまま渡すことで、通知の背景情報を調査に活用affectedEntitiesのstatus == "RESOLVED"を除外することで、対応済みリソースを調査対象から外すeventArnをincidentIdに使うことで同一イベントの重複調査を防ぐ
2-3. Lambda関数のデプロイ
AWS Healthのイベントは us-east-1 にのみ発行されるため、Lambdaも us-east-1 にデプロイします。
コードを zip に固めて関数をデプロイします。
<アカウントID> は実際のAWSアカウントIDに置き換えてください。
zip function.zip index.py
aws lambda create-function \
--function-name health-to-devops-agent \
--runtime python3.13 \
--role arn:aws:iam::<アカウントID>:role/health-to-devops-agent-lambda \
--handler index.handler \
--zip-file fileb://function.zip \
--region us-east-1
2-4. 環境変数の設定
Webhook の URL と Secret を環境変数として設定します。
本番環境では AWS Secrets Manager または Systems Manager Parameter Store での管理を推奨します。
| 環境変数名 | 値 |
|---|---|
DEVOPS_AGENT_WEBHOOK_URL |
Generic Webhook URL |
DEVOPS_AGENT_WEBHOOK_SECRET |
Generic Webhook の Secret |
aws lambda update-function-configuration \
--function-name health-to-devops-agent \
--environment 'Variables={
DEVOPS_AGENT_WEBHOOK_URL=<WebhookのURL>,
DEVOPS_AGENT_WEBHOOK_SECRET=<WebhookのSecret>
}' \
--region us-east-1
3. EventBridgeルールの設定
EventBridgeのルールもus-east-1に作成します。
今回はイベントパターンのフィルタリング条件を以下のようにしています。
| フィールド | 値 | 意味 |
|---|---|---|
source |
aws.health |
AWS Health からのイベントに限定 |
detail-type |
AWS Health Event |
Health イベントのみ対象 |
eventTypeCategory |
scheduledChange |
計画的な変更通知(ランタイム廃止・インスタンスタイプ廃止など) |
statusCode |
upcoming, open |
対応が必要なアクティブなイベントのみ(closed は除外) |
イベントパターンを指定してルールを作成します。
aws events put-rule \
--name "health-to-devops-agent" \
--event-pattern '{
"source": ["aws.health"],
"detail-type": ["AWS Health Event"],
"detail": {
"eventTypeCategory": ["scheduledChange"],
"statusCode": ["upcoming", "open"]
}
}' \
--state ENABLED \
--region us-east-1
ルールのターゲットとしてLambda関数を登録します。
aws events put-targets \
--rule "health-to-devops-agent" \
--targets '[{"Id":"lambda","Arn":"arn:aws:lambda:us-east-1:<アカウントID>:function:health-to-devops-agent"}]' \
--region us-east-1
EventBridgeからLambdaを呼び出す権限を付与します。
aws lambda add-permission \
--function-name health-to-devops-agent \
--statement-id allow-eventbridge \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:us-east-1:<アカウントID>:rule/health-to-devops-agent \
--region us-east-1
4. Skills の設定
4-1. skill の作成
DevOps Agent の Skills 機能を使うと、エージェントが調査に使う手順書を事前に定義できます。
skill なしでも調査は開始されますが、skill を設定することで調査の品質を安定させることができます。
今回は、LambdaだけでなくRDS・EC2など他のサービスのLifecycleイベントにも適用できるよう、汎用的な skill として定義しました。
skill で定義した調査手順は以下の5ステップです。
- 影響リソースの特定と現状確認(移行済みリソースは除外)
- リソースごとの役割・稼働頻度・下流依存を確認し、重要度を判定(HIGH / MEDIUM / LOW)
- 通知文からライフサイクルスケジュールを抽出し、各期限の影響を整理
- サービスごとの移行難度を評価(Lambdaはランタイムとレイヤー互換性、RDSはバージョンアップ影響など)
- 重要度・難度・スケジュールをもとに、優先度付きの移行計画を生成
SKILL.md
---
name: aws-health-lifecycle-investigation
description: >
Investigation procedures for AWS Health lifecycle events (scheduledChange category),
including runtime deprecations, end-of-support notices, and instance type retirement for any
AWS service. Use this skill when the incident title matches the pattern "AWS Health: {SERVICE} /
{EVENT_TYPE_CODE}" — for example "AWS Health: Lambda / AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT",
"AWS Health: RDS / AWS_RDS_PLANNED_LIFECYCLE_EVENT", or "AWS Health: EC2 / AWS_EC2_INSTANCE_RETIREMENT_SCHEDULED".
Activates whenever the incident originates from AWS Health and concerns a planned lifecycle change
requiring customer action.
---
# AWS Health Lifecycle Event Investigation
Use this skill when an AWS Health notification arrives for a planned lifecycle change
(runtime deprecation, end-of-support, instance type retirement, etc.) on any AWS service.
## Step 1: Identify affected resources and current state
From the incident metadata (eventArn, service, eventTypeCode, affectedResources):
- Confirm each affected resource exists and retrieve its current configuration
- Check whether the resource has already been migrated (if so, mark as "Already mitigated" and exclude from plan)
- Note the region for each resource
## Step 2: Analyze each resource's role and criticality
For each affected resource, determine:
- **Role / purpose**: What workload does this resource serve?
- **Public exposure**: Is it reachable from the internet or directly customer-facing?
- **Usage frequency**: Check relevant CloudWatch metrics over the past 30 days
- **Downstream dependencies**: What services or systems depend on this resource?
Classify each resource by criticality:
| Criticality | Criteria |
|---|---|
| HIGH | Directly customer-facing or on a critical data path |
| MEDIUM | Internal workloads, batch processing, event-driven pipelines |
| LOW | Scheduled jobs, dev/test resources, low-traffic background tasks |
Service-specific signals to look for:
- **Lambda**: trigger type (API Gateway → HIGH), attached Layers, invocation frequency
- **RDS**: Multi-AZ, read replicas, connected applications, backup retention
- **EC2**: instance type, attached EBS volumes, Elastic IP, Auto Scaling group membership
## Step 3: Extract the lifecycle timeline from the notification
Parse the schedule from the notification description (available in the incident description field).
Identify and present all deadline dates in chronological order, with the impact of each date.
## Step 4: Assess migration complexity per resource
- **Lambda**: target runtime version, breaking changes between current and target, Layer compatibility
- **RDS**: target engine version, major vs minor upgrade path, parameter group changes, downtime window
- **EC2**: replacement instance type, AMI compatibility, user data, instance store vs EBS
## Step 5: Produce a prioritized migration plan
Output a summary table with: Resource / Criticality / Complexity / Recommended action / Suggested deadline.
Scheduling guidance relative to the earliest hard deadline:
- HIGH: complete 3 months before / MEDIUM: 2 months before / LOW: 1 month before
## Notes
- The affectedEntities list may not enumerate all affected resources in large accounts.
Cross-check with service APIs (e.g., lambda:ListFunctions filtered by runtime).
- If a resource cannot be updated, flag for manual review and escalation.
4-2. skill の登録
-
対象のエージェントスペースを開き、
オペレーターアクセスをクリック -
左ペインの
スキルをクリックし、カスタムスキルの項目でスキルを追加をクリック

スキルをアップロードをクリック

- zip化した
SKILL.mdを追加し、エージェントタイプですべてのタスクを選択してアップロードをクリック

正常にアップロードができるとスキルの一覧画面に表示されます。

動作確認
テストイベントの用意
AWS Healthの通知は発生タイミングを制御できないため、テストイベントを用意して動作確認をしました。
EventBridgeのペイロード形式に準拠したテストイベントを用意します。
今回はLambda Python 3.10廃止通知を想定したイベントで検証しました。
(ペイロード形式は AWS公式ドキュメント を参照してください。)
test-event.json
{
"version": "0",
"id": "test-event-001",
"detail-type": "AWS Health Event",
"source": "aws.health",
"account": "<アカウントID>",
"time": "2026-05-24T02:00:00Z",
"region": "us-east-1",
"resources": [
"arn:aws:lambda:ap-northeast-1:<アカウントID>:function:myFunction"
],
"detail": {
"eventArn": "arn:aws:health:ap-northeast-1::event/LAMBDA/AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT/...",
"service": "LAMBDA",
"eventTypeCode": "AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT",
"eventTypeCategory": "scheduledChange",
"eventScopeCode": "ACCOUNT_SPECIFIC",
"communicationId": "...",
"statusCode": "upcoming",
"eventRegion": "ap-northeast-1",
"startTime": "Thu, 31 Oct 2026 07:00:00 GMT",
"lastUpdatedTime": "...",
"eventDescription": [{
"language": "en_US",
"latestDescription": "We are contacting you as we have identified..."
}],
"affectedEntities": [
{"entityValue": "arn:aws:lambda:...:function:myFunction", "status": "PENDING"}
],
"actionability": "ACTION_REQUIRED"
}
}
以下のコマンドでテストイベントを発行します。
aws lambda invoke \
--function-name health-to-devops-agent \
--payload fileb://test-event.json \
--region us-east-1 \
response.json && cat response.json
DevOps Agent コンソールのインシデントレスポンスダッシュボードに新しい調査が追加され、ステータスが 進行中 に変わることを確認します。

Slackと接続しておくと、調査の進行状況や結果を任意のSlackチャンネルに通知することもできます。
接続方法は公式ドキュメントを参照してください。
調査結果
以下がDevOps Agentの調査結果です。
調査ログには スキルを読み込み: aws-health-lifecycle-investigation と出力されており、事前に定義した skill の手順通りに調査が進められていることを確認できました。
調査結果
収集した情報を基に、移行計画をまとめます。
AWS Health: Lambda Python 3.10 ランタイム廃止対応 - 調査報告
概要
AWS Healthから、Python 3.10ランタイムの計画的な廃止に関する通知を受け取りました。アカウント内の3つのLambda関数が影響を受けます。
ステップ2: 影響を受けるリソースの分析
1. userRegistHandler
ARN: arn:aws:lambda:ap-northeast-1:<アカウントID>:function:userRegistHandler
役割: DynamoDBへの読み書きを行うバックエンド、RESTful APIエンドポイント(API Gateway連携)
構成:
ハンドラー: lambda_function.lambda_handler
タイムアウト: 10秒
メモリ: 512 MB
環境変数: SAVEBUCKET=example-contents
レイヤー: なし
最終更新: 2025-11-08
公開状態: API Gateway経由で外部公開されている可能性が高い
使用頻度: 過去30日間の呼び出しメトリクスなし(低使用率または未使用)
下流依存: DynamoDB、S3バケット
重要度: MEDIUM〜HIGH - API Gateway連携のため顧客向けの可能性あり
2. s3EventProcessor
ARN: arn:aws:lambda:ap-northeast-1:<アカウントID>:function:s3EventProcessor
役割: S3トリガーでオブジェクトメタデータを取得
構成:
ハンドラー: lambda_function.lambda_handler
タイムアウト: 3秒
メモリ: 128 MB
レイヤー: なし
最終更新: 2024-10-07
公開状態: 内部処理(S3イベント駆動)
使用頻度: 過去30日間の呼び出しメトリクスなし
下流依存: S3バケット
重要度: MEDIUM - イベント駆動の内部ワークロード
3. bounceNotifier
ARN: arn:aws:lambda:ap-northeast-1:<アカウントID>:function:bounceNotifier
役割: SNSトリガーでメッセージをログに記録
構成:
ハンドラー: lambda_function.lambda_handler
タイムアウト: 3秒
メモリ: 128 MB
レイヤー: なし
最終更新: 2024-10-07
公開状態: 内部処理(SNSイベント駆動)
使用頻度: 過去30日間の呼び出しメトリクスなし
下流依存: SNSトピック、CloudWatch Logs
重要度: LOW〜MEDIUM - ログ記録用の補助機能
ステップ3: ライフサイクルタイムライン
日付 影響内容
2026年10月31日 セキュリティパッチおよび更新の適用終了
2026年11月30日 Python 3.10を使用した新規Lambda関数の作成不可
2027年1月15日 Python 3.10を使用する既存関数の更新不可(ハードデッドライン)
ステップ4: 移行の複雑性評価
関数 移行の複雑性 理由
userRegistHandler 低 Layerなし、標準的なハンドラー構成
s3EventProcessor 低 Layerなし、標準的なハンドラー構成
bounceNotifier 低 Layerなし、標準的なハンドラー構成
移行要件:
ターゲットランタイム: Python 3.13 または Python 3.12(推奨)
破壊的変更の確認: Python 3.10から3.12/3.13への移行に伴う非互換性の確認が必要
依存ライブラリ: 各関数で使用されているPythonライブラリの互換性確認
テスト: 移行後の動作検証(特にuserRegistHandlerはAPI経由での検証が必要)
ステップ5: 優先順位付けされた移行計画
リソース 重要度 複雑性 推奨アクション 推奨期限
userRegistHandler MEDIUM〜HIGH 低 Python 3.13への移行、API Gateway経由での段階的ロールアウト(Canaryデプロイ推奨) 2026年10月15日まで(ハードデッドラインの3ヶ月前)
s3EventProcessor MEDIUM 低 Python 3.13への移行、S3イベントでの動作検証 2026年11月15日まで(ハードデッドラインの2ヶ月前)
bounceNotifier LOW〜MEDIUM 低 Python 3.13への移行、SNSイベントでの動作検証 2026年12月15日まで(ハードデッドラインの1ヶ月前)
推奨アクション
即時対応(1〜2週間以内)
コード互換性チェック:
各関数のコードをローカルまたは開発環境でPython 3.12/3.13環境でテスト
使用しているライブラリの互換性を確認(特にboto3、その他のAWS SDKや外部ライブラリ)
未使用関数の確認:
過去30日間のメトリクスがないため、これらの関数が実際に使用されているか確認
未使用の場合は削除を検討
短期対応(1〜3ヶ月以内)
userRegistHandler の優先移行:
API Gateway連携のため、顧客影響を避けるため最優先で対応
Lambda バージョニングとエイリアスを使用したCanaryデプロイを推奨:
新バージョン(Python 3.13)を作成
API Gatewayで加重ルーティング(例: 10% → 50% → 100%)を設定
各段階でエラー率、レイテンシを監視
s3EventProcessorとbounceNotifierの移行:
userRegistHandlerの移行が成功した後に実施
S3/SNSトリガーでの動作検証を実施
中期対応(移行完了後)
モニタリングと検証:
移行後、CloudWatch Logsでエラーを監視
Invocations、Errors、Durationメトリクスを確認
本番環境での動作を少なくとも2週間監視
ドキュメント更新:
ランタイムバージョンの変更履歴を記録
IaCコード(Terraform、CloudFormationなど)がある場合は更新
注意事項
Lambda Layer: 現在3つの関数すべてLayerを使用していないため、Layer互換性の懸念はありません
最終更新日: すべての関数が2023年10月頃に最終更新されており、約2年半更新されていません。コードレビューと動作確認が特に重要です
権限制約: 現在のIAMロール(DevOpsAgentRole)にはlambda:GetFunction権限がないため、関数コードの詳細確認には追加の権限が必要です
調査の制約
以下の制約により、一部の情報が取得できませんでした:
Lambda関数の詳細設定: lambda:GetFunction権限がないため、関数コードや詳細設定を直接確認できませんでした
実際の使用状況: 過去30日間のメトリクスが空のため、関数が実際に使用されているか、使用されていない(開発/テスト環境)かの判断ができませんでした
この報告書に基づき、まずuserRegistHandlerの優先移行から着手することを強く推奨します。ご不明点や追加の調査が必要な場合はお知らせください。
まとめ
AWS HealthとAWS DevOps Agentを組み合わせることで、以下の流れを自動化できました。
- Lifecycleイベント通知を受信
- skill に定義した手順でリソースの用途・重要度・依存関係を調査
- 対応優先度と移行計画をレポート生成
「通知が来たことに気づく」で終わっていた運用から、「通知が来たら調査と計画立案まで自動で完了している」状態に変えることができます。
今回はAWS Healthを例にしましたが、インシデント対応やセキュリティアラートの初動調査など、さまざまな運用業務に応用できますので是非試してみてください。







