All writing

Service Control Policies: guardrails, not permissions

AWS Service Control Policies define the maximum permissions available to affected principals in member accounts. They do not grant access. Used carefully, SCPs turn organisational invariants into tested, explainable and maintainable guardrails.

about 18 minutes min read

An administrator creates an IAM role in a development account.

The role receives:

{
  "Effect": "Allow",
  "Action": "organizations:LeaveOrganization",
  "Resource": "*"
}

The IAM policy says the role may call the action.

The organisation has decided that member accounts must leave only through the approved account-lifecycle process.

A Service Control Policy denies direct departure:

{
  "Effect": "Deny",
  "Action": "organizations:LeaveOrganization",
  "Resource": "*"
}

The result is not a conflict requiring AWS to choose one policy.

Both policies participate in the authorization decision.

The IAM policy provides a grant path.

The SCP places an organisational limit around the authority the account may grant.

IAM POLICY

Allow organizations:LeaveOrganization
               │
               ▼
SCP

Deny organizations:LeaveOrganization
               │
               ▼
EFFECTIVE RESULT

Denied

Attaching AdministratorAccess changes nothing.

The IAM policy cannot climb above the organisation’s permission ceiling.

Now reverse the example.

Suppose an SCP contains:

{
  "Effect": "Allow",
  "Action": "s3:*",
  "Resource": "*"
}

A developer has no S3 permission.

The developer still cannot read a bucket.

The SCP permits S3 authority to remain possible beneath the guardrail.

It does not grant that authority.

An SCP limits the authority that affected principals may receive in member accounts. It does not grant that authority or govern every principal that can access their resources.

That distinction is the foundation of useful SCP design.

What an SCP does and does not decide

An SCP defines an organisational permission ceiling.

It answers:

Which authority may remain
available to affected principals
in these member accounts?

It does not answer:

Which principal receives
that authority?

Identity-based and resource-based policies form the applicable grant path.

SCPs and other limiting controls constrain that path.

An applicable explicit deny remains decisive.

GRANT PATH

identity policy
or resource policy
        │
        ▼
LIMITING CONTROLS

permissions boundary
session policy
SCP
RCP
        │
        ▼
EXPLICIT DENIES
        │
        ▼
FINAL AUTHORIZATION

The detailed evaluation depends on the principal, resource, account relationship and AWS service. The companion chapter, “Allowed by the SCP” does not mean “allowed,” examines that authorization path in depth.

The SCP scope

SCPs constrain:

IAM users in affected
member accounts

IAM roles and their sessions
in affected member accounts

the member-account root user

SCPs do not constrain:

management-account principals

service-linked roles

external principals merely because
they access a member-account resource

documented exceptional tasks

Delegated-administrator accounts remain member accounts and remain subject to applicable SCPs.

A guardrail becomes dangerous when its description is broader than its enforcement.

SCPs and RCPs protect different sides

SCPs are principal-side organisational guardrails.

Resource Control Policies are resource-side organisational guardrails for supported resources in member accounts.

Control Governs Main question
SCP Principals in member accounts Which authority may these principals receive?
RCP Supported resources in member accounts Which authority may these resources accept?
Identity policy IAM principal Which actions does this identity receive?
Resource policy Resource Which principals may access this resource?
Permissions boundary IAM user or role How much authority may this identity receive?

Neither an SCP nor an RCP grants access.

Service and resource support must be checked explicitly.

Define the organisational invariant

An SCP is most useful when it enforces a stable rule that account administrators must not be able to override.

Examples include:

  • member accounts leave only through approved lifecycle automation
  • protected audit controls remain active
  • production requests use approved Regions
  • workload administrators cannot alter organisation-managed security integrations
  • selected services remain unavailable in a particular governance scope
  • protected identities cannot be impersonated to bypass a guardrail

These are organisational invariants.

They are different from workload permissions such as:

catalog-service may read
the catalog-products bucket

That belongs in IAM or a resource policy.

A useful policy-layer separation is:

Question Suitable control
May this workload read this bucket? IAM or bucket policy
May this role administer this database? IAM
How much authority may this role receive? Permissions boundary
May a member account leave or close itself? SCP
May production principals disable protected logging? SCP
May an external principal access this resource? Resource policy, potentially constrained by an RCP
Which authority may one temporary session use? Session policy

Trying to express application permissions through SCPs would make the organisation hierarchy responsible for detail it cannot sensibly own.

Give every SCP a guardrail contract

An SCP is not merely a JSON document.

It is an invariant, an attachment scope, an exception model and a body of evidence.

scp:
  name: protect-account-lifecycle
  intent: member accounts leave only through approved lifecycle automation
  owner: platform-governance

strategy:
  type: explicit-deny

scope:
  target: organisation-root
  affected_principals:
    - member-account IAM users
    - member-account IAM roles
    - member-account root users

actions:
  denied:
    - organizations:LeaveOrganization
    - account:CloseAccount

exceptions:
  supported: false

known_limitations:
  - management-account principals unaffected
  - service-linked roles unaffected

tests:
  expected_denials:
    - member-root-cannot-leave
    - account-administrator-cannot-leave
    - member-root-cannot-close
  expected_successes:
    - approved-management-lifecycle-can-remove-account
    - approved-management-lifecycle-can-close-account

rollout:
  first_target: policy-staging
  rollback: restore-previous-attachment-set
  last_verified: 2026-07-20

The contract makes seven dimensions explicit:

intent
strategy
scope
enforcement
exceptions
tests
ownership and lifecycle

A policy without those answers is a denial snippet, not an operated control.

Choose the policy strategy deliberately

Deny-based guardrail model

The organisation retains FullAWSAccess at the SCP layer and adds targeted denies.

SCP BASELINE

Allow *


TARGETED GUARDRAILS

deny account departure
deny protected audit changes
deny unapproved Regions

This works well when the organisation has a small number of high-confidence invariants.

Its main weakness is that services and actions not denied remain available to be granted through IAM.

Service-allowlist model

The organisation replaces broad SCP availability with explicit service or action allows.

Allow EC2
Allow S3
Allow RDS
Allow CloudWatch

Everything outside the effective allow coverage becomes unavailable.

This can support tightly constrained environments.

It also creates more maintenance.

AWS services gain actions. Integrations rely on operations that may not be obvious from the user-facing feature. A missing allow can surface as a failure far from the policy change.

Neither strategy is automatically mature.

The right choice depends on:

  • control requirements
  • ability to test changes
  • knowledge of service dependencies
  • operational capacity to maintain policy coverage

The hierarchy matters

SCPs can be attached to the organisation root, OUs and individual member accounts.

An OU is a governance scope. Attaching an SCP there changes the inherited permission ceiling for affected accounts beneath it.

Root
│
└── Workloads
    │
    └── Production
        │
        └── bfstore-prod

A role in bfstore-prod may be affected by SCPs attached at every level in that path.

For an allow-list strategy, appropriate allow coverage must survive every hierarchy level.

An explicit deny at any applicable level blocks the action.

At one level, all attached policies matter together. A broad allow beside a narrow allow may preserve more availability than the narrow policy’s name suggests.

Review the complete attachment set, not only one apparently restrictive document.

Engineer exceptions as carefully as denies

A guardrail often needs an approved administration path.

For example:

Deny changes to protected audit controls

except

through the approved security authority

The exception deserves as much scrutiny as the deny.

A risky educational pattern is:

"ArnNotLike": {
  "aws:PrincipalArn": [
    "arn:aws:iam::*:role/bfstore-security-administrator"
  ]
}

The wildcard account field and predictable role name may allow another account to create an identity that resembles the exception.

A safer shape names the controlled account and role path explicitly:

"ArnNotLike": {
  "aws:PrincipalArn": [
    "arn:aws:iam::111122223333:role/security/bfstore-security-administrator"
  ]
}

For multiple approved accounts, list them explicitly or generate the policy from governed account metadata.

The exempt role still needs:

  • narrow IAM permission
  • strong trust conditions
  • temporary access
  • complete audit evidence
  • clear ownership
  • tests proving other roles cannot imitate it

An exception removes one guardrail.

It does not grant authority or remove the need for least privilege.

Three representative controls

Protect account departure and closure

The lifecycle invariant is:

Member accounts leave or close
only through the central
account-lifecycle process.

The guardrail is:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyLeaveOrganizationAndCloseAccount",
      "Effect": "Deny",
      "Action": [
        "organizations:LeaveOrganization",
        "account:CloseAccount"
      ],
      "Resource": "*"
    }
  ]
}

As of July 10, 2026, AWS Organizations automatically enables SCPs and attaches this root control for organisations created through the Organizations console after that date.

It does not apply automatically to:

  • existing organisations
  • organisations created through the CLI
  • organisations created through SDKs
  • organisations created through CloudFormation

Those organisations must configure the control deliberately.

For bfstore, the policy remains represented in the policy repository even when AWS created the initial attachment. The platform should still know the intent, owner, tests and expected target.

Protect audit configuration

An illustrative CloudTrail guardrail may deny sensitive operations except for an exact security-administration role.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ProtectCloudTrail",
      "Effect": "Deny",
      "Action": [
        "cloudtrail:DeleteTrail",
        "cloudtrail:StopLogging",
        "cloudtrail:UpdateTrail"
      ],
      "Resource": "*",
      "Condition": {
        "ArnNotLike": {
          "aws:PrincipalArn": [
            "arn:aws:iam::111122223333:role/security/bfstore-security-administrator"
          ]
        }
      }
    }
  ]
}

This remains an educational example.

The real policy needs testing against:

  • organisation trails
  • service-linked behaviour
  • log-delivery paths
  • approved security automation
  • incident access
  • role-path governance

The policy may contain a few lines.

Its behavioural surface spans the platform.

Restrict requested Regions

An SCP can use aws:RequestedRegion to control which regional service endpoint receives a request.

That is not the same as controlling every geographical effect.

REQUEST REGION CONTROL

Which endpoint may be called?


RESOURCE LOCATION CONTROL

Where may the resource or data exist?


CROSS-REGION EFFECT CONTROL

Which remote Regions may
the operation affect?

For example, an S3 request made to one Region may configure replication into another. s3:CreateBucket can use s3:LocationConstraint to control the bucket’s Region.

A Region guardrail therefore needs:

  • an owned global-service exception list
  • service-specific location controls
  • tests for cross-Region effects
  • identity and security-service tests
  • deployment and recovery tests

The policy may be short.

Its semantics are not.

Deliver the control as code

An organisation-wide deny is production code.

It deserves:

  • source control
  • peer review
  • validation
  • behavioural tests
  • staged rollout
  • version history
  • rollback instructions
  • ownership
  • release evidence

The release unit is:

CONTROL RELEASE

policy document
      +
attachment target
      +
exception model
      +
test evidence

The attachment is as important as the JSON.

The same policy attached to:

bfstore-policy-test

has a deliberately small first blast radius.

Attached to:

organisation root

it becomes a constitutional rule for the member-account estate.

AWS applies SCP content and attachment changes immediately to affected permissions.

A change review should therefore show:

  • policy diff
  • attachment diff
  • accounts entering scope
  • accounts leaving scope
  • exception changes
  • expected successes and denials
  • tested workflows
  • rollback evidence

A single-line target change can matter more than a fifty-line policy change.

Do not disable SCPs as rollback

Disabling the SCP policy type is not a normal recovery mechanism.

AWS detaches all SCPs in that root. Re-enabling the policy type restores only the default FullAWSAccess attachments. The previous attachment model is not recovered automatically.

Normal rollback should usually mean:

detach the candidate policy

restore the previous policy version

restore the previous attachment set

move the canary account back
to its former governance scope

The rollback test must prove that the intended prior control state returned.

Test guardrails through workflows

An SCP test suite should include both negative and positive evidence.

EXPECTED DENIAL

workload administrator cannot
stop protected logging


EXPECTED SUCCESS

approved security automation can
perform the required change


REGRESSION CHECKS

log delivery continues
security aggregation continues
incident access still works

Testing only the intended denial can create a false sense of correctness.

The policy might block far more than intended.

A policy can also allow individual API calls while breaking a full workflow.

An EKS delivery path may depend on:

  • role assumption
  • registry access
  • Kubernetes API access
  • load-balancer integration
  • KMS operations
  • log delivery
  • service-linked roles

Guardrails protect workflows.

Their tests should operate at workflow level too.

For bfstore, the rollout path is:

AUTHOR
  │
  ▼
LINT AND VALIDATE
  │
  ▼
POLICY-STAGING OU
  │
  ▼
REPRESENTATIVE NON-PRODUCTION
  │
  ▼
PRODUCTION OU
  │
  ▼
BROADER ATTACHMENT

bfstore-policy-test exists to absorb the first consequences.

It is a blast-radius boundary for governance code.

Operate the SCP library

Produce explanations, not only denials

A developer may see AccessDenied even though the local IAM role appears broad.

The platform should explain:

  • which invariant blocked the action
  • which SCP and attachment introduced it
  • why the guardrail exists
  • whether an exception is supported
  • who owns the decision
policy:
  name: protect-account-lifecycle
  owner: platform-governance

intent:
  account_lifecycle: centrally-controlled

targets:
  - organisation-root

expected_denials:
  - organizations:LeaveOrganization
  - account:CloseAccount

exception:
  supported: false

tests:
  - member-root-cannot-leave
  - member-root-cannot-close
  - administrator-role-cannot-leave

The SCP produces the denial.

The platform should produce the explanation.

Use last-accessed data as evidence

AWS service last accessed reports can show services allowed by applicable SCPs and the most recent attempt by account principals within the selected root, OU, account or policy scope.

This is service-level evidence.

It is not proof about every action, resource or future requirement.

LAST-ACCESSED EVIDENCE
        │
        ▼
CANDIDATE RESTRICTION
        │
        ▼
SERVICE-OWNER REVIEW
        │
        ▼
REPRESENTATIVE TEST
        │
        ▼
STAGED ATTACHMENT

A recovery service may be rarely used and still be essential.

A disaster-recovery API absent from recent activity should not be prohibited merely because the disaster has been considerate enough not to occur lately.

Absence of activity is a useful question.

It is not automatically permission to remove capability.

The bfstore starting library

The first library should remain modest and precise.

Organisation-wide

  • deny organizations:LeaveOrganization
  • deny account:CloseAccount
  • deny exact changes that disable organisation-managed audit controls
  • deny exact changes that remove approved security-service delegation

Workloads

  • deny named changes to organisation-managed security integrations
  • deny creation of specific unapproved external resource-policy grants where an SCP is the appropriate control
  • protect named evidence and recovery administration actions

Production

  • deny selected destructive actions against protected recovery resources
  • apply tested requested-Region restrictions
  • require exact, governed administrative exception identities

Sandbox

  • deny selected expensive or unsuitable services
  • deny named paths to production data and administration
  • preserve central logging and security controls

Policy staging

  • candidate root policies
  • revised Region controls
  • new service restrictions
  • changed exception identities

Every guardrail description should let an engineer predict:

which caller

which action

which resource

which conditions

which outcome

A large catalogue of clever denies would create impressive JSON and uncertain operations.

The aim is to protect the organisation’s most important invariants.

Questions I now ask

Invariant

Which stable organisational rule
does this SCP enforce?

Principals

Which principals are actually
inside its scope?

Attachment

Which root, OU or accounts
should receive it?

Strategy

Is this a deny-based guardrail
or service allowlist?

Exception

Which identities are exempt,
and can they be imitated?

Continuity

Which expected operations
must remain possible?

Workflow

Which complete platform paths
could fail indirectly?

Release

Which policy and attachment changes
constitute rollout and rollback?

Evidence

What proves the guardrail
still works as intended?

These questions make SCPs part of the platform’s control design rather than a collection of denial snippets.

The mental model I am keeping

My earlier model was:

SCP

a powerful IAM policy
attached above the account

The stronger model is:

                    ORGANISATIONAL INVARIANT
                               │
                               ▼
                        SCP GUARDRAIL
                               │
             ┌─────────────────┼─────────────────┐
             │                 │                 │
             ▼                 ▼                 ▼
          POLICY           ATTACHMENT        EXCEPTION
             │                 │                 │
             └─────────────────┼─────────────────┘
                               ▼
                         TEST EVIDENCE
                               │
                               ▼
                 MAXIMUM AVAILABLE AUTHORITY

The invariant answers:

Which rule must account
administrators be unable to override?

The SCP answers:

Which authority remains available
to affected member-account principals?

The attachment answers:

Where should the rule
produce consequences?

The exception model answers:

Which governed path may cross
the guardrail, and why?

The evidence answers:

Did prohibited workflows fail
while required workflows survived?

SCPs are powerful because they operate above account administrators.

That same power makes careless SCPs dangerous.

An SCP is not a bag of permissions handed down from the organisation. It is a tested boundary around the permissions that affected member accounts are allowed to hand out.

Use IAM to grant the catalog service access to its bucket.

Use a trust policy to decide which workload may assume its role.

Use a permissions boundary when delegated role creation needs a ceiling.

Use resource policies and RCPs to govern resource-side access.

Use SCPs for rules the organisation is unwilling to let account administrators override.

Then release the policy, attachment, exception and evidence as one control.

A guardrail is valuable because it prevents the vehicle leaving the safe path.

Bolting one across the road without testing merely creates a very secure traffic jam.

References and further reading

  1. AWS Organizations: Service control policies
  2. AWS Organizations: SCP evaluation
  3. AWS Organizations: Default security controls
  4. AWS Organizations: Resource control policies
  5. AWS Organizations: Attaching policies
  6. AWS Organizations: Disabling a policy type
  7. AWS Organizations: SCP examples
  8. AWS IAM: Policy evaluation logic
  9. AWS IAM: Global condition context keys
  10. AWS IAM: Region-deny policy example
  11. AWS IAM: Service last accessed information for Organizations