Skip to main content

IAM Advanced - OIDC, Cross-Account Access, and Permission Boundaries

Manage multi-account AWS environments with Organizations, SCPs, IAM Identity Center SSO, Permission Boundaries, and cross-account role assumptions.

What you will learn

  • AWS Organizations — multi-account management, OUs, consolidated billing, and what SCPs actually do
  • SCP blocklist vs allowlist strategies and how inheritance flows down the OU tree
  • Why the management account is never affected by SCPs — the most commonly tested fact
  • IAM advanced conditions — SourceIp, RequestedRegion, ResourceTag, PrincipalTag, MFA required
  • IAM Roles vs Resource-Based Policies — when each is correct for cross-account access
  • Permission Boundaries — the ceiling on what a user or role can ever do
  • The exact IAM policy evaluation order — Deny, SCP, Resource Policy, Identity Policy, Boundary
  • IAM Identity Center — SSO for all accounts and business apps from one login
  • Microsoft Active Directory on AWS — three options and when each applies
  • AWS Control Tower — automated multi-account governance with preventive and detective guardrails

Why this matters

A startup running everything in one AWS account with one admin user gets away with basic IAM. A company like Razorpay or Hotstar running production, staging, dev, security, and logging in separate accounts — with hundreds of engineers across teams — needs a completely different approach. Getting this wrong means either locking engineers out of what they need to do their jobs, or leaving production open to accidental or malicious changes. SCPs, Permission Boundaries, and IAM Identity Center are the building blocks that serious AWS environments use to manage access at scale without creating security gaps or operational friction.

AWS Organizations

AWS Organizations lets you manage multiple AWS accounts from a single place under one organisational structure.

Key facts:

TEXT
Global service
One management account — has full control, never restricted by SCPs
All other accounts are member accounts — each can only belong to one org
Consolidated billing — one payment method, one invoice, discounts aggregate
Volume discounts — EC2 and S3 pricing improves as combined usage grows
Shared Reserved Instances and Savings Plans across all accounts

Structure:

◈ DIAGRAM
Root OU (top of the tree — one per organisation)
|
+-- Management Account (SCPs never apply here, full power always)
|
+-- OU (Dev)
| +-- Member Account A
| +-- Member Account B
|
+-- OU (Prod)
+-- OU (Finance)
| +-- Member Account C
+-- OU (Platform)
+-- Member Account D

Why multiple accounts instead of multiple VPCs?

TEXT
Separate accounts:
Complete blast radius isolation — breach in one cannot affect another
Clear billing per team or project
Independent permission boundaries
Cannot be replicated with VPCs inside one account

Ways to organise OUs:

◈ DIAGRAM
Business Unit → Sales OU, Retail OU, Finance OU
Environment → Prod OU, Dev OU, Test OU
Project → Project A OU, Project B OU

Service Control Policies

SCPs restrict what IAM users and roles can do inside an account or OU. They are not permission grants — they set the maximum permissions that can ever be used.

Key rules:

TEXT
Applied at OU level or individual account level
Management account is NEVER affected by SCPs — ever
Default behavior: deny everything — an explicit Allow must exist at every level
SCPs do not grant permissions — they only restrict what is already allowed
Even a user with AdministratorAccess is limited by whatever the SCP allows

Blocklist strategy — allow everything, deny specific services:

JSON
{
"Statement": [
{"Effect": "Allow", "Action": "*", "Resource": "*"},
{"Effect": "Deny", "Action": "dynamodb:*", "Resource": "*"}
]
}

Result: All services allowed except DynamoDB. Use when most services are fine and you just need to block a few risky ones.

Allowlist strategy — only specific services permitted:

JSON
{
"Statement": [
{"Effect": "Allow", "Action": ["ec2:*", "cloudwatch:*", "s3:*"], "Resource": "*"}
]
}

Result: Only EC2, CloudWatch, and S3 allowed. Everything else blocked. Use for locked-down sandbox or restricted environments.

SCP inheritance — how it flows down the tree:

◈ DIAGRAM
Root OU (FullAWSAccess)
|
+-- Management Account → can do anything (SCP never applies)
|
+-- Sandbox OU (Deny S3)
| +-- Account A → can do anything EXCEPT S3 (inherited from Sandbox OU)
| +-- Account B → can do anything EXCEPT S3 AND EC2 (extra deny on account)
|
+-- Workloads OU
+-- Test OU (Allow EC2 only)
| +-- Account D → EC2 only (Allow EC2 at this OU)
|
+-- Prod OU (FullAWSAccess)
+-- Account E → can do anything

A Deny at a parent OU automatically applies to all child accounts. An account inherits all policies from every OU above it all the way to Root.

Remember

The management account is completely exempt from all SCPs always. Never put actual workloads in the management account — it cannot be restricted by any SCP.

IAM Advanced Conditions

Conditions add extra rules to policies for precise access control beyond just service and action.

aws:SourceIp — restrict by caller's IP address (where request comes FROM):

JSON
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": ["192.0.2.0/24", "203.0.113.0/24"]
}
}
}

Deny everything if the request does not come from these IP ranges — only office network allowed.

aws:RequestedRegion — restrict by target AWS region (where request goes TO):

JSON
{
"Effect": "Deny",
"Action": ["ec2:*", "rds:*", "dynamodb:*"],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["ap-south-1", "ap-southeast-1"]
}
}
}

Deny EC2, RDS, and DynamoDB in every region except Mumbai and Singapore.

Remember

aws:SourceIp = controls where you call FROM (caller's IP). aws:RequestedRegion = controls which region you call TO (target region). Common trick question that catches engineers who confuse the two.

ec2:ResourceTag and aws:PrincipalTag — restrict by tags:

JSON
{
"Effect": "Allow",
"Action": ["ec2:StartInstances", "ec2:StopInstances"],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Project": "DataAnalytics",
"aws:PrincipalTag/Department": "Data"
}
}
}

Allow start/stop only if the EC2 instance has Project=DataAnalytics AND the caller has Department=Data on their IAM identity.

Bash
ec2:ResourceTag → checks the resource being accessed
aws:PrincipalTag → checks the person doing the accessing

aws:MultiFactorAuthPresent — require MFA for sensitive actions:

JSON
{
"Statement": [
{"Effect": "Allow", "Action": "ec2:*", "Resource": "*"},
{
"Effect": "Deny",
"Action": ["ec2:StopInstances", "ec2:TerminateInstances"],
"Resource": "*",
"Condition": {
"BoolIfExists": {"aws:MultiFactorAuthPresent": false}
}
}
]
}

Allow all EC2 actions, but deny stop and terminate if MFA was not used during login.

aws:PrincipalOrgID — restrict to your entire AWS Organization:

JSON
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject"],
"Resource": "arn:aws:s3:::devops-shared-bucket/*",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": ["o-yyyyyyyyyy"]
}
}
}

Allow access only if the requester belongs to your organization. Cleaner than listing every account ID manually.

IAM Roles vs Resource-Based Policies for Cross-Account Access

Two ways to give cross-account access. They behave very differently.

IAM Role — you go to them:

When you assume a role, you give up your original permissions and take on the role's permissions. You switch identity entirely.

◈ DIAGRAM
You (Account A) → assume Role in Account B → access S3 in Account B
While assuming the role: your Account A permissions are PAUSED

Resource-Based Policy — they invite you:

The target resource adds you to its allowed list directly. You keep your original identity and permissions.

◈ DIAGRAM
S3 in Account B has your account on its allowed list → you access S3
Your Account A permissions remain ACTIVE the whole time

When Resource-Based Policy wins:

◈ DIAGRAM
Scenario: You are in Account A
You need to read DynamoDB in Account A
AND write to S3 in Account B simultaneously
With IAM Role:
Assume role in Account B → Account A permissions PAUSED
Can access S3 in Account B ✓
Cannot access DynamoDB in Account A ✗ (permissions paused)
With Resource-Based Policy on S3 in Account B:
Access S3 directly → Account A permissions ACTIVE
Can access DynamoDB in Account A ✓
Can access S3 in Account B ✓
Remember

If you need to act in two accounts simultaneously, use a Resource-Based Policy — not a role assumption. Role assumption pauses your original permissions.

IAM Permission Boundaries

A Permission Boundary sets the maximum permissions a user or role can ever have — even if their IAM policy allows more. It acts as a ceiling, not a grant.

TEXT
Supported for: users and roles only (NOT groups)
Does not grant any permissions by itself
Effective permissions = what the IAM Policy allows AND what the Boundary allows

Example:

TEXT
Permission Boundary allows: s3:*, cloudwatch:*, ec2:*
IAM Policy allows: iam:CreateUser
Result: DENIED
iam:CreateUser is outside the boundary — blocked even though the policy allows it

Effective permissions — the intersection of all three layers:

◈ DIAGRAM
Organizations SCP
∩
Permission Boundary
∩
Identity-based Policy
─────────────────────
= Effective Permissions (only what all three allow simultaneously)

Use cases for Permission Boundaries:

TEXT
Delegate safely:
A senior engineer creates IAM users for junior engineers
Permission Boundary caps what permissions those users can ever have
Junior engineers cannot create users with more permissions than their boundary allows
Prevent privilege escalation:
Developers can manage their own policies
Permission Boundary prevents them from granting themselves admin
Restrict one specific user without account-wide SCPs:
SCPs are blunt (affect entire OUs)
Permission Boundary is precise (affects one user or role)

IAM Policy Evaluation Logic

Every API call in AWS goes through this exact sequence. A single NO at any step means DENIED.

◈ DIAGRAM
1. Explicit Deny → any policy has Deny for this action? → DENIED immediately
2. Organizations SCP → account inside an org with SCP?
SCP does not have Allow? → DENIED
3. Resource-Based Policy → resource has Allow? → can be allowed (short circuit)
4. Identity-Based Policy → IAM user or role policy has Allow? → proceed
No Allow found? → DENIED
5. Permission Boundary → user or role has a boundary?
Boundary does not include this action? → DENIED
6. Session Policy → role session or federated session?
Session policy does not allow? → DENIED
Final default: Implicit Deny → nothing explicitly allowed → DENIED

Simple memory order: Explicit Deny → SCP → Resource Policy → Identity Policy → Boundary → Session → Allow

Practice example:

JSON
{
"Statement": [
{"Action": "sqs:*", "Effect": "Deny", "Resource": "*"},
{"Action": ["sqs:DeleteQueue"], "Effect": "Allow", "Resource": "*"}
]
}
◈ DIAGRAM
Can you perform sqs:CreateQueue?
→ No. sqs:* is explicitly denied. Explicit deny always wins.
Can you perform sqs:DeleteQueue?
→ No. Even though there is an Allow for it, sqs:* Deny still wins.
→ Statement order inside a policy does not matter.
→ Explicit Deny beats any Allow regardless of which statement comes first.
Can you perform ec2:DescribeInstances?
→ No. No Allow exists for EC2 anywhere. Default is implicit deny.

AWS IAM Identity Center

Previously called AWS Single Sign-On. One login for everything — instead of signing into each account separately, you log in once and get access to all of them.

◈ DIAGRAM
One login → access to:
All AWS accounts in your AWS Organization
Business apps — Salesforce, Slack, Microsoft 365, Dropbox
SAML 2.0 enabled custom apps
EC2 Windows instances

Identity providers — where users come from:

Option What it is
Built-in Identity Store Users and groups created directly inside IAM Identity Center
Third-party Connect existing Active Directory, Okta, OneLogin, etc

Login flow:

◈ DIAGRAM
User opens IAM Identity Center login page
↓
Logs in once with credentials
↓
IAM Identity Center verifies identity
↓
Shows dashboard with all accounts and apps the user can access
↓
User clicks account → directly in, no second login needed

Permission Sets:

A collection of IAM policies that defines what a user can do across accounts. Create once in IAM Identity Center, assign to users or groups across multiple accounts.

◈ DIAGRAM
Example:
Group: Developers (Arjun, Priya, Rohan)
Permission Set: ReadOnlyAccess → Prod Account A, Prod Account B
Permission Set: FullAccess → Dev Account A, Dev Account B
Developers log in once, see all four accounts, have full access in Dev
and read-only in Prod — managed from one central place.

Three types of fine-grained permissions:

◈ DIAGRAM
Multi-Account Permissions → assign Permission Sets to users/groups across many accounts
Application Assignments → SSO to SAML 2.0 business apps
Attribute-Based Access Control (ABAC) → control access based on user attributes
like cost center, job title, locale
Change a user's attribute → permissions update automatically

Microsoft Active Directory on AWS

Active Directory is a Windows directory service that stores user identities, group memberships, and computer registrations centrally. Engineers at most enterprises use AD to log into their laptops and access corporate resources.

AWS gives you three options when you need directory services in the cloud:

AWS Managed Microsoft AD:

AWS creates a full AD for you inside AWS. Your users live in AWS. If you have an on-premises AD, connect both via a trust relationship.

◈ DIAGRAM
On-prem AD ←── trust ──→ AWS Managed AD

Number of ADs: two — your office AD and the AWS one, linked. Use when: you want a full AD in AWS, may have existing on-premises AD. Supports MFA.

AD Connector:

A proxy that redirects authentication requests to your existing on-premises AD. No users or data move to AWS.

◈ DIAGRAM
User → AD Connector (proxy in AWS) → On-prem AD → answer returned

Number of ADs: one — your office AD. AD Connector is just a middleman. Use when: keep all users in existing on-prem AD but use AWS services. Supports MFA.

Simple AD:

A basic AD-compatible directory inside AWS with no connection to on-premises AD.

Number of ADs: one — in AWS only. Use when: no existing AD anywhere, just need something simple. Does NOT support MFA. Cannot join to on-premises AD.

AWS Managed Microsoft AD AD Connector Simple AD
Users managed in AWS On-premises AWS
Connects to on-prem AD Yes (trust) Yes (proxy) No
MFA support Yes Yes No
Use when Need full AD in AWS Keep users on-prem No on-prem AD needed

AWS Control Tower

When a large company needs many AWS accounts — dev, prod, finance, HR, security — setting up each one with the right security, policies, and compliance individually is slow and error-prone. Control Tower automates all of this.

Control Tower sets up and governs a secure multi-account environment in a few clicks, following AWS best practices automatically. Uses AWS Organizations and AWS Config under the hood.

Guardrails — rules that apply automatically across all accounts:

◈ DIAGRAM
Preventive Guardrail:
Blocks something from happening using SCPs
Example: Restrict all accounts from deploying outside allowed regions
Action blocked before it occurs
Detective Guardrail:
Does not block but monitors and alerts using AWS Config
Example: Detect resources with no tags
When violation found:
Member Account (untagged resource detected)
↓
AWS Config triggers NON_COMPLIANT event
↓
SNS sends notification to Admin
↓
Lambda auto-tags the resource
Preventive Guardrail Detective Guardrail
What it does Blocks the action upfront Monitors and alerts after
Uses SCP AWS Config
Example Cannot deploy outside allowed region Finds untagged resource, auto-fixes

Hands-on Lab — Organization, SCP, and Permission Boundary

Step 1 — Create an AWS Organization

◈ DIAGRAM
AWS Organizations → Create an organization
Features: All features (required for SCPs)
Create organization
You are now the management account.
The management account is NEVER affected by SCPs — remember this.

Step 2 — Create an Organizational Unit

◈ DIAGRAM
AWS Organizations → AWS accounts → Root
Actions → Create new → Organizational unit
Name: Sandbox → Create OU
If you have a member account, move it into Sandbox:
Select the account → Actions → Move → select Sandbox → Move

Step 3 — Create an SCP that restricts regions

◈ DIAGRAM
AWS Organizations → Policies → Service control policies → Create policy
Policy name: RestrictToMumbaiOnly
Policy content — paste this:
JSON
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Deny",
"Action": ["ec2:*", "rds:*", "s3:CreateBucket"],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": "ap-south-1"
}
}
}]
}
TEXT
Create policy

Step 4 — Attach SCP to Sandbox OU

◈ DIAGRAM
AWS Organizations → Policies → RestrictToMumbaiOnly
Targets → Attach → select Sandbox OU → Attach policy
Any account inside Sandbox can now only create EC2, RDS, and S3 in ap-south-1.
Attempting those actions in us-east-1 returns Access Denied.

Step 5 — Create a Permission Boundary

◈ DIAGRAM
IAM → Policies → Create policy → JSON tab
JSON
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:*", "cloudwatch:*", "ec2:Describe*"],
"Resource": "*"
}]
}
◈ DIAGRAM
Policy name: DevEngineerBoundary → Create policy
Apply to a user:
IAM → Users → arjun-dev → Permissions → Set permissions boundary
Select DevEngineerBoundary → Set boundary
Now even if arjun-dev has AdministratorAccess attached,
he can only do s3:*, cloudwatch:*, and ec2:Describe*.
The boundary is the ceiling — it cannot grant, only limit.

Step 6 — Verify the boundary works

Bash
Log in as arjun-dev (or use CLI with his credentials)
Try: aws ec2 run-instances → Access Denied (ec2:RunInstances not in boundary)
Try: aws s3 ls → Works (s3:* is in the boundary)
This is Permission Boundaries in action — policies say what you can do,
boundary says what the maximum is. Effective = intersection of both.

Step 7 — Cleanup

◈ DIAGRAM
IAM → Users → arjun-dev → Remove permissions boundary
IAM → Policies → DevEngineerBoundary → Delete policy
Organizations → Policies → RestrictToMumbaiOnly → Detach from Sandbox → Delete
Organizations → Sandbox OU → move accounts back to Root → Delete OU

Production Best Practices and Common Pitfalls

  • Never put actual workloads in the management account — it cannot be restricted by any SCP and a breach there affects the entire org
  • Use the blocklist SCP strategy for most OUs — allow everything and deny the specific dangerous things — it is easier to maintain than an allowlist
  • Test SCPs in a sandbox OU before applying to production — a wrong SCP can silently break services for all accounts under that OU
  • Use IAM Identity Center instead of creating IAM users in every account — one login, one place to manage access, and full audit trail
  • Apply Permission Boundaries when delegating IAM management to team leads — prevents privilege escalation without removing the ability to manage users
  • Use aws:PrincipalOrgID in bucket policies instead of listing account IDs — automatically includes new accounts and does not require policy updates when accounts are added
  • Enable AWS Config and Security Hub in every account via Control Tower — centralised compliance visibility from day one

Quick Reference and Troubleshooting Commands

Task Command
Create organization aws organizations create-organization --feature-set ALL
List roots aws organizations list-roots
Create OU aws organizations create-organizational-unit --parent-id <root-id> --name <name>
List accounts aws organizations list-accounts
Move account to OU aws organizations move-account --account-id <id> --source-parent-id <root-id> --destination-parent-id <ou-id>
Create SCP aws organizations create-policy --type SERVICE_CONTROL_POLICY --name <name> --content file://scp.json
Attach SCP aws organizations attach-policy --policy-id <p-id> --target-id <ou-id>
List SCPs on target aws organizations list-policies-for-target --target-id <id> --filter SERVICE_CONTROL_POLICY

Common problems and fixes:

Problem Likely cause Fix
Action denied in member account despite AdministratorAccess SCP blocking the action Check SCPs on all OUs above the account including Root
Management account affected by SCP Thinking SCPs apply to management account SCPs never apply to management account — this should never happen
Cross-account access needed while keeping Account A permissions active Using role assumption which pauses Account A permissions Switch to Resource-Based Policy on the target resource
User has policy allowing IAM but cannot create admin users Permission Boundary blocking IAM admin actions Review boundary — it caps what policies can grant
Identity Center users cannot access an account Permission Set not assigned to that account Assign the Permission Set to the user/group for that specific account
Common Mistake

Confusing aws:SourceIp with aws:RequestedRegion. SourceIp controls where the API call comes FROM — the caller's IP address. RequestedRegion controls which AWS region the call goes TO. A policy restricting to an office IP range uses SourceIp. A policy restricting to specific regions uses RequestedRegion. They control completely different dimensions.

Common Mistake

Using role assumption when you need to act in two accounts simultaneously. Assuming a role pauses your original account's permissions. If your code needs to read from Account A's DynamoDB and write to Account B's S3 at the same time, use a Resource-Based Policy on the S3 bucket that allows your Account A identity directly — your permissions stay active in both accounts.

Security

An SCP Deny at the Root OU level affects every account in the organisation except the management account. Before applying any SCP to Root, test it thoroughly in a non-critical OU. A wrong SCP at Root can silently break services for every team across every account — and because SCPs do not generate obvious error messages, the issue can take hours to diagnose.

Common Mistakes to Avoid

Common Mistake

Putting workloads in the management account. The management account cannot be restricted by any SCP — ever. A breach of the management account means unrestricted access to every account in the organisation. Keep it empty except for organisational management tasks.

Common Mistake

Confusing aws:SourceIp with aws:RequestedRegion. SourceIp controls where the API call comes FROM (the caller's IP). RequestedRegion controls which AWS region the call goes TO. They control completely different dimensions.

Security

Test SCPs in a sandbox OU before applying to production. A wrong SCP at the Root OU level silently breaks services for every account in the organisation. One wrong deny rule and your entire company loses access to a service — with no obvious error message explaining why.

Resources

AWS Direct Connect vs Site-to-Site VPN Failover

AWS Direct Connect vs Site-to-Site VPN Failover

Direct Connect vs VPN isn't really either/or for production — it's a primary-plus-failover pattern. Here's how to design it, and when either/or is right.

5 min read•Aug 2026
Lambda vs Fargate vs EC2 Spot: The Cost Crossover

Lambda vs Fargate vs EC2 Spot: The Cost Crossover

Lambda vs Fargate vs EC2 Spot, at the crossover where Lambda stops being cheaper — 2026 pricing, invocation thresholds, and interruption math.

5 min read•Aug 2026
Secrets Manager vs Parameter Store vs Vault

Secrets Manager vs Parameter Store vs Vault

AWS Secrets Manager, Parameter Store, and HashiCorp Vault compared for 2026 - cost math, rotation, multi-cloud fit, and the Vault-to-OpenBao fork.

5 min read•Aug 2026
AWS VPC Security: Hardening Every Layer

AWS VPC Security: Hardening Every Layer

Most cloud security incidents start with a misconfigured VPC. Here's how to harden every layer — subnets, Security Groups, NACLs, and IAM — for production.

5 min read•Jul 2026
Event-Driven Architecture on AWS Explained

Event-Driven Architecture on AWS Explained

Event-driven architecture on AWS decouples services and absorbs traffic spikes using SQS, SNS, EventBridge, and Lambda — workflows that scale themselves.

5 min read•Jul 2026
S3 vs RDS vs DynamoDB: Choosing AWS Storage

S3 vs RDS vs DynamoDB: Choosing AWS Storage

Choosing S3, RDS, or DynamoDB wrong costs you in performance, cost, and scalability. Here is a practical decision guide based on your actual access patterns.

5 min read•Jul 2026
AWS Cost Optimisation: Cut Cloud Bills 40-60%

AWS Cost Optimisation: Cut Cloud Bills 40-60%

AWS bills surprise teams every month. Here are the 8 concrete actions that cut cloud spend by 40-60% without touching your application architecture.

5 min read•Jul 2026
EC2 vs Lambda vs Fargate: Choosing AWS Compute

EC2 vs Lambda vs Fargate: Choosing AWS Compute

EC2, Lambda, or Fargate — choosing the wrong AWS compute option costs you money and performance. Here is exactly when to use each one in production.

5 min read•Jul 2026

Explore More in AWS Networking and Security

All 6 Topics

Frequently Asked Questions

Is IAM Advanced - OIDC, Cross-Account Access, and Permission Boundaries free to learn on DevOps Network?

Yes - this topic, like everything on DevOps Network, is 100% free with no paywall or sign-up gate.

What does the IAM Advanced - OIDC, Cross-Account Access, and Permission Boundaries topic cover?

Manage multi-account AWS environments with Organizations, SCPs, IAM Identity Center SSO, Permission Boundaries, and cross-account role assumptions.