CoursesAdvanced cloud securityIdentity & access at scale

Multi-account & org identity architecture

Landing-zone identity, cross-account roles, and blast radius by design.

Advanced35 min · lesson 1 of 15

At one account, cloud identity is a policy problem. At fifty accounts it is an architecture problem: where identities live, how they cross account boundaries, and how a single compromise is contained. A landing zone answers those questions once, centrally, so every new account inherits the same guardrails instead of drifting into its own snowflake of permissions.

The account is the blast-radius boundary

An AWS account (or a GCP project, or an Azure subscription) is the strongest isolation the cloud gives you: separate resource namespaces, separate default trust, and a clean seam for billing and policy. Group them into organizational units and you can apply a service control policy (SCP) or organization policy to a whole branch of the tree at once. The design goal is that a total compromise of one workload account cannot read, write, or pivot into another — production is a different account from staging, security tooling is a different account from both, and the log archive is an account almost nobody can log into.

an OU layout and a baseline SCP
Organization (management account — no workloads)
|- Security OU
| |- log-archive (write-once audit sink)
| |- security-tooling (GuardDuty/Config aggregation)
|- Infrastructure OU
| |- shared-services (CI, DNS, networking)
|- Workloads OU
|- prod
|- staging
|- sandbox
# SCP attached to Workloads OU: deny leaving the approved region
# and deny disabling the guardrails, for EVERY principal incl. admins
{
"Version": "2012-10-17",
"Statement": [
{ "Sid": "RegionLock", "Effect": "Deny", "NotAction": ["iam:*","sts:*","cloudfront:*"],
"Resource": "*", "Condition": { "StringNotEquals": { "aws:RequestedRegion": "eu-west-1" } } },
{ "Sid": "ProtectGuardrails", "Effect": "Deny",
"Action": ["config:StopConfigurationRecorder","cloudtrail:StopLogging","guardduty:DeleteDetector"],
"Resource": "*" }
]
}

Cross-account access is a role you assume, never a key you share

Access between accounts should always flow through a role in the target account that the source principal assumes for a short, logged session. Never copy an IAM user key from one account into another — that destroys attribution and cannot be revoked without rotating the key everywhere. A role has a trust policy (who may assume it) separate from its permission policy (what it can do), and every assumption shows up in CloudTrail as an sts:AssumeRole event you can alert on.

a cross-account role trust policy
# Role "DeployBot" in the prod account. Its TRUST policy names who may assume it:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111111111111:role/ci-runner" },
"Action": "sts:AssumeRole",
"Condition": { "StringEquals": { "sts:ExternalId": "prod-deploys-2026" } }
}]
}
# The CI runner assumes it for a 15-minute, fully-logged session:
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/DeployBot \
--role-session-name ci-build-8891 \
--duration-seconds 900 \
--external-id prod-deploys-2026
Separate the identity planes
management / identity
management account
org root, SCPs — no workloads run here
IdP / SSO
humans authenticate here, mapped to roles
security plane
log-archive account
write-once trail, near-zero human access
security-tooling account
aggregates findings org-wide
workload plane
prod / staging / sandbox
isolated accounts; cross-account via assumed roles
The management account is a control plane, not a workspace. Running workloads there means a workload bug can reach org-wide policy.
The management account is the crown jewels
Whoever controls the organization management (root) account controls every SCP and can peel back every guardrail. Put nothing in it but the org itself, lock it behind hardware MFA, use it almost never, and alert on every sign-in. A landing zone is only as strong as the discipline around that one account.