Architecture AWS

AWS Landing Zone: Guardrails (SCPs & Controls) — Preventive SCPs, Detective Config Rules, Proactive Hooks & the Mandatory/Recommended/Elective Catalog

Where this fits

In AWS Landing Zone & Control Tower, parts 1–3 established the org structure and operating spine: the AWS Organizations account tree, the OU design (Security, Infrastructure, Workloads, Sandbox, Suspended), the three foundational accounts (management, Log Archive, Audit), and centralized CloudTrail/Config logging. None of that enforces anything on its own. Part 4 — Guardrails (SCPs & Controls) is where the landing zone grows teeth: it is the layer that takes governance intent and turns it into rules that block, detect, or prevent non-compliant behaviour automatically across every account, including ones that don’t exist yet. AWS Control Tower packages these as controls (the term that replaced “guardrails” in the console, though everyone still says guardrails), and a control is delivered through one of three behaviours — preventive via Service Control Policies, detective via AWS Config rules, proactive via CloudFormation Hooks — and assigned through one of three categories — mandatory, strongly recommended, elective. This article goes deep on all four of those sub-components, because getting the behaviour-to-mechanism mapping right is what separates a landing zone that scales to 800 accounts from one that becomes an exemption-ticket factory.

AWS Landing Zone & Control Tower — animated overview

Preventive guardrails: Service Control Policies (SCPs)

What it is

A Service Control Policy is an AWS Organizations policy that sets the maximum available permissions for the IAM principals (users and roles) in the accounts it is attached to. It is a guardrail, not a grant: an SCP never gives anyone permission — it only defines the ceiling that an account’s own IAM policies operate beneath. The effective permission of any principal is the intersection of what the SCP allows and what the principal’s IAM (identity and resource) policies allow. If either side says no, the answer is no. Crucially, SCPs apply to everyone in the member account including the account root user — but they explicitly do not apply to the management account, to service-linked roles, or to the org’s service-managed resources. That management-account blind spot is the single most important SCP fact to internalise: never run workloads there, because you cannot fence them in.

SCPs attach to three target types in the org tree — the root, an Organizational Unit, or an individual account — and they inherit downward. A policy on the root applies to every account; a policy on the Workloads OU applies to every account in and below it. Inheritance is additive in restriction: a child OU can make things stricter but can never loosen what a parent SCP forbade. There are two authoring styles:

A closely related newer control is the Resource Control Policy (RCP). Where an SCP bounds what principals in your accounts can do, an RCP bounds what any principal (including external/cross-account ones) can do to resources in your accounts — the resource-perimeter complement to the identity perimeter. SCPs and RCPs are both Organizations policies, both inherit down the tree, and both intersect with the relevant grant; a mature landing zone uses both.

Why it matters

SCPs are the only AWS mechanism that can make a permission impossible to grant — not merely ungranted, but unobtainable even by an account’s own administrator or root user. That property is what lets a platform team hand a workload account to a product team with full autonomy inside the box while guaranteeing certain things can never happen: the central CloudTrail can’t be stopped, the org can’t be left, the encryption key for the log bucket can’t be deleted, resources can’t be created outside approved regions. Without SCPs you are relying on every account’s IAM being authored correctly forever, which is a bet you will lose at the 50th account. With SCPs, a non-negotiable written once at the root is enforced on account 800 exactly as on account 1, and cannot be weakened by a child scope.

They are also the cleanest way to encode compliance and data-residency law as code: a single region-deny SCP on the EU OU does more for GDPR data-residency assurance than a hundred pages of policy documentation, because it is mechanically unbreakable.

How to do it well

The canonical SCP patterns

Guardrail intent Mechanism Where to attach
Prevent member accounts leaving the org Deny organizations:LeaveOrganization Root
Region allowlist (data residency) Deny NotAction:[global svcs] when aws:RequestedRegion ∉ allowlist Root or geo OU
Protect CloudTrail / Config / log bucket Deny cloudtrail:Stop*/Delete*, config:Delete*, S3 deletes on log bucket Root
Block root-user activity except break-glass Deny * with aws:PrincipalArn = root and aws:PrincipalType = Root Root
Require IMDSv2 / deny IMDSv1 launches Deny ec2:RunInstances unless ec2:MetadataHttpTokens = required Workloads OU
Sandbox service allowlist Deny NotAction:[approved services] Sandbox OU
Deny disabling security services Deny guardduty:Delete*, securityhub:Disable*, macie2:Disable* Security + Workloads OUs
Resource perimeter (block external access) RCP with aws:PrincipalOrgID StringNotEquals Root

Concrete artifacts, decisions, and tools

Callout: Control Tower writes and owns a set of SCPs to implement its preventive controls; they carry the aws-guardrails- name prefix and an aws-control-tower tag. Do not edit, reorder, or delete these manually — doing so puts the OU into a non-compliant/drift state that Control Tower will flag and may try to remediate. Layer your custom SCPs alongside them, not on top of them.

Detective guardrails: AWS Config rules

What it is

A detective control does not block anything — it continuously evaluates the live state of your resources against a desired configuration and reports compliant / non-compliant. In the landing zone this is delivered by AWS Config: Config records the configuration of supported resources as configuration items, stores their history, and runs Config rules against them. A rule is either AWS-managed (one of hundreds of prebuilt checks like s3-bucket-public-read-prohibited, encrypted-volumes, rds-storage-encrypted, iam-password-policy) or custom (backed by an AWS Lambda function or a Guard policy in Config Custom Policy rules). Rules evaluate on configuration change, on a periodic schedule, or both.

Across an organisation, detective controls are deployed at scale through AWS Config conformance packs — a pack is a named collection of Config rules and remediation actions deployed as a single CloudFormation-based unit, and an organization conformance pack rolls that bundle out to every member account from the management or a delegated administrator account in one operation. Control Tower’s detective controls are exactly this under the hood: managed Config rules deployed org-wide, with findings surfaced in the Control Tower console and (typically) aggregated into AWS Security Hub.

Why it matters

Preventive controls can only stop the things you thought to forbid in advance, and only at the API boundary. Detective controls cover the long tail: configuration drift introduced by a permitted-but-misused API, by an action a too-broad SCP exemption allowed, by a console change, or simply by a resource that was compliant when created and drifted later (a security group opened to 0.0.0.0/0 last Tuesday). They give you the continuous-compliance evidence auditors actually want — a timestamped, per-resource history of compliant/non-compliant state mapped to a framework — and they are the input to auto-remediation. A detective control is the difference between “we have a policy that says volumes must be encrypted” and “here is the live count of unencrypted volumes by account, trending down, with the remediation that runs on each new violation.”

They also catch what preventive controls structurally cannot: things created in the management account (no SCP), changes by service-linked roles, and slow drift. A landing zone with only preventive controls is blind to its own decay.

How to do it well

Detective control building blocks

Building block Role in the landing zone
Configuration recorder Captures configuration items per account; the data source for everything
AWS-managed Config rule Prebuilt compliance check (e.g. s3-bucket-server-side-encryption-enabled)
Custom Config rule (Lambda / Guard) Org-specific checks not covered by managed rules
Conformance pack A versioned bundle of rules + remediations deployed as one unit
Organization conformance pack The same bundle rolled out org-wide, current and future accounts
Config aggregator Single-pane org-wide compliance view (in Audit account)
SSM Automation remediation The corrective action a rule fires (auto or on approval)
Security Hub Normalises + scores findings against frameworks

Concrete artifacts, decisions, and tools

Proactive controls: CloudFormation Hooks

What it is

A proactive control is the third behaviour, and it closes the gap between preventive and detective. It checks resource configuration at provisioning time, before the resource is created or updated, and blocks the deployment if it would be non-compliant — but unlike an SCP, it inspects the desired resource properties, not just the API verb. The delivery mechanism is AWS CloudFormation Hooks: a hook runs during a CloudFormation stack operation, after the template is submitted but before resources are provisioned, and can return PASS or FAIL (with FAIL aborting the stack op, or WARN to advise without blocking). Control Tower’s proactive controls are managed CloudFormation Hooks AWS authors and operates on your behalf.

The conceptual difference is sharp:

Proactive controls therefore give you “encryption-required” semantics with no non-compliant window at all, for resources deployed via CloudFormation, without the bluntness of denying the whole API.

Why it matters

Proactive controls move enforcement left, into the pipeline, with zero remediation lag. For infrastructure-as-code shops — which any serious landing zone is — this is the highest-leverage control type for property-level requirements: encryption, versioning, public-access blocks, deletion protection, mandatory tags, instance-type allowlists, log-retention minimums. They catch the violation at cloudformation:CreateStack time, returning an error to the developer in their deploy with a clear reason, rather than blocking an opaque API call (SCP) or filing a finding hours later (Config). The result is a tighter feedback loop, fewer exemptions, and fewer resources that ever enter a non-compliant state in the first place.

The trade-off is scope: a CloudFormation Hook only fires for resources deployed through CloudFormation (which includes Service Catalog, CDK, and Control Tower’s own Account Factory). Resources created by the console, raw API/SDK calls, or Terraform are not seen by the hook — which is precisely why proactive, preventive, and detective controls are layered together rather than chosen between.

How to do it well

Behaviour comparison: the layering matrix

Property Preventive (SCP) Proactive (CFN Hook) Detective (Config rule)
When it acts At the API call At stack provisioning, pre-create After the resource exists
What it reasons about API action + condition keys Full proposed resource properties Recorded resource state
Effect Blocks the call Blocks the stack op Flags; can auto-remediate
Non-compliant window None None Yes (detect/remediate lag)
Coverage Every principal, every path CloudFormation-deployed only Every supported resource
Best for “Never allowed at all” “Property-level, in-pipeline” “Drift + audit evidence”
Underlying service AWS Organizations AWS CloudFormation Hooks AWS Config

Concrete artifacts, decisions, and tools

Mandatory, strongly-recommended and elective controls

What it is

This is the category axis of the Control Tower control library, orthogonal to behaviour. Every control AWS ships is classified by how strongly AWS recommends it and whether you can turn it off:

A separate axis, guidance, also marks some controls ELECTIVE/STRONGLY_RECOMMENDED/MANDATORY in the API alongside their behaviour, and AWS additionally groups controls into control objectives (e.g. “Establish logging and monitoring,” “Encrypt data at rest,” “Limit network access”) and frameworks so you can enable a coherent set rather than cherry-picking. The library is large (hundreds of controls) and spans the behaviours above — so a single elective control might be implemented as an SCP, a Config rule, or a hook.

Why it matters

The category model is how you right-size enforcement per OU without re-deriving it from first principles. Mandatory controls remove the question of whether the landing zone’s own integrity is protected — it always is, you can’t switch it off, and an auditor can rely on that. Strongly-recommended controls give you an AWS-curated, Well-Architected baseline you can apply estate-wide with confidence. Elective controls let you tighten specific OUs (a regulated-data OU, a PCI OU) without imposing those locks on teams that would only file exemptions. The practical payoff is that you express your control posture as “which categories of control on which OU” — a small, reviewable matrix — instead of evaluating hundreds of individual controls account by account.

It also keeps you aligned with AWS’s roadmap: AWS adds and updates controls over time, and because mandatory/strongly-recommended sets are curated by AWS, enabling them broadly means you inherit improvements rather than maintaining a bespoke catalogue forever.

How to do it well

Enabling a control on an OU

# Discover available controls and their behaviour/category
aws controltower list-controls

# Enable a strongly-recommended control on the Workloads-Prod OU
aws controltower enable-control \
  --control-identifier "arn:aws:controltower:us-east-1::control/AWS-GR_RESTRICTED_SSH" \
  --target-identifier "arn:aws:organizations::123456789012:ou/o-exampleorgid/ou-prod-xxxxxxxx"

# Inspect what's enabled on a target
aws controltower list-enabled-controls \
  --target-identifier "arn:aws:organizations::123456789012:ou/o-exampleorgid/ou-prod-xxxxxxxx"

Category vs behaviour: how they combine

Preventive (SCP) Detective (Config) Proactive (Hook)
Mandatory Protect CloudTrail/Config config; protect log roles Detect missing CloudTrail; log-bucket public access (Fewer; integrity-focused)
Strongly recommended Region/IMDSv2 hardening (as enabled) Public S3, open SSH/RDP, unencrypted EBS Require encryption / no-public-access on create
Elective Disallow specific cross-account actions Detect optional posture items Block creation of specific non-compliant types

Concrete artifacts, decisions, and tools

Real-world enterprise scenario

Meridian Logistics, a freight and supply-chain company, runs a Control Tower landing zone with 140 accounts across a familiar OU hierarchy: Security (Log Archive, Audit), Infrastructure (shared networking, CI/CD), WorkloadsProd / NonProd, PCI (their payments and customer-billing systems), EU (data that must stay in-region under GDPR), and Sandbox. A SOC 2 audit and a new EU data-residency obligation force them to make the guardrail layer real and provable. They work it sub-component by sub-component.

Preventive (SCPs). They keep FullAWSAccess at the root and author six dense deny-list SCPs as code in a org-scps repo, deployed by Terraform. At the root: an SCP denying organizations:LeaveOrganization, an SCP protecting CloudTrail/Config and the Log Archive buckets, and a root-user hardening SCP that denies all root activity except a documented break-glass role. On the EU OU: a region-lock SCP using aws:RequestedRegion restricted to eu-west-1/eu-central-1, with a NotAction exemption for IAM, Organizations, Route 53, CloudFront, STS, Support, and an aws:PrincipalArn carve-out for the Control Tower execution role. On Workloads: an IMDSv2-required SCP (ec2:RunInstances denied unless ec2:MetadataHttpTokens = required) and a security-services-protection SCP (Deny guardduty:Delete*, securityhub:Disable*). They hit the 5-SCP-per-target ceiling on Workloads and consolidate two drafts into one. They also adopt a single RCP at the root denying any S3/KMS access from principals outside aws:PrincipalOrgID (with approved-service exemptions) to close the resource perimeter. Every policy ships through CI with an IAM Policy Simulator check and a non-prod-OU canary before promotion.

Detective (Config rules). They enable Control Tower’s strongly-recommended detective controls estate-wide and add a custom organization conformance pack mapped to CIS AWS Foundations Benchmark v3.0 plus AWS Foundational Security Best Practices, deployed from the Audit account (delegated Config administrator) so it lands on all 140 accounts and every future one. They stand up a Config aggregator in Audit for a single org-wide compliance view, route findings to Security Hub, and tune the configuration recorder to skip a few high-churn resource types to keep the Config bill predictable. Low-risk rules (S3 default-encryption, public-access-block, missing tags) get automatic SSM Automation remediation; security-group changes get manual-approval remediation so they never disrupt a running app.

Proactive (CloudFormation Hooks). Because all Prod and PCI infrastructure deploys through Service Catalog (CDK-synthesised CloudFormation), Meridian enables Control Tower’s managed proactive controls there — “require encryption” and “disallow public access” on S3, RDS, and EBS — so a non-compliant resource is blocked at stack-create time with zero non-compliant window. They author one custom cfn-guard hook asserting a mandatory DataClassification tag and a log-retention minimum, land it in WARN mode for two sprints to socialise it (it would have blocked 38 deploys), then flip it to FAIL. NonProd and Sandbox, which still allow some Terraform, rely on the detective pack plus a cfn-guard/OPA check in their Terraform CI as the moral equivalent.

Categories. Mandatory controls stay untouched. Strongly-recommended controls are enabled on the Workloads OU root (covering Prod and NonProd and every future child). Elective controls are applied surgically: “disallow S3 bucket deletion” and “disallow versioning changes” on the PCI OU (records retention), and a Sandbox service-allowlist SCP keeps experimentation cheap and safe. The whole posture is captured in a one-page control-enablement matrix (category → OU) plus the SCP-attachment matrix, both in Git.

Outcome. Within one quarter: org-wide Config compliance moved from 71% to 96% with the remaining 4% tracked as accepted exemptions; the EU region-lock made GDPR data-residency mechanically provable (auditors were shown the SCP, not a spreadsheet); zero unencrypted S3/EBS resources entered Prod after the proactive hooks went to FAIL; the SOC 2 audit’s “logging integrity” and “encryption at rest” controls were evidenced directly from mandatory controls and the conformance pack with no manual screenshotting; and exemption tickets dropped because most violations were now caught in-pipeline by developers rather than in production by the platform team.

Deliverables & checklist

Common pitfalls

  1. Region-locking yourself out of IAM. A blanket aws:RequestedRegion deny without exempting global services (which authenticate through us-east-1) bricks IAM, Organizations, and Route 53 administration. Always pair the region lock with a NotAction exemption list and test in a non-prod OU first.
  2. Running workloads — or anything — in the management account. SCPs do not apply to the management account, so nothing you put there can be fenced in, and it has org-admin blast radius. Keep it empty of workloads; the landing zone’s whole trust model assumes this.
  3. Editing Control Tower’s managed SCPs by hand. The aws-guardrails-* policies are owned by Control Tower; manual edits cause drift, non-compliant OU status, and may be auto-reverted. Add your own SCPs alongside them instead.
  4. Treating detective controls as if they prevented anything. Config flags drift after the fact, with a detect/remediate lag. If a requirement cannot tolerate a non-compliant window, it needs a preventive (SCP) or proactive (hook) control — not a Config rule alone.
  5. Assuming proactive hooks cover everything. CloudFormation Hooks only fire for CloudFormation/Service Catalog/CDK deployments — never for console, raw API, or Terraform. Layer detective + preventive controls to cover the un-hooked paths, or replicate the Guard checks in your Terraform CI.
  6. Hitting SCP limits late. Discovering the 5-per-target / 5,120-character ceilings after you’ve drafted ten single-purpose policies forces a painful rewrite. Design dense, consolidated, well-commented SCPs from the start, and use NotAction/NotResource to stay compact.

What’s next

With guardrails enforced through preventive SCPs, detective Config rules, proactive Hooks, and the right mix of mandatory/strongly-recommended/elective controls, Part 5 of AWS Landing Zone & Control Tower turns to account vending and customization at scale — automating compliant account provisioning with Account Factory and Account Factory for Terraform (AFT) so every new account is born inside these guardrails.

AWSLanding ZoneGuardrails (SCPs & Controls)Enterprise
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

// part 4 of 6 · AWS Landing Zone & Control Tower

Keep Reading