Chapter 7 — Organisation structure and guardrails
In one sentence
Multi-account (or multi-project/subscription) structure plus org-wide guardrails turns "one mistake compromises everything" into "one mistake is contained to one blast-radius boundary that can't disable its own logging or exceed its own ceiling".
Where we are
A single cloud account with everything in it is the flat trust domain of Chapter 3, at cloud scale: prod and dev share a blast radius, one over-broad role reaches everything, and an attacker who gets in can turn off the logging that would catch them. The fix is structural.
How it works
Account/project structure (AWS Organizations; GCP folders; Azure management groups):
management (org root) -- ONLY org management + billing. No workloads.
Break-glass access only. Root creds in a safe,
MFA, alarmed.
security -- log archive (immutable), GuardDuty/Security Hub
delegated admin, IR tooling, the SOC's account.
log-archive -- write-only-from-org S3 buckets for CloudTrail/
Config; object lock; no human read except IR.
shared-services -- CI/CD, artifact registry, DNS, golden AMIs.
network -- Transit Gateway, central egress, DNS resolvers.
workloads/
prod/ -- one account PER application (or per team), so a
secureshop-prod compromise of one app is one account.
otherapp-prod
staging/ dev/ sandbox/
PRINCIPLE: an account is the strongest isolation boundary the cloud
gives you cheaply. Use it as the unit of blast radius.
Guardrails — Service Control Policies (AWS), Org Policy + IAM Deny (GCP), Azure Policy (Azure):
SCPs do NOT grant. They set the MAXIMUM available permissions for every
account they apply to (management account excepted). Two styles:
ALLOWLIST deny everything, allow named services/actions (tight; high
maintenance).
DENYLIST allow all, deny a curated set of dangerous things (common
starting point).
A solid denylist SCP set:
[ ] Deny disabling/altering CloudTrail, Config, GuardDuty, Security
Hub, Access Analyzer.
[ ] Deny writing to / deleting the log-archive buckets (except the
org logging principal).
[ ] Deny leaving the organization; deny modifying the account's
Organizations membership.
[ ] Deny use of regions you don't operate in (shrinks attack surface,
cuts crypto-mining blast radius).
[ ] Deny root user actions except a defined break-glass set.
[ ] Deny iam:CreateUser / CreateAccessKey / CreateLoginProfile
(force SSO + roles) except a break-glass path.
[ ] Deny making S3 buckets / EBS snapshots / RDS snapshots / AMIs
public.
[ ] Deny disabling default EBS encryption; deny creating unencrypted
RDS.
[ ] Require IMDSv2 (deny RunInstances without
MetadataOptions.HttpTokens=required, HttpPutResponseHopLimit=1).
[ ] Deny Create/UpdateFunction etc. that pass roles outside an
approved path (defence in depth for Ch 6).
GCP: Organization Policy constraints (constraints/compute.
requireOsLogin, iam.disableServiceAccountKeyCreation,
storage.publicAccessPrevention, sql.restrictPublicIp,
compute.vmExternalIpAccess, gcp.resourceLocations) + IAM Deny policies
for the deny-style rules.
Azure: Azure Policy definitions/initiatives (deny public IP, require
encryption, allowed locations, deny classic resources) assigned at the
management-group level; plus Entra Conditional Access for identity.
Landing zones package all of this: AWS Control Tower / Landing Zone Accelerator, GCP "Cloud Foundation Toolkit" / Fabric, Azure Landing Zones. They give you the account factory, baseline SCPs, centralised logging, and guardrails as IaC. Use one rather than hand-rolling — but understand what it's doing.
Delegated administration & centralisation: designate the security account
as the delegated admin for GuardDuty, Security Hub, Access Analyzer, Config, and
Detective, so findings from every account aggregate there and the workload
accounts can't turn them off.
Worked example
What a single leaked prod credential can and cannot do, before and after structure.
BEFORE (one account, denylist SCP = none):
leaked `secureshop-app` key -> attacker enumerates, finds a privesc
edge (Ch 6) -> account admin -> reads every app's data, disables
CloudTrail, launches mining instances in 14 regions, creates a
backdoor IAM user, pivots to the CI role and into every other system.
Blast radius: everything. Detection: CloudTrail was turned off.
AFTER (secureshop-prod is its own account; org SCPs applied):
same leaked key, same privesc edge -> admin OF secureshop-prod ONLY.
- cannot disable CloudTrail (SCP deny) -> the org trail in
log-archive still records every call.
- cannot create IAM users / access keys (SCP deny) -> persistence
must use roles, which are shorter-lived and more visible.
- cannot use regions outside eu-west-1/us-east-1 (SCP) -> mining
blast radius capped; RunInstances spikes alert.
- cannot make snapshots/buckets public (SCP) -> the easy exfil
path is closed; must exfil via API, which GuardDuty flags.
- cannot reach otherapp-prod (separate account, no trust) -> no
lateral movement across apps.
- the CI role lives in shared-services (separate account) with a
permission boundary -> not reachable from here.
Blast radius: one application's data in one account, with full audit
trail and multiple alerts firing. That is a bad day, not a company-
ending breach.
Real-world scenario: an exposed console, no guardrails, and cryptomining
In 2018, RedLock's (later Palo Alto Networks') research team
disclosed that Tesla's cloud infrastructure had been compromised via
an UNAUTHENTICATED KUBERNETES ADMINISTRATION CONSOLE, left reachable
on the internet with no password. Through it, attackers obtained AWS
credentials for a Tesla account and used the account's compute
capacity to run a CRYPTOCURRENCY MINING operation -- notably going to
some lengths to keep resource usage low and hide their traffic (using
a non-standard mining pool port, CloudFlare-fronted domains, and
throttled CPU usage) specifically to avoid tripping any obvious
monitoring.
THIS IS A GUARDRAIL FAILURE, NOT JUST A CONFIGURATION MISTAKE: had
this chapter's denylist SCPs been in place -- restricting which
regions could be used, denying unusual `RunInstances` volume spikes,
requiring approval for new instance types -- the exposed console would
still have been a real finding, but the BLAST RADIUS (unlimited
compute in any region, indefinitely) would have been capped instead
of open-ended. This incident is one of the earliest widely-reported
examples of "denial of wallet" (G1/this guide's resilience chapters)
as a real, cloud-native consequence of a credential leak, rather than
the more commonly assumed "attacker steals data" outcome.
Practice (60 min)
- If you have an org: enumerate its structure. Is there a dedicated
log-archiveandsecurityaccount? Are SCPs applied, and of which style? Run Prowler (prowler aws) and read the "Organizations" and "CloudTrail" sections. - In a sandbox org (or a mock with
localstack/Terraform), apply a starter denylist SCP (denycloudtrail:StopLogging, deny non-approved regions, denys3:PutBucketPublicAccessBlockremoval, require IMDSv2). Verify: try each denied action from a member account and confirmAccessDenied. - Delegate GuardDuty admin to a
securityaccount; generate a sample finding; confirm it aggregates there and the member account can't disable the detector. - Write your own org's "target structure" diagram and the gap list to get there.
Common mistakes
- Workloads in the management account. It's not SCP-restricted; a compromise there is uncapped. It should run nothing.
- One account for prod + staging + dev. No blast-radius boundary; test workloads become a pivot into prod.
- Allowlist SCPs adopted too early. They're powerful but high-maintenance; most orgs should start denylist and tighten.
- SCPs that lock out break-glass. Always keep a tested, alarmed emergency access path (a break-glass role excluded from the restrictive SCP, MFA-protected, use-triggers-page).
- Guardrails not as code. Click-ops SCPs drift and aren't reviewable. Manage them in Terraform/CloudFormation with the rest.
- Region sprawl. Every enabled region is attack surface and mining opportunity. Deny the ones you don't use.
Check yourself
- Why is a separate account the cheapest strong isolation boundary in the cloud?
- What does an SCP do and not do? Which account does it not affect?
- Give five things a denylist SCP set should deny and why each matters.
- What is a landing zone and why use one instead of hand-rolling?
- Why delegate GuardDuty/Config admin to a dedicated security account?
- What must you preserve when applying restrictive SCPs?
Further reading
- Docs: AWS "Organizations best practices", "SCP examples", Control Tower; GCP "Organization policy constraints" and "Landing zone design"; Azure "Cloud Adoption Framework — landing zones".
- Reference: AWS "Security Reference Architecture" (SRA) — the canonical
multi-account picture;
aws-samples/aws-secure-environment-accelerator. - Tools: Prowler, ScoutSuite, Steampipe/Powerpipe compliance mods,
org- formation(SCP-as-code). - Talk: re:Inforce sessions on multi-account strategy; "How to think about AWS Organizations" (Scott Piper).