4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ガバメントクラウドAWS環境における統合監視・AIによる障害時自動調査について検討してみた

4
Last updated at Posted at 2026-08-28

富士通 Japan 株式会社 Public & Education 事業本部
クラウドサービス事業部の吉村 康良です。

令和3年度のガバメントクラウド先行事業から、ガバメントクラウドを利用したインフラストラクチャの設計に従事し、現在は主にガバメントクラウド上のインフラ運用保守を担当しています。

監視サービスは随時アップデートされており、適宜監視設計を見直すことで、より運用改善につながると考えています。そのポイントを解説します。

はじめに

本記事の対象読者
ガバメントクラウド(デジタル庁の政府共通クラウド基盤)上で AWS を使っている地方公共団体や運用管理補助者の方を主な対象としています。
「Organizations の管理権限がない」「完全閉域ネットワーク」という 2 つの制約の下で、大量アカウント環境における統合監視をどのように実現するか、検討した内容を解説します。

本記事の前提(IaC 方針)
デジタル庁 GCAS ガイドに記載の「インフラ管理を IaC(Infrastructure as Code)化する」という、ガバメントクラウドにおけるモダン化の定義を前提に、構築手順は可能な限り CloudFormation テンプレートで記載しています。CloudFormation で未対応の操作については、AWS CLI や AWS マネジメントコンソールを利用した手順とします。

本記事でわかること:

  • CloudWatch OAM で Organizations なしに複数アカウントの監視を集約する方法
  • VPC Interface Endpoint(PrivateLink) を使った完全閉域構成
  • Network Synthetic Monitor / Syslog Ingestion(2026年6月新機能)によるネットワーク機器監視
  • Alarm Mute Rules(2026年1月新機能)によるメンテナンス通知抑止
  • AWS DevOps Agent による AI 駆動の効率的な障害調査

ガバメントクラウドの制約

ガバメントクラウド(デジタル庁が主導して整備・運用する政府共通のクラウド基盤)の AWS 環境は、地方公共団体の情報システム標準化のために整備された環境です。各自治体は、デジタル庁が管理する AWS Organizations 配下のアカウントを利用します。

通常の自己管理 AWS 環境 であれば、AWS Organizations を活用して Amazon CloudWatch オブザーバビリティアクセスマネージャー(OAM)のシンクポリシーを組織全体に一括適用できます。
OU にアカウントを追加するだけで監視対象が自動でオンボードされ、大量アカウント環境でもほぼ自動化が実現できます。

# Example sink policy in a standard environment (with Organizations)
Condition:
  StringEquals:
    aws:PrincipalOrgID: "o-xxxxxxxxxxxx"  # All accounts are covered by specifying the Organizations ID

後述の monitoring-account-sink.yaml に記載の Condition 句を、上記の値とします。

しかし、ガバメントクラウド環境には以下の制約があります。

  • AWS Organizations の管理権限が利用できない
    自治体はデジタル庁が管理する Organizations に所属するため、OU 操作・SCP・CloudFormation StackSets 等の組織管理機能を自由に使えません。
    OAM の Organizations 一括設定も同様に利用できません。

  • 閉域ネットワーク(運用管理アカウントを通じたパッチ適用、ウイルス対策ソフトのパターンファイル更新の用途を除きインターネット経由の接続が禁止)
    個人番号(マイナンバー)等を扱うシステムの性質上、AWS サービスへの通信も VPC Endpoint 経由に限定されます。

この 2 つの制約を踏まえ、本記事では OAM の個別アカウントリンクVPC Endpoint による完全閉域構成を用いて、多数の AWS アカウントと、オンプレミスに設置するクラウドと庁舎を接続するために必須のネットワーク機器オンプレミスサーバを、1 つの「集約アカウント」から統合監視する構成を解説します。

監視対象

場所 リソース
AWS(各アカウント) ALB、NLB、EC2
オンプレミス ネットワーク機器、オンプレミスサーバ

監視項目

サーバ監視

# 監視項目
1 死活監視
2 CPU 使用率
3 メモリ使用率
4 ディスク使用率
5 ログ(Windows イベントログ、テキストログ)
6 サービス/プロセス監視

ネットワーク監視

# 監視項目
1 死活監視
2 SNMP(性能・状態)
3 SNMPTrap(障害通知)
4 Syslog

目次

  1. 設計方針
  2. 全体構成図
  3. クロスアカウント観測の設定(OAM)
  4. 完全閉域ネットワークの設定
  5. サーバ監視の実装
  6. ネットワーク機器監視の実装
  7. メンテナンス通知の管理(Alarm Mute Rules)
  8. AI 駆動の運用効率化(AWS DevOps Agent)
  9. コストとクォータの管理
  10. まとめ

1. 設計方針

ガバメントクラウドAWS環境における統合監視実現のポイント

Amazon CloudWatch Observability Access Manager(OAM) は、AWS Organizations を使用しなくても個別アカウントを 1 つずつ監視アカウントにリンクできる仕組みを提供しています。

ガバメントクラウドでは Organizations 管理権限が利用できないため、各ソースアカウントで個別にリンクを作成するアプローチを取ります。

OAM で共有できる観測データの種類は以下のとおりです。

共有データの種類 内容
CloudWatch メトリクス 全ネームスペースまたはフィルタ指定
CloudWatch Logs 全ロググループまたはフィルタ指定
AWS X-Ray Traces 分散トレーシング
Application Insights アプリケーション監視
CloudWatch Internet Monitor インターネット経由の可用性監視
比較項目 Organizations あり Organizations なし(OAM 個別リンク)
アカウント追加方法 OU 追加で自動オンボード 各アカウントで手動リンク作成
最大ソースアカウント数 100,000 100,000(同じ上限)
共有データ メトリクス、ログ、X-Ray トレース、Application Insights、Internet Monitor 同左
追加コスト なし なし

Organizations がなくても、機能・上限・コストは同等です。

参考: CloudWatch cross-account observability - AWS 公式ドキュメント

構成のポイント

構成のポイントは、コストネットワーク運用性の 3 つの観点とします。
特に運用性について、システムの運用保守として発生するメンテナンス作業による計画作業であるのにアラーム通知されるなどで重要なアラートが埋もれてしまうケースが発生するため、抑止機能(ミュートルール)を使うことで重要なアラームのみに絞る対策が必要となります。

観点 原則 実現手段
コスト 重複コストは発生させない OAM によりソースアカウントのデータを参照
ネットワーク 完全閉域ネットワーク VPC Interface Endpoint(PrivateLink)経由のみ
運用性 アラーム通知の最適化 Alarm Mute Rules(2026年1月リリース)でメンテナンス時の不要通知を抑止

2. 全体構成図

統合監視構成図.jpg


以降に記載の CloudFormation テンプレートや AWS CLI コマンド、AWS マネジメントコンソール の手順はサンプルとなります。
実際の環境に合わせて適宜修正いただく必要があります。

3. クロスアカウント観測の設定(OAM)

Step 1: 集約アカウントでシンクを作成

集約アカウントに CloudFormation テンプレートを展開し、「シンク(Sink)」を作成します。

パラメータ AllowedSourceAccountIds に集約する対象の AWS アカウントID をカンマ区切りで入力します。

# monitoring-account-sink.yaml (deploy in monitoring account)
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudWatch Cross-Account Observability - Monitoring Account Sink

Parameters:
  AllowedSourceAccountIds:
    Type: CommaDelimitedList
    Description: Comma-separated list of source account IDs to allow
    # Example: "111111111111,222222222222,333333333333"

Resources:
  MonitoringSink:
    Type: AWS::Oam::Sink
    Properties:
      Name: central-monitoring-sink
      Policy:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: "*"
            Action:
              - oam:CreateLink
              - oam:UpdateLink
            Resource: "*"
            Condition:
              StringEquals:
                aws:PrincipalAccount: !Ref AllowedSourceAccountIds

Outputs:
  SinkArn:
    Value: !GetAtt MonitoringSink.Arn
    Export:
      Name: MonitoringAccountSinkArn
    Description: Sink ARN referenced by source-account CloudFormation templates

Step 2: 各ソースアカウントでリンクを作成

各ソースアカウントに CloudFormation テンプレートを展開します。

Step 1 で作成された MonitoringAccountSinkArn をパラメータへ入力します。

# cloudwatch-oam-link.yaml (deploy in each source account)
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudWatch Cross-Account Observability Link

Parameters:
  MonitoringAccountSinkArn:
    Type: String
    Description: ARN of the monitoring account sink

Resources:
  ObservabilityLink:
    Type: AWS::Oam::Link
    Properties:
      LabelTemplate: "$AccountName"
      ResourceTypes:
        - AWS::CloudWatch::Metric
        - AWS::Logs::LogGroup
        - AWS::XRay::Trace
        - AWS::ApplicationInsights::Application
        - AWS::InternetMonitor::Monitor
      SinkIdentifier: !Ref MonitoringAccountSinkArn

Outputs:
  LinkArn:
    Value: !GetAtt ObservabilityLink.Arn

Step 3: 集約アカウントでクロスアカウントアラームを作成

OAM のリンクが設定されると、集約アカウントの CloudWatch コンソールから各ソースアカウントのメトリクスをそのまま参照できるようになります。CloudFormation のアラーム定義では Metrics プロパティに AccountId を指定することでクロスアカウント参照が有効になります。
集約アカウントに CloudFormation テンプレートを展開し、アラームを作成します。

テンプレートは最小構成として、EC2のCPU使用率のクロスアカウントアラームのみ作成するサンプルとなります。

# monitoring-account-alarms.yaml (deploy in monitoring account)
AWSTemplateFormatVersion: '2010-09-09'
Description: Cross-Account CloudWatch Alarms - Monitoring Account

Parameters:
  SourceAccountId:
    Type: String
    Description: Source account ID to monitor
  TargetInstanceId:
    Type: String
    Description: EC2 instance ID to monitor
  AlertTopicArn:
    Type: String
    Description: SNS topic ARN for notifications

Resources:
  # Cross-account alarm for EC2 high CPU usage
  CrossAcctEC2HighCPUAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub "${SourceAccountId}-EC2-HighCPU-${TargetInstanceId}"
      AlarmDescription: !Sub "High CPU alarm for EC2 in source account ${SourceAccountId}"
      Metrics:
        - Id: m1
          AccountId: !Ref SourceAccountId
          MetricStat:
            Metric:
              Namespace: AWS/EC2
              MetricName: CPUUtilization
              Dimensions:
                - Name: InstanceId
                  Value: !Ref TargetInstanceId
            Period: 300
            Stat: Average
          ReturnData: true
      ComparisonOperator: GreaterThanOrEqualToThreshold
      Threshold: 80
      EvaluationPeriods: 3
      AlarmActions:
        - !Ref AlertTopicArn
      TreatMissingData: notBreaching

4. 完全閉域ネットワークの設定

ガバメントクラウドの閉域ネットワーク要件を満たすため、AWS サービスとの通信に VPC Interface Endpoint(PrivateLink)を使用します。インターネットゲートウェイまたはNATゲートウェイは不要で、通信はすべて AWS の内部ネットワーク上に閉じます。

❌ ガバメントクラウドでは禁止
[EC2/オンプレミスサーバ]
  ↓
[インターネット]
  ↓
[AWS サービスエンドポイント]

✅ ガバメントクラウド対応
[EC2/オンプレミスサーバ]
  ↓
[VPC Interface Endpoint (PrivateLink)]
  ↓(AWS 内部ネットワーク)
[AWS サービスエンドポイント]

必要な VPC エンドポイント一覧

本構成で必要な VPC Interface Endpoint は以下のとおりです。

エンドポイントサービス名 用途
com.amazonaws.{region}.monitoring CloudWatch メトリクスの送信
com.amazonaws.{region}.logs CloudWatch Logs への送信
com.amazonaws.{region}.syslog-logs Syslog Ingestion(2026年6月新機能)
ネットワーク機器からの Syslog 直接受信
com.amazonaws.{region}.secretsmanager Secrets Manager へのアクセス
(Lambda から Webhook シークレット取得)
com.amazonaws.{region}.event-ai AWS DevOps Agent
Webhook Events

PrivateDnsEnabled: true を設定すると、VPC 内のクライアントは monitoring.ap-northeast-1.amazonaws.com などの名前を解決した際に、Endpoint のプライベート IP を自動的に取得できます。

VPC エンドポイントの作成は後述の章で実施します。

オンプレミスからの接続フロー

[オンプレミスサーバ(CloudWatch Agent)]
        ↓
[AWS Direct Connect]
        ↓
[VPC Interface Endpoint (PrivateLink)]
        ↓
[CloudWatch / CloudWatch Logs]

Route 53 Resolver を使って、オンプレミス DNS から VPC Endpoint のプライベート DNS 名へ転送することで、オンプレミスサーバやネットワーク機器でも名前解決できるようにします。

参考: Hybrid Networking using VPC Endpoints (AWS PrivateLink) and Amazon CloudWatch for Financial Services

オンプレミスからの VPC Endpoint 名前解決(Route 53 Resolver)

Direct Connect で VPC に接続しているオンプレミスサーバ(オンプレミスサーバやネットワーク機器)が、monitoring.ap-northeast-1.amazonaws.com などの VPC Endpoint DNS 名を解決できるように、Route 53 Resolver インバウンドエンドポイントを VPC 内に作成します。

DNS 解決フロー

[オンプレミス DNS サーバ]
  転送ルール: *.amazonaws.com → Route 53 Resolver インバウンドエンドポイントの IP
  ↓(Direct Connect 経由)
[Route 53 Resolver インバウンドエンドポイント(VPC 内)]
        ↓
[VPC Endpoint のプライベート DNS(10.x.x.x)を返答]
        ↓
[CloudWatch Agent / ネットワーク機器が VPC Endpoint のプライベート IP に直接通信]

ソースアカウントに CloudFormation テンプレートを展開します。

パラメータ AllowedSourceCidr にはオンプレミス DNS サーバのIPアドレスを含む CIDR を入力します。

# route53-resolver.yaml (deploy in each source account)
AWSTemplateFormatVersion: '2010-09-09'
Description: Route 53 Resolver Inbound Endpoint for on-premises DNS forwarding

Parameters:
  VpcId:
    Type: AWS::EC2::VPC::Id
  SubnetId1:
    Type: AWS::EC2::Subnet::Id
    Description: Subnet for inbound endpoint (AZ1)
  SubnetId2:
    Type: AWS::EC2::Subnet::Id
    Description: Subnet for inbound endpoint (AZ2)
  AllowedSourceCidr:
    Type: String
    Description: CIDR block of on-premises DNS servers allowed to query the inbound endpoint

Resources:
  ResolverEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: route53-resolver-inbound-sg
      GroupDescription: Allow inbound DNS queries to the Route 53 Resolver inbound endpoint
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 53
          ToPort: 53
          CidrIp: !Ref AllowedSourceCidr
        - IpProtocol: udp
          FromPort: 53
          ToPort: 53
          CidrIp: !Ref AllowedSourceCidr
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0

  R53InboundResolver:
    Type: AWS::Route53Resolver::ResolverEndpoint
    Properties:
      Name: onprem-dns-inbound
      Direction: INBOUND
      IpAddresses:
        - SubnetId: !Ref SubnetId1
        - SubnetId: !Ref SubnetId2
      SecurityGroupIds:
        - !Ref ResolverEndpointSecurityGroup

Outputs:
  ResolverEndpointArn:
    Value: !GetAtt R53InboundResolver.Arn
    Description: Resolver endpoint ARN (check assigned IPs in console or API)
  ResolverSecurityGroupId:
    Value: !Ref ResolverEndpointSecurityGroup
    Description: Security group ID attached to the Route 53 Resolver inbound endpoint

インバウンドエンドポイントを作成したら、マネジメントコンソールで割り当てられた 2 つの IP アドレスを確認し、オンプレミスの DNS サーバ(Windows DNS や BIND 等)に以下の転送ルールを設定します。

# BIND (named.conf) example
zone "amazonaws.com" {
    type forward;
    forwarders {
        10.x.x.x;   # Route 53 Resolver インバウンドエンドポイント IP (AZ-a)
        10.x.x.y;   # Route 53 Resolver インバウンドエンドポイント IP (AZ-c)
    };
};

参考: Route 53 Resolver - AWS ドキュメント


5. サーバ監視の実装

監視項目と収集方法の例(EC2 / オンプレミスサーバ)

監視項目 対象リソース メトリクス / ログ名 収集方法
死活 EC2 StatusCheckFailed CloudWatch 標準
死活 ALB HealthyHostCount CloudWatch 標準
死活 NLB HealthyHostCount CloudWatch 標準
CPU 使用率 EC2 CPUUtilization CloudWatch 標準
CPU 使用率 オンプレミス Linux: CWAgent/cpu_usage_active
Windows: CWAgent/Processor % Processor Time
CloudWatch Agent
メモリ使用率 EC2 / オンプレミス Linux: CWAgent/mem_used_percent
Windows: CWAgent/Memory % Committed Bytes In Use
CloudWatch Agent
ディスク使用率 EC2 / オンプレミス Linux: CWAgent/disk_used_percent
Windows: CWAgent/LogicalDisk % Free Space
CloudWatch Agent
Windows イベントログ EC2 / オンプレミス CloudWatch Logs CloudWatch Agent
テキストログ EC2 / オンプレミス CloudWatch Logs CloudWatch Agent
サービス / プロセス監視 EC2 / オンプレミス Linux: CWAgent/procstat/cpu_usage
Windows: CWAgent/Process(*) % Processor Time
CloudWatch Agent

メモリ・ディスク使用率はEC2 インスタンスの CloudWatch 標準メトリクスに含まれません。
EC2 インスタンスにも CloudWatch Agent のインストールが必要です。

CloudWatch メトリクス / ログ 送信用 VPC Endpointの作成

EC2 とオンプレミスサーバ(Direct Connect 経由の CloudWatch Agent)から、CloudWatch メトリクスと CloudWatch Logs へ閉域で送信するため、ソースアカウントに CloudFormation テンプレートを展開し、VPC Interface Endpoint を作成します。

パラメータ AllowedSourceCidr にはオンプレミスサーバやネットワーク機器のIPアドレスを含む CIDR を入力します。

VPC 内に対象の Endpoint が作成済みの場合はエラーとなります。
作成済みの場合は本手順はスキップしてください。

# server-monitoring-vpc-endpoints.yaml (deploy in each source account)
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC Interface Endpoints for CloudWatch metrics and logs

Parameters:
  VpcId:
    Type: AWS::EC2::VPC::Id
  SubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
    Description: Subnets for VPC Interface Endpoints (multi-AZ recommended)
  AllowedSourceCidr:
    Type: String
    Description: Source CIDR allowed to send HTTPS traffic to endpoints (for example 10.0.0.0/16)

Resources:
  MonitoringLogsEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: cloudwatch-monitoring-logs-vpce-sg
      GroupDescription: Allow HTTPS traffic to CloudWatch monitoring and logs VPC endpoints
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref AllowedSourceCidr
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0

  VPCEndpointMonitoring:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VpcId
      VpcEndpointType: Interface
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.monitoring"
      SubnetIds: !Ref SubnetIds
      SecurityGroupIds:
        - !Ref MonitoringLogsEndpointSecurityGroup
      PrivateDnsEnabled: true

  VPCEndpointLogs:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VpcId
      VpcEndpointType: Interface
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.logs"
      SubnetIds: !Ref SubnetIds
      SecurityGroupIds:
        - !Ref MonitoringLogsEndpointSecurityGroup
      PrivateDnsEnabled: true

Outputs:
  MonitoringVPCEndpointId:
    Value: !Ref VPCEndpointMonitoring
    Description: VPC Interface Endpoint ID for CloudWatch metrics
  LogsVPCEndpointId:
    Value: !Ref VPCEndpointLogs
    Description: VPC Interface Endpoint ID for CloudWatch Logs
  MonitoringLogsEndpointSecurityGroupId:
    Value: !Ref MonitoringLogsEndpointSecurityGroup
    Description: Security group ID attached to both endpoints

オンプレミスサーバ監視の実装

オンプレミスサーバを監視する場合は、上記 2 つの VPC Endpoint(monitoring / logs)に加え、4 章の Route 53 Resolver インバウンドエンドポイント設定とオンプレミス DNS 転送設定が必要です。
CloudWatch Agent は Direct Connect 経由で VPC Endpoint のプライベート IP に到達し、インターネットを経由せずにメトリクスやログを送信します。

オンプレミスサーバ上の CloudWatch Agent の設定は複数パターンが存在するため、本記事では記載は省略します。

AWS ドキュメントで案内されている実装例を参照し設定してください。

参考: Install the CloudWatch agent on on-premises servers
参考: Configure on-premises servers that use SSM Agent and unified CloudWatch Agent to use only temporary credentials
参考: Installing the CloudWatch agent using Systems Manager(on-premises considerations)
参考: Starting the CloudWatch agent on an on-premises server(SSM Agent 利用)


6. ネットワーク機器監視の実装

監視項目と収集方法(ネットワーク機器)

監視項目 収集方法 送信先
死活 Network Synthetic Monitor(VPC サブネットから ICMP プローブ送信) CloudWatch メトリクス
SNMP CloudWatch のマネージド機能では直接サポートされない(別途連携設計が必要) 要件に応じて設計
SNMPTrap CloudWatch のマネージド機能では直接サポートされない(別途連携設計が必要) 要件に応じて設計
Syslog VPC Endpoint (syslog-logs) に直接送信(🆕 2026年6月新機能) CloudWatch Logs

死活監視:Network Synthetic Monitor

AWS マネージドサービスである Network Synthetic Monitor(Amazon CloudWatch のネットワーク監視機能) を使用して、VPC サブネットからオンプレミスのネットワーク機器に ICMP プローブを送信します。

仕組み

[VPC サブネット(AWS マネージドプローブ送信元)]
    ↓ ICMP probe
[Direct Connect]
    ↓
[ネットワーク機器の IP アドレス]
    → RTT / PacketLoss メトリクス → CloudWatch

出力メトリクス

メトリクス名 内容
RTT 往復遅延(ミリ秒)
PacketLoss パケットロス率(%)
NetworkHealthIndicator Direct Connect 経由の場合のみ。AWS 側ネットワーク健全性(0 or 1)

設定手順

ソースアカウントに対して CLI を実行し、Network Synthetic Monitor を設定します。

CloudFormation 非対応(2026-08-08 時点) — CLI で作成します。

下記コマンドの AWS アカウント IDサブネット IDIP アドレス はサンプル値です。実行前に必ず自環境の値へ修正してから実行してください。

# Step 1: 監視対象を束ねるモニターを作成
aws networkmonitor create-monitor \
  --monitor-name "network-device-monitor" \
  --aggregation-period 30 \
  --region ap-northeast-1

# Step 2: 監視するネットワーク機器ごとにプローブを追加
# 例: 機器1 (10.0.0.1) への ICMP プローブ
aws networkmonitor create-probe \
  --monitor-name "network-device-monitor" \
  --probe '{
    "sourceArn": "arn:aws:ec2:ap-northeast-1:111111111111:subnet/subnet-xxxxxxxxx",
    "destination": "10.0.0.1",
    "protocol": "ICMP",
    "packetSize": 56
  }' \
  --region ap-northeast-1

# 例: 機器2 (10.0.0.2) への ICMP プローブ
aws networkmonitor create-probe \
  --monitor-name "network-device-monitor" \
  --probe '{
    "sourceArn": "arn:aws:ec2:ap-northeast-1:111111111111:subnet/subnet-xxxxxxxxx",
    "destination": "10.0.0.2",
    "protocol": "ICMP",
    "packetSize": 56
  }' \
  --region ap-northeast-1

CloudWatch アラームの設定

Network Synthetic Monitor が発行するメトリクスは、OAM により集約アカウント側でクロスアカウントアラームとして設定できます。
集約アカウントに CloudFormation テンプレートを展開します。

上記で作成した ICMP プローブのID を ProbeId パラメータへ入力します。

# network-monitor-alarms.yaml (deploy in monitoring account)
AWSTemplateFormatVersion: '2010-09-09'
Description: Cross-account alarms for Network Synthetic Monitor probes

Parameters:
  SourceAccountId:
    Type: String
    Description: Source account ID where Network Synthetic Monitor was created
  MonitorName:
    Type: String
    Default: network-device-monitor
  ProbeId:
    Type: String
    Description: Probe ID returned by create-probe
  AlertTopicArn:
    Type: String

Resources:
  # Packet loss alarm for network device health
  CrossAcctFirewallPacketLossAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub "${SourceAccountId}-${MonitorName}-${ProbeId}-PacketLoss"
      AlarmDescription: !Sub "ICMP packet loss threshold exceeded in source account ${SourceAccountId}"
      Metrics:
        - Id: m1
          AccountId: !Ref SourceAccountId
          MetricStat:
            Metric:
              Namespace: AWS/NetworkMonitor
              MetricName: PacketLoss
              Dimensions:
                - Name: Monitor
                  Value: !Ref MonitorName
                - Name: Probe
                  Value: !Ref ProbeId
            Period: 60
            Stat: Average
          ReturnData: true
      EvaluationPeriods: 3
      Threshold: 10    # Alarm when packet loss exceeds 10%
      ComparisonOperator: GreaterThanOrEqualToThreshold
      AlarmActions:
        - !Ref AlertTopicArn
      TreatMissingData: breaching   # Treat missing probe data as a failure

TreatMissingData: breaching を設定する理由
ネットワーク機器が完全停止すると、プローブ自体が届かなくなりメトリクスが欠損します。breaching にすることで、データ欠損をアラーム状態として検知できます。

参考: Using Network Synthetic Monitor ドキュメント


Syslog 監視:CloudWatch Logs Syslog Ingestion

従来は Syslog 収集サーバ(EC2)を中継する必要がありましたが、CloudWatch Logs Syslog Ingestion により、ネットワーク機器から VPC Endpoint へエージェント不要で直接送信できるようになりました。

対応プロトコル・フォーマット

項目 対応内容
通信プロトコル TCP、TCP+TLS、UDP
Syslog フォーマット RFC 5424、RFC 3164、Cisco FTD/ASA
自動抽出フィールド facility、severity、hostname、application name

設定手順

ソースアカウントに CloudFormation テンプレートを展開し、VPC Interface Endpoint を作成します。

パラメータ AllowedSourceCidr にはネットワーク機器のIPアドレスを含む CIDR を入力します。

# syslog-ingestion-endpoint.yaml (deploy in each source account)
AWSTemplateFormatVersion: '2010-09-09'
Description: Syslog ingestion endpoint resources

Parameters:
  VpcId:
    Type: AWS::EC2::VPC::Id
  SubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
    Description: "Subnets for VPC Interface Endpoint (multi-AZ recommended)"
  AllowedSourceCidr:
    Type: String
    Description: "Source CIDR allowed to send syslog traffic (for example 10.0.0.0/16)"

Resources:
  # Create a security group
  SyslogEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: syslog-vpce-sg
      GroupDescription: Allow syslog traffic to VPC endpoint
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 6514
          ToPort: 6514
          CidrIp: !Ref AllowedSourceCidr
        - IpProtocol: tcp
          FromPort: 1514
          ToPort: 1514
          CidrIp: !Ref AllowedSourceCidr
        - IpProtocol: udp
          FromPort: 514
          ToPort: 514
          CidrIp: !Ref AllowedSourceCidr
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0

  # Create the VPC endpoint
  VPCEndpointSyslogLogs:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VpcId
      VpcEndpointType: Interface
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.syslog-logs"
      SubnetIds: !Ref SubnetIds
      SecurityGroupIds:
        - !Ref SyslogEndpointSecurityGroup
      PrivateDnsEnabled: true

  # Create a log group
  SyslogLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /syslog/network-devices
      RetentionInDays: 90

  # Add a resource policy
  SyslogResourcePolicy:
    Type: AWS::Logs::ResourcePolicy
    Properties:
      PolicyName: SyslogIngestionResourcePolicy
      PolicyDocument: !Sub |
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "AllowSyslogServiceToWrite",
              "Effect": "Allow",
              "Principal": {
                "Service": "syslog.logs.amazonaws.com"
              },
              "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
              ],
              "Resource": "${SyslogLogGroup.Arn}:*",
              "Condition": {
                "StringEquals": {
                  "aws:SourceAccount": "${AWS::AccountId}"
                },
                "ArnEquals": {
                  "aws:SourceArn": "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc-endpoint/${VPCEndpointSyslogLogs}"
                }
              }
            }
          ]
        }

Outputs:
  SyslogVPCEndpointId:
    Value: !Ref VPCEndpointSyslogLogs
    Export:
      Name: !Sub "${AWS::StackName}-SyslogVPCEndpointId"
  SyslogLogGroupArn:
    Value: !GetAtt SyslogLogGroup.Arn
    Export:
      Name: !Sub "${AWS::StackName}-SyslogLogGroupArn"
  SyslogEndpointSecurityGroupId:
    Value: !Ref SyslogEndpointSecurityGroup
    Export:
      Name: !Sub "${AWS::StackName}-SyslogEndpointSecurityGroupId"

PutSyslogConfiguration は CloudFormation 非対応(2026-08-08 時点) — CLI で作成します。
VPC Endpoint・セキュリティグループ・ロググループ・リソースポリシーまでは CloudFormation で作成し、Syslog 関連付け(put-syslog-configuration)のみ CLI で設定します。
スタック展開後、上記で作成した SyslogVPCEndpointId$VPCE_ID を置き換えて、1 度だけ実行してください。

# Syslog 取り込み設定を作成
aws logs put-syslog-configuration \
  --log-group-identifier /syslog/network-devices \
  --vpc-endpoint-id $VPCE_ID \
  --region ap-northeast-1

# Syslog 取り込み設定確認
aws logs list-syslog-configurations \
  --region ap-northeast-1

ネットワーク機器側の設定(DNS 名指定推奨)

設定内容は機種やファームウェアにより差異があるため、ご利用中の機器のマニュアルをご確認ください。

Syslog の送信先は、VPC Endpoint の DNS 名(FQDN)で指定することを推奨します。
運用要件により、VPC Interface Endpoint のプライベート IP を直接指定する構成も可能です。

VPC Endpoint の DNS 名は、ネットワーク機器が参照する DNS サーバが Route 53 Resolver 経由で解決できるよう設定してください。

参考: Syslog ingestion - AWS ドキュメント
参考: Setting up syslog ingestion


SNMP / SNMPTrap 監視について

AWS CloudWatch のマネージド機能では、SNMP および SNMPTrap は直接サポートされていません

そのため、SNMP 関連の監視を要件に含める場合は、別途連携方式を設計してください(本記事では具体的な実装手順は省略します)。


7. メンテナンス通知の管理(Alarm Mute Rules)

🆕 2026年1月リリースの新機能
Amazon CloudWatch Alarm Mute Rules — AWS What's New

メンテナンス時などの不要なアラーム通知を抑止する専用機能として、Alarm Mute Rules が 2026 年 1 月にリリースされました。
以前はスケジューラと組み合わせて無効化・有効化する必要がありましたが、この機能ではスケジュールを含めて設定できます。
また、ミュートルールのスケジュール終了時に ALARM 状態のままであれば、アクションが自動実行されます。

Alarm Mute Rules の仕様

項目 仕様
スケジュール形式 Cron 式(繰り返し)または At 式(1回限り)
1 ルール当たりの最大対象アラーム数 100 個
ミュート持続時間 最短 1 分(PT1M)〜 最長 15 日(P15D
タイムゾーン指定 対応(例: Asia/Tokyo
ミュート後の動作 ルール終了時に ALARM 状態のままならアクションを自動実行
適用状態 OK、ALARM、INSUFFICIENT_DATA

参考: Alarm Mute Rules - AWS ドキュメント

設定例

集約アカウントに CloudFormation テンプレートを展開し、ミュートルールを作成します。

パラメータ MuteTargetAlarmNames にミュートする対象のアラーム名をカンマ区切りで入力します。

# alarm-mute-rules.yaml (deploy in monitoring account)
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudWatch Alarm Mute Rules for maintenance windows

Parameters:
  MuteTargetAlarmNames:
    Type: CommaDelimitedList
    Description: "Comma-separated CloudWatch alarm names to mute (for example alarm-a,alarm-b)"
  MuteRuleName:
    Type: String
    Default: weekly-maintenance-sunday
    Description: "Rule name for the mute rule"
  MuteExpression:
    Type: String
    Default: "cron(0 2 * * SUN)"
    Description: "Schedule expression for mute rule (cron(...) or at(...))"
  MuteDuration:
    Type: String
    Default: PT4H
    Description: "Mute duration for rule"
  MuteDescription:
    Type: String
    Default: Mute notifications during the configured maintenance window.
    Description: "Description for the mute rule purpose"

Resources:
  AlarmMuteRule:
    Type: AWS::CloudWatch::AlarmMuteRule
    Properties:
      Name: !Ref MuteRuleName
      Description: !Ref MuteDescription
      Rule:
        Schedule:
          Expression: !Ref MuteExpression
          Duration: !Ref MuteDuration
          Timezone: Asia/Tokyo
      MuteTargets:
        AlarmNames: !Ref MuteTargetAlarmNames

本テンプレートを別のスタックとして作成することで、定期メンテナンス(Cron)や臨時メンテナンス(At)を作成できます。

1 ルールあたり最大 100 アラームの制限があります。
対象アラームが 100 を超える場合は複数のミュートルールに分割してください(後述のクォータ一覧参照)。


8. AI 駆動の運用効率化(AWS DevOps Agent)

OAM と組み合わせる理由

AWS DevOps Agent は、Agent Space を単位として複数 AWS アカウントへアクセスし、障害調査を自律的に実行できる運用支援サービスです。

CloudWatch + OAM AWS DevOps Agent
主目的 アラート検知と横断可視化 横断調査と運用支援
強み 低遅延の閾値検知、統合ダッシュボード 複数アカウント横断での自律的な原因調査
マルチアカウント設計 OAM Link/Sink Agent Space + AssumeRole
閉域対応 PrivateLink + Route 53 Resolver PrivateLink

OAM を観測データ統合の基盤として固定し、障害解析フェーズを DevOps Agent で標準化する、二層構成です。

DevOps Agent のマルチアカウント処理フロー

[集約アカウント]
  ├─ OAM Sink(可観測性データの集約窓口)
  └─ DevOps Agent Agent Space(運用オーケストレーション)
         ↓ AssumeRole
[ソースアカウント A/B/C ...]
  ├─ DevOpsAgentRole(AIDevOpsAgentAccessPolicy 付与)
  └─ OAM Link(メトリクス/ログ共有)

Step 1: Agent Space を作成

集約アカウントに CloudFormation テンプレートを展開します。

# devops-agent-space.yaml (deploy in monitoring account)
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS DevOps Agent Space for multi-account operations

Resources:
# IAM role for DevOps Agent Web App (Operator App)
  DevOpsOperatorRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: DevOpsAgentRole-WebappAdmin
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: aidevops.amazonaws.com
            Action:
              - sts:AssumeRole
              - sts:TagSession
            Condition:
              StringEquals:
                aws:SourceAccount: !Ref AWS::AccountId
              ArnLike:
                aws:SourceArn: !Sub arn:aws:aidevops:${AWS::Region}:${AWS::AccountId}:agentspace/*
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AIDevOpsOperatorAppAccessPolicy

  OpsAgentSpace:
    Type: AWS::DevOpsAgent::AgentSpace
    Properties:
      Name: central-monitoring-agent-space
      Description: Agent Space for OAM-based multi-account monitoring operations
      Locale: ja-JP
      OperatorApp:
        Iam:
          OperatorAppRoleArn: !GetAtt DevOpsOperatorRole.Arn

Outputs:
  AgentSpaceId:
    Value: !GetAtt OpsAgentSpace.AgentSpaceId
  OperatorAppRoleArn:
    Value: !GetAtt DevOpsOperatorRole.Arn

Step 2: ソースアカウント側 IAM ロールを作成

各ソースアカウントで DevOps Agent から引き受け可能なロールを作成します。
信頼ポリシーの aws:SourceAccount / aws:SourceArn 条件と、追加のインラインポリシーを設定します。
各ソースアカウントに CloudFormation テンプレートを展開します。

集約アカウントの AWS アカウントIDと Step 1 で作成した AgentSpaceId をパラメータへ入力します。

# source-account-devopsagent-role.yaml (deploy in each source account)
AWSTemplateFormatVersion: '2010-09-09'
Description: Role for AWS DevOps Agent cross-account investigation

Parameters:
  MonitoringAccountId:
    Type: String
    Description: 12-digit monitoring account ID that hosts the Agent Space
  AgentSpaceId:
    Type: String
    Description: Agent Space ID created in the monitoring account

Resources:
  DevOpsAgentRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: DevOpsAgentRole-AgentSpace
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: aidevops.amazonaws.com
            Action: sts:AssumeRole
            Condition:
              StringEquals:
                aws:SourceAccount: !Ref MonitoringAccountId
                aws:SourceArn: !Sub 'arn:aws:aidevops:${AWS::Region}:${MonitoringAccountId}:agentspace/${AgentSpaceId}'
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AIDevOpsAgentAccessPolicy
      Policies:
        - PolicyName: AIDevOpsAllowAwsSupportActionsPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: AllowCreateServiceLinkedRoles
                Effect: Allow
                Action:
                  - iam:CreateServiceLinkedRole
                Resource:
                  - !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/resource-explorer-2.amazonaws.com/AWSServiceRoleForResourceExplorer

Step 3: AWS アカウントを関連付け(Association)

AWS::DevOpsAgent::Association を使って、まず集約アカウント(monitor)を関連付け、必要に応じて各ソースアカウント(source)を追加します。集約アカウントに CloudFormation テンプレートを展開してください。

パラメータ SourceAccountIds に集約対象の AWS アカウントIDをカンマ区切りで入力します。

# devops-agent-associations.yaml (deploy in monitoring account)
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::LanguageExtensions'
Description: Associate monitor/source AWS accounts to DevOps Agent Space

Parameters:
  AgentSpaceId:
    Type: String
  SourceAccountIds:
    Type: CommaDelimitedList
    Description: Comma-separated list of 12-digit source account IDs
  SourceRoleName:
    Type: String
    Default: DevOpsAgentRole-AgentSpace
    Description: Role name that DevOps Agent assumes in source accounts

Resources:
  DevOpsAgentRoleAgentSpace:
    Type: AWS::IAM::Role
    Properties:
      RoleName: DevOpsAgentRole-AgentSpace
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: aidevops.amazonaws.com
            Action: sts:AssumeRole
            Condition:
              StringEquals:
                aws:SourceAccount: !Ref AWS::AccountId
              ArnLike:
                aws:SourceArn: !Sub arn:aws:aidevops:${AWS::Region}:${AWS::AccountId}:agentspace/*
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AIDevOpsAgentAccessPolicy
      Policies:
        - PolicyName: AIDevOpsAllowAwsSupportActionsPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: AllowCreateServiceLinkedRoles
                Effect: Allow
                Action:
                  - iam:CreateServiceLinkedRole
                Resource:
                  - !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/resource-explorer-2.amazonaws.com/AWSServiceRoleForResourceExplorer

  MonitorAwsAssociation:
    Type: AWS::DevOpsAgent::Association
    Properties:
      AgentSpaceId: !Ref AgentSpaceId
      ServiceId: aws
      Configuration:
        Aws:
          AccountId: !Ref AWS::AccountId
          AccountType: monitor
          AssumableRoleArn: !GetAtt DevOpsAgentRoleAgentSpace.Arn

  'Fn::ForEach::SourceAwsAssociations':
    - SourceAccountId
    - !Ref SourceAccountIds
    - 'SourceAwsAssociation${SourceAccountId}':
        Type: AWS::DevOpsAgent::Association
        DependsOn: MonitorAwsAssociation
        Properties:
          AgentSpaceId: !Ref AgentSpaceId
          ServiceId: aws
          Configuration:
            SourceAws:
              AccountId: !Sub '${SourceAccountId}'
              AccountType: source
              AssumableRoleArn: !Sub 'arn:aws:iam::${SourceAccountId}:role/${SourceRoleName}'

上記の Fn::ForEach 例は、ソースアカウント側のロール名が共通(例: DevOpsAgentRole-AgentSpace)である前提です。
アカウントごとにロール ARN が異なる場合は、個別の Association 定義で作成してください。

参考: Connecting multiple AWS Accounts

OAM 前提での運用パターン(複数アカウント管理)

  1. CloudWatch アラーム発報(集約アカウント)
  2. OAM を経由して対象アカウントのメトリクスやログを横断確認
  3. DevOps Agent を同一 Agent Space から実行し、関連アカウント横断で原因調査
  4. 調査結果に基づき、運用手順書(Runbook)に沿って手動または自動対応

OAM で監視可視化を集約し、DevOps Agent で調査を集中することで、大量アカウント環境でもインシデント対応の負荷を下げられます。

アラーム起点で DevOps Agent に自律調査させる手順

これは、閉域通信に必要な VPC Endpoint 構築と、CloudWatch アラーム起点の自律調査起動のための手順です。

[CloudWatch Alarm]
  ↓
[EventBridge Rule]
  ↓
[Lambda(VPC 内)]
  ↓
[DevOps Agent Webhook(event-ai VPC Endpoint)]

本構成(CloudWatch アラーム起点で Webhook を呼び出す経路)で必須のエンドポイントは以下です。

  • com.amazonaws.{region}.secretsmanager(Webhook シークレット参照)
  • com.amazonaws.{region}.event-ai(Webhook Events)

Step 1: DevOps Agent 用 VPC Endpoint を作成

集約アカウントに CloudFormation テンプレートを展開します。

パラメータ AllowedSourceCidr には VPC の CIDR を入力します。

# devops-agent-event-ai-vpc-endpoint.yaml (deploy in monitoring account)
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC Interface Endpoints for DevOps Agent webhook (event-ai) and Secrets Manager

Parameters:
  VpcId:
    Type: AWS::EC2::VPC::Id
  SubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
    Description: Subnets for VPC Interface Endpoint (multi-AZ recommended)
  AllowedSourceCidr:
    Type: String
    Description: Source CIDR allowed to send HTTPS traffic to endpoint (for example 10.0.0.0/16)

Resources:
  # Security group for event-ai VPC Interface Endpoint
  EventAIEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: devops-agent-event-ai-vpce-sg
      GroupDescription: Allow HTTPS traffic from Lambda subnet range to event-ai endpoint
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref AllowedSourceCidr
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0

  # DevOps Agent Webhook endpoint
  VPCEndpointEventAI:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VpcId
      VpcEndpointType: Interface
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.event-ai"
      SubnetIds: !Ref SubnetIds
      SecurityGroupIds:
        - !Ref EventAIEndpointSecurityGroup
      PrivateDnsEnabled: true

  # Secrets Manager endpoint for Lambda secret retrieval in private subnets
  VPCEndpointSecretsManager:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VpcId
      VpcEndpointType: Interface
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.secretsmanager"
      SubnetIds: !Ref SubnetIds
      SecurityGroupIds:
        - !Ref EventAIEndpointSecurityGroup
      PrivateDnsEnabled: true

Outputs:
  EventAIVPCEndpointId:
    Value: !Ref VPCEndpointEventAI
    Description: VPC Interface Endpoint ID for DevOps Agent webhook events
  SecretsManagerVPCEndpointId:
    Value: !Ref VPCEndpointSecretsManager
    Description: VPC Interface Endpoint ID for Secrets Manager access from Lambda
  EventAIEndpointSecurityGroupId:
    Value: !Ref EventAIEndpointSecurityGroup
    Description: Security group ID attached to event-ai endpoint

参考: DevOps Agent VPC Endpoints

Step 2: EventBridge + Lambda を作成

ALARM 遷移イベントを受信して Lambda から Webhook を呼び出す構成を作成するため、集約アカウントに CloudFormation テンプレートを展開します。

パラメータ AllowedSourceCidr には VPC の CIDR を入力します。
ResourcePrefix は任意です。

# devops-agent-alarm-pipeline.yaml (deploy in monitoring account)
AWSTemplateFormatVersion: '2010-09-09'
Description: Trigger DevOps Agent webhook from CloudWatch alarm via EventBridge and Lambda

Parameters:
  ResourcePrefix:
    Type: String
    Default: devops-agent
    Description: Prefix for resource names
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: VPC ID where Lambda and endpoints are deployed
  LambdaSubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
    Description: Private subnets for Lambda
  AllowedSourceCidr:
    Type: String
    Description: Source CIDR allowed to send HTTPS traffic to endpoint SG (for example 10.0.0.0/16)

Resources:
  DevOpsAgentWebhookSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub '${ResourcePrefix}-webhook-credentials'
      Description: DevOps Agent webhook URL and HMAC secret
      SecretString: '{"DEVOPS_AGENT_WEBHOOK_URL":"","DEVOPS_AGENT_WEBHOOK_SECRET":""}'
      Tags:
        - Key: Name
          Value: !Sub '${ResourcePrefix}-Webhook-Credentials'

  WebhookDLQ:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: !Sub '${ResourcePrefix}-Webhook-DLQ'
      SqsManagedSseEnabled: true
      MessageRetentionPeriod: 1209600
      Tags:
        - Key: Name
          Value: !Sub '${ResourcePrefix}-Webhook-DLQ'

  DevOpsAgentWebhookLambdaSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub '${ResourcePrefix}-Webhook-Lambda-SG'
      GroupDescription: Security group attached to DevOps Agent webhook Lambda
      VpcId: !Ref VpcId
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref AllowedSourceCidr
      Tags:
        - Key: Name
          Value: !Sub '${ResourcePrefix}-Webhook-Lambda-SG'

  DevOpsAgentWebhookRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub '${ResourcePrefix}-Webhook-Role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
      Policies:
        - PolicyName: SecretsManagerAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - secretsmanager:GetSecretValue
                Resource: !Ref DevOpsAgentWebhookSecret
              - Effect: Allow
                Action:
                  - sqs:SendMessage
                Resource: !GetAtt WebhookDLQ.Arn
      Tags:
        - Key: Name
          Value: !Sub '${ResourcePrefix}-Webhook-Role'

  DevOpsAgentWebhookFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub '${ResourcePrefix}-DevOpsAgent-Webhook'
      Runtime: python3.13
      Handler: index.lambda_handler
      Role: !GetAtt DevOpsAgentWebhookRole.Arn
      Timeout: 30
      ReservedConcurrentExecutions: 10
      DeadLetterConfig:
        TargetArn: !GetAtt WebhookDLQ.Arn
      VpcConfig:
        SubnetIds: !Ref LambdaSubnetIds
        SecurityGroupIds:
          - !Ref DevOpsAgentWebhookLambdaSecurityGroup
      Environment:
        Variables:
          SECRET_ARN: !Ref DevOpsAgentWebhookSecret
      Code:
        ZipFile: |
          import json
          import os
          import urllib3
          import hmac
          import hashlib
          import base64
          import boto3
          from datetime import datetime

          http = urllib3.PoolManager()
          secrets_client = boto3.client('secretsmanager')

          def get_webhook_credentials():
              secret_arn = os.environ['SECRET_ARN']
              response = secrets_client.get_secret_value(SecretId=secret_arn)
              return json.loads(response['SecretString'])

          def _find_account_id(obj):
            # CloudWatch Alarm State Change の configuration.metrics などを再帰探索して accountId を抽出
            if isinstance(obj, dict):
              for key in ('accountId', 'AccountId'):
                value = obj.get(key)
                if isinstance(value, str) and value.isdigit() and len(value) == 12:
                  return value
              for value in obj.values():
                found = _find_account_id(value)
                if found:
                  return found
            elif isinstance(obj, list):
              for item in obj:
                found = _find_account_id(item)
                if found:
                  return found
            return None

          def lambda_handler(event, context):
            print(f"Received event: {json.dumps(event)}")

            detail = event.get('detail', {})
            alarm_name = detail.get('alarmName', 'UnknownAlarm')
            alarm_description = detail.get('configuration', {}).get('description', 'No description')
            state = detail.get('state', {})
            new_state = state.get('value', 'UNKNOWN')
            reason = state.get('reason', 'No reason provided')
            timestamp = state.get('timestamp', datetime.utcnow().isoformat())
            region = event.get('region', os.environ.get('AWS_REGION', 'us-east-1'))
            monitoring_account_id = event.get('account', 'unknown')

            # OAM のクロスアカウントメトリクスに紐づく Alarm イベントから対象アカウント ID を推定
            target_account_id = _find_account_id(detail.get('configuration', {}))
            if not target_account_id:
              target_account_id = monitoring_account_id

            if new_state != 'ALARM':
              print(f"Alarm state is {new_state}, not triggering investigation")
              return {'statusCode': 200, 'body': 'Alarm not in ALARM state'}

            credentials = get_webhook_credentials()
            webhook_url = credentials['DEVOPS_AGENT_WEBHOOK_URL']
            webhook_secret = credentials['DEVOPS_AGENT_WEBHOOK_SECRET']
            if not webhook_url or not webhook_secret:
              print("Webhook credentials not configured yet")
              return {'statusCode': 200, 'body': 'Webhook credentials not configured'}

            payload = {
              'eventType': 'incident',
              'incidentId': f"{alarm_name}-{int(datetime.utcnow().timestamp())}",
              'action': 'created',
              'priority': 'HIGH',
              'title': f"CloudWatch Alarm: {alarm_name}",
              'description': f"{alarm_description}\n\nReason: {reason}\nMonitoringAccountId: {monitoring_account_id}\nTargetAccountId: {target_account_id}",
              'timestamp': timestamp,
              'service': alarm_name,
              'data': {
                'metadata': {
                  'region': region,
                  'environment': 'oam-cross-account-monitoring',
                  'monitoringAccountId': monitoring_account_id,
                  'targetAccountId': target_account_id,
                  'alarmName': alarm_name,
                  'alarmState': new_state
                }
              }
            }

            payload_str = json.dumps(payload)
            timestamp_str = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.000Z')
            message = f"{timestamp_str}:{payload_str}"
            signature = base64.b64encode(
              hmac.new(
                webhook_secret.encode('utf-8'),
                message.encode('utf-8'),
                hashlib.sha256
              ).digest()
            ).decode('utf-8')

            headers = {
              'Content-Type': 'application/json',
              'x-amzn-event-timestamp': timestamp_str,
              'x-amzn-event-signature': signature
            }

            try:
              response = http.request(
                'POST',
                webhook_url,
                body=payload_str,
                headers=headers
              )
              print(f"Webhook response: {response.status} - {response.data.decode('utf-8')}")
              return {
                'statusCode': 200,
                'body': json.dumps({
                  'message': 'DevOps Agent investigation triggered',
                  'alarmName': alarm_name,
                  'webhookStatus': response.status,
                  'targetAccountId': target_account_id
                })
              }
            except Exception as e:
              print(f"Error calling webhook: {str(e)}")
              return {
                'statusCode': 500,
                'body': json.dumps({'error': str(e)})
              }

  WebhookEventBridgeRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub '${ResourcePrefix}-EventBridge-Rule'
      State: ENABLED
      EventPattern:
        source:
          - aws.cloudwatch
        detail-type:
          - CloudWatch Alarm State Change
        detail:
          state:
            value:
              - ALARM
      Targets:
        - Id: DevOpsAlarmWebhookLambdaTarget
          Arn: !GetAtt DevOpsAgentWebhookFunction.Arn

  WebhookFunctionPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref DevOpsAgentWebhookFunction
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt WebhookEventBridgeRule.Arn

このテンプレートの WebhookEventBridgeRule は、alarmName 条件を指定していないため、対象リージョン内で ALARM に遷移した CloudWatch アラーム全般を対象にします。特定の複数アラームだけに限定したい場合は、EventPattern.detail.alarmName に対象アラーム名を列挙してください。

複数アラーム名をパラメータで受けて対象を限定したい場合は、例えば以下のように CommaDelimitedList パラメータを追加できます。

Parameters:
  TargetAlarmNames:
    Type: CommaDelimitedList
    Description: Comma-separated CloudWatch alarm names to trigger DevOps Agent

Resources:
  WebhookEventBridgeRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub '${ResourcePrefix}-EventBridge-Rule'
      State: ENABLED
      EventPattern:
        source:
          - aws.cloudwatch
        detail-type:
          - CloudWatch Alarm State Change
        detail:
          alarmName: !Ref TargetAlarmNames
          state:
            value:
              - ALARM
      Targets:
        - Id: DevOpsAlarmWebhookLambdaTarget
          Arn: !GetAtt DevOpsAgentWebhookFunction.Arn

Step 3: DevOps Agent Webhook を用意(コンソール / HMAC 署名用)

Webhookの作成 は CloudFormation および CLI 非対応(2026-08-08 時点) — AWS マネジメントコンソールで作成します。

AWS マネジメントコンソールで Agent Space の Webhook を作成します。Webhook は HMAC 認証で利用し、Step 2 の Lambda で署名ヘッダを付与して呼び出します。

  1. AWS コンソールで AWS DevOps Agent を開き、対象の エージェントスペース を選択
  2. エージェントスペース の 機能 タブを開き、Agent Space ウェブフック セクションで 追加 を選択
  3. データスキーマを検証 はそのまま 次へ をクリック
  4. ウェブフックの認証タイプ で HMAC を選択し、次へ をクリック
  5. ウェブフックを作成してエージェントスペースの調査を開始 で URL と認証情報を生成する をクリック
  6. 表示された ウェブフック URLシークレットキー を控えて 自分の URL と認証情報を保存して保管しました にチェックを入れて 追加 をクリック

シークレットキー および ウェブフック URL は機密情報として扱い、取得後すぐに Secrets Manager に保存してください。
シークレットキー は画面遷移後に再表示できないため、作成時に必ず安全な場所へ保存してください。

Step 4: Webhook 情報を Secrets Manager に登録(CLI)

Step 2 の CloudFormation で作成した Secrets Manager シークレットに、Step 3 で取得した Webhook 情報を登録します。

  • DEVOPS_AGENT_WEBHOOK_URL
  • DEVOPS_AGENT_WEBHOOK_SECRET

CloudFormation でシークレット「リソース」は作成し、シークレット値の更新のみ AWS CLI で実施します。

# Step 2 で作成したシークレット名を指定して値を投入
aws secretsmanager put-secret-value \
  --secret-id devops-agent-webhook-credentials \
  --secret-string '{\"DEVOPS_AGENT_WEBHOOK_URL\":\"https://example.event-ai.ap-northeast-1.amazonaws.com/...\",\"DEVOPS_AGENT_WEBHOOK_SECRET\":\"replace-me\"}' \
  --region ap-northeast-1

Step 5: 動作確認

  1. 任意の CloudWatch アラームをテスト条件で ALARM に遷移していることを確認
    CloudWatchアラーム.png

  2. EventBridge ルールの モニタリング タブを開き、MatchedEvents がカウントされていることを確認
    EventBridge.png

  3. Lambda の モニタリング タブを開き、エラーカウントと成功率 に成功率100%がカウントされていることを確認
    Lambda.png

  4. DevOps Agent のウェブアプリから インシデントレスポンス を開き、対象のCloudWatch アラームに対して調査が開始されていることを確認

  • インシデントレスポンスダッシュボード
    インシデントレスポンスダッシュボード.png

  • 調査タイムライン
    調査タイムライン.png

  • 根本原因
    根本原因.png

  • 緩和計画
    緩和計画.png


9. コストとクォータの管理

主要リソースのコスト抑止の整理

機能を豊富に利用するとコストがかさむため、非機能要件に合わせて必要なリソースを適切に利用することでコストを抑止することが重要となります。

項目 発生アカウント 削減ポイント
CloudWatch OAM 各ソースアカウント 集約アカウントはソースアカウントのデータをリアルタイムで参照するため、重複コスト無し
CloudWatch メトリクス保存 各ソースアカウント 高解像度(1秒)メトリクスを避け標準(60秒)を使用
CloudWatch Logs 保存 各ソースアカウント ロググループの保持期間を明示的に設定(デフォルトは無期限)
Route 53 Resolver Inbound Endpoint 各ソースアカウント サブネット数を最小限に(AZ 冗長を考慮しつつ)
VPC Interface Endpoint 各アカウント サブネット数を最小限に(AZ 冗長を考慮しつつ)
CloudWatch アラーム 集約アカウント 複合アラームでアラーム数を集約して削減
DevOps Agent 集約アカウント 自律調査を自動起動させる対象のアラームを選定

公式ドキュメント引用: "CloudWatch のクロスアカウントオブザーバビリティでは、ログとメトリクス、Application Signals の追加コストは発生せず"
出典: CloudWatch のクロスアカウントオブザーバビリティ


クォータ制限:設計前に確認すべき上限値

「主に注意すべきアカウント」は、アラーム・通知制御を集約アカウントに集める本記事の運用前提で整理しています。

本構成で使用する主要リソースのクォータを整理します。大量アカウント環境をまとめて管理する場合は、設計前に必ず確認してください。

クォータ値は 2026-08-08 時点で AWS 公式ドキュメントを確認した内容です。

クォータは変更される場合があります。
設計時は必ず AWS Service Quotas コンソール で最新値を確認してください。

OAM(Observability Access Manager)

クォータ名 デフォルト値 変更可否 主に注意すべきアカウント 注意点
シンク数(アカウントあたり・リージョンごと) 1 不可 集約アカウント 集約アカウントは1リージョンにつきシンクが1つのみです。マルチリージョン構成では各リージョンにシンクを作成します。
シンクあたりのリンク数(ソースアカウント数) 100,000 不可 集約アカウント 地方公共団体向け環境では十分な数量となります。
ソースアカウントあたりのリンク数(監視アカウント数) 5 不可 ソースアカウント 1ソースアカウントが接続できる監視アカウントの上限です。複数の監視アカウントを持つ場合でも5つ以内に収める必要があります。

参考: CloudWatch Observability Access Manager endpoints and quotas

CloudWatch アラーム

クォータ名 デフォルト値 変更可否 主に注意すべきアカウント 注意点
PutMetricAlarm API レート 3 リクエスト/秒 集約アカウント 大量のアラームを一括作成するスクリプト実行時はスロットリングに注意し、exponential backoff を実装します。
PutCompositeAlarm API レート 3 リクエスト/秒 集約アカウント 同様にスロットリングに注意します。

参考: CloudWatch endpoints and quotas

Alarm Mute Rules

クォータ名 デフォルト値 変更可否 主に注意すべきアカウント 注意点
ミュートルール数(アカウントあたり・リージョンごと) 2,000 不可 集約アカウント 集約アカウントでクロスアカウントアラームを大量作成する場合は上限に注意します。
1ルールあたりの対象アラーム数 100 不可 集約アカウント 監視対象が100超のアラームをまとめてミュートしたい場合は複数のルールに分割する必要があります。

参考: CloudWatch endpoints and quotas
参考: Amazon CloudWatch - AWS SDK for PHP V3

Network Synthetic Monitor

クォータ名 デフォルト値 変更可否 主に注意すべきアカウント 注意点
モニター数(アカウントあたり・リージョンごと) 100 ソースアカウント 1 アカウント 1 リージョンに 100 モニターまでです。大量アカウント環境でも各アカウントに 1 モニター作成で問題ありません。
プローブ数(1 モニターあたり) 24 ソースアカウント 1 モニターで監視できる宛先(ネットワーク機器)の上限です。デバイス数が多い場合は複数モニターに分割します。
プローブ数(1 サブネット・1 モニターあたり) 4 ソースアカウント 同一サブネットから同一モニター内に作成できるプローブ数の上限です。

参考: Network Synthetic Monitor endpoints and quotas

VPC Interface Endpoint

クォータ名 デフォルト値 変更可否 主に注意すべきアカウント 注意点
VPCあたりのエンドポイント数 50 両方(集約・ソース) 監視用(monitoring, logs, ssm 等)に加え、他サービスのエンドポイントも同一 VPC に作成する場合は合計数に注意します。集約アカウントでは event-ai など運用系エンドポイントも考慮します。

参考: AWS PrivateLink quotas

CloudWatch Logs

クォータ名 デフォルト値 変更可否 主に注意すべきアカウント 注意点
ロググループ数(アカウントあたり) 1,000,000 ソースアカウント 上限は余裕がありますが、命名規則を統一して管理コストを抑えます。
PutLogEvents スロットリング 5,000/秒 ソースアカウント 大量送信時はアカウント/リージョンごとの取り込み上限を監視し、必要に応じて Service Quotas で引き上げます。
PutLogEvents バッチサイズ 1 MB / バッチ 不可 ソースアカウント 大量ログ送信時はバッチサイズに注意します。

参考: CloudWatch Logs endpoints and quotas


10. まとめ

AWSサービスで実装する統合監視機能の構成について

課題

SNMP 監視および SNMP Trap 監視が未対応であることや大量アカウント環境で AWS の統合監視を実装する際にミュートルールなどクォータが不足する可能性があるため、現時点では本構成に完全移行することは困難であり、他の統合監視システムと組み合わせて構成する必要があると思います。

課題 内容 根拠(AWS ドキュメント/公開情報) 主な対策
SNMP 監視 / SNMP Trap 監視のマネージド未対応 CloudWatch のマネージド機能だけでは SNMP/SNMP Trap を直接取り込めず、統合監視要件を満たせません。 AWS Cloud Operations Blog の SNMP 連携例は Logstash 経由であり、CloudWatch ネイティブの直接取り込みではありません。 SNMP/SNMP Trap は初期段階で別連携方式を検討し、監視対象ごとに責務分界を定義します。
Alarm Mute Rules の上限管理 大量アラームを単一ルールで扱えず、メンテナンス時のミュート設計が複雑化します。また、ルール数が不足する可能性があります。 クォータによりミュートルール数の上限が 2,000、仕様により1 ルール対象アラームが100 サービス別・機能グループ別にルールを集約します。

所感

今年(2026年)に入り、Syslog 監視やアラームのミュート機能が追加されていることから、AWSのマネージドサービスによる統合監視を実現できる日が近づいていると感じ嬉しく思います。
また、DevOps Agentによる自律的な調査で対応時間が実体験として短縮できています。
上記の通り課題はありますが、今後の機能追加を期待し、適宜最新情報を確認して本記事についてもブラッシュアップしていきたいと思います。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?