bigonotes
CloudIdentity (IAM)

IAM Policy Types

Identity, resource, trust, SCP, boundary, session and ACL policies: what each attaches to and how AWS combines them into allow or deny.

7 min readLast updated

A policy is a JSON document that allows or denies actions. AWS has several policy types, and they attach to different things: identities, resources, accounts and sessions. Some grant permissions. Others only set a ceiling. When a request arrives, AWS reads every policy that applies and combines them. When you hit an AccessDenied error, knowing which type does what is how you find the cause.

This note assumes you know users, groups and roles from IAM basics. The JSON syntax itself is in Writing IAM policies.

Grant vs guardrail#

Seven policy types sounds like a lot, but they split into two groups. The first thing to learn about each one is whether it can grant access at all.

Policy type Attaches to Grants? Typical use
Identity-based (managed or inline) User, group, role ✓ Day-to-day permissions
Resource-based A resource (S3 bucket, SQS queue, KMS key) ✓ Cross-account access to one resource
Trust policy A role ✓ (who may assume it) Who can use a role
Service control policy (SCP) Account or OU in AWS Organizations ✗ Org-wide guardrails
Permissions boundary User or role ✗ Cap what delegated admins can grant
Session policy One assumed-role or federated session ✗ Narrow one session further
Access control list (ACL) Some resources, e.g. S3 objects ✓ Legacy cross-account grants

Guardrails (✗) only remove permissions. A permission must still come from an identity-based or resource-based policy.

Identity-based policies#

The rest of the note takes each type in the table's order, starting with the one you'll write most. Identity-based policies attach to a user, group or role and say what that identity may do. They come in three forms.

  • AWS managed policies are written and updated by AWS, such as AmazonS3ReadOnlyAccess. They are quick to use but often broad.
  • Customer managed policies are standalone policies you write. You can attach one to many identities, and AWS keeps versions so you can roll back.
  • Inline policies are embedded in one identity. They are deleted with it and can't be reused.

Prefer customer managed policies. Use inline only for a strict one-to-one link, where the permission must never be attached elsewhere by accident.

Resource-based policies#

Identity policies are written from the caller's side. Resource-based policies flip that: they attach to a resource and list who (the Principal) may do what to it. S3 bucket policies, SQS queue policies, SNS topic policies, KMS key policies and Lambda function policies are all resource-based.

Their main use is cross-account access. A bucket policy can name a role in another account directly. For that request to succeed, both sides must agree: the bucket policy must allow the other account's principal, and that principal's own identity policy must allow the action.

Trust policies#

A role is itself a resource, so it gets a resource-based policy too. That's the trust policy, which names who may call sts:AssumeRole (or a variant such as sts:AssumeRoleWithWebIdentity).

  • "Service": "ec2.amazonaws.com" lets EC2 instances use the role.
  • "AWS": "arn:aws:iam::123456789012:root" lets that account delegate the role to its own principals.
  • "Federated" principals let SAML or OIDC identity providers use it.

A role is only as safe as its trust policy. For roles that third parties assume, add a condition such as sts:ExternalId so another customer of that third party can't trick it into using your role.

Service control policies (SCPs)#

The remaining types are guardrails, and the widest one works across whole accounts. SCPs belong to AWS Organizations. You attach them to the root, an organizational unit (OU) or a single account. They set the maximum permissions for every principal in the affected member accounts.

  • SCPs never grant. An action that the SCP allows still needs an identity or resource policy.
  • An action that an SCP denies is denied for everyone in that account, whatever other policies say.
  • SCPs do apply to the root user of member accounts. This is how an org stops a member root user from, for example, leaving the organization.
  • SCPs don't apply to the management account, or to service-linked roles.

Common SCPs deny actions outside approved Regions, block disabling CloudTrail, or block deleting backups. AWS Organizations also has resource control policies (RCPs), which set the same kind of ceiling on resources instead of principals.

Permissions boundaries#

SCPs cap whole accounts. A permissions boundary does the same for a single identity: it is a managed policy that you set as the ceiling for one user or role. The identity's effective permissions are the overlap of its identity policies and its boundary.

Boundaries solve delegation. Say you let a team create roles for their own Lambda functions. Without a boundary, they could create a role with AdministratorAccess and escalate. With a policy that says "you may create roles only if you attach boundary X", every role they make stays inside X.

Session policies#

The narrowest guardrail lasts only as long as one session. A session policy is passed in when you assume a role or get federated credentials. It narrows that one session. The session gets the overlap of the role's policies and the session policy, never more.

Use them when one role serves many callers, and each caller should see only part of what the role allows. The role itself is unchanged.

Access control lists (ACLs)#

The last row of the table is a grant mechanism from before IAM policies. ACLs are an older, non-JSON way to grant access, mainly on S3 buckets and objects. They name a grantee (an account or a predefined group) and a permission such as READ, WRITE or FULL_CONTROL.

New S3 buckets have ACLs disabled by default (Object Ownership set to "bucket owner enforced"). Use bucket policies instead. VPC network ACLs share the name but are a firewall feature, not an IAM policy.

How AWS evaluates a request#

Now that each type is clear, here's how they combine on a real request. AWS gathers every policy that applies and follows a fixed order, and three rules sum it up:

  1. Default deny. If nothing allows the action, it is denied.
  2. Explicit deny wins. A Deny in any applicable policy beats every Allow.
  3. Guardrails cap, never grant. SCPs, RCPs, boundaries and session policies must each allow the action. If any of them doesn't, the request is denied.
IAM evaluation flow: an explicit deny in any policy ends in deny; then the SCP, permissions boundary and session policy must each allow the action; finally an identity-based or resource-based policy must allow it, otherwise the default deny applies

Worked examples#

The three rules are short, but they interact in ways that surprise people. These cases show them in action.

Situation Result Why
A user is in group A (allows S3) and group B (denies S3) Denied Explicit deny wins
The role allows ec2:*, the SCP allows only listed Regions Denied outside those Regions The SCP caps the role
The boundary allows s3:*, but no identity policy mentions S3 Denied A boundary never grants
Same account: the bucket policy allows a role, but the role has no S3 policy Allowed In one account, either side's allow is enough
Cross-account: the bucket policy allows a role, but the role has no S3 policy Denied Across accounts, both sides must allow

The same-account rule has exceptions. KMS key policies and role trust policies must allow the principal directly. When in doubt, test with the IAM policy simulator.

Key takeaways#

  • Only identity-based policies, resource-based policies (including trust policies) and ACLs grant access.
  • SCPs, RCPs, permissions boundaries and session policies only cap what other policies grant.
  • An explicit deny in any applicable policy beats every allow. With no allow, the default is deny.
  • SCPs restrict member accounts, including their root users, but not the management account.
  • Cross-account access needs an allow on both sides: the resource policy and the caller's identity policy.
  • Prefer customer managed policies; use inline policies only for strict one-to-one links.
Revision notes · 2 min

Core idea#

AWS combines every policy that applies to a request. Some policy types grant access; others only cap it.

Policy types#

Type Attaches to Grants?
Identity-based (managed, inline) User, group, role ✓
Resource-based Resource, e.g. S3 bucket, SQS queue ✓
Trust policy Role ✓ (who may assume)
SCP / RCP Account or OU in AWS Organizations ✗
Permissions boundary User or role ✗
Session policy One session ✗
ACL Some resources, e.g. S3 ✓ (legacy)

Key points#

  • Prefer customer managed policies. Use inline policies only for strict one-to-one links.
  • Resource-based policies name a Principal and enable cross-account access.
  • Add sts:ExternalId to trust policies that third parties assume.
  • SCPs apply to member accounts, including their root users. They don't apply to the management account or service-linked roles.
  • A permissions boundary caps what a delegated admin's roles can do.
  • A session policy narrows one session to the overlap with the role's policies.
  • New S3 buckets have ACLs disabled. Use bucket policies.

Evaluation rules#

  1. Default deny: no allow means deny.
  2. An explicit deny in any applicable policy beats every allow.
  3. SCPs, RCPs, boundaries and session policies must each allow the action.
  4. An identity-based or resource-based policy must then allow it.

Pitfalls#

  • A boundary or SCP that allows an action still grants nothing alone.
  • Cross-account access needs an allow on both sides.
  • In one account, either side's allow is enough, except for KMS key policies and trust policies.

Say it in an interview#

  • "Explicit deny wins. Guardrails cap permissions but never grant them."
  • "SCPs restrict member-account root users, but not the management account."

Found a mistake? Email ask@bigonotes.com

Further reading#