"GuardDuty, we did enable it in the production account… but the staging and audit accounts, not yet." — talk with teams running multi-account AWS, and almost without fail this line comes up.
The more accounts grow, the more quietly the "forgot to add GuardDuty" cases accumulate. Every time you carve out a new account, someone enables it by hand, enables it in all Regions, and aligns the protection plans — this manual work, the moment it's forgotten, creates a hole: an "unmonitored account." And attackers come at your weakest account, your weakest Region.
This article is an implementation guide for governing Amazon GuardDuty org-wide with AWS Organizations. Single-account enablement is covered in this pillar article, so this article digs into what comes after — the governance layer of "spreading and maintaining GuardDuty across the whole org, without human hands, with no gaps." It runs through the delegated-administrator model, why you don't operate from the management account, the reason for setting auto_enable_organization_members to ALL, the all-Regions strategy, and a Terraform multi-region implementation using provider alias and for_each.
As the subject matter, I'll weave in the perspective from my experience on a serverless payment platform on multi-account AWS — where I separated accounts for production / staging / audit and implemented IAM, observability, and DR across them — because it handled actual money, carbon credits, and regional currencies, "not creating a hole in the monitoring net" against account additions and removals was a requirement.
The rule of this article: The specs for the delegated administrator, auto-enablement, Regions, and Terraform resources are based on the AWS official documentation and the Terraform AWS Provider resource specs (as of June 2026). Because GuardDuty is per-Region and specs get revised, always check the latest official information before going to production. And the major premise — GuardDuty is one layer of detection; it does not replace WAF, least-privilege IAM, or encryption. The governance design in this article itself is also run through with the principle of least privilege: "don't concentrate permissions in the management account."
0. Mental model: who configures what, and where
The biggest cause of confusion in org-level GuardDuty governance is that "in which account you configure which resource" is split across three parties. Let's pin this down first.
GuardDuty org governance = a three-tier division of roles: "the management account 'designates' the delegated administrator, the delegated administrator 'governs' all members, and the members are actually 'monitored.'" The resource you configure and the account differ for each.
| Role | Account | What you configure here |
|---|---|---|
| Management account (payer / management) | The org's root billing account | Only the designation of the delegated administrator (aws_guardduty_organization_admin_account) |
| Delegated administrator | A dedicated security / audit account | The detector, the org setting (auto-enablement), org auto-enablement of protection plans, finding aggregation |
| Member accounts | Production, staging, each service | (Since the delegated administrator auto-enables, in principle hands-off) |
Three consequences follow from here. This is the foundation of everything in this article.
-
The delegated administrator must not be the "management account" (not recommended). AWS officially states "the AWS security best practices follow the principle of least privilege and doesn't recommend" and does not recommend making the management account the delegated administrator. You make a dedicated security account the delegated administrator. The reason is simple: if you collect responsibilities of differing natures — billing, org management, threat detection — into one account, a compromise of that one account drags the whole org in (SRP / least privilege).
-
The account you configure splits into two. The "designation" of the delegated administrator is done in the management account, while the org setting and auto-enablement are done in the delegated administrator account. In Terraform terms, you need two different providers (= two different roles / states). Confuse this and you get stuck with
AccessDeniedor "I configured it but it doesn't take effect." -
GuardDuty is per-Region. Org governance is also repeated "per Region." AWS Organizations is global, but GuardDuty is Regional. The official wording is "a delegated GuardDuty administrator account is Regional". The designation of the delegated administrator and the org setting both need to be done in each Region you want to enable. This is precisely why Terraform's
for_each× provider alias pays off later.
Grasp these three points and you'll see org governance is the three steps "① designate the delegated administrator in the correct account → ② auto-enable all members → ③ roll that out to all Regions." Let's build them in order.
1. Why you don't operate from the management account: the delegated-administrator model
1.1 What is a delegated administrator?
In AWS Organizations, the management account can designate any account within the org as the delegated GuardDuty administrator account. The official definition is — "the management account can designate any account within this organization as the delegated GuardDuty administrator account". The designated account becomes able to enable and manage GuardDuty for all member accounts in the org within that Region ("the administrator account can enable and manage GuardDuty for all the member accounts in the organization within that Region").
1.2 Why not make the management account the delegated administrator
"If I do it in the management account, I get by with one role and it's easier, no?" — technically it's possible. The official docs even acknowledge "Your organization's management account can be the delegated GuardDuty administrator account". But they go on to clearly not recommend it: "However, the AWS security best practices follow the principle of least privilege and doesn't recommend this configuration".
Let me articulate the reasoning structurally.
- Separate the blast radius of a compromise. The management account holds the strongest permissions in the org — "creating the org, adding/removing accounts, consolidated billing." Add threat-detection operational permissions on top, and a compromise of one account = control of the whole org + disabling of all detection.
- Minimize the account you operate daily. With the delegated administrator, daily operations occur — triaging findings, editing suppression rules, adjusting protection plans. Doing this in "the management account, which you should rarely touch" is a breeding ground for operational mistakes and excessive permissions.
- Audit independence. Consolidating detection and aggregation into a dedicated security account keeps the audit trail of "who changed the detection settings" from mixing with the operational noise of running the org.
Separating accounts for production / staging / audit on the payment platform was the same philosophy. "The stronger the permissions an account holds, the less you touch it daily" — GuardDuty's delegated administrator is a mechanism that embodies this principle at the org level. You make a dedicated security-tooling (or audit) account the delegated administrator.
1.3 The "hard constraints" around the delegated administrator (official)
Before designing, let's pin down the official constraints you should know in a table. Not knowing these will trap you later.
| Constraint | Content (official) |
|---|---|
| Member cap | A maximum of 50,000 members per delegated administrator ("a maximum of 50,000 members"). Exceeding it triggers notification via CloudWatch / Health Dashboard / email |
| Per-Region | The delegated administrator is Regional. Designation is needed in each Region you want to enable ("must be added through AWS Organizations in each desired Region") |
| Same account in all Regions | You must make the same account the delegated administrator in all Regions. A different delegated administrator per Region is not allowed |
| Changing the delegated administrator doesn't stop detection | Even if you remove the delegated administrator, members' GuardDuty stays enabled ("GuardDuty still remains enabled for all these member accounts") |
Rows 2 and 3 in particular tie directly into Terraform design. "Designation is needed per Region" and "the same account in all Regions" — that is, the code becomes one that applies the same admin_account_id repeatedly across multiple Regions (described later).
2. Organizations method vs. invitation method (and migration)
There are two ways to bundle multiple accounts with GuardDuty. The official docs clearly recommend AWS Organizations integration ("GuardDuty recommends that you integrate with AWS Organizations").
| Aspect | AWS Organizations method (recommended) | Invitation method (legacy) |
|---|---|---|
| Account association | Automatic from org membership | The administrator sends invitations, and each member approves |
| Onboarding new accounts | Automatic via auto-enablement (ALL/NEW) | Manual invitation/approval each time |
| Scale | Suited for large scale (max 50,000) | Small scale / accounts outside the org |
| Risk of missing accounts | Low (structurally automatic) | High (missed approvals / missed invitations) |
| Main use | Multi-account governance within the same org | Temporarily bundling external accounts not in the org |
2.1 Which to choose
If you're governing a set of accounts under the same AWS Organizations, the Organizations method is the only choice. The invitation method incurs a human step in each account — "an org member approves the invitation" — and this is a breeding ground for missing accounts. An account that forgot to approve can be left outside monitoring forever.
Where the invitation method still has value is limited cases like "I want to temporarily add an external account (a different org's / a business partner's account), not belonging to the org, to finding aggregation." For this article's theme (org-wide governance), we proceed with the Organizations method.
2.2 Migrating from the invitation method to the Organizations method
If you already operate with the invitation method and want to shift to the Organizations method, the idea is simple.
- Designate the GuardDuty delegated administrator in the management account (next section).
- Set
auto_enable_organization_members = "ALL"in the delegated administrator. - Members that were associated via the invitation method are integrated under the delegated administrator's management as members of the org. Note that the delegated administrator's 50,000 cap says "includes member accounts that are added through AWS Organizations or those who accepted the GuardDuty administrator account's invitation" — be aware that invitation-route members count in the same quota.
The iron rule during migration is "to not miss existing members, choose ALL, not NEW" (the reason is in the next section). Before going to production, always verify with a sample finding that "findings get aggregated to the delegated administrator" (see create-sample-findings in the pillar article).
3. Designating the delegated administrator: Terraform on the management-account side
Here's the code. First, just "designate" the delegated administrator in the management account. This itself configures nothing of GuardDuty's internals — it's only a declaration: "entrust GuardDuty management to this account."
# ──────────────────────────────────────────────────────────────
# 【管理(management/payer)アカウントで実行する provider】
# このスタックは「委任管理者の指名」だけを担う。中身の設定はしない。
# ──────────────────────────────────────────────────────────────
provider "aws" {
alias = "management"
region = "ap-northeast-1"
assume_role {
# 管理アカウントの「組織管理用ロール」を引き受ける。
# 日常運用ではめったに使わない、強い権限のロール。
role_arn = "arn:aws:iam::${var.management_account_id}:role/OrgGuardDutyAdminSetup"
}
}
# GuardDuty の委任管理者を、専用 security アカウントに指名する。
# これは「指名」であって、GuardDuty の検知設定ではない点に注意。
resource "aws_guardduty_organization_admin_account" "delegate" {
provider = aws.management
admin_account_id = var.security_account_id # 例: 専用 security-tooling / audit アカウント
}
admin_account_idis not the management account's ID: what goes here is the delegation target's (the security account's) ID. Confuse it and put the management account's own ID, and you get exactly the non-recommended "management account as delegated administrator" config we wanted to avoid in Section 1.
When you apply this aws_guardduty_organization_admin_account, AWS behind the scenes prepares a service-linked role for GuardDuty in the delegated administrator account, putting the delegated administrator in a state where it can call the org APIs. The moment you designate it, GuardDuty in the delegated administrator account is automatically enabled in that Region (official: "GuardDuty gets enabled automatically only in the current AWS Region").
4. Auto-enabling all members: Terraform on the delegated-administrator side
Once the designation is done, now switch to the delegated administrator account's provider and put in the org setting. This is the heart of governance.
# ──────────────────────────────────────────────────────────────
# 【委任管理者(security-tooling)アカウントで実行する provider】
# detector / 組織設定 / 保護プラン自動有効化 は、すべてこちら側で行う。
# ──────────────────────────────────────────────────────────────
provider "aws" {
alias = "security"
region = "ap-northeast-1"
assume_role {
role_arn = "arn:aws:iam::${var.security_account_id}:role/GuardDutyDelegatedAdmin"
}
}
# 委任管理者アカウント自身の detector。
# 指名時に自動有効化されるが、Terraform 管理下に置いて構成をコード化する。
resource "aws_guardduty_detector" "security" {
provider = aws.security
enable = true
finding_publishing_frequency = "FIFTEEN_MINUTES" # 自動対応の遅延を縮める(ピラー記事 6章)
}
# 組織メンバーの自動有効化。これが「全社に漏れなく広げる」中核。
# ALL = 既存 + 将来すべてのアカウントを有効化(推奨:サイレントな穴を作らない)
# NEW = 今後 join するアカウントのみ(既存は対象外のまま残り得る)
# NONE = 自動有効化しない
resource "aws_guardduty_organization_configuration" "this" {
provider = aws.security
detector_id = aws_guardduty_detector.security.id
auto_enable_organization_members = "ALL"
}
The required arguments of aws_guardduty_organization_configuration are detector_id and auto_enable_organization_members (value is "ALL" / "NEW" / "NONE").
[Important] Don't use the old
auto_enable(boolean): the formerauto_enable = true/falseanddatasources { ... }block are deprecated, and per-protection-plan org settings were separated into theaws_guardduty_organization_configuration_featuredescribed later. For new builds, write it withauto_enable_organization_members(a 3-value string) + the_featureresource. Copy-pasting code from old blog articles is a source of deprecation warnings and unintended behavior.
4.1 Why choose ALL — the silent hole of NEW
The choice among the three values directly decides "whether you create a hole in the security net."
| Value | Targets | Risk |
|---|---|---|
ALL (recommended) | All members, existing + future | None. Every account in the org at config time immediately becomes a target |
NEW | Only members that join going forward | Existing accounts can be left out of scope forever (a silent hole) |
NONE | No auto-enablement | Manual management per member. Frequent missing accounts |
The pitfall of NEW is serious. Choose NEW and accounts already in the org at "the very moment" you put in the setting do not become targets of auto-enablement. Because only new accounts become targets, existing production / staging accounts can be left without GuardDuty. Against the security goal of "detecting org-wide with no gaps," NEW is a structural hole.
Furthermore, the official docs raise the trap of NEW's order dependency in opt-in Regions. In NEW operation, unless you keep the order "① the member enables the opt-in Region → ② add that member to the org," it becomes "the member account is no longer new to the organization" and NEW doesn't take effect. With ALL, this order problem itself disappears ("the order of these steps is not relevant") — this too is a practical reason to push for ALL.
Only when there's an account you want to intentionally exclude from GuardDuty (e.g. a sandbox), it's safer to individually disable just that one account while keeping ALL, rather than loosening the whole with NEW/NONE.
4.2 What happens when a new account joins
Set up ALL (or NEW), and an account newly created in / invited to the org automatically comes under GuardDuty, without human hands. This is the greatest value of the Organizations method.
In operations like the payment platform, where you separate accounts by role and carve out an account on every service addition, this pays off — the accident of "I created a new account but forgot to add GuardDuty" stops happening structurally. You stop relying on operational carefulness and have the setting (ALL) take it over.
5. Auto-enabling protection plans org-wide too (per-feature)
Beyond foundational detection, protection plans like S3 Protection and Runtime Monitoring can also be "auto-enabled org-wide." What you use is aws_guardduty_organization_configuration_feature.
# S3 Protection を組織全体で自動 ON。
# 全アカウントで S3 データイベントを監視し、ETD の S3 攻撃シーケンス相関を全社で効かせる。
resource "aws_guardduty_organization_configuration_feature" "s3_org" {
provider = aws.security
detector_id = aws_guardduty_detector.security.id
name = "S3_DATA_EVENTS"
auto_enable = "ALL" # ここも ALL(既存+将来の全メンバー)
}
# Runtime Monitoring を組織で自動 ON し、各環境のエージェント配置も自動管理させる。
# ★コストが vCPU 比例で増えるため、「全社一律 ALL」は慎重に。重要ワークロードに絞る判断もあり。
resource "aws_guardduty_organization_configuration_feature" "runtime_org" {
provider = aws.security
detector_id = aws_guardduty_detector.security.id
name = "RUNTIME_MONITORING"
auto_enable = "ALL"
additional_configuration {
name = "EKS_ADDON_MANAGEMENT" # EKS のエージェントを自動デプロイ・更新
auto_enable = "ALL"
}
additional_configuration {
name = "ECS_FARGATE_AGENT_MANAGEMENT" # Fargate タスクにサイドカーを自動注入
auto_enable = "ALL"
}
additional_configuration {
name = "EC2_AGENT_MANAGEMENT" # EC2 のエージェントを SSM 経由で自動管理
auto_enable = "ALL"
}
}
The required arguments of aws_guardduty_organization_configuration_feature are detector_id / name / auto_enable (auto_enable is ALL/NEW/NONE). Representative protection-plan features you can specify in name are as follows.
name (feature) | What's monitored | Org auto-enablement judgment |
|---|---|---|
S3_DATA_EVENTS | CloudTrail's S3 data events | ALL is the standard (cheap, big effect, spreads ETD correlation org-wide) |
EKS_AUDIT_LOGS | EKS audit logs (control plane) | ALL if the org uses EKS, unneeded if not |
RUNTIME_MONITORING | Processes / syscalls inside containers / hosts | The most expensive, billed per vCPU. Judge whether org-wide ALL or limited to critical WLs |
EBS_MALWARE_PROTECTION | Agentless scanning of EBS on EC2-originated findings | ALL if EC2-centric |
RDS_LOGIN_EVENTS | Login activity of Aurora / RDS | Enable for orgs that have DBs |
LAMBDA_NETWORK_LOGS | Lambda's network activity (VPC Flow Logs) | Enable if serverless-centric |
Articulating the trade-off (per-feature
ALLis not uniform): foundational detection and S3 Protection win on cost-effectiveness with org-wideALL. On the other hand, Runtime Monitoring is billed per vCPU, so "org-wide uniformALL" is not necessarily optimal. The tug-of-war between the org's detection coverage and cost is covered in detail in the GuardDuty cost-optimization article — since the delegated administrator can see the projected usage per member account, the proper approach is to visualize first, then decide "which features to setALLand which to limit."
RUNTIME_MONITORINGandEKS_RUNTIME_MONITORINGare mutually exclusive: on the Terraform Provider, "Only one of two features EKS_RUNTIME_MONITORING or RUNTIME_MONITORING can be added". The current way is to use the consolidatedRUNTIME_MONITORINGfor new setups and control EKS/ECS/EC2 agent management individually withadditional_configuration.
6. The all-Regions strategy: don't miss global events
This is the most misunderstood point in org governance. "Just enabling GuardDuty in the Tokyo Region is enough" is dangerous.
6.1 Why enable even unused Regions
GuardDuty is a per-Region service. And events of global services like IAM, STS, S3, CloudFront, and Route 53 receive special treatment. The official explanation is — GuardDuty "replicates those events and processes them in each Region where you have enabled GuardDuty" for these global service events (GSE). That is, global events are replicated and processed in all Regions where you have enabled GuardDuty.
What this means is — in Regions where you haven't enabled GuardDuty, some of these global events are not processed. Attackers come at that spot. The official docs also warn "Threat actors can potentially launch attacks through global services... They can attempt to create unauthorized resources to exploit Regions where you have limited presence" and conclude that you should "enable in all Regions" ("We recommend that you enable GuardDuty in all AWS Regions available in your AWS account"). Both default Regions and opt-in Regions are targets ("including both default and opt-in Regions").
A note on a finding's Region value: a finding originating from a global event may have a finding
Regionvalue that differs from the Region where it was actually detected. The official docs note "a finding might show us-east-1 as the Region even if GuardDuty creates the detection in a different Region". When you branch on the Region as a key in automated response (EventBridge), factor in that global events come in with an unexpected Region value.
6.2 Repeating "designation → org setting" per Region
You need to repeat in each Region you want to enable the sequence "designation (management account) → org setting / protection plans (delegated administrator)" from up through Section 5. Official: the delegated administrator "must be added through AWS Organizations in each desired Region", and you must use the same delegated administrator account in all Regions.
Configuring all Regions × each resource by hand is unrealistic. This is where Terraform's provider alias × for_each shows its true worth.
6.3 Notes on opt-in Regions
Opt-in Regions (some Asia-Pacific Regions and the like, which require explicit enablement) have their own notes. Officially, if the delegated administrator opts out of an opt-in Region, even with the NEW/ALL setting it may become unable to enable members where GuardDuty is currently disabled. Furthermore, the aforementioned NEW order-dependency problem is also specific to opt-in Regions. Adopting ALL avoids the order problem, so the ALL recommendation pays off here too.
7. Terraform: a multi-region implementation with provider alias × for_each
Let's build a structure where "the code doesn't bloat linearly as you add Regions." The keys are (1) having a provider alias per Region, and (2) separating state for the delegated-administrator registration and the org setting.
7.1 Design: split state and roles into two
| Stack | Execution account | Role | Responsibility |
|---|---|---|---|
org-admin-registration | Management account | OrgGuardDutyAdminSetup (strong, low-frequency) | Designating the delegated administrator (for all Regions) |
guardduty-org-config | Delegated administrator account | GuardDutyDelegatedAdmin (daily operations) | detector, org setting, protection plans (for all Regions) |
The reason to split into two is precisely Section 1's least privilege. You don't want to run daily operations (adjusting protection plans, etc.) with the management account's high-privilege role. Nor do you want the delegated administrator's operational role to hold the "account designation" permission. Split the state and the roles used for apply naturally split too. The thinking on state separation and drift detection is dug into in the Terraform module-design article.
7.2 Stack ①: designating the delegated administrator (management account, all Regions)
# variables.tf
variable "guardduty_regions" {
description = "GuardDuty を有効化する全リージョン(未使用・opt-in 含む)"
type = set(string)
default = ["ap-northeast-1", "us-east-1", "eu-west-1"] # 実際は対象を網羅する
}
variable "management_account_id" { type = string }
variable "security_account_id" { type = string }
# 各リージョンの provider を alias で定義する。
# ★ Terraform の制約: provider は for_each で動的生成できないため、対象リージョンを明示列挙する。
provider "aws" {
alias = "mgmt_apne1"
region = "ap-northeast-1"
assume_role { role_arn = "arn:aws:iam::${var.management_account_id}:role/OrgGuardDutyAdminSetup" }
}
provider "aws" {
alias = "mgmt_use1"
region = "us-east-1"
assume_role { role_arn = "arn:aws:iam::${var.management_account_id}:role/OrgGuardDutyAdminSetup" }
}
provider "aws" {
alias = "mgmt_euw1"
region = "eu-west-1"
assume_role { role_arn = "arn:aws:iam::${var.management_account_id}:role/OrgGuardDutyAdminSetup" }
}
# 各リージョンで同一の security アカウントを委任管理者に指名する。
# 全リージョンで同じ admin_account_id(公式の必須要件)。
resource "aws_guardduty_organization_admin_account" "apne1" {
provider = aws.mgmt_apne1
admin_account_id = var.security_account_id
}
resource "aws_guardduty_organization_admin_account" "use1" {
provider = aws.mgmt_use1
admin_account_id = var.security_account_id
}
resource "aws_guardduty_organization_admin_account" "euw1" {
provider = aws.mgmt_euw1
admin_account_id = var.security_account_id
}
A practical Terraform constraint: the
providerblock itself cannot be dynamically generated withfor_each(the number of providers must be settled before plan). So explicitly enumerate a provider alias per Region and write resources for each alias. If there are many Regions, modularize this enumeration part, or lean toward a structure that calls a "child module taking a Region as an argument" withfor_each, as described below.
7.3 Stack ②: the org setting via a cross-region module (delegated administrator)
Since protection plans and org settings have many items, carve out "the setting for one Region" into a child module and call it per Region by passing a provider. With this, "adding a Region = adding one module block" is all it takes.
# modules/guardduty-org-region/variables.tf
variable "finding_publishing_frequency" {
type = string
default = "FIFTEEN_MINUTES"
}
# modules/guardduty-org-region/main.tf
# このモジュールは「呼び出し側が渡した1つの provider(=1リージョン)」に対して
# detector + 組織設定 + 保護プランを一式作る。リージョンの知識はモジュール内に持たない(ETC)。
# 呼び出し側から provider を受け取る前提なので、configuration_aliases を宣言する。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
configuration_aliases = [aws]
}
}
}
resource "aws_guardduty_detector" "this" {
enable = true
finding_publishing_frequency = var.finding_publishing_frequency
}
resource "aws_guardduty_organization_configuration" "this" {
detector_id = aws_guardduty_detector.this.id
auto_enable_organization_members = "ALL" # 全社・漏れなく
}
resource "aws_guardduty_organization_configuration_feature" "s3" {
detector_id = aws_guardduty_detector.this.id
name = "S3_DATA_EVENTS"
auto_enable = "ALL"
}
# 呼び出し側(委任管理者アカウントの provider を各リージョン分用意して渡す)
provider "aws" {
alias = "sec_apne1"
region = "ap-northeast-1"
assume_role { role_arn = "arn:aws:iam::${var.security_account_id}:role/GuardDutyDelegatedAdmin" }
}
provider "aws" {
alias = "sec_use1"
region = "us-east-1"
assume_role { role_arn = "arn:aws:iam::${var.security_account_id}:role/GuardDutyDelegatedAdmin" }
}
# リージョンを足したいときは、provider alias と module 呼び出しを1つ追加するだけ。
module "guardduty_apne1" {
source = "./modules/guardduty-org-region"
providers = { aws = aws.sec_apne1 }
}
module "guardduty_use1" {
source = "./modules/guardduty-org-region"
providers = { aws = aws.sec_use1 }
}
Apply order (dependency): Stack ② (the org setting) fails unless Stack ① (designating the delegated administrator) is completed in that Region. This is because an undesignated account has no permission to call the org-setting API. Apply in the order ① → ② (since they're separate states, guaranteeing order via CI job dependencies is robust). Keyless apply from CI can ride on the configuration in the OIDC keyless CI/CD article (separating roles for
planandapply).
7.4 Per-member overrides
When you want to keep org-wide uniformity with ALL while changing the protection plan for only specific accounts (e.g. turn off Runtime Monitoring for just a sandbox), you individually override the member account's detector from the delegated administrator. In Terraform you apply aws_guardduty_detector_feature to the member's detector, or manage it individually with an operation equivalent to UpdateMemberDetectors. The principle is "the org-wide default is ALL, and exceptions are explicit, one account at a time" — structurally safer than loosening the whole with NEW/NONE and creating a hole.
8. Finding aggregation, publishing, and the landing zone
8.1 Findings are automatically aggregated to the delegated administrator
Set up the org, and findings from all members and all Regions are automatically aggregated to the delegated administrator account (official: the delegated administrator can "review all generated findings"). The delegated administrator can survey the org-wide security posture at a glance and check the findings and projected usage per member account. This is the practical benefit of the "consolidate detection into a dedicated security account" design.
8.2 Export to S3 and aggregate to Security Hub at the org level
Starting from the delegated administrator, export findings to S3 (long-term retention / analysis) and feed them into AWS Security Hub CSPM to prioritize across other detections (Macie, etc.). For deep-dive investigation, Amazon Detective. "Detect with GuardDuty → aggregate at the delegated administrator → cross-cut at Security Hub → dig deep with Detective" is the royal road of org operation.
The EventBridge → idempotent automated response that turns findings into action is beyond this article's scope, so I leave it to the automated-response / incident-response article. In an org configuration, the standard is to build EventBridge rules starting from findings aggregated in the delegated administrator account.
8.3 Relationship to the landing zone / Control Tower
If you're designing an org from scratch, it's natural to ride on the context of the AWS Control Tower / landing zone. Control Tower typically provisions an Audit account and a Log Archive account. The standard placement is to assign the GuardDuty delegated administrator to this Audit (or a dedicated Security) account — completely consistent with the "a dedicated security account, not the management account" I've said throughout this article.
Retrofitting onto an existing org: even if you don't use Control Tower, this article's configuration applies as-is. What matters is not the tool but the principle — place the delegated administrator in a dedicated account, and auto-enable all Regions with
ALL. Control Tower just lays that down "as a convention."
9. Least-privilege boundaries between accounts (IAM design)
Finally, let me make explicit the boundary of the two roles we split in this article. This isn't decoration — it's the main body of the governance design.
| Role | Where it's placed | Main allowed operations | Disallowed operations |
|---|---|---|---|
OrgGuardDutyAdminSetup | Management account | guardduty:EnableOrganizationAdminAccount / Disable... / related organizations:* (minimal) | Adjusting protection plans, finding operations, editing suppression rules |
GuardDutyDelegatedAdmin | Delegated administrator account | guardduty:UpdateOrganizationConfiguration / Update*Detector* / CreateFilter (suppression) / referencing findings | Account designation (registering the delegated administrator), adding/removing org accounts |
Let me articulate the design principles.
- Don't cross the designation permission and the operational permission. The management account's role goes only as far as "designate / un-designate." The delegated administrator's role goes only as far as "daily operations." Make it so neither role can step into the other's domain. This is the main body of separating the blast radius of a compromise.
- Keep the management account's high-privilege role "low-frequency, approval-required."
OrgGuardDutyAdminSetupis used only about when you change the delegated administrator. If touched from CI, limit it to an OIDC role with anenvironmentapproval gate (the environment approval in the OIDC article). - For APIs where you can narrow
Resource, narrow it. Split finding-reference operations into a read-only role, and config-change operations into a role with a permissions boundary. - GuardDuty is not a replacement for IAM. A reminder. GuardDuty detects "the misuse of leaked credentials," but least-privilege IAM, keyless authentication, and encryption to avoid leaking are separately needed. GuardDuty plays the "layer that quickly signals indications across the org" within this defense-in-depth.
10. Summary: a GuardDuty org-governance cheat sheet
A quick-reference table for when you're unsure.
- Method: for multi-account, AWS Organizations integration is the official recommendation. The invitation method is a limited use for bundling external accounts. During migration,
ALLso you don't miss existing members. - Delegated administrator: don't operate from the management (payer) account (officially not recommended from the least-privilege standpoint). Make a dedicated
Security/Auditaccount the delegated administrator. Designate in the management account (aws_guardduty_organization_admin_account), and configure the org setting in the delegated administrator account. - Auto-enablement:
auto_enable_organization_members = "ALL"(existing + future) ofaws_guardduty_organization_configuration.NEWis a hole where existing accounts silently fall out of scope. The oldauto_enable(boolean) /datasourcesblock is deprecated — don't use it. - Protection plans: org auto-enablement via
aws_guardduty_organization_configuration_feature(name+auto_enable).ALLis standard for S3; Runtime Monitoring is billed per vCPU, so judge org-wide vs. limited.RUNTIME_MONITORINGandEKS_RUNTIME_MONITORINGare mutually exclusive. - Regions: GuardDuty is Regional. Repeat designation → org setting in each Region. The same delegated administrator account in all Regions is required. Global events (IAM/STS/S3/CloudFront/Route 53) are replicated and processed across all enabled Regions, so enable all Regions including unused and opt-in. A finding's
Regionvalue can differ from the detection Region. - Terraform: providers can't use
for_each→ enumerate an alias per Region, and modularize one Region's worth and pass the provider. Separate state and roles for ① designation (management account, high-privilege role) and ② org setting (delegated administrator, operational role). Apply in the order ① → ②. - New accounts: under
ALL, an account that joins the org comes under GuardDuty automatically. Forgetting to add it disappears structurally. - Aggregation: findings are auto-aggregated to the delegated administrator. Cross-cut with S3 export, Security Hub, and Detective. Control Tower's
Auditaccount is the standard placement for the delegated administrator. - IAM boundaries: don't cross the designation permission and the operational permission. GuardDuty is one layer of detection; it doesn't replace least-privilege IAM, keyless authentication, or encryption.
Org-level GuardDuty is not "the work of manually enabling it in all accounts," but a governance design: "consolidate to the delegated administrator, auto-enable with ALL, and roll out to all Regions with Terraform." The greatest leverage is in guaranteeing — with code, not operational vigilance — a structure where no hole opens in the monitoring net even as accounts grow and shrink.
On the multi-account serverless payment platform, I implemented IAM, observability, and DR across a platform handling actual money, carbon credits, and regional currencies, and supported the production / staging / audit account separation with the structure of code rather than "operational carefulness." I design GuardDuty org governance with the same philosophy — ① place the delegated administrator in a dedicated account to separate the blast radius, ② structurally eliminate missing accounts with ALL × all Regions, and ③ keep "adding a Region = adding one line" with a Terraform multi-region configuration.
"How should I roll out GuardDuty org-wide on my multi-account AWS, where should I place the delegated administrator, and which Regions / which protection plans should I set to ALL?" — from Organizations design through Terraform implementation, least-privilege boundaries between accounts, and finding aggregation, I can accompany you fast and safely, one person × generative AI (Claude Code). Whether retrofitting onto an existing org or starting from the requirements-organizing stage, feel free to consult me.
Reference (official documentation)
- Managing GuardDuty accounts with AWS Organizations — the delegated-administrator concept, the 50,000 cap, the Regional constraint, opt-in Region notes, the recommendation against making the management account the delegated administrator
- Multiple accounts in Amazon GuardDuty — Organizations method vs. invitation method, the delegated administrator–member relationship, the official recommendation
- Amazon GuardDuty Regions and endpoints — the recommendation to enable all Regions, feature differences by Region
- GuardDuty foundational data sources (global service events) — all-Region replication/processing of global service events (IAM/STS/S3/CloudFront/Route 53), the note that a finding's Region value can differ
- Terraform: aws_guardduty_organization_configuration —
auto_enable_organization_members(ALL/NEW/NONE), the deprecation of thedatasourcesblock - Terraform: aws_guardduty_organization_configuration_feature —
name/auto_enable,additional_configuration(EKS_ADDON_MANAGEMENT and others), the mutual exclusivity of RUNTIME_MONITORING and EKS_RUNTIME_MONITORING - Terraform: aws_guardduty_organization_admin_account —
admin_account_idto register the delegated administrator in the management account