# IAM Deep Dive — Part 1: Principals, Policies and Evaluation

`01-fundamentals_and_iam/` introduced users, groups, roles and policies. This deep dive covers how authorization decisions are actually made, how roles and temporary credentials work, and the policy types that matter in real organizations.

## 1. Principals and Credentials

| Principal | Credentials | Use |
|---|---|---|
| **IAM user** | long-lived access keys / password | avoid for humans and workloads; legacy or break-glass only |
| **IAM role** | **temporary** credentials from STS (15 min – 12 h) | workloads (EC2/ECS/Lambda/EKS), cross-account access, humans via SSO, CI via OIDC |
| **federated identity** | IAM Identity Center (SSO), SAML, OIDC → role session | humans |
| **AWS service principal** | `lambda.amazonaws.com`, `ecs-tasks.amazonaws.com` | in trust policies |
| **root user** | account owner | lock away with MFA; almost never used |

## 2. A Role Has Two Policies

```json
// TRUST policy — WHO may assume the role (resource policy on the role)
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "ecs-tasks.amazonaws.com" },
    "Action": "sts:AssumeRole",
    "Condition": { "ArnLike": { "aws:SourceArn": "arn:aws:ecs:eu-west-1:111111111111:*" } }
  }]
}

// PERMISSIONS policy — WHAT the role may do once assumed
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["s3:GetObject", "s3:PutObject"],
    "Resource": "arn:aws:s3:::petpal-uploads/*"
  }]
}
```

## 3. Policy Types

| Type | Attached to | Effect |
|---|---|---|
| **identity-based** (managed or inline) | users, groups, roles | grants permissions |
| **resource-based** | S3 buckets, KMS keys, SQS queues, SNS topics, Lambda functions, Secrets, role trust policies | grants access to principals (incl. other accounts) |
| **permissions boundary** | users/roles | **caps** what identity policies can grant |
| **SCP** (Service Control Policy) | AWS Organizations OU/account | **caps** everything in the account (even root) — `23-multi_account_and_organizations/` |
| **RCP** (Resource Control Policy) | Organizations | caps what resource policies can allow (e.g. no access from outside the org) |
| **session policy** | passed when assuming a role | further restricts that session |
| **ACLs** | legacy S3/VPC | avoid |

## 4. The Evaluation Logic

For a request in a single account:

```
1. explicit DENY in any applicable policy?            → DENY  (deny always wins)
2. SCPs / RCPs allow it?                              → if not, DENY
3. resource-based policy allows the principal?         → (can grant on its own within the same account)
4. identity policy allows it?                          → needed unless 3 granted it
5. permissions boundary allows it?                     → must also allow (for identity grants)
6. session policy allows it?                           → must also allow
default                                                → implicit DENY
```

**Cross-account**: the request must be allowed by **both** the caller's identity policy (in account A) **and** the resource policy in account B (or the role trust policy, if assuming a role in B).

## 5. Statement Anatomy and Conditions

```json
{
  "Sid": "ReadOwnTenantData",
  "Effect": "Allow",
  "Action": ["dynamodb:GetItem", "dynamodb:Query"],
  "Resource": "arn:aws:dynamodb:eu-west-1:111111111111:table/helpdesk",
  "Condition": {
    "ForAllValues:StringLike": { "dynamodb:LeadingKeys": ["TENANT#${aws:PrincipalTag/tenant}*"] },
    "Bool": { "aws:SecureTransport": "true" }
  }
}
```

Useful condition keys: `aws:PrincipalTag/*` and `aws:ResourceTag/*` (**ABAC** — attribute-based access control), `aws:SourceIp`, `aws:SourceVpce`, `aws:PrincipalOrgID`, `aws:SecureTransport`, `aws:MultiFactorAuthPresent`, `aws:RequestedRegion`, service-specific keys (`s3:prefix`, `kms:ViaService`, `ec2:InstanceType`). Policy variables (`${aws:username}`, `${aws:PrincipalTag/team}`) let one policy serve many principals.

`NotAction` / `NotResource` invert matches — powerful and easy to get wrong (an `Allow` with `NotAction` grants almost everything).

## Under the Hood: STS and Temporary Credentials

`sts:AssumeRole` (or `AssumeRoleWithWebIdentity` for OIDC tokens, `AssumeRoleWithSAML` for SAML) returns three values: `AccessKeyId` (starting with `ASIA…` for temporary keys), `SecretAccessKey`, and a `SessionToken` that encodes the role, session name, tags, session policy and expiry. Every API call is signed with **SigV4** using the secret key; the receiving service validates the signature and token, then evaluates policies for the **role session** principal (`arn:aws:sts::111111111111:assumed-role/RoleName/SessionName`). Because credentials expire automatically, a leaked session key is useful only until expiry (and can be revoked by denying sessions issued before a time via `aws:TokenIssueTime`). SDKs refresh credentials transparently from the instance/task metadata endpoints or the OIDC token file — which is why workloads should never be given long-lived keys.

![A request is evaluated by checking explicit denies, then service control and resource control policies, then resource-based and identity-based policies, then permissions boundaries and session policies, defaulting to deny; roles combine a trust policy with permissions and hand out temporary STS credentials](diagrams/01-policy-evaluation.svg)

## Quick Reference (Part 1)

```
humans: SSO → roles · workloads: roles (instance profile, task role, Lambda role, Pod Identity) · CI: OIDC → role
role = trust policy (who) + permissions (what) · STS temporary creds (ASIA…)
evaluation: explicit deny > SCP/RCP > resource ∪ identity > boundary > session > implicit deny
cross-account: caller identity policy AND target resource/trust policy
conditions: PrincipalTag/ResourceTag (ABAC), PrincipalOrgID, SourceVpce, SecureTransport, MFA, ViaService
