はじめに ─ 検出結果が、誰にも見られていなかった
MOOBON は AWS Organizations で複数の AWS アカウントを束ねて運用しています。GuardDuty(脅威の検出)や Inspector(脆弱性の検出)は、どれもアカウントごと・リージョンごとに動くサービスです。アカウントが増えるほど、「どのアカウントの、どのリージョンの画面を見ればいいのか」が増えていきます。
実際には、アカウントを切り替えてコンソールを一つずつ開いて確認する、ということは続きません。検出はされていても、誰の目にも触れていない。これが一番まずい状態です。
そこで 2026 年 8 月、セキュリティを見るためだけのアカウント moobon-security を組織に追加し、組織内の検出結果をそこへ集め、対応が必要なものだけがメールと Slack に届く形を作りました。
ところが、記事にまとめるために設定を見直していて、最初に作った通知は東京リージョンの検出しか拾えていなかったことに気づきました。本記事では、その落とし穴と直し方まで含めて書いています。
本記事のアカウント ID・メールアドレス・組織 ID などは、すべて
<SECURITY_ACCOUNT_ID> のようなプレースホルダに置き換えています。コマンドは、設定の形と考え方が伝わるように整理したものです。1. なぜセキュリティ専用アカウントを分けるのか
「全部の検出結果を 1 か所で見る」だけなら、組織の管理アカウントで見る手もあります。それでもあえて専用のアカウントを作るのには、理由が 3 つあります。
管理アカウントには、なるべく入らない
管理アカウントは、請求や SCP(組織全体のガードレール)を握る組織で最も強いアカウントです。日常的にログインする人も、持たせる権限も、最小にしておきたい場所です。AWS も、セキュリティサービスの委任管理者には管理アカウント以外を指定することを推奨しています。
見張る側と、見張られる側を分ける
サービスを動かしているアカウントが乗っ取られたとき、同じアカウントに検出結果があると、攻撃者に検出の設定ごと消されるおそれがあります。見張る仕組みを別のアカウントに置けば、ワークロード側で何が起きても、記録と通知は残ります。
権限をきれいに切り出せる
「検出結果は見られるが、本番の環境は触れない」という権限を作りたいとき、アカウントが分かれていれば、moobon-security へのアクセス権を渡すだけで済みます。アカウントそのものが権限の境界になります。
2. 全体像 ─ 3 つのサービスと委任管理者
使うサービスは 3 つです。それぞれ役割が違います。
| サービス | 何を見つけるか | 例 |
|---|---|---|
| GuardDuty | いま起きている不審な動き(脅威) | 見知らぬ国からの API 呼び出し、EC2 の仮想通貨マイニング、漏れた認証情報の利用 |
| Inspector | 放っておくと狙われる弱点(脆弱性) | EC2・コンテナイメージ・Lambda に入っているパッケージの既知の脆弱性(CVE) |
| Security Hub | 上の 2 つを集めて一覧にする場所 | 全アカウント・全リージョンの検出結果を、重要度順に 1 画面で |
これらを組織全体で動かすときの鍵が委任管理者(delegated administrator)です。管理アカウントが「このサービスの組織全体の管理は moobon-security に任せる」と指定すると、moobon-security から全メンバーアカウントの有効化と検出結果の閲覧ができるようになります。
[ 管理アカウント ] … 委任管理者を指定するだけ(以後はほぼ触らない)
│
▼ 委任
[ moobon-security ] … GuardDuty / Inspector / Security Hub の委任管理者
│ ▲
│ │ 検出結果が自動で集まる(組織のアカウント × 全リージョン)
│ │
│ ├── [ 管理アカウント ]
│ └── [ 自社サービス用のアカウント ]
│
▼ Security Hub(東京に全リージョンを集約)
▼ GuardDuty の重要度 MEDIUM 以上だけ
EventBridge → SNS → メール / Slack(Amazon Q Developer)2025 年 12 月に Security Hub は刷新され、従来の Security Hub は Security Hub CSPM という名前に変わりました。新しい Security Hub は、GuardDuty・Inspector・CSPM の検出結果を関連づけてリスクを示す上位のサービスです。本記事のコマンドと通知ルールは、検出結果を集約する土台として長く使われている Security Hub CSPM の API(
aws securityhub)と検出結果の形式(ASFF)を使っています。MOOBON も、まずはこの CSPM で集約と通知の形を作りました。新しい Security Hub は CSPM や GuardDuty・Inspector の検出結果を材料にする上位のサービスなので、本記事の構成の上に後から足せます。委任管理者も両方で共通です。3. moobon-security アカウントを作る
ここからの 3〜4 章は管理アカウントで実行します。まず組織の中に新しいアカウントを作ります。
# 管理アカウントで実行 aws organizations create-account \ --email aws-security@example.com \ --account-name moobon-security # 作成の進み具合を確認(State が SUCCEEDED になれば完了) aws organizations list-create-account-status --states SUCCEEDED IN_PROGRESS
- メールアドレスは個人ではなく共有の宛先に。このアドレスがアカウントのルートユーザーになります。担当が替わっても受け取れる、グループのアドレスにしておきます。
- Security OU に移す。ワークロード用のアカウントとは別の OU にしておくと、後から SCP をかけ分けやすくなります。
# Security OU を作って、moobon-security を移す aws organizations create-organizational-unit \ --parent-id <ROOT_ID> --name Security aws organizations move-account \ --account-id <SECURITY_ACCOUNT_ID> \ --source-parent-id <ROOT_ID> \ --destination-parent-id <SECURITY_OU_ID>
ログインは、IAM Identity Center(SSO)で moobon-security に Permission Set を割り当てて行います。ルートユーザーには MFA を設定し、ふだんは使いません。SSO の設定は、姉妹記事 AI 開発現場で IAM ユーザーをやめる ── AWS SSO + AssumeRole で詳しく書いています。
# ~/.aws/config に moobon-security 用のプロファイルを追加 [profile moobon-security] sso_session = moobon-sso sso_account_id = <SECURITY_ACCOUNT_ID> sso_role_name = AdministratorAccess region = ap-northeast-1
4. 管理アカウントで委任管理者を指定する
管理アカウントでやる作業は、実質ここまでです。3 つのサービスそれぞれで、moobon-security を委任管理者に指定します。
# 管理アカウントで実行
SEC=<SECURITY_ACCOUNT_ID>
# Security Hub(集約先のリージョン = ap-northeast-1 で 1 回)
aws securityhub enable-organization-admin-account \
--admin-account-id $SEC --region ap-northeast-1
# GuardDuty と Inspector はリージョンごとに指定が必要
for r in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
aws guardduty enable-organization-admin-account \
--admin-account-id $SEC --region $r
aws inspector2 enable-delegated-admin-account \
--delegated-admin-account-id $SEC --region $r
doneここが一番見落としやすい点です。東京リージョンで委任管理者を指定しても、ほかのリージョンには効きません。使っていないリージョンこそ、攻撃者がマイニング用の EC2 を立ち上げる場所になりやすいので、全リージョンで指定しておきます(9 章も参照)。
5. GuardDuty を組織全体で有効化する
ここからは moobon-security で実行します。委任管理者に指定されると、moobon-security 自身の GuardDuty は有効になっています。あとは、組織のアカウントをメンバーとして追加します。
# moobon-security で実行(リージョンごと)
DET=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text \
--profile moobon-security)
# 組織のアカウントをメンバーに追加(組織内のアカウントなら招待メールは不要)
aws guardduty create-members \
--detector-id $DET \
--account-details AccountId=<ACCOUNT_ID_1> AccountId=<ACCOUNT_ID_2> \
--profile moobon-security
# メンバーが揃ったか確認(RelationshipStatus が Enabled になっていれば OK)
aws guardduty list-members --detector-id $DET --profile moobon-security \
--query 'Members[].[AccountId,RelationshipStatus]' --output tableMOOBON は管理アカウントを含めて数個のアカウントなので、メンバーを個別に追加しています。アカウントがよく増える組織なら、update-organization-configuration で --auto-enable-organization-members ALL を指定しておくと、既存のアカウントも、これから組織に入るアカウントも自動で対象になります。
GuardDuty のメンバー管理もリージョンごとです。コンソールで東京だけ見て「全員 Enabled」でも、ほかのリージョンでは追加されていない、ということが起こります。
for でリージョンを回して確認しておくと安心です。6. Inspector を組織全体で有効化する
Inspector は、これから組織に入るアカウントを自動で有効化する設定と、既存のアカウントを有効化する操作が別になっています。自動有効化の設定だけでは、既存のアカウントはスキャンされません。
# moobon-security で実行 # ① これから入るアカウントを自動で有効化 aws inspector2 update-organization-configuration \ --auto-enable ec2=true,ecr=true,lambda=true \ --profile moobon-security # ② 既存のアカウントをメンバーにして、スキャンを有効化 for acct in <ACCOUNT_ID_1> <ACCOUNT_ID_2>; do aws inspector2 associate-member --account-id $acct --profile moobon-security done aws inspector2 enable \ --account-ids <ACCOUNT_ID_1> <ACCOUNT_ID_2> \ --resource-types EC2 ECR LAMBDA \ --profile moobon-security
コンソールなら、Inspector の「アカウント管理」画面にある「すべてのアカウントをアクティブ化」で同じことができます。
Inspector を初めて有効にすると、EC2 の OS パッケージや ECR に残っている古いコンテナイメージまでスキャンされ、想像していた桁とは違う件数の脆弱性が並びます。MOOBON でもそうでした。古いイメージの整理(ECR のライフサイクルポリシー)や、実際に動いているリソースから順に片づけるのが現実的で、これを全部通知に流すのは無理です。8 章で Inspector を通知に入れていないのはこのためです。
7. Security Hub に集約する
GuardDuty と Inspector の検出結果は、Security Hub を有効にしたアカウントでは自動的に Security Hub に送られます。あとは、①全リージョンの結果を 1 つのリージョンに集め、②組織のアカウントをメンバーにする、の 2 つを設定します。
① 全リージョンの結果を東京に集める
# moobon-security の ap-northeast-1 で実行 aws securityhub create-finding-aggregator \ --region-linking-mode ALL_REGIONS \ --region ap-northeast-1 --profile moobon-security
これで東京リージョンが集約リージョンになり、ほかのリージョンの検出結果もここに集まります。この集約が、8 章の通知を直すときの鍵になります。
② 組織のアカウントをメンバーにする
aws securityhub create-members \
--account-details '[{"AccountId":"<ACCOUNT_ID_1>"},{"AccountId":"<ACCOUNT_ID_2>"}]' \
--profile moobon-security
aws securityhub list-members --only-associated --profile moobon-security \
--query 'Members[].[AccountId,MemberStatus]' --output table設定チェックの基準は、AWS 基礎セキュリティのベストプラクティス(FSBP)と CIS AWS Foundations Benchmark を有効にしています。アカウント数が多い組織なら、中央設定(Central configuration)で「どの基準を使うか」をポリシーとして組織のルートや OU に関連づけると、新しいアカウントにも同じ設定が自動で適用されます。
8. 通知 ─ 東京しか拾えていなかった
1 画面にまとまっても、画面を開かなければ気づけません。最後に、対応が必要なものがメールと Slack に届くよう通知を作ります。条件は「GuardDuty の検出で、重要度が MEDIUM(4)以上」に絞りました。Inspector と設定チェックは件数が多いので、通知ではなく画面で片づけます。
最初に作った通知 ── GuardDuty のイベントを直接拾う
最初は、よく紹介されている形で、GuardDuty のイベントを EventBridge で直接拾うルールを東京リージョンに作りました。
{
"source": ["aws.guardduty"],
"detail-type": ["GuardDuty Finding"],
"detail": { "severity": [{ "numeric": [">=", 4] }] }
}届け先は SNS トピックを 2 つ。1 つはメール用で、EventBridge の入力トランスフォーマーで日本語の本文に組み立てています。もう 1 つは Slack 用で、Amazon Q Developer in chat applications(旧 AWS Chatbot)につないで #aws-security チャンネルに流しています。
東京でサンプルの検出を発生させるとメールも Slack も届き、これで完成だと思っていました。
落とし穴 ── 東京以外の検出は、どこにも届かない
記事にまとめるために設定を見直していて、気づきました。GuardDuty のイベントは、検出が起きたリージョンの EventBridge にしか届きません。東京にルールを 1 つ置いただけでは、たとえばオレゴン(us-west-2)で起きた検出は、どこにも通知されないのです。
認証情報が漏れたとき、攻撃者はふだん誰も見ていないリージョンで EC2 を立ち上げて仮想通貨をマイニングするのが定番の手口です。GuardDuty を全リージョンで有効にしていても、通知が東京だけなら、まさにその検出が届きません。Security Hub の画面を開きに行かない限り、気づけない状態でした。
直し方 ── 通知の起点を Security Hub に変える
各リージョンにルールを作って東京へ転送する方法もありますが、MOOBON では 7 章で全リージョンの検出結果を Security Hub の東京に集約済みでした。それなら、Security Hub が取り込んだ検出結果のイベントを東京で拾えば、ルール 1 つで全リージョンを拾えます。下記を pattern.json として保存します。
{
"source": ["aws.securityhub"],
"detail-type": ["Security Hub Findings - Imported"],
"detail": {
"findings": {
"ProductName": ["GuardDuty"],
"Severity": { "Label": ["MEDIUM", "HIGH", "CRITICAL"] },
"Workflow": { "Status": ["NEW"] },
"RecordState": ["ACTIVE"]
}
}
}# moobon-security の ap-northeast-1(集約リージョン)で実行 aws events put-rule \ --name securityhub-guardduty-medium-plus \ --event-pattern file://pattern.json \ --profile moobon-security aws events put-targets \ --rule securityhub-guardduty-medium-plus \ --targets file://targets.json \ --profile moobon-security
Security Hub の検出結果は ASFF という共通形式なので、メール本文を組み立てる入力トランスフォーマーの参照先も書き換えます。検出結果は detail.findings[0] の下に入っています。
// targets.json(メール用ターゲットの入力トランスフォーマー部分)
"InputPathsMap": {
"acct": "$.detail.findings[0].AwsAccountId",
"region": "$.detail.findings[0].Region",
"sev": "$.detail.findings[0].Severity.Product",
"label": "$.detail.findings[0].Severity.Label",
"type": "$.detail.findings[0].Types[0]",
"title": "$.detail.findings[0].Title",
"desc": "$.detail.findings[0].Description",
"first": "$.detail.findings[0].FirstObservedAt",
"last": "$.detail.findings[0].LastObservedAt"
},
"InputTemplate": "\"【GuardDuty 検知】重要度 <sev>(<label>)\"\n\"アカウント: <acct> リージョン: <region>\"\n..."メール本文には、SSO 経由で moobon-security に入り、該当リージョンの GuardDuty を直接開くリンクも入れています。IAM Identity Center のアクセスポータルの URL に #/console?account_id=…&role_name=…&destination=… を付けると、ログイン後にそのコンソールの画面まで直接飛べます。通知を受けてから画面を開くまでの手間が少ないほど、確認が後回しになりません。
Slack 側は、生のイベントを SNS に流すだけです。Amazon Q Developer は Security Hub のイベントを読みやすい形に整えて投稿してくれるので、追加の設定はいりません。
確認 ── オレゴンでサンプルを発生させる
# 東京以外のリージョンで、重要度 MEDIUM のサンプル検出を 1 件だけ発生させる
DET=$(aws guardduty list-detectors --region us-west-2 \
--query 'DetectorIds[0]' --output text --profile moobon-security)
aws guardduty create-sample-findings --region us-west-2 \
--detector-id $DET --finding-types "Recon:EC2/Portscan" \
--profile moobon-security結果は、約 1 分で東京のルールが反応し、メールと Slack の両方に届きました。同じタイミングで、古いルール(GuardDuty 直結)は 1 回も反応していません。東京以外の検出を拾えていなかったことが、実際に確かめられた形です。確認できたら古いルールは無効にし(東京の検出が二重に届くため)、サンプルの検出はアーカイブしておきます。
SNS トピックのアクセスポリシーで、EventBridge からの送信を「特定のルールから」(
aws:SourceArn)に限定している場合、新しいルールの ARN を追加しないと通知が届きません。コンソールでルールを作るとこのポリシーは自動で足されますが、CLI で作るときは自分で足す必要があります。「Imported」のイベントは、新しい検出だけでなく既存の検出が更新されたときにも送られます。GuardDuty は同じ不審な動きが続くと検出結果を更新するため、同じ内容が繰り返し届くことがあります。対応を始めたら Security Hub でワークフローの状態を NOTIFIED や RESOLVED に変えておけば、ルールの条件(NEW)から外れて止まります。
9. 費用とハマりどころ
通知の起点を変えても、費用はほぼ増えない
Security Hub はすでに有効で、全リージョンの集約にも追加料金はかかりません。AWS のサービスが送るイベントを EventBridge で受けるのは無料で、SNS のメール通知は月 1,000 件まで無料枠があります。Amazon Q Developer in chat applications 自体も無料です。直すのにお金の心配はいりません。
サービス本体の費用は、無料トライアル中に見込みを確かめる
GuardDuty と Security Hub CSPM には 30 日、Inspector には 15 日の無料トライアルがあります。トライアル中もコンソールに「このまま使うといくらになるか」の見込みが出るので、有効にしてから見込み額を見て保護プランやスキャン対象を絞る順番が安全です。費用はログやリソースの量で決まるため、使っていないリージョンではほとんどかかりません。
「有効にした」と「通知が届く」は別物
今回の一番の学びです。GuardDuty を全リージョンで有効にし、通知のテストも東京で成功していたので、全部カバーできていると思い込んでいました。通知のテストは、ふだん使わないリージョンでもやる。サンプル検出を使えば 1 分で確かめられます。
使わないリージョンは SCP で閉じる
全リージョンを見張るのと合わせて、使わないリージョンでの操作そのものを SCP で禁止しておくと、守る範囲が小さくなります。ただし IAM や CloudFront などのグローバルサービスは us-east-1 を使うので、禁止の対象から外す設定が必要です。
委任管理者は 1 つのアカウントにそろえる
GuardDuty と Security Hub の委任管理者を別々のアカウントにすると、検出結果がうまく集約されないことがあります。AWS も同じアカウントにそろえることを推奨しています。セキュリティ系のサービスはすべて moobon-security に任せるのが一番シンプルです。
あとがき
セキュリティのサービスは、有効にした時点ではまだ半分だと考えています。検出結果が 1 か所に集まり、本当に必要なものだけが届き、届いたら誰かが見る ── そこまでつながって、初めて意味を持ちます。今回は、その「つながり」の一部が切れていたことに、記事を書くための見直しで気づけました。有効にした設定も、テストが通った通知も、本当に全部をカバーしているかは、外側から確かめるまで分からないと実感しています。
セキュリティ専用のアカウントを分けたことで、管理アカウントに入る機会が減り、検出結果も通知も moobon-security の東京 1 か所で管理できるようになりました。人が気をつけることに頼らず、仕組みで漏れをなくすという点で、SSO + AssumeRole への切り替えと同じ考え方です。当社は ISMS(ISO/IEC 27001)の認証を受けており、その管理の一環としても、この形を続けていきます。
AWS のセキュリティ設定の点検は、セキュリティ無料診断でご相談いただけます。マルチアカウントの設計や、GuardDuty・Security Hub の運用を含めた保守は AWS 運用保守サービス でお手伝いしています。
参考
- AWS Security Hub ユーザーガイド「Central configuration」
- Amazon GuardDuty ユーザーガイド「Managing accounts with AWS Organizations」
- Amazon Inspector ユーザーガイド「Managing multiple accounts with AWS Organizations」
- AWS What's New「AWS Security Hub is now generally available with near real-time risk analytics」(2025年12月)
- AWS Security Reference Architecture(AWS SRA)
よくある質問
Q管理アカウントで GuardDuty や Security Hub を見るのではだめですか?
動きはしますが、おすすめしません。管理アカウントは組織全体の請求や SCP を握る最も強いアカウントなので、日常的にログインする人と権限を最小にしておきたい場所です。AWS も、セキュリティサービスの委任管理者には管理アカウント以外のアカウントを指定することを推奨しています。セキュリティ担当がふだん見る場所を専用アカウントに分けておけば、管理アカウントに入る機会そのものを減らせます。
Q使っていないリージョンでも GuardDuty を有効にする必要がありますか?
有効にしておくのが安全です。認証情報が漏れたとき、攻撃者はふだん誰も見ていないリージョンで EC2 を大量に立ち上げることがよくあります。ふだん使うリージョンだけ見張っていると、そこが死角になります。費用はデータ量に応じて決まるため、使っていないリージョンではほとんどかかりません。SCP で使わないリージョンの操作そのものを禁止するのも、あわせて効果的です。
Q費用はどれくらいかかりますか?
アカウントの規模とログの量で大きく変わるので、一律には言えません。GuardDuty と Security Hub CSPM には 30 日、Inspector には 15 日の無料トライアルがあり、その期間中もコンソールに『このまま使うといくらになるか』の見込みが表示されます。まずは全体で有効化し、トライアル中に見込み額を確かめてから、必要に応じて保護プランを絞るのが現実的です。
Q通知が多すぎて、結局見なくなりませんか?
そこが一番の落とし穴です。MOOBON では、通知は『GuardDuty の検出のうち、重要度が MEDIUM 以上で、まだ誰も対応していないもの』だけに絞っています。Inspector の脆弱性と設定チェックは件数が桁違いに多いので、通知ではなく Security Hub の画面で重要度順に片づけていきます。通知は『来たら必ず見る』と言える量に保つことが大切です。
Q通知を作ったのに、東京以外の検出が届かないのはなぜですか?
GuardDuty のイベントは、検出が起きたリージョンの EventBridge にしか届かないからです。東京に通知ルールを 1 つ置いただけでは、ほかのリージョンの検出は拾えません。MOOBON も最初はこの状態でした。Security Hub で全リージョンの検出結果を東京に集約しているなら、通知の起点を Security Hub に変えると、東京のルール 1 つで全リージョンを拾えます(本文 8 章)。
