内容
以前、こちらのAWS公式ブログにて、アラート要約ツールを紹介いただきました。この仕組みは、Security HubやCloudWatchアラームから連携されるJSONデータをAmazon Bedrockで要約し、その結果をSNS経由でメール送信するものです。
今回、この仕組みを少し拡張し、MCPサーバを利用してAWS公式ドキュメントを検索したうえで要約結果を返す構成を作成してみました。Security HubやCloudWatchアラームの情報をEventBridge経由で連携し、Lambdaで受信する点は公式ブログの構成と同様です。一方で、要約処理の送信先をStrands AgentとAmazon Bedrock AgentCoreで構築したAIエージェントとしています。アラート受信後、必要に応じてAWS Knowledge MCP Serverを検索し、公式ドキュメントに基づいた要約結果を返す仕組みです。
回答サンプル
前回作成したアラート要約ツールでも、アラート内容の要約や対応方法を出力することは可能でした。
### 問題の詳細説明
このアラートは、AWS Security Hubによって検出されたIAMルートユーザーのアクセスキーの存在を示しています。ルートユーザーは、AWSアカウント内ですべてのリソースに完全な管理権限を持つ最も特権のあるユーザーです。ルートユーザーのアクセスキーが存在すると、アカウントのセキュリティリスクが高まります。なぜなら、アクセスキーが悪意のある者に知られると、アカウント全体が制御される可能性があるからです。
### 推奨される対応方法
以下のステップに従って、ルートユーザーのアクセスキーを削除し、アカウントのセキュリティを強化してください:
1. **ルートユーザーのアクセスキーを削除する**
- ルートユーザーは通常、日常的なタスクには使用しないでください。アクセスキーが存在する場合は削除してください。
~~~~~続く~~~~~~~
今回の仕組みでは、これに加えて参照したAWS公式ドキュメントの情報も併せて出力されます。
### 公式ドキュメントに基づく具体的な修正手順
以下の公式ドキュメントを参照してください:
1. **Secure access keys - AWS Identity and Access Management**
- [https://docs.aws.amazon.com/IAM/latest/UserGuide/securing_access-keys.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/securing_access-keys.html)
- このドキュメントでは、ルートユーザーにアクセスキーを作成しないことの重要性と、IAMユーザーに対するアクセスキーの適切な管理方法について説明しています。
2. **Security control recommendations for managing identity and access - AWS Prescriptive Guidance**
- [https://docs.aws.amazon.com/prescriptive-guidance/latest/security-controls-by-caf-capability/identity-and-access-controls.html](https://docs.aws.amazon.com/prescriptive-guidance/latest/security-controls-by-caf-capability/identity-and-access-controls.html)
- このドキュメントでは、ルートユーザーへのアクセスキーの作成を避けることの重要性を強調しています。
~~~~~続く~~~~~~~
要約対象アラート
本仕組みでは、アラートを以下の2種類に分けています。
- MCPサーバを使用して要約・情報補完を行うアラート
- 要約のみを行うアラート
Security HubやAWS Healthをソースとするアラートは、AWS側が提供している内容であり、対応時にAWS公式ドキュメントを参照するケースが多くなります。そのため、これらのアラートではMCPサーバを利用して、公式情報に基づいた要約を行います。一方で、CloudWatchアラームなどのアラートは要約のみを行います。今回の例では、CloudWatchによるEC2のディスク使用率監視や、EventBridgeを利用したEC2ステータス監視を想定しています。これらは自分たちで定義・運用している監視項目であり、アラート発生時の対応も社内で作成した運用マニュアルに沿って行うため、MCPサーバを用いた公式ドキュメント検索は不要としています。
| アラート種別 | アラート例 | MCPサーバ |
|---|---|---|
| Security Hub | ベストプラクティスチェック | ● |
| AWS Health | ソフトウェアのEOLなど仕様変更 | ● |
| CloudWatch | ディスク使用率、死活監視 | × |
| その他 | EC2の起動・停止 | × |
手順
環境の準備
検証用としてUbuntuのEC2インスタンスを用意します。IAMロールにはAdministratorAccessを付与し、インターネット接続が可能な環境とします。
cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.3 LTS (Noble Numbat)"
python3 -V
Python 3.12.3
仮想環境の作成およびパッケージのインストールを行います。
apt update
apt install python3-pip -y
apt install python3-venv -y
# 仮想環境作成
python3 -m venv /root/strands-env
# 仮想環境有効化
source /root/strands-env/bin/activate
# pip アップグレード
pip install --upgrade pip
# パッケージインストール
pip install strands-agents bedrock-agentcore bedrock-agentcore-starter-toolkit boto3 uv
ローカルでの試験
ローカル環境にプログラムを配置し、動作確認を行います。EventBridge経由で連携されることを想定し、以下のテストデータを用意します。
- CloudWatchアラームから連携されるJSONデータ
- Security Hubから連携されるJSONデータ
# CloudWatchアラームテストデータ
vim cw_event_test.json
# Security Hubテストデータ
vim sh_event_test.json
# メインプログラム
mkdir alert_summarize
cd alert_summarize/
vim alert.py
CloudWatchアラームテストデータ
{
"version": "0",
"id": "test-event-xxx",
"detail-type": "CloudWatch Alarm State Change",
"source": "aws.cloudwatch",
"account": "XXXXXXXXXXXX",
"time": "2026-02-01T09:00:00Z",
"region": "ap-northeast-1",
"resources": [
"arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXXX:alarm:sample-alarm"
],
"detail": {
"alarmName": "sample-alarm",
"state": {
"value": "ALARM",
"reason": "Threshold Crossed: datapoint exceeded the threshold.",
"reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2026-02-01T09:00:00.000+0000\"}",
"timestamp": "2026-02-01T09:00:00.000+0000"
},
"previousState": {
"value": "INSUFFICIENT_DATA",
"reason": "Initial alarm creation",
"timestamp": "2026-02-01T08:58:00.000+0000"
},
"configuration": {
"metrics": [
{
"id": "metric-001",
"metricStat": {
"metric": {
"namespace": "AWS/EC2",
"name": "CPUUtilization",
"dimensions": {
"InstanceId": "i-xxxxxxxxxxxxxxxxx"
}
},
"period": 60,
"stat": "Maximum"
},
"returnData": true
}
]
}
}
}
Security Hubテストデータ
{
"version": "0",
"id": "test-event-xxx",
"detail-type": "Security Hub Findings - Imported",
"source": "aws.securityhub",
"account": "XXXXXXXXXXXX",
"time": "2026-02-01T09:30:00Z",
"region": "ap-northeast-1",
"resources": [
"arn:aws:securityhub:ap-northeast-1:XXXXXXXXXXXX:subscription/sample-standard/finding/sample-finding-id"
],
"detail": {
"findings": [
{
"SchemaVersion": "2018-10-08",
"Id": "arn:aws:securityhub:ap-northeast-1:XXXXXXXXXXXX:finding/sample-finding-id",
"ProductArn": "arn:aws:securityhub:ap-northeast-1::product/aws/securityhub",
"GeneratorId": "sample-security-standard/IAM.1",
"AwsAccountId": "XXXXXXXXXXXX",
"Types": [
"Software and Configuration Checks/Security Best Practices"
],
"CreatedAt": "2026-02-01T09:30:00.000Z",
"UpdatedAt": "2026-02-01T09:30:00.000Z",
"Severity": {
"Label": "MEDIUM",
"Normalized": 40
},
"Title": "IAM root user access key should not exist",
"Description": "This finding indicates that a root user access key exists in the account.",
"Resources": [
{
"Type": "AwsAccount",
"Id": "AWS::::Account:XXXXXXXXXXXX",
"Partition": "aws",
"Region": "ap-northeast-1"
}
],
"Compliance": {
"Status": "FAILED"
},
"WorkflowState": "NEW",
"Workflow": {
"Status": "NEW"
},
"RecordState": "ACTIVE"
}
]
}
}
import json
from strands import Agent
from strands.tools.mcp import MCPClient
from strands.models.bedrock import BedrockModel
from bedrock_agentcore import BedrockAgentCoreApp
from mcp.client.streamable_http import streamablehttp_client
app = BedrockAgentCoreApp()
def detect_alert_source(event):
"""EventBridgeのsourceフィールドからアラートソースを判定する"""
source = event.get('source', '')
# Security Hub または AWS Health の判定
if source in ['aws.securityhub', 'aws.health']:
return 'use_mcp_tool'
# その他
else:
return 'other'
@app.entrypoint
def invoke(event, context=None):
alert_text = json.dumps(event, ensure_ascii=False, indent=2)
alert_source = detect_alert_source(event)
try:
model = BedrockModel(
region_name="ap-northeast-1",
model_id="jp.amazon.nova-2-lite-v1:0",
max_tokens=4096
)
# Security Hub または AWS Health の場合のみ MCP Server を使用
if alert_source == 'use_mcp_tool':
mcp = MCPClient(
lambda: streamablehttp_client(
"https://knowledge-mcp.global.api.aws"
)
)
system_prompt = """あなたはAWS運用の専門家です。
このアラートはSecurity HubまたはAWS Healthからの連携です。
AWS Knowledge MCP Server を使用し、公式ドキュメントに基づいて以下を提供してください:
1. 問題の詳細説明
2. 推奨される対応方法
3. 公式ドキュメントに基づく具体的な修正手順
正確性を重視し、公式情報のみを参照してください。"""
agent = Agent(
model=model,
system_prompt=system_prompt,
tools=[mcp],
)
else:
# Security Hub・AWS Health 以外の場合は MCP Server を使用せず、要約のみ
system_prompt = """あなたはAWS運用の専門家です。
このアラートはSecurity Hub・AWS Health以外からの連携です。
アラート内容の事実を正確に要約し、以下を提供してください:
1. アラートの概要
正確性を重視し、アラート内容の事実のみを基に回答してください。"""
agent = Agent(
model=model,
system_prompt=system_prompt,
)
result = agent(alert_text)
return {
'statusCode': 200,
'body': json.dumps({
'alert_source': alert_source,
'source_field': event.get('source', 'unknown'),
'result': result.message
}, ensure_ascii=False, indent=2)
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({
'error': 'Processing failed',
'details': str(e)
})
}
if __name__ == "__main__":
app.run()
上記プログラムを実行します。
python3 alert.py
また、別のコンソールから下記コマンドを実行します。JSONファイルは上記で作成したCloudWatchアラームのテストデータを指定しています。
curl -X POST http://localhost:8080/invocations \
-H "Content-Type: application/json" \
-d @cw_event_test.json
下記、要約した結果が返ってきました。
### **アラートの概要**
このアラートは、**CloudWatch アラームの状態変更**を通知するものです。具体的には、アラームが `ALARM` 状態に変化したことが報告されています。
#### **アラート詳細の要約**
1. **アラーム名**: `sample-alarm`
2. **アラーム状態**:
- **現在の状態**: `ALARM`
- **前回の状態**: `INSUFFICIENT_DATA`(初期アラーム作成時)
3. **アラームがトリガーされた理由**:
- **原因**: 閾値を超えたデータポイントが発生しました。
- **詳細**: アラームが設定されたメトリクス値が、設定された閾値を超えたため、アラームが `ALARM` に変更されました。
4. **メトリクス情報**:
- **メトリクスネーム**: `CPUUtilization`(EC2 インスタンスの CPU 使用率)
- **ネームスペース**: `AWS/EC2`
- **インスタンスID**: `i-xxxxxxxxxxxxxxxxx`
- **統計値**: `Maximum`(最大値)
- **期間**: 60秒ごと
5. **発生日時**:
- **アラーム状態変更日時**: `2026-02-01T09:00:00Z`
- **前回状態のタイムスタンプ**: `2026-02-01T08:58:00Z`
6. **リージョン**: `ap-northeast-1`
7. **リソースARN**:
arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXXX:alarm:sample-alarm
#### **要約ポイント**
- アラームが `ALARM` に変化した原因は、EC2 インスタンス `i-xxxxxxxxxxxxxxxxx` の CPU 使用率が設定された閾値を超えたことです。
- アラームは初期状態から `INSUFFICIENT_DATA` であり、今回の `ALARM` が初めての有効な状態変化です。
- アラームは 60 秒ごとのデータポイントを監視し、`Maximum` 統計値に基づいて動作しています。
次に下記コマンドを実行します。JSONファイルは上記で作成したSecurity Hubアラームのテストデータを指定しています。
curl -X POST http://localhost:8080/invocations \
-H "Content-Type: application/json" \
-d @sh_event_test.json
こちらは出力結果が長いので折りたたんで表示しますが。最初のTool #1: aws___search_documentationの箇所でMCPサーバを使用したことが確認出来ます。また参照した公式ドキュメントのリンクを確認することが出来ます。
Security Hubアラーム要約結果
Tool #1: aws___search_documentation
### **問題の詳細説明**
AWS Security Hubから検出されたアラート「IAM root user access key should not exist」は、アカウントのルートユーザーにアクセスキーがあることを示しています。ルートユーザーはAWSアカウントで最も権限を持つ存在であり、アクセスキーが存在すると、悪意のある攻撃者によってアカウントが乗っ取られるリスクが高まります。このため、セキュリティの観点から、ルートユーザーのアクセスキーを削除することが推奨されています。
### **推奨される対応方法**
1. **ルートユーザーのアクセスキーを削除する**
- ルートユーザーのアクセスキーが存在する場合は、すぐに削除する必要があります。
- ルートユーザーには、コンソールにログインするためのパスワードとMFA(多要素認証)が必要です。アクセスキーは削除し、日常的な作業にはIAMユーザーを使用するようにしてください。
2. **IAMユーザーを作成し、適切な権限を付与する**
- 日常的なAWSリソースの管理には、IAMユーザーを作成し、必要な権限を付与してください。
- 最小権限の原則に従い、ユーザーに必要な権限のみを付与します。
3. **ルートユーザーへのアクセスを制限する**
- ルートユーザーは緊急時や特定のタスクにのみ使用するようにしてください。
- ルートユーザーのメールアドレスや電話番号を正確に設定し、セキュリティを強化してください。
4. **MFAを有効にする**
- ルートユーザーとすべてのIAMユーザーにMFAを有効にすることで、セキュリティをさらに強化できます。
5. **定期的な監査とレビューを行う**
- 定期的にアカウントのセキュリティ設定を確認し、不要なアクセスキーや権限がないかを確認してください。
- AWS ConfigやSecurity Hubを使用して、自動的な監査とアラートを設定することが推奨されます。
### **公式ドキュメントに基づく具体的な修正手順**
#### **1. ルートユーザーのアクセスキーを削除する**
**手順:**
1. **AWSマネジメントコンソールにログインする**
- ルートユーザーとしてAWSマネジメントコンソールにログインします。
2. **IAMコンソールに移動する**
- 左側のメニューから「IAM」を選択します。
3. **ユーザーを選択する**
- 上部の「ユーザー」を選択し、ルートユーザー(通常は「root」)をクリックします。
4. **アクセスキーを削除する**
- 「セキュリティ認証情報」タブに移動します。
- 「アクセスキー」セクションで、「アクセスキーを削除」をクリックします。
- 確認メッセージが表示されたら、「はい」をクリックして削除を確定します。
**公式ドキュメント:**
- [Secure access keys - AWS Identity and Access Management](https://docs.aws.amazon.com/IAM/latest/UserGuide/securing_access-keys.html)
- [SEC01-BP02 Secure account root user and properties - AWS Well-Architected Framework](https://docs.aws.amazon.com/wellarchitected/latest/framework/sec_securely_operate_aws_account.html)
#### **2. IAMユーザーを作成し、適切な権限を付与する**
**手順:**
1. **IAMコンソールに移動する**
- AWSマネジメントコンソールで「IAM」を選択します。
2. **ユーザーを作成する**
- 左側のメニューから「ユーザー」を選択し、「ユーザーを作成」をクリックします。
- ユーザーの名前を入力し、「次のページ」をクリックします。
3. **アクセスタイプの選択**
- 「コンソールアクセス」を選択し、「パスワード」を設定します。
- 必要に応じて「アクセスキー」を選択することもできますが、日常的な作業にはIAMユーザーを使用するため、コンソールアクセスのみでも構いません。
4. **権限の付与**
- 「次の:権限」をクリックします。
- 適切な権限を付与する方法を選択します(例:グループに追加、ポリシーの直接付与など)。
- 最小権限の原則に従い、ユーザーに必要な権限のみを付与します。
5. **ユーザーを作成する**
- 「ユーザーを作成」をクリックして、プロセスを完了します。
**公式ドキュメント:**
- [Creating an IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html)
#### **3. ルートユーザーへのアクセスを制限する**
**手順:**
1. **ルートユーザーのメールアドレスと電話番号を更新する**
- AWSマネジメントコンソールにログインし、「アカウント設定」を選択します。
- 「アカウント設定」をクリックし、「アカウントの詳細」を選択します。
- メールアドレスと電話番号を更新し、正確な情報を設定します。
2. **MFAを有効にする**
- ルートユーザーでログインし、「IAM」を選択します。
- 左側のメニューから「ユーザー」を選択し、ルートユーザーを選択します。
- 「セキュリティ認証情報」タブに移動し、「多要素認証(MFA)」セクションで「MFAデバイスを追加」をクリックします。
- MFAデバイス(例:Google Authenticator、YubiKeyなど)を設定します。
**公式ドキュメント:**
- [SEC01-BP02 Secure account root user and properties - AWS Well-Architected Framework](https://docs.aws.amazon.com/wellarchitected/latest/framework/sec_securely_operate_aws_account.html)
- [Enable MFA for the root user](https://docs.aws.amazon.com/IAM/latest/UserGuide/enable-mfa-for-root.html)
#### **4. 定期的な監査とレビューを行う**
**手順:**
1. **AWS Configを設定する**
- AWS Configを使用して、IAMリソースの監査を行います。
- 「AWS Config」を選択し、「ルール」をクリックします。
- 「iam-root-access-key-check」ルールを有効にします。このルールは、ルートユーザーのアクセスキーが存在しないかどうかをチェックします。
2. **Security Hubを使用する**
- AWS Security Hubを使用して、セキュリティファインダingsを監視します。
- Security Hubで「IAM.1」標準のファインダingsを確認し、適切な対応を行います。
3. **定期的なレビューとアクション**
- 定期的にIAMユーザーとアクセスキーをレビューし、不要なアクセスキーや権限がないかを確認します。
- AWS CloudTrailログを分析し、不正なアクセスやアクティビティがないかを確認します。
**公式ドキュメント:**
- [iam-root-access-key-check - AWS Config](https://docs.aws.amazon.com/config/latest/developerguide/iam-root-access-key-check.html)
- [AWS Security Hub controls for AWS Identity and Access Management](https://docs.aws.amazon.com/securityhub/latest/userguide/iam-controls.html)
### **まとめ**
- **ルートユーザーのアクセスキーを削除し、IAMユーザーを使用してください。**
- **ルートユーザーのセキュリティを強化するために、MFAを有効にし、メールアドレスと電話番号を更新してください。**
- **定期的な監査とレビューを行い、セキュリティファインダingsに対応してください。**
AgentCoreにデプロイ
必要なパッケージをインストールします。
apt install zip
デプロイ方法にDirect Code Deploy deploymentとContainer deploymentがあります。zip utilityがないと今回使用するDirect Code Deploy deploymentが使用出来ないため、インストールしておきます。
requirements.txtファイルを作成します。
cd ../
cd alert_summarize/
pwd
/root/alert_summarize
vim requirements.txt
strands-agents
bedrock-agentcore
デプロイします。選択項目はデフォルトで進めていきます。
agentcore configure -e alert.py -r ap-northeast-1
agentcore deploy
Amazon Bedrock AgentCoreコンソールから「エージェントランタイム」に進みます。ランタイムリソースに下記が追加されていることを確認します。
Lambda関数の作成
検証のため、下記を準備しておきます。
- Lambda関数用のAdministratorAccessを付与したIAMロール
- Eメールに通知するためのSNS Topic
下記Lambda関数を作成します。
- Lambdaの「設定」からタイムアウトを1分に変更します。
- AGENTCORE_ARNを上記「ランタイムリソース」の画面から確認後、指定します。
- 作成したSNS TopicのARNを指定します。
import json
import boto3
import os
AGENTCORE_ARN = "arn:aws:bedrock-agentcore:ap-northeast-1:****:runtime/*****"
SNS_TOPIC_ARN = "arn:aws:sns:ap-northeast-1:****:****"
# クライアント初期化
bedrock_agentcore = boto3.client('bedrock-agentcore')
sns = boto3.client('sns')
def lambda_handler(event, context):
# AgentCore呼び出し
response = bedrock_agentcore.invoke_agent_runtime(
agentRuntimeArn=AGENTCORE_ARN,
payload=json.dumps(event)
)
# レスポンス読み取り
result = response['response'].read().decode('utf-8')
# JSONパースして整形
try:
result_json = json.loads(result)
body_json = json.loads(result_json['body'])
message = body_json['result']['content'][0]['text']
except:
message = result
# SNS送信
sns.publish(
TopicArn=SNS_TOPIC_ARN,
Message=message
)
return {'statusCode': 200}
動作確認
Lambdaの「テスト」タブに移動後、ローカル試験の際に使用した、Security Hubのテストデータを「イベントJSON」の箇所に貼り付け後「テスト」をクリックします。
SNSで指定したメールアドレスに下記要約メールが送信されることを確認します。
ローカル試験の際と同様、MCPサーバを参照し、参照したAWS公式ドキュメントのリンクが記載されています。
まとめ
本記事では、以前紹介させていただいたアラート要約ツールを拡張し、MCPサーバを活用してAWS公式ドキュメントに基づいた要約を行う仕組みを紹介しました。アラートの種類に応じて
- 公式ドキュメント参照が必要なものはMCPサーバを利用
- 自前で運用している監視アラートはシンプルに要約
と切り分けることで、不要な検索を避けつつ、実運用で使いやすい構成にしています。Security HubやAWS Healthのアラート対応を効率化したい場合の一例として、参考になれば幸いです。





