AWSのマルチアカウント環境でセキュリティサービスの通知をアカウントごとに振り分ける仕組みを作ってみた

AWSのマルチアカウント環境でセキュリティサービスの通知をアカウントごとに振り分ける仕組みを作ってみた

AWSのマルチアカウント環境で、Security Hub、GuardDuty、IAM Access Analyzer、Inspectorの検出結果をEventBridgeとStep Functionsで集約・整形し、アカウントごとにSNSトピックへ振り分けて通知する仕組みを構築しました。
2026.05.19

こんにちは!クラウド事業本部の吉田です。

以前、マルチアカウント環境におけるセキュリティサービスの構成についてまとめた記事を執筆しました。

https://dev.classmethod.jp/articles/multi-account-aws-security-services-architecture/

この記事では、Security Hub CSPM、GuardDuty、IAM Access Analyzer、Inspectorの検出結果をAuditアカウントのSecurity Hub CSPMに集約する構成を紹介しました。
今回は、集約した検出結果をアカウントごとに振り分けて通知する仕組みを構築してみます。

【ブログ使用】セキュリティサービス全体構成図.png

画像引用:AWSのマルチアカウント環境におけるセキュリティサービスの構成をまとめてみた | DevelopersIO

やりたいこと

セキュリティサービスの検出結果を、発生元のアカウントに応じて担当者へ振り分けて通知したいと思います。

今回構築する通知基盤の全体像は次のとおりです。

【使用】セキュリティサービス通知.png

処理の流れは以下のようになります。

  • 管理アカウントのSecurity Hub CSPM検出結果をEventBridgeでAuditアカウント上のEventBridgeデフォルトイベントバスに転送
  • AuditアカウントのEventBridgeルールでサービスごとにフィルタリング
  • Step Functions(整形処理)で通知文を整形し、EventBridgeカスタムイベントバスへ転送
  • カスタムイベントバスからStep Functions(振り分け処理)を起動
  • アカウントIDに基づいて対応するSNSトピックへ振り分け

整形処理と振り分け処理を2つのStep Functionsに分離しています。
これにより、通知文のフォーマット変更と通知先の追加をそれぞれ独立して行えます。

この整形処理と振り分け処理は、以前執筆したマルチアカウント環境でCloudWatch Alarmを一元管理する構成と同じような仕組みとなっております。

https://dev.classmethod.jp/articles/multi-account-cloudwatch-alarm-centralized-management/

通知対象

今回の構成で通知する検出結果は以下のとおりです。

サービス 通知対象 フィルタ条件
Security Hub CSPM コントロール違反 MEDIUM/HIGH/CRITICAL、FAILED/WARNING/NOT_AVAILABLE
GuardDuty 脅威検知 MEDIUM/HIGH/CRITICAL
IAM Access Analyzer 外部アクセス検出 すべての検出結果(組織外のアクセス)
Inspector 脆弱性検知 MEDIUM/HIGH/CRITICAL

Security Hub CSPMはセキュリティ基準(AWS Foundational Security Best Practices)のコントロール違反のみを対象としています。

通知文フォーマット

Step Functions(整形処理)で生成される通知文のフォーマットを紹介します。
通知文はStates.Format関数を使って整形し、件名と本文を生成しています。

Security Hub CSPM

件名

緊急度: {Severity.Label} Security Hubセキュリティアラート Account: {AwsAccountId}

本文

Security Hubで設定の問題が検知されました。

検知内容: {Title}
リソース種類: {Resources[0].Type}
リソースID: {Resources[0].Id}
詳細: {Description}
リージョン: {Region}
推奨事項URL: {ProductFields.RecommendationUrl}

サンプル

件名: 緊急度: MEDIUM Security Hubセキュリティアラート Account: 123456789012

Security Hubで設定の問題が検知されました。

検知内容: S3.8 S3 Block Public Access setting should be enabled at the bucket level
リソース種類: AwsS3Bucket
リソースID: arn:aws:s3:::example-bucket
詳細: This control checks whether Amazon S3 buckets have bucket-level public access blocks applied.
リージョン: ap-northeast-1
推奨事項URL: https://docs.aws.amazon.com/console/securityhub/S3.8/remediation

GuardDuty

件名

緊急度: {Severity.Label} GuardDutyセキュリティアラート Account: {AwsAccountId}

本文

以下の脅威を検知しました。

検出タイプ: {Types[0]}
詳細: {Description}
リージョン: {Region}
推奨事項URL: https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/guardduty_finding-types-active.html

サンプル

件名: 緊急度: HIGH GuardDutyセキュリティアラート Account: 123456789012

以下の脅威を検知しました。

検出タイプ: TTPs/Command and Control/Backdoor:EC2-C&CActivity.B
詳細: EC2 instance i-0abc123def456 is communicating with a known command and control server.
リージョン: ap-northeast-1
推奨事項URL: https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/guardduty_finding-types-active.html

IAM Access Analyzer

件名

IAM Access Analyzerセキュリティアラート Account: {AwsAccountId}

本文

以下リソースが外部共有されています。

リソース種類: {Resources[0].Type}
リソース名: {Resources[0].Id}
リージョン: {Region}
詳細: {Description}

サンプル

件名: IAM Access Analyzerセキュリティアラート Account: 123456789012

以下リソースが外部共有されています。

リソース種類: AWS::S3::Bucket
リソース名: arn:aws:s3:::example-public-bucket
リージョン: ap-northeast-1
詳細: The S3 bucket policy grants public access to the bucket.

Inspector

件名

緊急度: {Severity.Label} Inspectorセキュリティアラート Account: {AwsAccountId}

本文

脆弱性が検出されました。

タイトル: {Title}
リソースタイプ: {Resources[0].Type}
リソースID: {Resources[0].Id}
初回検出日時: {FirstObservedAt}
最終検出日時: {LastObservedAt}
リージョン: {Resources[0].Region}

サンプル

件名: 緊急度: HIGH Inspectorセキュリティアラート Account: 123456789012

脆弱性が検出されました。

タイトル: CVE-2023-12345 - Example Package Remote Code Execution
リソースタイプ: AwsEc2Instance
リソースID: arn:aws:ec2:ap-northeast-1:123456789012:instance/i-0abc123def456
初回検出日時: 2024-01-15T10:30:00Z
最終検出日時: 2024-01-20T14:00:00Z
リージョン: ap-northeast-1

通知文のカスタマイズは、Step Functionsのステートマシン定義を修正します。

構築手順(Auditアカウント)

CloudShellでAWS CLIを使って構築します。リソースは処理フローの逆順に作成していきます。ターゲットとなるリソースを先に用意しないと、ルールやステートマシンの設定時に参照できないためです。

変数の設定

まず、環境に合わせて変数を設定します。

# Auditアカウント(自アカウント)
AUDIT_ACCOUNT_ID="123456789012"

# 管理アカウント
MGMT_ACCOUNT_ID="111122223333"

# メンバーアカウント
MEMBER1_ACCOUNT_ID="444455556666"
MEMBER2_ACCOUNT_ID="777788889999"

# リージョン
REGION="ap-northeast-1"

SNSトピックの作成

振り分け先となるSNSトピックを作成します。今回は管理アカウント、Auditアカウント、メンバーアカウント2つの4アカウント分と、デフォルト通知先を用意します。

# デフォルト通知先(未登録アカウント用)
aws sns create-topic --name security-alert-default --region ${REGION}

# 管理アカウント用
aws sns create-topic --name security-alert-management --region ${REGION}

# Auditアカウント用
aws sns create-topic --name security-alert-audit --region ${REGION}

# メンバーアカウント1用
aws sns create-topic --name security-alert-member1 --region ${REGION}

# メンバーアカウント2用
aws sns create-topic --name security-alert-member2 --region ${REGION}

サブスクリプションを追加してください。

確認メールが届くので、リンクをクリックして承認します。他のトピックにも同様にサブスクリプションを追加してください。

Step Functions(振り分け処理)の作成

整形済みイベントをアカウントIDに基づいてSNSトピックに振り分けるステートマシンを作成します。

まず、IAMロールを作成します。

sfn-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "states.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
aws iam create-role \
  --role-name security-alert-sfn-dispatcher-role \
  --assume-role-policy-document file://sfn-trust-policy.json

SNSトピックへのPublish権限を付与します。<AuditアカウントID>は環境に合わせて置き換えてください。

sfn-dispatcher-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sns:Publish",
      "Resource": [
        "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-default",
        "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-management",
        "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-audit",
        "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-member1",
        "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-member2"
      ]
    }
  ]
}
aws iam put-role-policy \
  --role-name security-alert-sfn-dispatcher-role \
  --policy-name security-alert-sfn-dispatcher-policy \
  --policy-document file://sfn-dispatcher-policy.json

ステートマシンを作成します。ChoiceステートでアカウントIDを判定し、一致するSNSトピックへPublishします。
どのアカウントにも一致しない場合はデフォルトトピックへ通知します。

<管理アカウントID><AuditアカウントID><メンバーアカウント1ID><メンバーアカウント2ID>は環境に合わせて置き換えてください。

dispatcher-state-machine.json
{
  "Comment": "Security Alert Dispatcher State Machine",
  "StartAt": "DetermineNotificationTarget",
  "States": {
    "DetermineNotificationTarget": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.detail.AccountId",
          "StringEquals": "<管理アカウントID>",
          "Comment": "Management Account",
          "Next": "NotifyManagement"
        },
        {
          "Variable": "$.detail.AccountId",
          "StringEquals": "<AuditアカウントID>",
          "Comment": "Audit Account",
          "Next": "NotifyAudit"
        },
        {
          "Variable": "$.detail.AccountId",
          "StringEquals": "<メンバーアカウント1ID>",
          "Comment": "Member Account 1",
          "Next": "NotifyMember1"
        },
        {
          "Variable": "$.detail.AccountId",
          "StringEquals": "<メンバーアカウント2ID>",
          "Comment": "Member Account 2",
          "Next": "NotifyMember2"
        }
      ],
      "Default": "NotifyDefault"
    },
    "NotifyManagement": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-management",
        "Subject.$": "$.detail.Subject",
        "Message.$": "$.detail.Message"
      },
      "End": true
    },
    "NotifyAudit": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-audit",
        "Subject.$": "$.detail.Subject",
        "Message.$": "$.detail.Message"
      },
      "End": true
    },
    "NotifyMember1": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-member1",
        "Subject.$": "$.detail.Subject",
        "Message.$": "$.detail.Message"
      },
      "End": true
    },
    "NotifyMember2": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-member2",
        "Subject.$": "$.detail.Subject",
        "Message.$": "$.detail.Message"
      },
      "End": true
    },
    "NotifyDefault": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "arn:aws:sns:ap-northeast-1:<AuditアカウントID>:security-alert-default",
        "Subject.$": "$.detail.Subject",
        "Message.$": "$.detail.Message"
      },
      "End": true
    }
  }
}
aws stepfunctions create-state-machine \
  --name security-alert-dispatcher \
  --definition file://dispatcher-state-machine.json \
  --role-arn "arn:aws:iam::${AUDIT_ACCOUNT_ID}:role/security-alert-sfn-dispatcher-role" \
  --region ${REGION}

カスタムイベントバスとEventBridgeルールの作成

整形済みイベントを受け取るカスタムイベントバスを作成します。

aws events create-event-bus \
  --name security-alert-custom-bus \
  --region ${REGION}

カスタムイベントバスから振り分け用Step Functionsを呼び出すEventBridgeルールを作成します。まず、IAMロールを作成します。

eventbridge-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
aws iam create-role \
  --role-name security-alert-eb-to-dispatcher-role \
  --assume-role-policy-document file://eventbridge-trust-policy.json
eb-to-sfn-dispatcher-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "states:StartExecution",
      "Resource": "arn:aws:states:ap-northeast-1:<AuditアカウントID>:stateMachine:security-alert-dispatcher"
    }
  ]
}
aws iam put-role-policy \
  --role-name security-alert-eb-to-dispatcher-role \
  --policy-name security-alert-eb-to-dispatcher-policy \
  --policy-document file://eb-to-sfn-dispatcher-policy.json

ルールを作成します。整形処理からPutされたイベントを受け取るためのパターンを設定しています。

event-pattern-custom-bus.json
{
  "source": ["custom.securityalert.stepfunctions"],
  "detail-type": ["Shaped Security Findings"]
}
aws events put-rule \
  --name security-alert-custom-to-dispatcher \
  --event-bus-name security-alert-custom-bus \
  --event-pattern file://event-pattern-custom-bus.json \
  --state ENABLED \
  --region ${REGION}

ターゲットを設定します。

aws events put-targets \
  --rule security-alert-custom-to-dispatcher \
  --event-bus-name security-alert-custom-bus \
  --targets "[{
    \"Id\": \"DispatcherTarget\",
    \"Arn\": \"arn:aws:states:${REGION}:${AUDIT_ACCOUNT_ID}:stateMachine:security-alert-dispatcher\",
    \"RoleArn\": \"arn:aws:iam::${AUDIT_ACCOUNT_ID}:role/security-alert-eb-to-dispatcher-role\"
  }]" \
  --region ${REGION}

Step Functions(整形処理)の作成

各セキュリティサービスの検出結果を通知用文章に整形するステートマシンを作成します。

IAMロールを作成します。信頼ポリシーは先ほど作成したsfn-trust-policy.jsonを再利用します。

aws iam create-role \
  --role-name security-alert-sfn-formatter-role \
  --assume-role-policy-document file://sfn-trust-policy.json

カスタムイベントバスへのPutEvents権限を付与します。

sfn-formatter-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "events:PutEvents",
      "Resource": "arn:aws:events:ap-northeast-1:<AuditアカウントID>:event-bus/security-alert-custom-bus"
    }
  ]
}
aws iam put-role-policy \
  --role-name security-alert-sfn-formatter-role \
  --policy-name security-alert-sfn-formatter-policy \
  --policy-document file://sfn-formatter-policy.json

ステートマシンを作成します。
ChoiceステートでProductNameを判定し、サービスごとに通知文を整形します。
Security HubはStandardsArnの有無でコントロール違反かどうかを判別しています。

formatter-state-machine.json
{
  "Comment": "Security Alert Shaping State Machine",
  "StartAt": "ChoiceService",
  "States": {
    "ChoiceService": {
      "Type": "Choice",
      "Choices": [
        {
          "And": [
            {
              "Variable": "$.detail.findings[0].ProductName",
              "StringEquals": "Security Hub"
            },
            {
              "Variable": "$.detail.findings[0].ProductFields.StandardsArn",
              "IsPresent": true
            }
          ],
          "Next": "SecurityHubShaping"
        },
        {
          "Variable": "$.detail.findings[0].ProductName",
          "StringEquals": "GuardDuty",
          "Next": "GuardDutyShaping"
        },
        {
          "Variable": "$.detail.findings[0].ProductName",
          "StringEquals": "IAM Access Analyzer",
          "Next": "AccessAnalyzerShaping"
        },
        {
          "Variable": "$.detail.findings[0].ProductName",
          "StringEquals": "Inspector",
          "Next": "InspectorShaping"
        }
      ],
      "Default": "Fail"
    },
    "SecurityHubShaping": {
      "Type": "Pass",
      "Parameters": {
        "Subject.$": "States.Format('緊急度: {} Security Hubセキュリティアラート Account: {}', $.detail.findings[0].Severity.Label, $.detail.findings[0].AwsAccountId)",
        "Message.$": "States.Format('Security Hubで設定の問題が検知されました。\n\n検知内容: {}\nリソース種類: {}\nリソースID: {}\n詳細: {}\nリージョン: {}\n推奨事項URL: {}', $.detail.findings[0].Title, $.detail.findings[0].Resources[0].Type, $.detail.findings[0].Resources[0].Id, $.detail.findings[0].Description, $.detail.findings[0].Region, $.detail.findings[0].ProductFields.RecommendationUrl)",
        "AccountId.$": "$.detail.findings[0].AwsAccountId"
      },
      "Next": "PutToCustomBus"
    },
    "GuardDutyShaping": {
      "Type": "Pass",
      "Parameters": {
        "Subject.$": "States.Format('緊急度: {} GuardDutyセキュリティアラート Account: {}', $.detail.findings[0].Severity.Label, $.detail.findings[0].AwsAccountId)",
        "Message.$": "States.Format('以下の脅威を検知しました。\n\n検出タイプ: {}\n詳細: {}\nリージョン: {}\n推奨事項URL: https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/guardduty_finding-types-active.html', $.detail.findings[0].Types[0], $.detail.findings[0].Description, $.detail.findings[0].Region)",
        "AccountId.$": "$.detail.findings[0].AwsAccountId"
      },
      "Next": "PutToCustomBus"
    },
    "AccessAnalyzerShaping": {
      "Type": "Pass",
      "Parameters": {
        "Subject.$": "States.Format('IAM Access Analyzerセキュリティアラート Account: {}', $.detail.findings[0].AwsAccountId)",
        "Message.$": "States.Format('以下リソースが外部共有されています。\n\nリソース種類: {}\nリソース名: {}\nリージョン: {}\n詳細: {}', $.detail.findings[0].Resources[0].Type, $.detail.findings[0].Resources[0].Id, $.detail.findings[0].Region, $.detail.findings[0].Description)",
        "AccountId.$": "$.detail.findings[0].AwsAccountId"
      },
      "Next": "PutToCustomBus"
    },
    "InspectorShaping": {
      "Type": "Pass",
      "Parameters": {
        "Subject.$": "States.Format('緊急度: {} Inspectorセキュリティアラート Account: {}', $.detail.findings[0].Severity.Label, $.detail.findings[0].AwsAccountId)",
        "Message.$": "States.Format('脆弱性が検出されました。\n\nタイトル: {}\nリソースタイプ: {}\nリソースID: {}\n初回検出日時: {}\n最終検出日時: {}\nリージョン: {}', $.detail.findings[0].Title, $.detail.findings[0].Resources[0].Type, $.detail.findings[0].Resources[0].Id, $.detail.findings[0].FirstObservedAt, $.detail.findings[0].LastObservedAt, $.detail.findings[0].Resources[0].Region)",
        "AccountId.$": "$.detail.findings[0].AwsAccountId"
      },
      "Next": "PutToCustomBus"
    },
    "PutToCustomBus": {
      "Type": "Task",
      "Resource": "arn:aws:states:::events:putEvents",
      "Parameters": {
        "Entries": [
          {
            "Detail": {
              "Subject.$": "$.Subject",
              "Message.$": "$.Message",
              "AccountId.$": "$.AccountId"
            },
            "DetailType": "Shaped Security Findings",
            "EventBusName": "security-alert-custom-bus",
            "Source": "custom.securityalert.stepfunctions"
          }
        ]
      },
      "End": true
    },
    "Fail": {
      "Type": "Fail",
      "Error": "UnknownSource",
      "Cause": "Unknown event source"
    }
  }
}
aws stepfunctions create-state-machine \
  --name security-alert-formatter \
  --definition file://formatter-state-machine.json \
  --role-arn "arn:aws:iam::${AUDIT_ACCOUNT_ID}:role/security-alert-sfn-formatter-role" \
  --region ${REGION}

EventBridgeルール(デフォルトバス→整形SFN)の作成

各セキュリティサービスからの検出結果をフィルタリングし、整形用ステートマシンに転送するルールを作成します。

IAMロールを作成します。このロールは4つのルールで共通利用します。
信頼ポリシーは先ほど作成したeventbridge-trust-policy.jsonを再利用します。

aws iam create-role \
  --role-name security-alert-eb-to-formatter-role \
  --assume-role-policy-document file://eventbridge-trust-policy.json
eb-to-sfn-formatter-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "states:StartExecution",
      "Resource": "arn:aws:states:ap-northeast-1:<AuditアカウントID>:stateMachine:security-alert-formatter"
    }
  ]
}
aws iam put-role-policy \
  --role-name security-alert-eb-to-formatter-role \
  --policy-name security-alert-eb-to-formatter-policy \
  --policy-document file://eb-to-sfn-formatter-policy.json

Security Hub CSPM用ルール

Security Hubのコントロール違反を通知対象とします。
ProductFields.StandardsArnでセキュリティ基準を指定しています。

event-pattern-securityhub.json
{
  "detail-type": ["Security Hub Findings - Imported"],
  "source": ["aws.securityhub"],
  "detail": {
    "findings": {
      "Compliance": {
        "Status": ["FAILED", "WARNING", "NOT_AVAILABLE"]
      },
      "RecordState": ["ACTIVE"],
      "ProductFields": {
        "StandardsArn": ["arn:aws:securityhub:::standards/aws-foundational-security-best-practices/v/1.0.0"]
      },
      "Workflow": {
        "Status": ["NEW"]
      },
      "Severity": {
        "Label": ["MEDIUM", "HIGH", "CRITICAL"]
      }
    }
  }
}
aws events put-rule \
  --name security-alert-securityhub \
  --event-pattern file://event-pattern-securityhub.json \
  --state ENABLED \
  --region ${REGION}
aws events put-targets \
  --rule security-alert-securityhub \
  --targets "[{
    \"Id\": \"FormatterTarget\",
    \"Arn\": \"arn:aws:states:${REGION}:${AUDIT_ACCOUNT_ID}:stateMachine:security-alert-formatter\",
    \"RoleArn\": \"arn:aws:iam::${AUDIT_ACCOUNT_ID}:role/security-alert-eb-to-formatter-role\"
  }]" \
  --region ${REGION}

GuardDuty用ルール

event-pattern-guardduty.json
{
  "detail-type": ["Security Hub Findings - Imported"],
  "source": ["aws.securityhub"],
  "detail": {
    "findings": {
      "ProductName": ["GuardDuty"],
      "RecordState": ["ACTIVE"],
      "Workflow": {
        "Status": ["NEW"]
      },
      "Severity": {
        "Label": ["MEDIUM", "HIGH", "CRITICAL"]
      }
    }
  }
}
aws events put-rule \
  --name security-alert-guardduty \
  --event-pattern file://event-pattern-guardduty.json \
  --state ENABLED \
  --region ${REGION}
aws events put-targets \
  --rule security-alert-guardduty \
  --targets "[{
    \"Id\": \"FormatterTarget\",
    \"Arn\": \"arn:aws:states:${REGION}:${AUDIT_ACCOUNT_ID}:stateMachine:security-alert-formatter\",
    \"RoleArn\": \"arn:aws:iam::${AUDIT_ACCOUNT_ID}:role/security-alert-eb-to-formatter-role\"
  }]" \
  --region ${REGION}

IAM Access Analyzer用ルール

event-pattern-accessanalyzer.json
{
  "detail-type": ["Security Hub Findings - Imported"],
  "source": ["aws.securityhub"],
  "detail": {
    "findings": {
      "ProductName": ["IAM Access Analyzer"],
      "RecordState": ["ACTIVE"],
      "Workflow": {
        "Status": ["NEW"]
      }
    }
  }
}
aws events put-rule \
  --name security-alert-accessanalyzer \
  --event-pattern file://event-pattern-accessanalyzer.json \
  --state ENABLED \
  --region ${REGION}
aws events put-targets \
  --rule security-alert-accessanalyzer \
  --targets "[{
    \"Id\": \"FormatterTarget\",
    \"Arn\": \"arn:aws:states:${REGION}:${AUDIT_ACCOUNT_ID}:stateMachine:security-alert-formatter\",
    \"RoleArn\": \"arn:aws:iam::${AUDIT_ACCOUNT_ID}:role/security-alert-eb-to-formatter-role\"
  }]" \
  --region ${REGION}

Inspector用ルール

event-pattern-inspector.json
{
  "detail-type": ["Security Hub Findings - Imported"],
  "source": ["aws.securityhub"],
  "detail": {
    "findings": {
      "ProductName": ["Inspector"],
      "RecordState": ["ACTIVE"],
      "Workflow": {
        "Status": ["NEW"]
      },
      "Severity": {
        "Label": ["MEDIUM", "HIGH", "CRITICAL"]
      }
    }
  }
}
aws events put-rule \
  --name security-alert-inspector \
  --event-pattern file://event-pattern-inspector.json \
  --state ENABLED \
  --region ${REGION}
aws events put-targets \
  --rule security-alert-inspector \
  --targets "[{
    \"Id\": \"FormatterTarget\",
    \"Arn\": \"arn:aws:states:${REGION}:${AUDIT_ACCOUNT_ID}:stateMachine:security-alert-formatter\",
    \"RoleArn\": \"arn:aws:iam::${AUDIT_ACCOUNT_ID}:role/security-alert-eb-to-formatter-role\"
  }]" \
  --region ${REGION}

デフォルトイベントバスのリソースポリシー設定

管理アカウントからのイベント受信を許可します。

aws events put-permission \
  --event-bus-name default \
  --action events:PutEvents \
  --principal ${MGMT_ACCOUNT_ID} \
  --statement-id AllowManagementAccountPutEvents \
  --region ${REGION}

構築手順(管理アカウント)

管理アカウントのSecurity Hub検出結果をAuditアカウントに転送するEventBridgeルールを作成します。

変数の設定

# 管理アカウント(自アカウント)
MGMT_ACCOUNT_ID="111122223333"

# Auditアカウント
AUDIT_ACCOUNT_ID="123456789012"

# リージョン
REGION="ap-northeast-1"

EventBridgeルールの作成

IAMロールを作成します。
信頼ポリシーはAuditアカウントで作成したeventbridge-trust-policy.jsonと同じ内容です。

eventbridge-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
aws iam create-role \
  --role-name security-alert-eb-to-audit-role \
  --assume-role-policy-document file://eventbridge-trust-policy.json

Auditアカウントのイベントバスへのevents:PutEvents権限を付与します。

eb-to-audit-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "events:PutEvents",
      "Resource": "arn:aws:events:ap-northeast-1:<AuditアカウントID>:event-bus/default"
    }
  ]
}
aws iam put-role-policy \
  --role-name security-alert-eb-to-audit-role \
  --policy-name security-alert-eb-to-audit-policy \
  --policy-document file://eb-to-audit-policy.json

ルールを作成します。
Security Hubのすべての検出結果をAuditアカウントに転送します。

event-pattern-management-to-audit.json
{
  "source": ["aws.securityhub"],
  "detail-type": ["Security Hub Findings - Imported"]
}
aws events put-rule \
  --name security-alert-to-audit \
  --event-pattern file://event-pattern-management-to-audit.json \
  --state ENABLED \
  --region ${REGION}

ターゲットを設定します。

aws events put-targets \
  --rule security-alert-to-audit \
  --targets "[{
    \"Id\": \"AuditEventBusTarget\",
    \"Arn\": \"arn:aws:events:${REGION}:${AUDIT_ACCOUNT_ID}:event-bus/default\",
    \"RoleArn\": \"arn:aws:iam::${MGMT_ACCOUNT_ID}:role/security-alert-eb-to-audit-role\"
  }]" \
  --region ${REGION}

動作確認

では、GuardDutyのサンプル検出結果を使って動作を確認します。
今回のEventBridgeルールではMEDIUM以上の重要度をフィルタしているため、重要度HIGHのサンプル検出結果を作成します。

各アカウントのCloudShellで以下のコマンドを実行し、サンプル検出結果を生成します。

aws guardduty create-sample-findings \
  --detector-id $(aws guardduty list-detectors --query 'DetectorIds[0]' --output text --region ap-northeast-1) \
  --finding-types "Backdoor:EC2/C&CActivity.B" \
  --region ap-northeast-1

無事4アカウント分、各アカウントとして指定したメールアドレスに通知メールが届きました!

メンバーアカウント1

screenshot.png

メンバーアカウント2

screenshot 1.png

Auditアカウント

screenshot 2.png

管理アカウント

screenshot 3.png

さいごに

マルチアカウント環境でセキュリティサービスの通知をアカウントごとに振り分ける仕組みを構築しました。

どなたかのお役に立てれば幸いです。

以上、クラウド事業本部の吉田でした!

参考資料

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事