Security Governance — Organizations · SCP · Account Monitoring
When and how to move from a single account to multi-account. This chapter lays out the structure of grouping accounts into OUs with AWS Organizations, how to set organization-wide guardrails with SCP (Terraform example), the Control Tower landing zone, how to turn GuardDuty · Security Hub · Config · Inspector on for the whole organization from a delegated administrator, connecting IAM Identity Center SSO, and the one-account → N-account migration pattern.
In Chapter 28, while building the mental model of splitting a VPC into several, we noted that true isolation is stronger with account separation. This chapter is the next step — when to split accounts, and how to group the split accounts into one organization and control them.
If Chapter 2 IAM covered who can do what inside one account, this chapter covers the governance of having multiple accounts and drawing boundaries at the organization level. This book centers on the path from a single account to dividing into OUs, and touches on large-scale multi-account operations as an overview.
The Limits of a Single Account — When to Split #
Parts 1 ~ 4 assumed a single account. For a small team with one or two services, that’s enough. It’s time to split accounts when you see these signals.
- Blast radius — a structure where a mistake in dev can touch prod resources. Splitting accounts makes the permission boundary line up with the account boundary.
- Billing visibility — within a single account you can only separate which team / environment spent what by tags. Splitting accounts naturally separates the bills.
- Regulation / audit — compliance requirements to keep a specific workload in an isolated account.
- Permission limits — with IAM policies alone it’s hard to cleanly express organization-level prohibitions like “in this environment, don’t allow this region / this service at all.”
AWS Organizations — Grouping Accounts #
AWS Organizations is a tool for grouping multiple accounts into one organization.
- Management account — the top-level account that created the organization. It only does billing consolidation and organization management; you don’t put workloads on it.
- Member accounts — the rest of the accounts in the organization (prod / staging / dev / sandbox, etc.).
- OU (Organizational Unit) — a folder that groups accounts. Usually divided by environment (Prod OU / Non-Prod OU) or by team.
- Consolidated Billing — every account’s billing gathers into the management account, and volume discounts and Savings Plans are shared across the whole organization.
Root
├── Management account (billing · org management)
├── Security OU
│ ├── Log archive account
│ └── Security audit account
├── Prod OU
│ └── prod account
└── Non-Prod OU
├── staging account
└── dev accountWith Terraform you declare the organization · OUs · accounts as code. Run it from the management account.
resource "aws_organizations_organization" "org" {
feature_set = "ALL" # enable all features including SCP
# allow delegation for services you'll turn on org-wide
aws_service_access_principals = [
"guardduty.amazonaws.com",
"securityhub.amazonaws.com",
"config.amazonaws.com",
"sso.amazonaws.com",
]
}
resource "aws_organizations_organizational_unit" "prod" {
name = "Prod"
parent_id = aws_organizations_organization.org.roots[0].id
}
resource "aws_organizations_organizational_unit" "nonprod" {
name = "Non-Prod"
parent_id = aws_organizations_organization.org.roots[0].id
}
resource "aws_organizations_account" "prod" {
name = "myapp-prod"
email = "aws+prod@example.com" # a unique email per account
parent_id = aws_organizations_organizational_unit.prod.id
}SCP — Organization-wide Guardrails #
An SCP (Service Control Policy) is a ceiling on permissions applied to an OU or account. The difference from IAM is the key.
| IAM policy | SCP | |
|---|---|---|
| Applies to | users / roles inside an account | a whole OU / account |
| Role | grants permissions | sets the ceiling on permissions (cannot grant) |
| Effect | only what’s allowed is possible | if the SCP blocks it, allowing it via IAM inside the account still won’t work |
In other words, an SCP is a guardrail that says “no account in this OU can do this.” Effective permission = the intersection of (allowed by SCP) ∩ (allowed by IAM). What an SCP blocks, not even the account’s root user can do.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyOutsideApproved",
"Effect": "Deny",
"NotAction": ["iam:*", "organizations:*", "route53:*", "cloudfront:*"],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["ap-northeast-2", "us-east-1"]
}
}
}]
}Accounts in an OU with this SCP attached cannot create resources in regions other than Seoul and Virginia. Global services (IAM · Route 53 · CloudFront, etc.) must be excepted with NotAction so they don’t get locked out. Another guardrail you’ll often apply is protecting audit logs.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ProtectAudit",
"Effect": "Deny",
"Action": [
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail",
"config:DeleteConfigurationRecorder",
"config:StopConfigurationRecorder"
],
"Resource": "*"
}]
}With Terraform you create the SCP and attach it to an OU.
resource "aws_organizations_policy" "region_lock" {
name = "region-lock"
type = "SERVICE_CONTROL_POLICY"
content = file("${path.module}/scp/region-lock.json")
}
resource "aws_organizations_policy_attachment" "region_lock_prod" {
policy_id = aws_organizations_policy.region_lock.id
target_id = aws_organizations_organizational_unit.prod.id
}A commonly used bundle of guardrails: ① forbid risky actions by the root user, ② forbid use of regions outside the approved list, ③ forbid disabling CloudTrail / Config, ④ forbid unauthorized use of specific high-cost services.
Control Tower — Landing Zone Automation #
Setting up Organizations + SCP + log account + baseline guardrails all by hand is a hassle. Control Tower lays down this initial setup (the landing zone) automatically.
- It configures the OU structure (usually Security · Sandbox), the log archive / audit accounts, and recommended SCP guardrails (mandatory / strongly recommended / elective) in one go.
- Account Factory stamps out new accounts in a standard form (network · guardrails · SSO included).
- It’s a good starting point when a small organization first moves to multi-account.
This book touches only on the existence and role of Control Tower. If you’re at the stage of starting with one account and dividing into two or three OUs, Organizations plus a few SCPs you write yourself is enough, and Control Tower earns its keep in organizations where accounts grow quickly.
Watching the Whole Account Fleet — GuardDuty · Security Hub · Config · Inspector #
Once you’ve split accounts, you need tools to watch the whole organization at a glance. Four of them form a set.
| Service | Role |
|---|---|
| GuardDuty | Threat detection. Analyzes CloudTrail / VPC Flow Log / DNS logs to alert on anomalous behavior (credential theft, crypto mining, etc.) |
| Security Hub | A unified security-posture dashboard. Gathers many accounts · many check results in one place and scores them against standards (CIS, AWS FSBP) |
| Config | Resource configuration tracking. Records rule violations like “did this security group open 0.0.0.0/0?” and auto-remediates |
| Inspector | Vulnerability scanning. Automatically checks EC2 / ECR images / Lambda for known vulnerabilities (CVEs) |
The key to operating these is to turn them on across the whole organization at once from a delegated administrator account (usually the audit account in the Security OU), rather than enabling them account by account. That way, newly created accounts are auto-registered too.
# In the management account: designate the audit account as the GuardDuty delegated administrator
resource "aws_guardduty_organization_admin_account" "this" {
admin_account_id = aws_organizations_account.audit.id
}
# In the audit account (provider alias): auto-enable for new accounts
resource "aws_guardduty_organization_configuration" "this" {
provider = aws.audit
detector_id = aws_guardduty_detector.audit.id
auto_enable_organization_members = "ALL" # all existing + future accounts
}GuardDuty’s threat alerts (findings) are received with the EventBridge rule from Chapter 19 EventBridge / SQS / SNS and sent via SNS → Slack / email. Config rule violations are connected to auto-remediation.
resource "aws_cloudwatch_event_rule" "gd" {
name = "guardduty-findings"
event_pattern = jsonencode({ source = ["aws.guardduty"], "detail-type" = ["GuardDuty Finding"] })
}
resource "aws_cloudwatch_event_target" "gd_sns" {
rule = aws_cloudwatch_event_rule.gd.name
arn = aws_sns_topic.security_alerts.arn
}IAM Identity Center — Permissions Across Accounts #
Once you have several accounts, creating IAM users in each account is unmanageable. With IAM Identity Center (formerly AWS SSO) you log in once and pick roles across multiple accounts (Chapter 5).
- A Permission Set = a role template you deploy commonly across multiple accounts (e.g.,
AdminAccess,ReadOnly,Developer). - Assign a user/group to an (account, Permission Set) combination, and the matching role is auto-created in that account.
resource "aws_ssoadmin_permission_set" "developer" {
instance_arn = local.sso_instance_arn
name = "Developer"
session_duration = "PT8H"
}
resource "aws_ssoadmin_account_assignment" "dev_to_prod" {
instance_arn = local.sso_instance_arn
permission_set_arn = aws_ssoadmin_permission_set.developer.arn
principal_id = local.dev_group_id
principal_type = "GROUP"
target_id = aws_organizations_account.prod.id
target_type = "AWS_ACCOUNT"
}The One Account → N Accounts Migration Pattern #
If you’re already operating on a single account, here’s the realistic order for moving to multi-account.
- Create the Organization — create a new management account and invite the current account as a member. As a principle, don’t put workloads on the management account (since its permissions are the strongest, you minimize the attack surface).
- Separate log / audit accounts — gather the CloudTrail organization trail and the log archive S3 into dedicated accounts. Protect this account most strongly with SCPs.
- Separate environment accounts — split dev / staging / prod into accounts. Don’t migrate resources all at once; put new workloads on the new accounts first.
- Apply SCP guardrails — start with region restriction, root protection, and audit-log protection.
- Link accounts — link VPCs with the Transit Gateway from Chapter 28, and permissions with the SSO of IAM Identity Center.
Multi-account isn’t irreversible, but migration is costly. Fill new accounts with new workloads first, and slowly empty out the existing single account. The Part 6 capstone assumes a single account, but once its infrastructure is codified in Terraform, moving it to a new account gets close to “apply with a different account provider.”
Exercises #
- Draw your organization (or a hypothetical one) as a Root → OU → account structure. At minimum, decide which OUs the management account · log account · prod · dev go into, and connect each boundary in one sentence to which problem in §“The Limits of a Single Account” it solves.
- Explain the difference between applying “no use of regions other than ap-northeast-2 and us-east-1 in any account” as an IAM policy versus as an SCP, and write why global services must be excepted with
NotAction, basing it on the JSON in §“SCP — Organization-wide Guardrails.” - Find which setting is needed so that GuardDuty turns on automatically when a new member account is added, in the Terraform from §“Watching the Whole Account Fleet,” and write it down. Then draw, as one flow, which service from Chapter 19 the alert passes through to reach the responsible person.
In short: When you see the signals of blast radius, billing visibility, regulation, or permission limits, split a single account into multi-account. AWS Organizations groups accounts into OUs to consolidate billing, and an SCP — unlike IAM — is a deny boundary that sets a ceiling on permissions for a whole OU or account, while effective permission is the intersection of SCP ∩ IAM (even root can’t exceed an SCP). Global services are excepted with NotAction. Control Tower automates the landing zone, and GuardDuty, Security Hub, Config, and Inspector are turned on for the whole organization, including future accounts, from a delegated administrator account with
auto_enable_organization_members. Link permissions across accounts with IAM Identity Center Permission Sets and the network with Transit Gateway, and migrate gradually by putting new workloads on new accounts.
Next Chapter #
In the next Chapter 30 disaster recovery & backup, we cover how to bring data and services back when one region / one AZ collapses. We’ll set up backups with RDS PITR · S3 versioning / replication · AWS Backup, and lay out how to choose among the cross-region DR patterns Pilot Light · Warm Standby · Multi-Site by RTO / RPO criteria.