
IAM Permission Boundaries + SCPs - The Complete Safety Net Explained
AWS Interview Question I love: "If Identity allows, Resource allows, but request is still denied — why?" 90% say "explicit deny". 10% say "SCP, Boundary, RCP, Session Policy, and here's the evaluation order" Which one are you? Full visual flow:
I Gave Everyone AdministratorAccess And Nothing Broke
Your Identity Policy doesn't protect you. Your Boundaries and SCPs do.
I watched a developer with AdministratorAccess try to delete a prod S3 bucket.
AccessDenied.
No explicit deny in his policy. No deny in the bucket policy. So what blocked him?
Two layers he didn't even know existed.
The Problem With Least Privilege Alone
Most teams obsess over writing perfect least-privilege identity policies. The moment you let teams create their own roles, one iam:CreateRole with : can undo all your hard work.
Mature AWS orgs do it backwards. They control the maximum you can ever get.
Try The Interactive Version
I built an interactive Venn + ALLOW/DENY flow

safety net demo
The Complete Safety Net - 4 Layers, 1 Effective Allow
Effective Allow = Identity ∩ Permissions Boundary ∩ SCP ∩ Resource Policy
- Identity Policy - What you want to allow (Accelerator)
- Permissions Boundary - Max ceiling for an IAM entity (Seatbelt)
- SCP - Max ceiling for an entire AWS account, even root can't bypass (Concrete Wall)
- Resource Policy - Who can touch this specific resource (Bouncer)
Rule: By default everything is implicitly denied. Any explicit DENY in ANY policy wins. Then AWS checks if every layer has an explicit ALLOW.
Click the 3 scenarios: Developer trying s3:DeleteBucket, Admin blocked by SCP, Full Allow path.
Real Policy from my AWS account
1. Permissions Boundary - Developer Sandbox
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDevReadsInApprovedRegions",
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*",
"dynamodb:Get*",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:Describe*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": [
"us-east-1",
"ap-south-1"
]
}
}
},
{
"Sid": "AllowLambdaDeploy",
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:UpdateFunctionCode",
"lambda:Get*",
"lambda:List*",
"lambda:InvokeFunction"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": [
"us-east-1",
"ap-south-1"
]
}
}
},
{
"Sid": "AllowObservability",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:Describe*",
"cloudwatch:*",
"xray:*"
],
"Resource": "*"
},
{
"Sid": "DenyIAMAndOrgByBoundary",
"Effect": "Deny",
"Action": [
"iam:*",
"organizations:*",
"s3:DeleteBucket",
"dynamodb:DeleteTable"
],
"Resource": "*"
}
]
}
The Seatbelt: This is NOT what the dev can do. This is the MAX he can ever do. Even if I attach AdministratorAccess, he can only do s3:Get* in 2 regions. IAM creation, S3 deletion, Org leave — all explicitly denied at the boundary level
2. Dev-Identity-Policy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "FullAccessInSandbox",
"Effect": "Allow",
"Action": [
"s3:*",
"dynamodb:*",
"lambda:*",
"logs:*",
"cloudwatch:*"
],
"Resource": "*"
}
]
}This looks like full access, right? This is the point — Boundary will still limit it.
3.IAM roles:
- Create the Role with BOTH
IAM > Roles > Create Role > AWS Service > Lambda (or EC2) > Next
2Attach policy: Dev-Identity-Policy
3 Scroll down to Set permissions boundary -> Use a permissions boundary to control the maximum role permissions -> Select Dev-Boundary-Guardrail
4 Create Role -> Name: DevRole-Sandbox-Demo
Punchline: That one scroll-down(3) is the difference between "oops, prod is gone" and "AccessDenied, prod is safe."
The console won't warn you. It won't say "hey, you forgot the seatbelt." You have to remember to add it.
4.Test with Policy Simulator — Allowed vs Denied

Proof it works: Same role, same request. s3:GetObject in us-east-1 = ALLOW (green). s3:DeleteBucket = DENY by boundary, iam:CreateRole = DENY by boundary (red). No explicit deny in identity policy. The boundary just saved your SOC2 at 2 AM.
Where This Goes Wrong
- Using Boundary to grant permissions (it can't, only limits)
- Using allow-list SCPs on day 1 (you will break everything)
- Forgetting to exempt Break-Glass role
Golden Rules
- SCPs for what should NEVER happen (no prod deletion, enforce regions)
- Boundaries for what teams CAN delegate
- Identity for day-to-day
If this helped, let me know what guardrail saved you at 2 AM.
You don't secure AWS by writing perfect Allow policies. You secure it by writing ruthless Boundary and SCP Deny policies.Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article