AWS 256: Service Control Policies
Why this matters to an architect
A member-account administrator can attach powerful IAM policies, but should not be able to disable enterprise logs, leave the organization, deploy in prohibited Regions, or grant access outside approved boundaries. A Service Control Policy (SCP) places a centrally managed maximum around principals in member accounts.
An SCP is not a permission grant and not a firewall. A correct request needs an IAM/resource-policy grant and must survive every applicable SCP. A careless root-level SCP can stop production and incident recovery across an organization immediately, so policy reasoning, staging, observability, and rollback are part of the control.
Outcomes
By the end, you can:
- explain SCP purpose, scope, inheritance, allow-list, deny-list, implicit deny, and explicit deny;
- calculate effective SCP permission across root, nested OUs, and account attachments;
- apply current full IAM policy-language support without relying on obsolete SCP restrictions;
- identify management-account, service-linked-role, and other practical exceptions;
- design Region, organization membership, security-service, log, data-perimeter, root-user, and tag controls;
- avoid
NotAction,NotResource, wildcard, condition, and missing-context traps; - validate syntax, analyze service last accessed data, stage behavior, deploy progressively, and roll back;
- diagnose an SCP denial separately from IAM, boundary, session, RCP, resource, KMS, and endpoint-policy failures.
History: older SCP syntax is now obsolete
SCPs launched with AWS Organizations in 2017. Historically, their policy language was more limited than an IAM managed policy. On September 19, 2025, AWS announced full IAM policy-language support for SCPs. Current capabilities include conditions, specific resource ARNs in Allow, NotAction with Allow, NotResource in allow/deny statements, and */? wildcards at the beginning or middle of action strings.
This enables precise controls but increases review risk. An old course claiming “Allow SCPs must use Resource: *” is outdated. Conversely, valid syntax is not necessarily safe: Allow with NotAction or NotResource can include future AWS actions/resources that were not considered. Prefer understandable invariants, peer review, automated tests, and current documentation.
The permission-maximum model
For a principal in a member account:
effective request requires
a valid identity/resource grant
AND an applicable allow through every SCP level
AND permissions boundary/session-policy maximums
AND applicable RCP maximums
AND no explicit deny anywhere
AND service-specific resource/key/endpoint conditions
An SCP that allows s3:GetObject does not give a role that permission. The role still needs an IAM or valid resource-based grant. If IAM allows s3:* but an SCP allows only s3:GetObject, the role's maximum is narrowed. An explicit SCP deny wins over an IAM administrator policy and over the member-account root user.
SCPs are principal-centric: they apply based on the organization account that owns the requesting principal, even when that principal accesses a resource in another account. RCPs are resource-centric and can constrain external principals accessing supported member resources. Use both where the invariant needs both sides.
Inheritance through the hierarchy
Assume this path:
root -> Workloads OU -> Production OU -> Payments account
The effective SCP set includes policies attached to all four nodes. Evaluation uses two rules:
- An explicit
Denyin any applicable SCP denies. - The requested action must have an applicable
Allowat every level from root to account.
AWS attaches the managed FullAWSAccess SCP by default. In a deny-list strategy, keep broad allow and add targeted explicit denies. In an allow-list strategy, detach/replace broad allow and explicitly allow only approved capabilities at each hierarchy level. A child cannot restore an action that an ancestor did not allow, and a child allow cannot override a parent deny.
Example: root allows all; Workloads allows EC2/S3/KMS; Production allows EC2/S3; Payments allows KMS. KMS fails at Production, while EC2/S3 fail at Payments. Separate policy documents at one node combine, but the node's resulting allow still intersects with ancestors and descendants.
An account move can change this path and therefore effective permissions immediately. Model both source and destination before moving it.
Deny list versus allow list
| Strategy | Benefit | Risk/operation |
|---|---|---|
| broad allow + explicit denies | new services/actions generally remain usable; concise invariants | must identify every dangerous path; new APIs may evade action-specific denies |
| explicit allow list | tight service/action maximum | new required APIs fail until reviewed; dependent/global actions are easy to miss |
| hybrid | broad at root, stricter sensitive OUs/accounts | requires clear ownership and path calculation |
Use deny statements for invariants such as “nobody in member accounts may leave the organization” or “only security automation may change the log destination.” Use allow lists where regulatory or sandbox requirements justify operational overhead. Do not call an allow list “least privilege” unless identity policies are also least privilege; SCPs only set the ceiling.
Scope and exceptions
SCPs affect IAM users, IAM roles, federated/assumed-role sessions, and root users in member accounts, including delegated-administrator accounts. They do not affect:
- principals in the Organizations management account;
- service-linked roles, whose AWS-defined permissions support integrated services.
That is why workloads should not run in the management account. A root SCP cannot protect management-account resources from its administrators. Use tightly scoped IAM, resource policies, monitoring, root-credential controls, and separation there.
Do not mistake every role used by a service for a service-linked role. Ordinary customer-created service roles remain subject to SCPs. Inspect the session issuer and IAM role path/name rather than assuming “AWS service” means exempt.
An SCP also does not alter service quotas, create network isolation, configure resources, or prevent an external principal from accessing your resource merely because that external principal belongs outside your organization; use RCP/resource policies for the resource side.
Current policy language and review traps
SCP statements use Effect, Action or NotAction, Resource or NotResource, optional Condition, Sid, and Version. Principal/NotPrincipal are unsupported because scope comes from the attached organization target.
Review these hazards:
Deny+NotActiondenies everything except listed actions. It is useful for Region controls but a missing global service can block recovery.Allow+NotActionmay allow future actions by default; use only with a clearly tested reason.Allow+NotResourcemay include future/unexpected resources; explicit targeted controls are easier to audit.- action wildcards such as
iam:*Policy*match future/extra APIs; enumerate security invariants where practical. - condition keys are not present in every request. Use
...IfExists,Null, and set operators only after studying missing/multivalued behavior. - ARN formats, partition, Region/account fields, and resource-level permission support differ by action.
- a deny exception based only on role name can be recreated or assumed unexpectedly; govern who can create/assume the exception role.
Full language support makes Access Analyzer policy validation and source-controlled tests more valuable, not less.
Region restriction without breaking global services
A common SCP denies API operations when aws:RequestedRegion is not approved, while excluding global services with NotAction:
{
"Effect": "Deny",
"NotAction": [
"iam:*", "organizations:*", "route53:*", "cloudfront:*",
"support:*", "budgets:*", "waf:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {"aws:RequestedRegion": ["ap-south-1", "us-east-1"]}
}
}
This is illustrative, not copy-ready. Global-service calls can use us-east-1 or service-specific behavior; service lists evolve; STS global and Regional endpoints have audit/policy nuances; IAM may create resources used globally; CloudFront depends on certificates in us-east-1; and service-to-service calls may carry unexpected context. Start from current AWS examples, inventory actual services, use Regional STS endpoints, test creation/read/update/delete/recovery, and monitor denials.
A Region SCP does not move or delete resources already outside approved Regions. Add discovery, quarantine/remediation, and cost handling.
Protect organization membership and account closure
AWS recommends denying member principals these actions unless an approved path requires them:
{
"Effect": "Deny",
"Action": ["organizations:LeaveOrganization", "account:CloseAccount"],
"Resource": "*"
}
Organizations created in the console after July 10, 2026 receive this default root control automatically; older or programmatically created organizations require review. It does not stop management-account principals from calling management-side account closure operations, so protect those with management-account IAM and account tags/conditions as documented.
Leaving also has delegated-administrator and standalone-account prerequisites, but those are not preventive security controls.
Protect logs, security services, and guardrail roles
High-value denies can prevent ordinary member principals from stopping/deleting CloudTrail trails, Config recorders, GuardDuty detectors, Security Hub configuration, log buckets, KMS keys, or baseline roles. A safe design:
- lists exact mutation actions and protected resource ARNs/conditions where supported;
- exempts only a centrally governed security automation/incident role;
- restricts creation, trust, assumption, and modification of that exception role;
- handles service-linked-role operations and delegated administrators;
- includes legitimate rotation, retention, incident, and account-decommission workflows;
- tests target and non-target resources so the deny is not broader than intended.
Do not simply deny all KMS deletion or IAM changes organization-wide without an operating path. A guardrail that makes required rotation/recovery impossible will eventually be bypassed or disabled.
Data and network perimeter conditions
SCPs can restrict what member principals do based on organization/resource/network context, for supported services and requests:
aws:ResourceOrgID/aws:ResourceOrgPathsfor organization-owned resources;aws:PrincipalOrgIDis usually more relevant on resource-side policies/RCPs;aws:SourceVpce,aws:SourceVpc, or neweraws:VpceAccount,aws:VpceOrgID,aws:VpceOrgPathswhere supported;- principal/resource/request tags for governed ABAC;
aws:ViaAWSServiceandaws:CalledViato avoid breaking supported service-to-service paths.
Global keys are not uniformly present or supported. A data-perimeter deny that treats a missing key as “outside” can block AWS services, console operations, presigned workflows, or calls through unsupported paths. Start in monitor/analyze mode using CloudTrail, classify exceptions, use Null/IfExists deliberately, and test direct plus service-mediated requests. SCP alone is defense in depth, not a complete data perimeter.
Root-user and tag-governance controls
Member-account root users are subject to SCPs. You can deny most root activity using aws:PrincipalArn conditions while preserving explicitly documented root-only recovery tasks. Protect root email/MFA separately; an SCP cannot secure credentials it does not govern in the management account.
If authorization depends on resource/principal tags, prevent unauthorized tag mutation with action-, resource-, principal-, request-tag, and tag-key conditions. Do not freeze every tag for every service: creation often needs tags atomically, tag APIs differ, and automation needs a controlled path. Test create-with-tag, post-create tagging, untagging, case variants, missing values, service-created resources, and exception-role abuse.
Validation and rollout workflow
- Write the security invariant in plain language and enumerate principals, actions, resources, contexts, and exceptions.
- Inventory last-accessed/CloudTrail activity and service dependencies; absence of observed use is not proof an action is unnecessary.
- Author in source control with owner, target, expiry/review, and rollback.
- Run JSON/parser checks and IAM Access Analyzer
validate-policyforSERVICE_CONTROL_POLICY; review every finding. - Calculate attachments from root through target account and compare source/destination OU paths.
- Attach in a representative PolicyStaging OU/account.
- Run authorized, unauthorized, root, federated, automation, service-linked-role, global-service, each-Region, incident, and rollback tests.
- Canary one real account, monitor CloudTrail
AccessDenied, support/health and service telemetry, then roll out in batches. - Verify behavior - not only attachment - and preserve evidence.
Policy changes take effect quickly and do not wait for application maintenance windows. Prepare management-account break-glass access that can detach/revise a bad SCP, but tightly protect and alert on it. Never make the only rollback operator subject to the policy being tested.
Diagnosing AccessDenied
Start with caller ARN/account, action, resource, Region, and context. Then collect:
- all SCPs attached to root, every ancestor OU, and account;
- identity policies, boundaries, and session policy;
- RCP/resource/key/endpoint policy;
- CloudTrail event/error, session issuer, source identity, tags, endpoint/Region;
- whether the principal is management-account or service-linked role.
Some same-organization denial messages identify an explicit SCP deny, but do not depend on friendly text. Cross-account callers can receive generic denials, and multiple layers can deny simultaneously. Correct one layer and retest; never broaden to administrator merely to discover the next failure.
Practical lab
Download the AWS256 SCP engineering pack. It contains:
SCP_EVALUATION_WORKBOOK.md;SUPPLIED_SCP_CASES.mdwith seven failures;CURRENT_LANGUAGE_POLICY_SET.md;STAGED_ROLLOUT_AND_RECOVERY.md;ANSWER_DIRECTIONS.md, opened after independent calculation.
Calculate every hierarchy path, classify implicit/explicit denies, validate modern language, identify missing-context/future-action risks, and design positive, negative, exception, service-linked-role, and rollback tests. The supplied route creates nothing.
Read-only CLI evidence
With authorized Organizations access:
aws organizations list-policies --filter SERVICE_CONTROL_POLICY
aws organizations describe-policy --policy-id p-REDACTED
aws organizations list-targets-for-policy --policy-id p-REDACTED
aws organizations list-policies-for-target \
--target-id 111122223333 --filter SERVICE_CONTROL_POLICY
aws organizations list-parents --child-id 111122223333
aws accessanalyzer validate-policy \
--policy-type SERVICE_CONTROL_POLICY --policy-document file://candidate-scp.json
Walk parents recursively and paginate. list-policies-for-target shows direct attachments, not a precomputed effective SCP or live behavior. Redact IDs/ARNs/business controls. Do not attach/detach anything in the read-only track.
Cost, quotas, and cleanup
SCPs and Organizations have no additional service charge. CloudTrail/Lake, Config, Access Analyzer workflows, SIEM, testing accounts, support, and outage response can cost money. Current quotas include policy size and per-target attachment limits that have changed over time; verify current Organizations quota/policy-type documentation rather than memorizing older 5-policy/5,120-character figures.
Whitespace counts toward size. Do not minify away maintainability until necessary; split by invariant/owner while respecting attachment limits. Removing a lab policy is not sufficient cleanup if roles, exceptions, CloudTrail selectors, or account moves remain. The supplied lab changes nothing.
Knowledge check
- Why does an SCP allow not grant an IAM role permission?
- How do allows and explicit denies combine across four hierarchy levels?
- What changed in SCP language support in September 2025?
- Why can
AllowwithNotActionorNotResourceadmit future capability? - Which principals are and are not restricted by SCPs?
- Why can a service-linked role succeed while a similarly named customer role is denied?
- What must a Region restriction exempt and test?
- Why does the leave/close SCP not protect management-account closure calls?
- How can a log-protection exception role become a bypass?
- What happens when a network/data condition key is absent?
- Why is service last accessed data insufficient to approve an allow list?
- Which evidence distinguishes SCP denial from KMS/resource-policy denial?
- Why must rollback authority sit outside the tested blast radius?
- When should an RCP accompany an SCP?
Lesson acceptance
Pass requires correct evaluation of all seven cases and every hierarchy level; grant-versus-maximum explanation; current full-language usage and old-syntax correction; management/service-linked/root treatment; deny/allow/hybrid decision; Region, membership, logging, tag, and perimeter tests; parser/Access Analyzer evidence; staged/canary rollout; CloudTrail diagnosis; tested external rollback; quota/cost statement; and no-create or verified cleanup proof.