# Governing GuardDuty Org-Wide with AWS Organizations: Delegated Administrator, Auto-Enable (ALL), All Regions, and a Terraform Multi-Region Implementation

> An implementation guide for governing GuardDuty org-wide with AWS Organizations. In code: why you consolidate to a delegated administrator (a dedicated security account) rather than operating from the management account, migrating from the invitation method, why you set auto_enable_organization_members to ALL, org auto-enablement of protection plans, an all-Regions strategy that doesn't miss global service events, a Terraform multi-region implementation with provider alias / for_each, and the least-privilege boundaries between accounts.

- Published: 2026-06-27
- Author: 友田 陽大
- Tags: セキュリティ, AWS, GuardDuty, Terraform, AWS Organizations
- URL: https://tomodahinata.com/en/blog/aws-guardduty-multi-account-organizations-delegated-administrator-terraform-guide
- Category: Amazon GuardDuty in production
- Pillar guide: https://tomodahinata.com/en/blog/aws-guardduty-threat-detection-multi-account-terraform-eventbridge-guide

## Key points

- Multi-account GuardDuty with AWS Organizations integration is the official recommendation. For operations, you don't use the management (payer) account; you designate a dedicated security account as the 'delegated administrator' to consolidate — the principle of least privilege itself
- The delegated administrator is registered in the management account, and the org setting (auto_enable_organization_members) is configured in the delegated administrator account. Choosing `ALL` makes existing + all future members targets, so no silent hole is created (with `NEW` alone, existing accounts can be left out forever)
- GuardDuty is per-Region. Designating the delegated administrator, the org setting, and auto-enablement must be repeated 'in each Region you want to enable.' Because global service events (IAM/STS/S3/CloudFront/Route 53) are replicated and processed in each Region, enabling all Regions — including unused and opt-in Regions — is the official recommendation
- In Terraform, use provider alias and for_each to structure it so the code doesn't grow linearly as you add Regions. Separate the delegated-administrator registration (management-account side) from the org setting and protection-plan auto-enablement (delegated-administrator-account side) by state and by role
- When a new account joins the org, it automatically comes under GuardDuty under the ALL setting. You can eliminate the room for 'forgetting to add it' on every account addition by structure, not by operational vigilance

---

"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](/blog/aws-guardduty-threat-detection-multi-account-terraform-eventbridge-guide), 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](/case-studies/payment-platform-reliability) 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.

1. **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).

2. **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 `AccessDenied` or "I configured it but it doesn't take effect."

3. **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.

1. **Designate the GuardDuty delegated administrator** in the management account (next section).
2. Set **`auto_enable_organization_members = "ALL"`** in the delegated administrator.
3. 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](/blog/aws-guardduty-threat-detection-multi-account-terraform-eventbridge-guide)).

---

## 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."

```hcl
# ──────────────────────────────────────────────────────────────
# 【管理(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_id` is 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.

```hcl
# ──────────────────────────────────────────────────────────────
# 【委任管理者(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 former `auto_enable = true/false` and `datasources { ... }` block are **deprecated**, and per-protection-plan org settings were separated into the `aws_guardduty_organization_configuration_feature` described later. For new builds, write it with **`auto_enable_organization_members` (a 3-value string) + the `_feature` resource**. 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`.

```hcl
# 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 `ALL` is not uniform)**: foundational detection and S3 Protection **win on cost-effectiveness with org-wide `ALL`**. On the other hand, **Runtime Monitoring is billed per vCPU**, so "org-wide uniform `ALL`" 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](/blog/aws-guardduty-cost-optimization-pricing-finops-guide) — since **the delegated administrator can see the projected usage per member account**, the proper approach is to visualize first, then decide "which features to set `ALL` and which to limit."

> **`RUNTIME_MONITORING` and `EKS_RUNTIME_MONITORING` are 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 consolidated `RUNTIME_MONITORING` for new setups and control EKS/ECS/EC2 agent management individually with `additional_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 `Region` value 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](/blog/terraform-module-design-state-isolation-drift-detection-guide).

### 7.2 Stack ①: designating the delegated administrator (management account, all Regions)

```hcl
# 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 `provider` block itself cannot be dynamically generated with `for_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" with `for_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.

```hcl
# 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"
}
```

```hcl
# 呼び出し側（委任管理者アカウントの 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](/blog/github-actions-oidc-keyless-cicd-aws-gcp-guide) (separating roles for `plan` and `apply`).

### 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](/blog/aws-guardduty-eventbridge-automated-remediation-incident-response-guide). 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."** `OrgGuardDutyAdminSetup` is used only about when you change the delegated administrator. If touched from CI, limit it to an OIDC role with an `environment` approval gate (the environment approval in the [OIDC article](/blog/github-actions-oidc-keyless-cicd-aws-gcp-guide)).
- **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, **`ALL`** so 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`/`Audit` account 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) of `aws_guardduty_organization_configuration`. `NEW` is a hole where existing accounts silently fall out of scope. **The old `auto_enable` (boolean) / `datasources` block is deprecated** — don't use it.
- **Protection plans**: org auto-enablement via `aws_guardduty_organization_configuration_feature` (`name` + `auto_enable`). `ALL` is standard for S3; **Runtime Monitoring is billed per vCPU, so judge org-wide vs. limited**. `RUNTIME_MONITORING` and `EKS_RUNTIME_MONITORING` are 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 `Region` value 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 `Audit` account 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](/case-studies/payment-platform-reliability), 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](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_organizations.html) — 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](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_accounts.html) — Organizations method vs. invitation method, the delegated administrator–member relationship, the official recommendation
- [Amazon GuardDuty Regions and endpoints](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_regions.html) — the recommendation to enable all Regions, feature differences by Region
- [GuardDuty foundational data sources (global service events)](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_data-sources.html) — 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](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/guardduty_organization_configuration) — `auto_enable_organization_members` (ALL/NEW/NONE), the deprecation of the `datasources` block
- [Terraform: aws_guardduty_organization_configuration_feature](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/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](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/guardduty_organization_admin_account) — `admin_account_id` to register the delegated administrator in the management account
