open atlas
↑ Back to track
Cloud & Infra Security CLOUD · 01 · 01

The cloud identity model

Cloud authz is not one ACL but several policy documents evaluated together: a request is allowed only if some policy explicitly allows it and none denies it. Get the principal, the policy types, and the deny-by-default evaluation order right and most access mysteries dissolve.

CLOUD Middle ◷ 15 min
Level
FoundationsJuniorMiddleSenior

Your service can read a bucket it was never granted access to. You stare at the role’s policy — nothing mentions that bucket. You stare at the bucket’s policy — it allows a different account entirely. Yet aws s3 ls works. Nobody made a mistake in the obvious file, because cloud authorization is never decided by one file. The decision is a merge of several documents — the caller’s identity policy, the resource’s own policy, an account-wide guardrail, maybe a permission boundary — evaluated by fixed rules. The bucket was readable because a resource policy on it granted your role, and your role had no deny to override it. Until you can replay that merge in your head, every cloud-access surprise looks like magic.

By the end of this lesson you’ll be able to name who the principal is, list the policy types that attach to identities versus resources, and walk an authorization request through the exact deny-by-default evaluation cloud platforms run.

The principal: who is asking

Every authorization decision starts with a principal — the entity making the request. In a cloud IAM model the principal is almost never a human typing a password. It is an identity that has already been authenticated and now carries a set of short-lived credentials: an IAM role assumed by an EC2 instance, a Kubernetes service account exchanged for a cloud token via workload identity, a CI job that federated in with an OIDC token, a Lambda’s execution role. The login already happened; by the time a policy is evaluated, the platform knows which principal is asking. IAM is the authorization layer, not the authentication layer — it answers “is this already-known principal allowed to do this action on this resource,” and that distinction is where most confusion starts.

This matters for a senior reason: principals are usually machines, and they are long-lived in intent but short-lived in credential. A role doesn’t have a password; a principal assumes it and receives credentials that expire in an hour. So the interesting attack surface is not “guess the password” — it’s “who is allowed to become this principal,” which is governed by a separate policy we’ll get to.

Two policy questions: identity vs resource

A cloud platform asks the same request from two directions, and both must agree.

  • An identity-based policy is attached to the principal (a role, a user, a group). It says what this principal can do: “the report-writer role may s3:PutObject on reports-bucket.” Read it as a sentence starting with the actor.
  • A resource-based policy is attached to the resource itself (an S3 bucket, an SQS queue, a KMS key). It says who may act on this resource: “this bucket allows arn:aws:iam::111:role/report-writer to read.” Read it as a sentence starting with the object.

The same access can be expressed from either side, and the combination is what makes cross-account access work without anyone editing the other account’s roles. If account A’s bucket has a resource policy naming account B’s role, and B’s role has an identity policy allowing the action, the request succeeds — neither side could grant it alone across an account boundary. This is also the single most common source of “why can it read that?”: the grant lives on the resource, not the identity, so reading only the role’s policy will never explain it.

Policy typeAttaches toAnswersTypical use
Identity-basedRole / user / groupWhat can this principal do?Grant an app its permissions
Resource-basedBucket / queue / keyWho may act on this resource?Cross-account access
Trust policyRole (the AssumeRole door)Who may become this principal?Federation, role chaining
Permission boundary / SCPIdentity / whole accountWhat is the ceiling, regardless of grants?Org-wide guardrails

The trust policy: who may become this principal

A role has a door, and the trust policy is the lock on it. It is a resource-based policy that lives on the role and answers a question the identity policy never touches: who is allowed to assume this role at all? The identity policy says what the role can do once you’re inside; the trust policy says whether you may walk in.

This split is the whole engine of cloud federation. A GitHub Actions job presenting an OIDC token can become a deploy role only because that role’s trust policy says “principals federated from this OIDC provider, with this sub claim, may assume me.” A human in your SSO directory becomes an admin role because the trust policy trusts the identity provider. Get the trust policy wrong — trust *, or trust an OIDC sub with a sloppy wildcard like repo:org/* — and you have handed the role to the entire internet, no matter how tight its identity policy is. The trust policy is the part juniors forget exists and seniors review first, because it is the actual authentication boundary for a machine principal.

Why this works

Why two separate policies on one role instead of one combined permission list? Because “who may use this capability” and “what this capability can do” change independently and are owned by different people. The platform team curates the trust policy (which OIDC providers, which accounts, which SSO groups may assume the role); the application team curates the identity policy (which API calls the app needs). Merging them would force every permission change to re-open the federation boundary, and every federation change to re-audit app permissions. Separating the door from the room is least privilege applied to the structure itself.

How the decision is actually evaluated

Here is the rule that dissolves the mysteries. Cloud authorization is deny by default, and evaluation is not “find a matching allow” — it is a fixed precedence:

  1. Start at implicit deny. No statement matches → the request is denied. Nothing is permitted unless something grants it.
  2. An explicit Deny always wins. If any applicable policy — identity, resource, boundary, or org guardrail — contains a Deny that matches, the request is denied, full stop. No allow can override it.
  3. An explicit Allow lifts the implicit deny — but only within the ceiling. A permission boundary or org-level guardrail (an SCP) can cap what is reachable even when an identity policy says Allow; the effective permission is the intersection of what’s granted and what the ceiling permits.

So the real evaluation is: deny unless (some policy allows) AND (no policy denies) AND (the grant is inside every applicable ceiling). That ordering is why an over-broad Allow * is far less dangerous than people fear when a boundary caps it — and why a single stray Deny can break a deploy that “obviously has permission.”

Reading a real grant: cross-account in one merge

Walk the opening mystery through the model. Your role in account B can s3:ListBucket on a bucket in account A. Trace it:

  • Trust policy on B’s role lets your EC2 instance / CI job assume it. Authentication of the machine principal: done.
  • Identity policy on B’s role allows s3:ListBucket on arn:...:bucket-in-A. B’s side of the grant: present.
  • Resource policy on A’s bucket allows arn:aws:iam::B:role/yours to s3:ListBucket. A’s side of the grant: present.
  • No Deny anywhere, and the action sits inside B’s permission boundary and A’s org guardrails.

Both sides agreed, no deny intervened, the ceiling allowed it → permitted. The reason reading the role alone failed is that half the grant lived on the resource in another account. The senior habit is to ask, for any surprising access: “show me every policy in the merge — both identities, both resources, the boundary, the org guardrail — not just the one I expected.”

Pick the best fit

A GitHub Actions workflow needs to deploy to your cloud account. You want CI to assume a deploy role. Which approach is the correct identity model?

Quiz

An identity policy on a role says `Allow s3:*`, but a permission boundary on that same role only permits `s3:GetObject`. The principal calls `s3:DeleteObject`. What happens?

Quiz

A bucket in account A is readable by a role in account B, but A's identity policies never mention B. Where does the grant live, and why didn't reading B's role explain it?

Order the steps

Order the steps of how a cloud authorization decision is evaluated, from start to verdict:

  1. 1 Start at implicit deny (nothing is allowed by default)
  2. 2 Check every applicable policy for an explicit Deny — if any matches, deny outright
  3. 3 Look for an explicit Allow in an identity or resource policy
  4. 4 Confirm the grant sits inside the permission-boundary / org-guardrail ceiling
  5. 5 Permit only if allowed, not denied, and within the ceiling
Recall before you leave
  1. 01
    Distinguish a principal's identity policy, a resource policy, and a trust policy. What question does each answer, and why are they separate?
  2. 02
    Walk through how a cloud platform evaluates an authorization request, including the role of permission boundaries.
Recap

Cloud IAM never decides access from a single file. The principal is an already-authenticated identity — almost always a machine with short-lived assumed credentials, not a human with a password. Three policy questions get merged: an identity-based policy says what the principal can do, a resource-based policy says who may act on a resource (the mechanism behind cross-account grants), and the trust policy on a role says who may become that principal at all — the real authentication boundary, and the thing seniors review first because a wildcard there hands the role to everyone. Evaluation is deny-by-default with fixed precedence: any explicit Deny wins, an explicit Allow lifts the implicit deny but only inside the permission-boundary or org-guardrail ceiling, so the effective permission is the intersection of grant and ceiling. The next time access surprises you, don’t read one policy — replay the whole merge: both identities, both resources, the trust door, and every ceiling.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 7 done
Connected lessons

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.