はじめに

平素は大変お世話になっております。
クイックガードのパー子です。

弊社は MSP (Managed Service Provider) として、お客様の AWS環境のインフラ管理をお引き受けしています。
AWS環境においてシステムを安定的に運用するためには Health Event を適時&確実にキャッチアップすることが肝要です。

システムごとに AWSアカウントを細かく分割することがベストプラクティスとなっている一方で、逆に 1つの AWSアカウントに複数のシステムが同居する中の一部のみを弊社にお任せいただくケースも少なくありません。

Health Event はアカウント単位で通知されるため、そのような全部入りのアカウントでは担当外のシステムに関する通知もすべて飛んできてしまいます。
多数の通知の取捨選択は地味に面倒な作業であり、これを軽減するために、通知されたリソースが弊社の担当範囲かどうかを AI で一次判定する仕組みを構築しました。

本記事ではこの仕組みの概要をご紹介します。

なお、現時点ではまだ試験運用段階であり、実務に耐え得るかどうかは引き続き評価中です。

仕組みの方針

「通知対象のリソースに特定のタグが付与されているかどうかを確認する」という単純な方針としました。

弊社が担当するリソースにはあらかじめ ManagedBy: QuickGuard のようなタグを付与する運用とします。
Health Event が届いたとき、その通知が指しているリソースにタグが付与されていれば弊社の担当範囲、なければスコープ外と判定します。

ただし、ここで考慮点がありまして、Health Event のペイロードに含まれるリソース識別子の形式がイベントの種類によって異なるのです。

タグの有無を確認するためには、Resource Groups Tagging API に ARN を渡す必要があります。
しかし、例えば EC2 のイベント例 を見てみると、resourcesdetail.affectedEntities に含まれるのはインスタンスID (i-abcd1111) だけであり、ARN は含まれていません。

{
    "version": "0",
    "id": "121345678-1234-1234-1234-123456789012",
    "detail-type": "AWS Health Event",
    "source": "aws.health",
    "account": "123456789012",
    "time": "2022-06-03T06:27:57Z",
    "region": "us-west-2",
    "resources": [
        "i-abcd1111"
    ],
    "detail": {
        "eventArn": "arn:aws:health:us-east-1::event/AWS_EC2_INSTANCE_STORE_DRIVE_PERFORMANCE_DEGRADED_90353408594353980",
        "service": "EC2",
        "eventTypeCode": "AWS_EC2_INSTANCE_STORE_DRIVE_PERFORMANCE_DEGRADED",
        "eventTypeCategory": "issue",
        "eventScopeCode": "ACCOUNT_SPECIFIC",
        "communicationId": "01b0993207d81a09dcd552ebd1e633e36cf1f09a-1",
        "startTime": "Fri, 3 Jun 2022 05:01:10 GMT",
        "endTime": "Fri, 3 Jun 2022 05:30:57 GMT",
        "statusCode": "open",
        "eventRegion": "us-east-1",
        "eventDescription": [{
            "language": "en_US",
            "latestDescription": "A description of the event will be provided here"
        }],
        "affectedEntities": [{
            "entityValue": "i-abcd1111"
        }],
        "page": "1",
        "totalPages": "1",
        "backupEvent": "true",
        "affectedAccount": "123456789012",
        "personas": ["OPERATIONS"]
    }
}

インスタンスID から ARN を組み立てるには arn:aws:ec2:{region}:{account-id}:instance/{instance-id} というフォーマットに当てはめる必要があり、リージョンやアカウントID はペイロードの別フィールドから補完しなければなりません。
さらに、RDS や ELB など別のサービスになれば ARN のフォーマットも変わります。

サービスやイベントの種類ごとに個別の変換ロジックを実装するのは、継続的なメンテナンスを要するのでやりたくありません。
そこで今回は、「ペイロード全体を Bedrock Agent に渡し、ARN の推測/組み立てから管理タグの確認までを一括して委ねる」という方針を採りました。

具体的な構成については次のセクションで説明します。

アーキテクチャ

以下の構成で仕組みを構築しました。

全体アーキテクチャ
コンポーネント説明
1EventBridge (Default bus)各AWSアカウント (“管理アカウント”) において発生する Health Event を捕捉する
2EventBridge (Custom bus)イベントを単一のアカウント (“集約アカウント”) に集約して処理する
3Lambda (オーケストレーター)Bedrock Agent とのやり取りなど一連の処理をオーケストレートする
4Bedrock Agentイベントの解析と判定を行う
5Lambda (Action Group)Bedrock Agent が呼び出す Action として、リソースタグを検索する
6SNS判定結果をスタッフに通知する

設計のポイント

仕組みの要点は以下のとおりです。

Custom bus によるイベント集約

判定システムをアカウントごとに用意するのは管理コストが高いため、判定用の専用アカウントに EventBridge の Custom bus を配置し、各アカウントのイベントを集約する構成としました。

各アカウントの Default bus から Custom bus へのイベント転送には、EventBridge のクロスアカウント配信機能を利用します。

{
  "source": ["aws.health"],
  "detail-type": ["AWS Health Event"]
}

上記のパターンを各アカウントの Default bus に設定し、ターゲットとして判定用アカウントの Custom bus を指定します。

なお、クロスアカウントでイベントを転送するために、双方のアカウントで適切に IAM を設定する必要があります。

判定エンジンとしての Bedrock Agent

Bedrock Agent には、ペイロードの構造を柔軟に解釈し、妥当な ARN を推測/組み立てることを期待しています。

もちろん、LLM に頼る以上、正確性の保証はありません。
しかし、全件を人間が確認している現状と比べれば、ある程度まで自動でふるい分けてくれるだけでも充分に価値があると判断しました。

Action Group によるタグ参照

Bedrock Agent は、単独では AWS上の実リソースを参照してタグを判別することはできません。

そこで、リソース参照用の Lambda関数を Action Group として登録しました。
Bedrock Agent がリソースの ARN を組み立てたあとに、その Lambda関数を用いてリソースに付与されたタグを確認できるようになります。

Lambda関数では Resource Groups Tagging API の GetResources を呼び出してタグを取得します。

ただし、GetResources API は、別アカウントのリソースに対してクロスアカウントでは実行できません。
判定対象のアカウントごとに IAMロールを用意し、Assume したうえで実行する必要があります。

通知

オーケストレーター Lambda に対して、Bedrock Agent は次の情報を JSON で返します。

項目内容
担当判定担当範囲のリソースかどうか
影響リソース影響を受けるリソースの ARN
影響度影響の大きさ (Critical, Medium など)
サマリーHealth Event の内容を Bedrock Agent が要約したもの
判定の根拠担当判定や影響度の算出根拠

元の Health Event のペイロードと併せてこれらの情報を SNSトピックに Publish し、スタッフに通知します。

今後の課題

現時点で認識している課題を挙げます。

ARN 推測の精度

Bedrock Agent が組み立てる ARN が常に正しいとは限りません。
ペイロード中のリソース識別子がサービス固有の ID のみで、ARN を構成するための追加情報 (サービス名など) をイベントのコンテキストから補完しなければならない場合、誤った ARN を生成するミスがそこそこ発生している印象です。

あまりに精度が悪いようなら、ARN のパターンリストを事前に用意しておいて Bedrock Agent に参照させることで改善を図ろうかと考えています。

Bedrock Agent からの応答形式

Bedrock Agent からの応答は、規定のスキーマにしたがった JSON となっていることを期待しています。

しかし、プロンプトで強く念押ししているにもかかわらず、結構な確率で余計な文言を付け足してきます。
(判定しました。結果は次のとおりです。 {...<期待するJSON>...} のように勝手に序文を入れてみたり…)

緩和策として、もう少しプロンプトを練ってみたり、規定の JSON でない場合はオーケストレーター側で Bedrock Agent の呼び出しを何度かリトライしてみることを検討しています。

まとめ

MSP としてお客様 AWS環境内の一部リソースのみを担当する中で、Health Event の通知対象を自動で判定する仕組みを Bedrock Agent を活用して構築しました。

  • EventBridge の Custom bus でマルチアカウントの Health Event を集約
  • Bedrock Agent がペイロードからリソースの ARN を推測/組み立て
  • Bedrock Agent から Lambda関数 (Action Group) を呼び出して Resource Groups Tagging API でタグを確認
  • SNS で判定結果を通知

この仕組みが実運用でどこまで有用かは引き続き検証中ですが、「判断のためにいちいちペイロードを目視確認する」という労力の軽減効果は、少なくとも部分的には得られると期待しています。

今後ともよろしくお願い申し上げます。