DEV Community

Alam Ahmed
Alam Ahmed

Posted on

SCP Propagation Delays and Session Revocation: When "Attached" Doesn't Mean "Enforced"

I deployed a Service Control Policy (SCP) via Terraform to block access to a pre-production S3 bucket. The terraform apply succeeded. AWS Organizations showed the policy as "Attached." I even saw the AttachPolicy event in CloudTrail.
But when I tested access immediately after, the request went through. Not because tokens are "grandfathered" (I got that wrong initially), but because SCPs exhibit eventual consistency—there is a propagation delay between "attached" and "enforced."
The Assumption
Like many automation-focused engineers, I assumed that a successful API response for AttachPolicy meant the restriction was active. The Terraform state said the resource was created. The AWS Console showed the SCP in the OU.
The docs mention that changes "might take time to propagate," but don't specify that this delay can be measurable in minutes—long enough for a CI/CD pipeline to finish, an auditor to check compliance, or a security incident to continue.
The Technical Reality
SCPs are evaluated at request time, not baked into session tokens. When you attach a Deny policy, it doesn't invalidate existing credentials—it simply adds a new evaluation step to future API calls. However, that policy must propagate across AWS's internal systems first.
During the propagation window (typically under 5 minutes, but I've observed 10-15 minutes in eu-west-2 during high-load periods), requests from existing sessions continue to succeed because the SCP hasn't reached the evaluation point for that specific service/region yet.
The Session Revocation Confusion
When I discovered the delay, my first instinct was to "revoke the sessions" to force immediate enforcement. I initially thought aws iam update-role would do this.
Incorrect. Updating a role does not invalidate active session tokens.
To actually revoke existing sessions immediately, you have two options:
Option 1: Create Role Revocation (Immediate)
Use the create-role-revocation API to block all sessions issued before a specific timestamp:

aws iam create-role-revocation \
  --role-name DevTestRole \
  --timestamp 2026-03-14T17:00:00
Enter fullscreen mode Exit fullscreen mode

This generates an internal policy that denies requests from tokens issued before that time, regardless of propagation delays.
Option 2: Inline Policy with TokenIssueTime (Terraform-friendly)
Add an inline policy with a condition on aws:TokenIssueTime:

resource "aws_iam_role_policy" "immediate_revocation" {
  name = "RevokeOldSessions"
  role = aws_iam_role.dev_test.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Deny"
        Action   = "*"
        Resource = "*"
        Condition = {
          DateLessThan = {
            "aws:TokenIssueTime" = timestamp()  # Denies tokens issued before now
          }
        }
      }
    ]
  })
}

Enter fullscreen mode Exit fullscreen mode

Note: Inline policies also propagate eventually, though typically faster than SCPs.
How to Actually Verify
Don't trust the Console or Terraform state. Trust the API response:

#!/bin/bash
# validate_scp.sh - Check if SCP is actually enforced

ACCOUNT_ID=$1
ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/OrganizationAccountAccessRole"
TEST_BUCKET="s3://company-preprod-data/"

# Assume role fresh each time (ensures we're testing current state, not cached creds)
CREDS=$(aws sts assume-role --role-arn $ROLE_ARN --role-session-name scp-test --duration-seconds 900)
export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r '.Credentials.SessionToken')

# Test multiple times over 60 seconds
for i in {1..6}; do
  if aws s3 ls $TEST_BUCKET 2>&1 | grep -q "AccessDenied"; then
    echo "[$i] ✅ SCP enforced"
    exit 0
  else
    echo "[$i] ⏳ Still accessible (propagation pending...)"
    sleep 10
  fi
done

echo "❌ SCP not enforced after 60 seconds - check policy attachment"
Enter fullscreen mode Exit fullscreen mode

The Compliance Angle
If your auditor asks "When was access revoked?" the answer isn't the AttachPolicy timestamp. It's the timestamp of the first AccessDenied error in CloudTrail.
For incident response, don't rely on SCPs alone for immediate containment. They're for guardrails, not emergency brakes. For offboarding or breach containment, use create-role-revocation or rotate credentials immediately.
Has anyone else measured SCP propagation times across different regions? I'm curious if GovCloud or isolated regions exhibit different consistency behavior than standard commercial regions.

Top comments (0)