AWS Organizations SCP Quotas Have Doubled, So I Actually Tried Attaching 10 Policies and a 10,240-Character Policy
This page has been translated by machine translation. View original
On May 15, 2026, an increase to the AWS Organizations SCP quotas was announced.
These are the main changes in this update.
| Item | Old | New |
|---|---|---|
| Number of SCP attachments per target (root/OU/account) | 5 | 10 |
| SCP policy size | 5,120 characters | 10,240 characters |
The number of attachments and the policy size have each doubled. Because AWS Organizations is a global service, this quota change becomes available without any action on the user's side. No configuration changes are needed in individual Regions.
If you left FullAWSAccess as the default, under the old limit you could add only 4 more custom SCPs. With the new limit of 10, you can now manage policies separated by purpose, as shown below.
| SCP | Description |
|---|---|
| FullAWSAccess | The SCP attached by default. Assumes a Deny-list approach |
| Region restriction | Deny everything outside the allowed Regions |
| IP restriction | Deny operations from outside the corporate network |
| Guardrail (IAM) | Prevent deletion/modification of IAM roles |
| Guardrail (CloudTrail) | Prevent disabling CloudTrail |
| Guardrail (S3) | Prevent S3 public access |
| Guardrail (EC2) | Restrict specific instance types |
| Guardrail (Organizations) | Prevent leaving the Organization |
| Cost control | Restrict use of expensive services |
Under the old limit, compromises such as "combining the Region restriction and guardrails into a single SCP" were necessary, but with the new limit you can manage one SCP per purpose with one responsibility each, and the impact scope of changes also becomes clear.
Test 1: Attachment Limit
I created an empty OU for testing and attached dummy SCPs one after another in addition to FullAWSAccess (attached automatically). Since I only wanted to test the number of attachments, I used dummy SCPs with Allow * that add no permission restrictions.
| Test | Description | Result |
|---|---|---|
| Exceeding the old limit | FullAWSAccess + 6 = 7 total | ✅ Success |
| Reaching the new limit | FullAWSAccess + 9 = 10 total | ✅ Success |
| Exceeding the new limit | Attempt to attach an 11th | ❌ Error |
This is the list-policies-for-target output with 10 attachments successfully made.
aws organizations list-policies-for-target \
--target-id ou-xxxx-xxxxxxxx \
--filter SERVICE_CONTROL_POLICY \
--region us-east-1
{
"Policies": [
{"Id": "p-FullAWSAccess", "Name": "FullAWSAccess"},
{"Id": "p-abc00001", "Name": "SCP-QuotaTest-01"},
{"Id": "p-abc00002", "Name": "SCP-QuotaTest-02"},
{"Id": "p-abc00003", "Name": "SCP-QuotaTest-03"},
{"Id": "p-abc00004", "Name": "SCP-QuotaTest-04"},
{"Id": "p-abc00005", "Name": "SCP-QuotaTest-05"},
{"Id": "p-abc00006", "Name": "SCP-QuotaTest-06"},
{"Id": "p-abc00007", "Name": "SCP-QuotaTest-07"},
{"Id": "p-abc00008", "Name": "SCP-QuotaTest-08"},
{"Id": "p-abc00009", "Name": "SCP-QuotaTest-09"}
]
}
When I tried to attach an 11th, the following error was returned.
An error occurred (ConstraintViolationException) when calling the AttachPolicy operation:
You have attached the maximum number of policies to the specified target.
Additional error details:
Reason: MAX_POLICY_TYPE_ATTACHMENT_LIMIT_EXCEEDED
Policies applied through inheritance are not counted toward the attachment count. Policies attached to a parent OU are evaluated through inheritance, but they do not consume the attachment quota of child OUs (only direct attachments are counted).
When isolating causes during IaC execution, it is more reliable to decide based on the Reason code than on the human-readable message body. An attachment count overrun is MAX_POLICY_TYPE_ATTACHMENT_LIMIT_EXCEEDED, and a size overrun, described below, is POLICY_CONTENT_LIMIT_EXCEEDED.
Test 2: Policy Size Limit
Assuming a use case where an IP restriction SCP lists many site CIDRs, I adjusted the character count by lining up a large number of CIDRs in Condition.NotIpAddress.aws:SourceIp.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyUnlessFromApprovedIPs",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"10.0.0.0/24",
"10.0.1.0/24",
"10.0.2.0/24",
...(中略、全体で 650 CIDRs)...
"10.2.137.0/24"
]
}
}
}]
}
In this test data, up to about 650 CIDRs fit under the new limit. The number that actually fits varies depending on the length of the CIDR strings and the policy structure.
I measured the byte count of the compact JSON, composed only of ASCII, with wc -c (since it is ASCII only, it matches the character count. The official documentation uses the term "characters").
| Test | Policy size | Result |
|---|---|---|
| Within the limit | 10,236 characters (650 CIDRs) | ✅ Success |
| Over the limit | 10,252 characters (651 CIDRs) | ❌ Error |
This is the error when the limit is exceeded.
An error occurred (ConstraintViolationException) when calling the CreatePolicy operation:
You have exceeded the maximum policy size.
Additional error details:
Reason: POLICY_CONTENT_LIMIT_EXCEEDED
Test 3: Handling of Whitespace
The official documentation states that whitespace is automatically removed in the console, and is stored as is with the CLI/SDK. This time I confirmed that whitespace is included in the size when saving with the CLI.
In the Management Console, extra whitespace between JSON elements is automatically removed on save, so it is not included in the size. On the other hand, with the CLI/SDK the policy body you send is handled as is, so line breaks and indentation are also included in the size.
| Save method | Policy size (when sent via CLI) | Result |
|---|---|---|
| CLI pretty-print | 17,359 characters (*9,448 characters in compact terms, within the limit) | ❌ The 17,359 characters at send time were counted as is, exceeding the limit |
| CLI pretty-print | 5,950 characters (3,239 characters in compact terms) | ✅ Success, confirmed that whitespace is retained |
Even a policy that would fit within the limit if converted to compact failed with a size-exceeded error when saved via the CLI in pretty-printed form. I also confirmed that when retrieved with describe-policy, the indentation and line breaks were retained as is. When managing SCPs with the CLI, we recommend saving them as compact JSON (using jq -c or similar).
Reproduction Steps
The following script can reproduce the tests of the attachment limit and the policy size limit. You need credentials for the Organizations management account and an Organization with SCPs enabled. Create an empty OU for testing and run it there. Do not run it in an OU to which production accounts belong.
The script generates policies near the limit that fit within 10,240 characters. The character counts in the text are values measured during testing.
test-scp-quota.sh (click to expand)
#!/bin/bash
# AWS Organizations SCP クォータ引き上げ検証スクリプト
# 前提: Organizations 管理アカウントの認証情報、python3
# 実行: ./test-scp-quota.sh
set -euo pipefail
REGION="us-east-1"
SCP_CONTENT='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}'
GREEN='\033[0;32m'; RED='\033[0;31m'; NC='\033[0m'
pass() { echo -e "${GREEN}✅ PASS${NC}: $1"; }
fail() { echo -e "${RED}❌ FAIL${NC}: $1"; }
ROOT_ID=$(aws organizations list-roots --region "$REGION" --query 'Roots[0].Id' --output text)
echo "=== Part 1: アタッチ数上限テスト ==="
OU_ID=$(aws organizations create-organizational-unit \
--parent-id "$ROOT_ID" --name "SCP-Quota-Test" \
--region "$REGION" --query 'OrganizationalUnit.Id' --output text)
POLICY_IDS=()
for i in $(seq -w 1 10); do
PID=$(aws organizations create-policy \
--name "SCP-QuotaTest-${i}" --description "Quota test ${i}" \
--type SERVICE_CONTROL_POLICY --content "$SCP_CONTENT" \
--region "$REGION" --query 'Policy.PolicySummary.Id' --output text)
POLICY_IDS+=("$PID")
sleep 1
done
for i in $(seq 0 5); do
aws organizations attach-policy --policy-id "${POLICY_IDS[$i]}" --target-id "$OU_ID" --region "$REGION"
sleep 1
done
COUNT=$(aws organizations list-policies-for-target --target-id "$OU_ID" \
--filter SERVICE_CONTROL_POLICY --region "$REGION" --query 'length(Policies)' --output text)
[ "$COUNT" -eq 7 ] && pass "旧上限超え: ${COUNT}個" || fail "期待7個、実際${COUNT}個"
for i in $(seq 6 8); do
aws organizations attach-policy --policy-id "${POLICY_IDS[$i]}" --target-id "$OU_ID" --region "$REGION"
sleep 1
done
COUNT=$(aws organizations list-policies-for-target --target-id "$OU_ID" \
--filter SERVICE_CONTROL_POLICY --region "$REGION" --query 'length(Policies)' --output text)
[ "$COUNT" -eq 10 ] && pass "新上限到達: ${COUNT}個" || fail "期待10個、実際${COUNT}個"
if ERROR=$(aws organizations attach-policy --policy-id "${POLICY_IDS[9]}" \
--target-id "$OU_ID" --region "$REGION" 2>&1); then
fail "11個目がエラーにならなかった"
else
echo "$ERROR" | grep -q "MAX_POLICY_TYPE_ATTACHMENT_LIMIT_EXCEEDED" && \
pass "11個目でエラー: MAX_POLICY_TYPE_ATTACHMENT_LIMIT_EXCEEDED" || fail "$ERROR"
fi
echo "=== クリーンアップ ==="
for PID in "${POLICY_IDS[@]}"; do
aws organizations detach-policy --policy-id "$PID" --target-id "$OU_ID" --region "$REGION" 2>/dev/null || true
sleep 0.5
aws organizations delete-policy --policy-id "$PID" --region "$REGION"
sleep 0.5
done
aws organizations delete-organizational-unit --organizational-unit-id "$OU_ID" --region "$REGION"
echo "=== Part 2: ポリシーサイズ上限テスト ==="
python3 -c "
import json
cidrs = [f'10.{i}.{j}.0/24' for i in range(50) for j in range(256)]
policy = {'Version':'2012-10-17','Statement':[{'Sid':'Test','Effect':'Deny','Action':'*','Resource':'*','Condition':{'NotIpAddress':{'aws:SourceIp':cidrs}}}]}
compact = json.dumps(policy, separators=(',',':'))
while len(compact) > 10240:
cidrs.pop()
policy['Statement'][0]['Condition']['NotIpAddress']['aws:SourceIp'] = cidrs
compact = json.dumps(policy, separators=(',',':'))
with open('/tmp/scp-max.json','w') as f: f.write(compact)
cidrs.append(f'10.{len(cidrs)//256}.{len(cidrs)%256}.0/24')
policy['Statement'][0]['Condition']['NotIpAddress']['aws:SourceIp'] = cidrs
with open('/tmp/scp-over.json','w') as f: f.write(json.dumps(policy, separators=(',',':')))
print(f'Max: {len(compact)} chars ({len(cidrs)-1} CIDRs), Over: {len(json.dumps(policy, separators=(chr(44),chr(58))))} chars ({len(cidrs)} CIDRs)')
"
if PID=$(aws organizations create-policy --name "SCP-SizeTest-Max" --description "Size test" \
--type SERVICE_CONTROL_POLICY --content file:///tmp/scp-max.json \
--region "$REGION" --query 'Policy.PolicySummary.Id' --output text 2>&1); then
pass "上限以内のポリシー作成成功"
aws organizations delete-policy --policy-id "$PID" --region "$REGION"
else
fail "$PID"
fi
if ERROR=$(aws organizations create-policy --name "SCP-SizeTest-Over" --description "Size test over" \
--type SERVICE_CONTROL_POLICY --content file:///tmp/scp-over.json \
--region "$REGION" 2>&1); then
fail "上限超過がエラーにならなかった"
else
echo "$ERROR" | grep -q "POLICY_CONTENT_LIMIT_EXCEEDED" && \
pass "上限超過でエラー: POLICY_CONTENT_LIMIT_EXCEEDED" || fail "$ERROR"
fi
echo "=== 全検証完了 ==="
Summary
The SCP attachment limit and the policy size have each doubled. There is no impact on existing SCP configurations, and because AWS Organizations is a global service, you can use the new quotas without any action on the user's side. It is now easier to design with SCPs separated by purpose, and the policy size constraint has also been eased. However, if you manage SCPs with the CLI/SDK, whitespace is counted toward the character count as is, so we recommend saving them as compact JSON.

