Session policies and session tags

Lesson 4 of 4 in Temporary Credentials.

Two things you can attach to a session at the moment it is created, doing opposite jobs. A session policy takes permissions away. A session tag adds attributes that policies can then test.

Start with the session policy, because its one rule is absolute: it can only narrow. Pass it on the STS call — one inline JSON document and/or up to ten managed policy ARNs, with the plaintext limited to roughly 2,048 characters — and the resulting session's permissions are the intersection of the role's identity-based policy and the session policy. A session policy granting s3:* on a role that can only read one bucket yields a session that can only read one bucket. There is no configuration in which passing a session policy increases access.

That makes it the right tool for one specific shape: one role, many narrow sessions. A multi-tenant broker assumes a single role and passes a session policy scoping each session to one customer's prefix. A pipeline assumes a deployment role and passes a session policy limiting the run to the stack it is deploying. GetFederationToken requires one, because its entire purpose is handing a federated user a slice of an IAM user's permissions.

The uncomfortable part, worth stating plainly: a session policy is supplied at runtime and is not visible in IAM afterwards. An administrator reading the role's policies sees the wide grant, not the narrow session. Session scoping therefore belongs in code review as much as in policy review.

A five-layer stack read bottom-up, each layer narrowing the one below it. Bottom: the role identity policy, the widest grant and the only layer that actually grants anything. Second: the permissions boundary attached to the role, capping what that identity policy can grant. Third: the session policy passed at AssumeRole time, intersecting further for this session only. Fourth: organization policies, SCPs capping the principal and RCPs capping the resource. Top, emphasized: the effective session permissions, which are the intersection of everything beneath — and which no layer above the identity policy can ever enlarge.

Four narrowing layers around one role. Each is an intersection — not one of them can grant. (illustrative — source: IAM User Guide — policy evaluation logic)

Session tags come at the problem from the other direction: instead of removing permissions, they supply the facts a policy needs in order to decide.

Pass them as Tags on AssumeRole, or have the identity provider carry them — a SAML assertion attribute named https://aws.amazon.com/SAML/Attributes/PrincipalTag:project, or an OIDC claim mapped in. The role's trust policy must allow sts:TagSession for the tagging to be permitted at all. Once set, the session's tags are readable in any policy as aws:PrincipalTag/<key>, which is what makes one statement serve every team:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadOwnProjectBuckets",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:ResourceTag/project": "${aws:PrincipalTag/project}"
        }
      }
    }
  ]
}

Three mechanics the exam tests.

Session tags override role tags of the same key for that session, so a role tagged project=shared assumed with a session tag project=payments behaves as payments.

Tags are dropped at the next hop unless marked transitive. List the keys in TransitiveTagKeys and they persist through every subsequent AssumeRole in the chain, where they cannot be overwritten. Omit it, and an ABAC condition that worked on the first hop fails silently on the second — a genuinely common production bug, and a satisfying exam distractor.

A missing tag fails closed. If aws:PrincipalTag/project is not in the request context, the condition does not match and the Allow does not apply. That is the desirable direction, but it means a principal with no project tag can do nothing under this statement — which is why ABAC designs need a tagging gate at identity-provisioning time, not just at resource-creation time.

Where a session tag comes from, and where it dies

  1. The attribute exists in the IdP (or is chosen by the caller)
  2. Passed at AssumeRole: Tags, or a SAML PrincipalTag attribute, or an OIDC claim

    The role’s trust policy must allow sts:TagSession, or the call is rejected.

  3. In the request context as aws:PrincipalTag/<key>

    Readable by identity policies, resource policies, boundaries, session policies, SCPs and RCPs alike.

  4. Does the session assume another role?

    Role chaining: the new session is a fresh session with its own tag set.

  5. Marked transitive? It persists, and cannot be overwritten
  6. Not transitive? Dropped — ABAC conditions on it stop matching
  7. Used for the ABAC decision on this session

Key terms: Session policy, Session tag, Transitive session tag, Permissions boundary

Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.