Skip to content
DevOps AI ToolKit
Newsletter
All guides
AWS with AI By James Joyner IV · · 9 min read

AWS Error Guide: 'explicit deny in a service control policy' Organizations SCP Block

Fix the AWS 'explicit deny in a service control policy' error: identify the blocking SCP, understand org guardrails, and adjust policy attachments correctly.

  • #aws
  • #troubleshooting
  • #errors
  • #organizations

Exact Error Message

An error occurred (AccessDenied) when calling the RunInstances operation: User: arn:aws:iam::123456789012:role/deploy-role is not authorized to perform: ec2:RunInstances on resource: arn:aws:ec2:eu-west-1:123456789012:instance/* with an explicit deny in a service control policy

The distinguishing clause is with an explicit deny in a service control policy. The principal may have full IAM permissions and still be blocked.

What the Error Means

In AWS Organizations, Service Control Policies (SCPs) define the maximum available permissions for every principal in an account — they are guardrails, not grants. An SCP can never give a principal a permission it does not already have through IAM; it can only take permissions away. A request must be allowed by IAM and permitted by every SCP in the account’s path from the organization root through its organizational units (OUs) down to the account itself. AWS evaluates this as a logical AND: the effective permission set is the intersection of what IAM allows and what each SCP in the chain allows. An explicit Deny in any single attached SCP overrides any IAM Allow, so a principal can hold the AdministratorAccess managed policy and still be stopped cold.

You cannot fix this by editing the account’s IAM policies, attaching another role, or escalating the principal’s permissions — none of those touch the SCP layer. The change must happen at the Organizations level, in the management account or through a delegated administrator. That separation is deliberate: SCPs exist so that no action inside a member account can weaken an organization-wide guardrail.

Common Causes

  • Region restriction. An SCP denies all actions outside an approved region list, typically with a Deny using StringNotEquals on aws:RequestedRegion, often carving out global services like IAM and CloudFront so they keep working everywhere.
  • Service deny. A guardrail denies an entire service — for example blocking expensive services like SageMaker or non-compliant data stores. The deny applies to every action in that service namespace at once.
  • Action deny. Specific high-risk actions (deleting CloudTrail, disabling GuardDuty or Config, leaving the org, modifying SCPs) are explicitly denied to protect the security baseline. These are common in landing-zone setups and cannot be overridden from inside the account.
  • Condition-based deny. The SCP denies unless a condition is met — for example, requiring a specific instance type, a tag on resource creation, or requests through a specific VPC endpoint. The action succeeds only when the request satisfies the condition exactly.
  • OU move. An account was moved into an OU with stricter SCPs, suddenly blocking previously working calls. Because SCPs are inherited down the tree, relocating an account silently changes its permission ceiling.
  • Root-attached deny. A broad deny attached at the org root applies to every account, including members of the management account. A single overly broad statement here can block an entire fleet at once.

How to Reproduce the Error

In an account governed by a region-restricting SCP (e.g., allowing only us-east-1), attempt an action in a denied region:

aws ec2 run-instances --image-id ami-0abcd1234 --instance-type t3.micro \
  --region eu-west-1 --count 1
An error occurred (AccessDenied) when calling the RunInstances operation: ... with an explicit deny in a service control policy

The same call in the allowed region succeeds, confirming the SCP — not IAM — is the gate.

Diagnostic Commands

Confirm which identity is calling and in which account:

aws sts get-caller-identity

List the SCPs attached directly to the account (run in the management account or as a delegated admin):

aws organizations list-policies-for-target \
  --target-id 123456789012 --filter SERVICE_CONTROL_POLICY \
  --query 'Policies[].[Name,Id]' --output text

Walk up the hierarchy — find the account’s parent OU and its attached SCPs:

aws organizations list-parents --child-id 123456789012 \
  --query 'Parents[].[Id,Type]' --output text
aws organizations list-policies-for-target \
  --target-id ou-abcd-1234 --filter SERVICE_CONTROL_POLICY \
  --query 'Policies[].Name' --output text

Read a suspect SCP’s document to find the denying statement:

aws organizations describe-policy --policy-id p-0123456789 \
  --query 'Policy.Content' --output text | python3 -m json.tool

Step-by-Step Resolution

  1. Verify the message says “service control policy.” Read the trailing clause carefully. If it instead says “identity-based policy,” “permissions boundary,” or “VPC endpoint policy,” the fix lives in a different layer and chasing SCPs will waste time. Only the SCP wording routes you to Organizations.

  2. Enumerate every SCP in the path. List policies attached to the account, then walk up to each parent OU and finally the org root. An inherited deny three levels up is just as binding as one on the account, so inspect the whole chain.

  3. Find the denying statement. Inspect each SCP’s Content for a Deny whose Action, Resource, and Condition match the failed call. Watch for NotAction/StringNotEquals constructs, which deny everything except a named set and are easy to misread. The aws:RequestedRegion, aws:PrincipalTag, and service-prefix fields usually reveal why your request matched.

  4. Choose the right remediation in the management account:

    • If the deny is intentional (a guardrail), perform the action within the allowed scope — correct region, approved service, required tag — instead of bypassing it. Weakening it for one call may expose the whole org.
    • If the account was placed in the wrong OU, move it so it inherits the intended policy set rather than editing the SCP itself.
    • If the guardrail is genuinely too broad, narrow the SCP’s Condition, resource scope, or action list. Make the smallest change that unblocks the legitimate use case.
  5. Re-test the original call from the same principal and region that failed. The error should clear once the request falls within the SCP’s allowed scope. If it still fails, check for a second deny further up the tree — multiple SCPs can each contribute an independent block.

Prevention and Best Practices

  • Document every SCP and the OU it applies to so engineers know the org ceiling before debugging account IAM that “looks correct.”
  • Prefer narrow, condition-scoped denies (region, tag, action) over blanket service denies that surprise teams.
  • Test SCP changes in a non-production OU before attaching to production accounts.
  • When onboarding accounts, place them in the correct OU first to avoid sudden denies after a later move.
  • Surface the trailing with an explicit deny in a service control policy clause in runbooks so responders route the fix to the Organizations admin, not the app team.
  • Use a delegated administrator for Organizations read access so app teams can diagnose SCP blocks without management-account credentials.
  • AccessDenied ... with an explicit deny in an identity-based policy — the deny is in the account’s own IAM, fixable locally.
  • AccessDenied ... because no identity-based policy allows the action — implicit deny; add an IAM grant.
  • AccessDenied ... with an explicit deny in a permissions boundary — a boundary, not an SCP, caps the role.
  • AccessDenied ... with an explicit deny in a VPC endpoint policy — an endpoint policy blocked the call.

Frequently Asked Questions

Can I override an SCP deny with an IAM Allow? No. An explicit Deny in an SCP always wins, regardless of how permissive the IAM policy is. No IAM grant, role assumption, or escalation defeats it — the only path is to change the SCP itself at the Organizations level.

Where do I fix this? In AWS Organizations, from the management account or a delegated administrator — not in the member account’s IAM. Editing the member account’s roles has no effect on the SCP ceiling, so make sure a team with Organizations access owns the change.

Why did a working call suddenly start failing? The account was likely moved into an OU with a stricter SCP, or a new SCP was attached to an OU in its path. SCP changes take effect immediately, so a governance edit can break a deploy pipeline with no change to the pipeline’s own permissions.

Do SCPs affect the management account? SCPs do not restrict the management account itself — its actions are never blocked, which is why you should run the fewest workloads there. They do restrict every member account and the principals within them.

How do I find which exact statement blocked me? Read each SCP’s Content and match the failed action against Action/NotAction and any Condition keys such as aws:RequestedRegion. AWS does not name the offending policy, so this manual correlation across the OU path is how you pinpoint it.

How do I see the full org hierarchy? Use list-parents repeatedly from the account up to the root, listing SCPs at each level, or view it in the Organizations console. See the AWS guides for org-structure patterns.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.