Account Structure, Organizations, and Landing Zones
What This Concept Is
A single cloud account is fine for a toy. Real organizations run many accounts, and the structure of those accounts is a first-order security and operations decision.
- AWS Account / GCP Project / Azure Subscription - the primary isolation boundary. Each has its own IAM, its own resources, its own bill.
- AWS Organization / GCP Organization / Azure Management Group - a hierarchy that owns multiple accounts with a shared management layer.
- Organizational Unit (OU) / Folder - a grouping inside the organization that policies can target (e.g.,
Workloads/Production). - Service Control Policy (SCP) - an organization-level Deny-list that caps what any principal in a target account can do, even root. The strongest preventive guardrail available. On GCP the equivalent is organization policies; on Azure, Azure Policy assignments at management-group scope.
- Landing zone - a reference architecture for a multi-account setup: opinionated account layout, baseline IAM, guardrails, logging, and network design applied uniformly to every new account.
The point is to give each workload its own account (for blast radius), while still managing identity, billing, logging, and policy centrally.
Why It Matters Here
A sloppy account layout creates permanent problems:
- shared "everything" account -> any incident in staging risks prod
- no org-level guardrails -> a junior engineer can create an IAM user with console root-equivalents
- no central log archive -> logs get deleted along with the account they lived in
- no tagging or billing tags on the root account -> no way to attribute cost
- shared credentials or shared roles across accounts -> one leaked key compromises many blast radii at once
Most providers publish a reference landing zone (AWS Control Tower / Landing Zone Accelerator, GCP Cloud Foundation Toolkit, Azure CAF Enterprise-scale). They all agree on the same broad shape, even if names differ: core accounts for governance, log archive, security tooling, shared services, and workload accounts per team × environment.
Concrete Example
A small-to-mid-sized organization's landing zone:
Organization Root
├── Core OU
│ ├── Management Account (org root, billing, policies only)
│ ├── Log Archive Account (central, immutable audit logs)
│ ├── Security Tooling Account (GuardDuty, Security Hub, central IAM)
│ └── Shared Services Account (central DNS, identity, CI/CD)
├── Workloads OU
│ ├── Non-prod OU
│ │ ├── team-a-dev
│ │ ├── team-a-staging
│ │ └── team-b-dev
│ └── Production OU
│ ├── team-a-prod
│ └── team-b-prod
└── Sandbox OU
└── exploratory-<username>
Guardrails (SCPs) applied at the OU level:
- Production OU: deny disabling CloudTrail, deny creation of IAM users, deny actions in disallowed regions, deny root access key creation
- Non-prod OU: smaller set; maybe allow IAM users but forbid privileged instance types
- Sandbox OU: per-account budget; SCP forbids production-grade services (direct connect, etc.)
Example SCP (deny leaving the approved regions):
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyOutsideApprovedRegions",
"Effect": "Deny",
"NotAction": ["iam:*", "route53:*", "cloudfront:*", "organizations:*", "support:*"],
"Resource": "*",
"Condition": { "StringNotEquals": { "aws:RequestedRegion": ["us-east-1", "eu-west-1"] } }
}]
}
Baseline in every account (applied by automation):
- CloudTrail enabled, logs shipped to the Log Archive account
- AWS Config enabled with common rules
- VPC with the org's CIDR plan
- IAM SSO/Identity Center integrated with the central identity provider
- Default tags required on every resource (
owner,cost-center,env) - GuardDuty (or Security Command Center, Microsoft Defender for Cloud) enabled
- S3 Block Public Access on by default at account level
Common Confusion / Misconception
"Accounts are a billing thing." They are the primary security boundary. You cannot have an IAM role in account A accidentally list resources in account B unless you explicitly set up cross-account trust.
"One account is simpler, so start there." It is simpler today. It becomes painful the moment an incident in dev threatens prod, or when Finance asks who is spending what, or when your auditor asks to isolate PCI workloads. Paying the multi-account tax early is cheaper than untangling later.
"SCPs replace IAM policies." They do not grant anything; they only deny. You still need identity-based and resource-based policies inside each account. Think of SCPs as the outer wall and IAM as the inner locks.
"Landing zones are AWS-specific." The language is AWS-native, but the pattern is universal. GCP's Cloud Foundation Toolkit and Security Foundations blueprint produce the same outputs with folders and organization policies. Azure's Cloud Adoption Framework landing zones ship Bicep/Terraform with management groups, subscriptions, policy initiatives.
Gotcha: The management account should be used only for organization-level operations (billing, SCPs, creating accounts). Running workloads in the management account is an antipattern because an incident there can cascade across the organization. Also: the management account cannot be attached to most SCPs - it is trusted by the org. Never store production workloads there, ever.
Second gotcha: New-account provisioning should never require a human. If someone has to click through 30 screens, baseline drift is guaranteed. Automate with Control Tower account factory, GCP project factory, or Azure Enterprise-scale templates - or roll your own with Terraform and an approval gate.
How To Use It
When designing or reviewing an org:
- One account per environment per workload; favor more accounts, not fewer.
- Segregate core accounts (log archive, security, shared services, management) from workloads.
- Apply SCPs at OU level; start with permissive "deny the truly dangerous" (no disabling CloudTrail, no root keys, region deny-list) and tighten over time.
- Use Identity Center (or an equivalent SSO IdP) for human access; never use long-lived IAM users for humans.
- Automate account creation so every new account gets the same baseline; drift is your enemy.
- Run a quarterly account-inventory review: who owns each, what's in it, is it still needed?
- Version your landing-zone IaC in Git (a multi-account landing zone is a 10k+ line monorepo;
Pro Gitbranching patterns become critical). - Define closure criteria for an account - what it takes to decommission one. "Forever accounts" accumulate orphaned resources.
Check Yourself
- Why is the management account a bad place for workloads?
- What does an SCP do that an IAM policy cannot?
- Given a brand-new team, describe the first three accounts they should be granted under your landing zone.
- You need to forbid usage of a region entirely across production. Which primitive do you use, and at what scope?
- On GCP or Azure, what is the equivalent of an SCP, and what is one subtle difference from AWS?
Mini Drill or Application
Sketch a landing zone for a 50-engineer company in twenty minutes. Include OU structure, core accounts, workload account naming, two SCPs with intent, the identity source, and one central log destination. Name one thing this structure makes easy and one it makes harder.
Extension: write the shortest possible SCP that would have prevented a real-world cloud breach you have read about (e.g., CloudTrail disablement, S3 ACL making a bucket public). This exercise is the single best calibration for what an SCP is for.
Read This Only If Stuck
- AWS Control Tower: Multi-account strategy for your landing zone - the canonical AWS guidance
- AWS Prescriptive Guidance: Account structure and OUs - OU layouts and rationale
- AWS Organizations: Service control policies - SCP syntax, evaluation, examples
- Google Cloud: Resource hierarchy - the org/folder/project model
- Google Cloud: Landing zone design - GCP's equivalent of AWS landing zones
- Azure Cloud Adoption Framework: Landing zones - Azure's management-group + subscription blueprint
- Pro Git: Distributed Git - workflows - multi-account IaC repos look a lot like a monorepo; branching patterns matter
- Pro Git: Branch management - long-running environment branches vs per-change branches when deploying landing-zone changes