examhub .cc The most efficient path to the most valuable certifications.
In this note ≈ 36 min

IAM Roles, Policies, and Resource-Based Permissions

7,100 words · ≈ 36 min read

AWS Identity and Access Management (IAM) is the authorization layer every AWS developer lives inside. When your AWS Lambda function calls Amazon DynamoDB, when your Amazon ECS task pulls a container image from Amazon ECR, when your Amazon EC2 instance reads a secret from AWS Secrets Manager, every one of those calls hits the AWS IAM engine first and must be approved by at least one IAM policy and blocked by no IAM policy. For the DVA-C02 exam, Task Statement 2.1 ("Implement authentication and/or authorization for applications and AWS services") makes IAM roles, IAM policies, AWS STS operations, and the policy evaluation algorithm the single highest-frequency subject in Domain 2, and the answers to those scenarios surface in Domain 1, Domain 3, and Domain 4 questions too.

This guide is written from a developer's perspective. It covers the full IAM policy anatomy that shows up in code reviews, every AWS STS operation you might call from an AWS SDK, every IAM role flavour used by every AWS compute service (AWS Lambda, Amazon EC2, Amazon ECS on EC2, Amazon ECS on AWS Fargate, Amazon EKS with IRSA), the rules for credential refresh inside AWS SDK clients, and the newer mechanisms — AWS IAM Roles Anywhere, AWS IAM Identity Center, AWS IAM Access Analyzer policy generation — that a developer is expected to understand on DVA-C02 v2.1.

What IAM Means to a Developer on DVA-C02

On CLF-C02 the IAM conversation stops at "users, groups, roles, MFA, least privilege". On DVA-C02 it starts at "here is a JSON policy, find the reason your Lambda function is getting AccessDeniedException at runtime". Every IAM scenario on DVA-C02 assumes you can read an IAM policy the way you read application code: you can name the six required sibling keys inside a Statement, you can predict which Principal AWS STS will return in the response, you know which condition keys are present at runtime for a given AWS service, and you know exactly which IAM role type is pulling credentials for the compute platform in the question.

The DVA-C02 exam guide (v2.1, December 2024) explicitly calls out cross-account access via sts:AssumeRole, permissions boundaries, IAM condition keys, resource-based policies, and the policy evaluation algorithm. It also folds in Amazon Cognito (covered in its own topic) and AWS IAM Identity Center at awareness level. IAM Roles Anywhere is now part of the AWS 2026 vocabulary that developers running hybrid workloads are expected to recognize.

  • IAM policy: JSON document that allows or denies AWS API actions on resources, optionally filtered by conditions.
  • Identity-based policy: IAM policy attached to a principal (an IAM user, IAM group, or IAM role).
  • Resource-based policy: IAM policy attached to a resource (an Amazon S3 bucket, an AWS Lambda function, an AWS KMS key).
  • Trust policy: the resource-based policy on an IAM role that names which principals are allowed to call sts:AssumeRole.
  • Permissions boundary: identity-based policy that caps the maximum permissions an IAM role or IAM user can be granted.
  • Session policy: temporary IAM policy passed into an sts:AssumeRole call that narrows that session's permissions.
  • Service control policy (SCP): AWS Organizations guardrail that caps what any IAM policy in a member account can grant.
  • Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies.html

The IAM policy document is the developer's contract

Every IAM-related DVA-C02 question either hands you a JSON policy or describes one in words. The rest of this topic teaches you to read both representations at speed, to predict the outcome of the IAM policy evaluation algorithm, and to map the scenario onto the specific IAM role flavour the compute platform uses.

Plain-Language Explanation: — Three Analogies for IAM

Three distinct analogies cover every IAM concept on DVA-C02. Pick the one that sticks and keep it in your head for the exam.

Analogy 1 — Building security, access cards, and shift supervisors

Picture a secure data centre. An IAM user is a permanent employee badge belonging to one person, stored in their wallet, and programmed to open certain doors 24/7. An IAM role is a shift-supervisor lanyard kept at the security desk; anyone who can prove they are an authorized supervisor (the trust policy) can check the lanyard out, wear it for up to one hour, and it automatically deactivates at the end of the shift. AWS STS is the security desk clerk who checks your credentials, issues the lanyard, writes the expiry on the back, and records the handoff in a logbook. A permissions boundary is the written job description on the back of the lanyard saying "this supervisor is allowed to open doors on floors 1-5 only, regardless of what their badge might otherwise permit". A session policy is a sticky note the clerk attaches to the lanyard for today's specific visit: "today only, no server room". The resource-based policy on a door is the rule on the door itself that lists which lanyards are welcome. An explicit deny is a red lockout tag on the door — no lanyard, no matter what it says, can open it while the tag is on. And IAM Roles Anywhere is the arrangement for off-site contractors who show up with their company ID from another building: the clerk verifies the contractor's ID card (an X.509 certificate from a trusted partner certificate authority), and issues the same kind of temporary lanyard to the outside worker.

Analogy 2 — The open-book exam with a strict proctor

An IAM policy evaluation is exactly like a proctored open-book exam. The proctor (AWS IAM) receives every request, checks your identity, then reviews four layered rulebooks: the service control policy from AWS Organizations (the exam board's outer rules), the permissions boundary (your particular seating section's rules), the identity-based policy (your personal crib sheet), and the resource-based policy (the rule written on the specific book you are trying to open). If any rulebook contains an explicit "do not" on the action you are attempting, your request dies — an explicit deny always wins. Otherwise the proctor needs to see at least one explicit "allowed" somewhere, and none of the four rulebooks may be silent on the specific action. A session policy is the post-it the proctor stuck to your desk today because you asked for a temporary scope reduction. An IAM condition key is the "only if" clause — "allowed, only if you are wearing the badge and it's before 5pm". This analogy maps cleanly onto the six-part IAM policy evaluation algorithm and will steer you through the trickiest DVA-C02 scenario questions.

Analogy 3 — Kitchen brigade, recipes, and temporary helpers

Think of a busy restaurant kitchen running the shift. The head chef is the IAM user account with long-term credentials. A line cook is an IAM role — a named station (sauté, garde manger, pastry) that anyone qualified can fill for one service. The recipe card is the IAM policy — it spells out exact ingredients the cook at that station is allowed to touch, which stoves they can use, and the conditions ("only from the walk-in, only between 4 and 10 pm"). The pass to the dining room is the resource-based policy on the pass — only dishes from authorized stations come through. An AWS Lambda execution role is the recipe card handed to a robotic sous-chef that runs for a maximum of 15 minutes per dish. An Amazon EC2 instance profile is the personal recipe folder clipped to a fixed workstation. An Amazon ECS task role is the recipe card issued to a hired temp cook for a single catering job, separate from the task execution role which is the kitchen manager's card used only to pull the ingredients out of cold storage (Amazon ECR image pull, Secrets Manager fetch). An Amazon EKS IRSA binding is the laminated Kubernetes service-account name tag that the temp wears so the kitchen management software (Amazon EKS) knows which recipe card to hand them when the shift begins.

On exam day, when a question mentions sts:AssumeRole, picture the security desk clerk issuing a shift supervisor lanyard. When it mentions a permissions boundary, picture the job description on the back of the lanyard. When it mentions a session policy, picture the sticky note with today's specific restriction. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html

IAM Policy Anatomy — Version, Statement, Effect, Action, Resource, Condition

An IAM policy is a JSON document with two top-level keys and one array of statements:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowS3ReadExampleBucket",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::example-bucket",
        "arn:aws:s3:::example-bucket/*"
      ],
      "Condition": {
        "StringEquals": {"aws:RequestedRegion": "us-east-1"},
        "Bool": {"aws:MultiFactorAuthPresent": "true"}
      }
    }
  ]
}

The Version element

"Version": "2012-10-17" is the current AWS IAM policy language version and is required for condition keys and policy variables to work. "2008-10-17" is legacy and should never appear in new policies. If you leave Version out, AWS defaults to the 2008-10-17 grammar and several modern features silently stop working — a classic DVA-C02 debugging trap.

The Statement element

Statement is the list of one or more statements. Each statement is an independent rule that AWS IAM evaluates in isolation and then combines via the allow/deny union logic.

The Sid element

"Sid" is an optional statement identifier. It is not used by the evaluation engine — it only helps humans and tooling reference a particular statement. For an AWS KMS key policy the Sid is important because AWS KMS console tooling looks for specific Sid values to detect the default statements.

The Effect element

"Effect" is exactly one of "Allow" or "Deny". There is no third value. Deny always beats Allow in the final decision — remember this is the cornerstone of IAM policy evaluation logic.

The Action element (and NotAction)

"Action" names the AWS API operations the statement applies to. Actions are always lowercased service prefix plus camelCase verb: s3:GetObject, dynamodb:PutItem, lambda:InvokeFunction, kms:Decrypt. Wildcards are allowed (s3:Get*, s3:*). A statement can list one string, an array of strings, or a single "*". NotAction lists every action except these — use it carefully because the negation surface is usually bigger than intended.

The Resource element (and NotResource)

"Resource" is an ARN or an array of ARNs the statement applies to. Some actions (like s3:ListAllMyBuckets) only make sense account-wide, so they accept only "*". Object-level Amazon S3 actions need the bucket/* ARN pattern. Always list the bucket ARN and the bucket/* ARN in the same statement when you want both bucket-level and object-level access. NotResource is the negation and is rarely correct in practice.

The Principal element (resource-based policies only)

"Principal" only appears in resource-based policies and trust policies. It names who this rule applies to: an AWS account ({"AWS": "arn:aws:iam::111122223333:root"}), an IAM user, an IAM role, an AWS service ({"Service": "lambda.amazonaws.com"}), a federated identity ({"Federated": "cognito-identity.amazonaws.com"}), or "*". Identity-based policies never contain a Principal because the principal is already the identity the policy is attached to.

The Condition element

"Condition" is the most expressive part of an IAM policy and the most tested on DVA-C02. It maps a condition operator (StringEquals, StringLike, NumericLessThan, DateGreaterThan, Bool, IpAddress, ArnLike, and many more) to a map of condition key and expected value. AWS IAM evaluates every condition block as AND across operators, AND across keys within an operator, and OR across the array of values for a single key. Commonly tested condition keys include:

  • aws:MultiFactorAuthPresent — require MFA for this action.
  • aws:SourceIp — restrict by caller IP (useful for on-premises VPN clients).
  • aws:RequestedRegion — limit an action to one or more AWS Regions.
  • aws:PrincipalTag/Department, aws:ResourceTag/Project — attribute-based access control (ABAC).
  • aws:SecureTransport — require TLS (HTTPS).
  • aws:SourceVpce, aws:SourceVpc — restrict to a specific VPC endpoint.
  • sts:ExternalId — the confused-deputy protection key for cross-account role assumption.
  • aws:PrincipalOrgID — restrict access to identities inside your AWS Organizations organization.

Even if a condition block is on a Deny statement, if the condition matches, the deny fires and nothing else can override it. This is the knob you use to enforce blanket restrictions like "never allow unencrypted S3 uploads" — Effect: Deny, Action: s3:PutObject, Condition: {StringNotEquals: {s3:x-amz-server-side-encryption: AES256}}. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html

IAM Policy Types — Identity vs Resource, Managed vs Inline, Boundaries, Sessions, SCPs

AWS IAM has six distinct policy types. DVA-C02 expects you to name them, attach them to the correct object, and reason about how they combine.

Identity-based policies

Attached to an IAM user, IAM group, or IAM role. They list actions that principal can perform. Come in two flavours: AWS-managed, customer-managed, or inline.

Resource-based policies

Attached to a resource — Amazon S3 bucket policy, AWS Lambda function resource policy, Amazon SNS topic policy, Amazon SQS queue policy, AWS KMS key policy, Amazon ECR repository policy, Amazon API Gateway resource policy. They must include a Principal element because the identity isn't implied. Resource-based policies are the only IAM policy type that can grant cross-account access without the other account also granting permission — a resource-based policy that says "account 111122223333 is allowed s3:GetObject on this bucket" is sufficient, as long as the other account's identity-based policy also allows s3:GetObject. For AWS KMS specifically, the key policy is mandatory and the identity-based policy alone is never enough.

AWS-managed vs customer-managed vs inline policies

  • AWS-managed: prebuilt IAM policies like AmazonS3ReadOnlyAccess, AWSLambdaBasicExecutionRole. Convenient, but usually broader than least privilege.
  • Customer-managed: you author and version these. They can be attached to many identities. AWS keeps up to five versions and you can roll back.
  • Inline: embedded inside exactly one IAM user, IAM group, or IAM role. They cannot be reused. Delete the identity and the inline IAM policy dies with it — which is sometimes exactly what you want (one-off tight coupling).

AWS generally recommends customer-managed IAM policies for reusability and versioning. Reach for inline IAM policies when you deliberately want a permission to live and die with one IAM role — for example, a one-off IAM role dedicated to a single AWS Lambda function whose IAM policy should never be copy-pasted elsewhere. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html

Permissions boundaries

A permissions boundary is an identity-based IAM policy attached as a boundary to an IAM user or IAM role. It does not grant anything; it only caps the effective permissions. An identity's actual permissions are the intersection of its identity-based policies and its permissions boundary. The classic DVA-C02 use case is delegated administration: you give a developer permission to create IAM roles for their AWS Lambda functions, but you attach a permissions boundary requirement to that delegation so that every role they create can itself never exceed the boundary. That stops privilege-escalation by letting developers hand themselves a new IAM role with AdministratorAccess.

Session policies

A session policy is a temporary IAM policy that is passed into an sts:AssumeRole call (or AssumeRoleWithSAML, AssumeRoleWithWebIdentity, or GetFederationToken) as the Policy or PolicyArns parameter. It only applies to the credentials returned by that specific call. The session's effective permissions are the intersection of the IAM role's identity-based policies AND the session policy. Session policies are ideal for a pattern like "this single AWS Lambda function invocation should be limited to exactly this one Amazon S3 prefix".

Service control policies (SCPs)

SCPs live in AWS Organizations, attached to the organization root, an organizational unit, or an individual AWS account. They set the maximum permissions any IAM policy in a member account can grant. SCPs never grant permissions themselves; they only restrict. For DVA-C02 you need to know that an SCP that denies s3:DeleteBucket will block even the root user's call in a member account, and an SCP that allows s3:* still requires an IAM policy in the account to actually grant the action.

How the six types layer

The effective permissions of a principal making a request are computed as:

  1. Start from an implicit deny (nothing is permitted by default).
  2. If any SCP denies the action, the request is denied.
  3. If any permissions boundary denies (or simply fails to allow) the action, the request is denied.
  4. If any resource-based policy or any identity-based policy or any session policy has an explicit deny on the action, the request is denied.
  5. Otherwise the request is allowed if at least one identity-based policy, resource-based policy, or session policy has an explicit allow that passes every condition, subject to the SCP and boundary still allowing it.
  6. Otherwise the request is denied by default.

IAM Policy Evaluation Logic — Explicit Deny Always Wins

Memorize this algorithm. It is the most testable concept in all of DVA-C02 Domain 2.

  1. Default: implicit deny.
  2. Collect every applicable IAM policy: identity-based, resource-based, permissions boundary, session policy, and SCPs.
  3. If any of them has Effect: Deny matching the action, resource, and conditions — result is Deny (final).
  4. Otherwise look for at least one Effect: Allow that matches action, resource, and conditions. Not found → implicit deny.
  5. For cross-account access, both accounts must allow the action (unless the resource-based policy alone grants cross-account, which is allowed only for a subset of AWS services like Amazon S3 and AWS KMS).
  6. Permissions boundary and SCPs must also allow the action — they restrict but never grant. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html

Why explicit deny wins — a developer's mental model

Think of it like a defensive if statement at the top of your request handler: if (policy.explicitlyDenies(action)) return 403; runs before anything else. The allow logic only runs after the deny gate has been cleared. In production this lets you ship a "deny-all-dangerous-things" SCP at the organization root and stop worrying that a junior engineer's customer-managed IAM policy could accidentally grant it.

Cross-account access evaluation

When the calling principal and the target resource live in different AWS accounts, AWS IAM evaluates the call in both accounts. The caller's identity-based policy must allow the action, AND the target account must either (a) have a resource-based policy allowing the caller, or (b) have an IAM role the caller assumes via sts:AssumeRole whose identity-based policy allows the action. Amazon S3 is the most permissive case because Amazon S3 bucket policies alone can grant cross-account access.

A very common DVA-C02 wrong answer says "attach an IAM policy to the user in Account A granting s3:GetObject on an Amazon S3 bucket in Account B". That's necessary but not sufficient — Account B's Amazon S3 bucket policy must also allow the caller, or the caller must first assume a role in Account B. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic-cross-account.html

AWS Lambda Execution Role — The Most Tested Compute IAM Role

An AWS Lambda execution role is an IAM role that AWS Lambda assumes when your function starts. The trust policy must allow lambda.amazonaws.com to call sts:AssumeRole:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "lambda.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }]
}

Every AWS Lambda function must have exactly one execution role. AWS Lambda injects temporary credentials from that role into the function's environment as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables. The AWS SDK picks those up automatically through the default credential provider chain. You never hard-code credentials in an AWS Lambda handler — the execution role is how credentials get in.

At minimum the execution role should have the AWS-managed policy AWSLambdaBasicExecutionRole attached, which grants logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents on Amazon CloudWatch Logs. If the function runs inside a VPC it also needs AWSLambdaVPCAccessExecutionRole. If it reads from an Amazon Kinesis data stream, AWSLambdaKinesisExecutionRole. For an Amazon SQS event source, AWSLambdaSQSQueueExecutionRole. For Amazon DynamoDB streams, AWSLambdaDynamoDBExecutionRole. Beyond that you add the AWS service permissions the function's code actually needs — dynamodb:PutItem on a specific table, s3:GetObject on a specific prefix — using the principle of least privilege.

Don't confuse the Lambda execution role (what the function is allowed to do) with the Lambda resource-based policy (who is allowed to invoke the function). An Amazon API Gateway integration, an Amazon S3 bucket event, and an Amazon EventBridge rule each add a statement to the Lambda function's resource-based policy — that's what lets the caller invoke the function. The execution role is about outbound permissions; the resource-based policy is about inbound invocation. Reference: https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html

EC2 Instance Profile — The EC2 Wrapper Around an IAM Role

An Amazon EC2 instance cannot use an IAM role directly. Instead, you wrap the IAM role in an instance profile (a 1:1 container) and attach the instance profile to the Amazon EC2 instance. Amazon EC2 then exposes rotating short-term credentials via the Instance Metadata Service (IMDS) at http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME. AWS SDKs use IMDS automatically and rotate credentials transparently — a fresh set is issued roughly every 6 hours. Use IMDSv2 (session-token-based) to protect against SSRF attacks; configure the instance to require IMDSv2 with HttpTokens=required when launching.

For the AWS Management Console and AWS CloudFormation, attaching an IAM role to an Amazon EC2 instance automatically creates a matching instance profile with the same name. If you use the AWS CLI or the AWS SDK directly, you must create the instance profile and call aws iam add-role-to-instance-profile yourself.

DVA-C02 distractor answers often say "attach the IAM role to the Amazon EC2 instance." The technically correct phrasing is "attach the instance profile (which contains the IAM role) to the Amazon EC2 instance." The distinction rarely matters in the AWS console (which hides the instance profile), but it does matter in AWS CLI and AWS CloudFormation scenarios. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html

ECS Task Role vs ECS Execution Role — A Classic Confusion

Amazon ECS uses two separate IAM roles per task, and mixing them up is the #1 DVA-C02 trap in the container deployment subject area.

ECS Task Role

The task role is the IAM role your application code inside the container uses. If your container calls aws s3 cp ... or aws dynamodb put-item ... at runtime, the required permissions belong on the task role. The task role is the direct analogue of an AWS Lambda execution role or an Amazon EC2 instance profile.

ECS Task Execution Role

The task execution role is the IAM role Amazon ECS (the managed service, not your container) uses to set the task up. It needs permission to pull the container image from Amazon ECR (ecr:GetAuthorizationToken, ecr:BatchGetImage), to write logs to Amazon CloudWatch Logs (logs:CreateLogStream, logs:PutLogEvents), and — critically — to retrieve secrets from AWS Secrets Manager or AWS Systems Manager Parameter Store when the task definition references them via the secrets attribute. That resolution happens during task startup, before your container runs, so Amazon ECS needs those permissions, not your container.

Side-by-side

IAM Role Who uses it Typical permissions When it fires
Task role Your application code inside the container dynamodb:PutItem, s3:GetObject, sqs:ReceiveMessage At runtime inside the container
Task execution role Amazon ECS agent on your behalf ecr:GetAuthorizationToken, logs:CreateLogStream, ssm:GetParameters, secretsmanager:GetSecretValue, kms:Decrypt During task launch

Both apply on AWS Fargate too — AWS Fargate tasks use the same task role and task execution role model. AWS Fargate adds one wrinkle: because there's no underlying Amazon EC2 instance with an IMDS, credentials for the task role are delivered via a specialized credentials endpoint inside the Amazon ECS agent, reached at http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI. The AWS SDK picks this up automatically through the default credential provider chain.

When your Amazon ECS task definition references a secret via secrets: [{name: DB_PASSWORD, valueFrom: arn:aws:secretsmanager:...}], the permission to call AWS Secrets Manager belongs to the task execution role, not the task role, because Amazon ECS resolves the secret before the container starts and injects it as an environment variable. Reference: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html

Amazon EKS IRSA — IAM Roles for Service Accounts

On Amazon EKS, individual pods can assume individual IAM roles via the IAM Roles for Service Accounts (IRSA) mechanism. IRSA works by:

  1. The Amazon EKS cluster publishes an OpenID Connect (OIDC) identity provider URL.
  2. You register that OIDC provider as an IAM identity provider in the AWS account.
  3. You create an IAM role whose trust policy allows sts:AssumeRoleWithWebIdentity for that OIDC provider, with a condition on system:serviceaccount:<namespace>:<serviceAccountName>.
  4. You annotate a Kubernetes service account with eks.amazonaws.com/role-arn: arn:aws:iam::...:role/....
  5. Every pod using that service account gets a projected service account token; the AWS SDK inside the pod picks it up and calls sts:AssumeRoleWithWebIdentity automatically.

The result: pod-level IAM isolation without any shared node-level credentials. This is the Amazon EKS equivalent of the Amazon ECS task role. Amazon EKS also now offers EKS Pod Identity, a simpler alternative that uses an agent on the node to inject credentials, but IRSA remains the DVA-C02 vocabulary you should know.

If a DVA-C02 question describes a Kubernetes pod running on Amazon EKS that needs to access Amazon S3 with its own dedicated IAM role, the answer involves IRSA and the STS call is sts:AssumeRoleWithWebIdentity — not the node's instance profile and not sts:AssumeRole. Reference: https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html

AWS STS Operations You Will Call from Code

AWS Security Token Service (AWS STS) is the AWS service that issues temporary security credentials. Every temporary credential set has three parts: an access key ID, a secret access key, and a session token — all three must be sent with every signed request. DVA-C02 expects you to name each of the four primary STS operations and know their differences.

sts:AssumeRole

The most common STS call. Any IAM principal (IAM user or another IAM role) calls AssumeRole with the ARN of the target role. The target role's trust policy must allow the caller. AWS STS returns credentials valid for 15 minutes to 12 hours (DurationSeconds parameter; default 1 hour; maximum capped by the target role's MaxSessionDuration). AssumeRole is how cross-account access works in code. You can pass:

  • ExternalId — an opaque string the target account requires, protecting against the confused-deputy problem for third-party vendors.
  • Policy or PolicyArns — session policies to further restrict this session.
  • DurationSeconds — 900 to 43200 (role max session duration).
  • SerialNumber + TokenCode — require MFA at assumption time.
  • RoleSessionName — a label that shows up in AWS CloudTrail logs so auditors can trace the session.

sts:AssumeRoleWithWebIdentity

Called by code that has already authenticated the user with a web identity provider (Amazon Cognito, Login with Amazon, Google, Facebook, or any OIDC-compliant IdP including Amazon EKS's OIDC issuer for IRSA). The caller does not need AWS credentials to call it; they present a WebIdentityToken issued by the IdP. AWS STS validates the token, checks the target IAM role's trust policy for the OIDC provider and conditions on the token claims, and returns credentials. This is the STS call behind Amazon Cognito identity pools, mobile-app-to-Amazon-S3 scenarios, and Amazon EKS IRSA.

sts:AssumeRoleWithSAML

The SAML equivalent of AssumeRoleWithWebIdentity. Used by workforce SSO integrations when the IdP speaks SAML 2.0 (Active Directory Federation Services, Microsoft Entra ID without IAM Identity Center, Okta, Ping). Less common in application code — usually done by the sign-in flow.

sts:GetSessionToken

Returns temporary credentials for the calling IAM user itself (not a different IAM role), typically in an MFA-wrapping scenario. The main use case: an IAM user has an IAM policy that requires MFA for destructive actions. The user first calls GetSessionToken with their MFA code; the returned credentials carry the aws:MultiFactorAuthPresent: true flag, and the user then uses those credentials for the MFA-gated calls. GetSessionToken never returns credentials that broaden the user's effective permissions — the session credentials inherit exactly the user's permissions, nothing more.

sts:GetFederationToken

Called by a trusted IAM user (never by a role) on behalf of a federated user that does not exist in AWS IAM. The classic pattern: a backend service has IAM user credentials, an external customer authenticates to that backend with their own non-AWS identity, and the backend calls GetFederationToken with a session policy scoped to that customer's data. AWS STS returns credentials valid for 15 minutes to 36 hours. Modern AWS architecture almost always prefers AssumeRole over GetFederationToken, but the operation is still on the DVA-C02 blueprint.

STS call-site comparison

STS operation Who calls it Input credentials Duration range Typical use
AssumeRole Any IAM principal Required 15 min – 12 h Cross-account, role switching, explicit role elevation
AssumeRoleWithWebIdentity Anyone with an OIDC/Web token No AWS creds 15 min – 12 h Mobile apps, Cognito, EKS IRSA
AssumeRoleWithSAML Anyone with a SAML assertion No AWS creds 15 min – 12 h Corporate SSO to AWS Console/CLI
GetSessionToken IAM user Required 15 min – 36 h MFA-wrapping the caller's own credentials
GetFederationToken IAM user (trusted backend) Required 15 min – 36 h Legacy federation with session policies

Temporary credentials refresh inside the AWS SDK

Every AWS SDK (boto3 for Python, AWS SDK for JavaScript v3, AWS SDK for Java v2, AWS SDK for Go, etc.) ships a default credential provider chain that looks for credentials in this order: environment variables, shared credentials file, AWS IAM Identity Center SSO cache, container credentials endpoint (for Amazon ECS / AWS Fargate), IMDSv2 (for Amazon EC2), AssumeRoleWithWebIdentity (for Amazon EKS IRSA or AWS Lambda with AWS_WEB_IDENTITY_TOKEN_FILE), and finally any explicit credentials you pass. When the resolved credential provider returns temporary credentials, the AWS SDK caches them and automatically re-fetches when the expiry is within a small buffer (typically 5 to 15 minutes). You never call sts:AssumeRole manually in a loop; the SDK handles the refresh. For AssumeRole specifically, the SDK's STS.AssumeRoleProvider re-calls STS ahead of Expiration and swaps the credentials behind the scenes — your code just keeps calling the high-level AWS SDK client.

  • Temporary credentials always carry an Expiration timestamp.
  • AWS SDKs refresh automatically when near expiry; you should not re-call STS manually.
  • On an AWS Lambda function, the per-invocation credentials are already refreshed by AWS Lambda on your behalf — don't store them in module-level variables across cold-start boundaries without caching checks.
  • On an Amazon EC2 instance, credentials come from IMDS and rotate every ~6 hours; always use IMDSv2.
  • On Amazon ECS / AWS Fargate, credentials come from the container credentials endpoint — rotate on the same schedule.
  • On Amazon EKS IRSA, the SDK re-calls AssumeRoleWithWebIdentity as the projected token file changes. Reference: https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html

IAM Roles Anywhere — IAM for On-Premises and Non-AWS Workloads

AWS IAM Roles Anywhere lets workloads running outside AWS (on-premises servers, containers in another cloud, CI runners) obtain temporary AWS credentials without creating long-term IAM users. The workload holds an X.509 certificate issued by a certificate authority that you have registered as a trust anchor in AWS IAM Roles Anywhere. The workload presents the certificate and a signed request to the CreateSession endpoint, AWS IAM Roles Anywhere validates it, and returns temporary AWS credentials scoped to a profile (which names the IAM role to assume and optional session policies). DVA-C02 treats this as awareness-level: know that it exists, know it is the modern replacement for distributing long-term access keys to data-centre servers or build agents, and know it issues the same kind of temporary credentials sts:AssumeRole does.

If a question describes an on-premises batch job that needs to call Amazon S3 and the distractors include "create an IAM user with access keys on the server", the correct answer in 2026 is almost always AWS IAM Roles Anywhere with a trust anchor pointing at the company's private certificate authority. Reference: https://docs.aws.amazon.com/rolesanywhere/latest/userguide/introduction.html

IAM Identity Center — Workforce SSO, Brief for Developers

For DVA-C02 you need awareness-level knowledge of AWS IAM Identity Center even though it's primarily a workforce and governance tool. Key developer-facing facts:

  • IAM Identity Center federates human sign-in across many AWS accounts. Developers sign in once at a portal URL, pick an AWS account, pick a permission set, and get short-term credentials.
  • Permission sets materialize as IAM roles inside each target account with a name prefixed AWSReservedSSO_.
  • IAM Identity Center integrates with the AWS CLI v2 via aws configure sso and refreshes credentials for developers without ever placing long-term access keys in ~/.aws/credentials.
  • IAM Identity Center is the modern recommended way for workforce access; classic SAML 2.0 federation directly to IAM roles still works but IAM Identity Center is simpler.

IAM Access Analyzer Policy Generation from AWS CloudTrail

AWS IAM Access Analyzer has a policy generation capability that inspects an IAM role's activity in AWS CloudTrail over a configurable time window (up to 90 days) and produces a tight, least-privilege IAM policy listing only the actions that role actually used. On DVA-C02, this is the answer whenever a question asks "how can a developer refine an overly broad IAM policy after shipping a prototype?" Steps:

  1. Deploy with a wide AWS-managed IAM policy (or a wildcard for speed).
  2. Run the workload for a representative period.
  3. Run IAM Access Analyzer policy generation against that IAM role.
  4. Review the generated IAM policy; attach it in place of the wide one.
  5. Redeploy and retest.

Access Analyzer also has external access analysis that watches resource-based policies (Amazon S3 bucket policies, IAM role trust policies, AWS KMS key policies, AWS Lambda resource policies, Amazon SNS/SQS resource policies) and flags any grant of access to a principal outside your trust zone.

When a DVA-C02 scenario asks about tightening overly broad permissions based on actual activity, think AWS IAM Access Analyzer policy generation. When it asks about detecting Amazon S3 buckets shared outside the account by mistake, think AWS IAM Access Analyzer external access findings. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-policy-generation.html

Cross-Account Access Patterns for Developers

Three DVA-C02 patterns repeat for cross-account access, and you should be able to choose between them in your sleep.

Pattern A — sts:AssumeRole with trust policy

Account A developer needs occasional access to Amazon DynamoDB in Account B. Create an IAM role in Account B whose trust policy allows arn:aws:iam::111111111111:root (Account A) or a specific IAM user/role in Account A to call sts:AssumeRole. Attach the least-privilege Amazon DynamoDB IAM policy to the role. The developer calls aws sts assume-role --role-arn arn:aws:iam::222222222222:role/DynamoReader ..., receives short-term credentials, and uses them. Add an ExternalId if Account B is a third party.

Pattern B — Resource-based policy only

Account A AWS Lambda function needs to read from an Amazon S3 bucket in Account B. Add an Amazon S3 bucket policy in Account B allowing the Account A Lambda execution role ARN s3:GetObject. The AWS Lambda function's execution role also needs s3:GetObject on that ARN. No AssumeRole call needed — Amazon S3 supports cross-account via resource-based policy alone. Amazon SNS, Amazon SQS, AWS Lambda, AWS KMS, and Amazon ECR are other AWS services that support this pattern.

Pattern C — IAM Identity Center permission sets

Human developer needs to switch between five AWS accounts every day. IAM Identity Center, permission sets, aws configure sso. No manual AssumeRole scripts at all.

DVA-C02 distractors often suggest attaching an IAM policy in Account B directly to an IAM user in Account A. You can't — an IAM policy in Account B can only be attached to a principal inside Account B. Cross-account access must go through either sts:AssumeRole or a resource-based policy in Account B. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_common-scenarios_aws-accounts.html

IAM Condition Keys — Deep Dive for Developers

Condition keys are how DVA-C02 questions distinguish good candidates from great ones. Know these by heart:

  • aws:MultiFactorAuthPresent / aws:MultiFactorAuthAge — require MFA, optionally within N seconds.
  • aws:SourceIp — CIDR list for caller IP. Uses IpAddress or NotIpAddress operators.
  • aws:SourceVpc / aws:SourceVpce — restrict to a specific VPC or VPC endpoint. Essential for "only accessible from our VPC" Amazon S3 bucket policies.
  • aws:RequestedRegion — enforce "no Amazon EC2 outside us-east-1".
  • aws:SecureTransport — require HTTPS ("aws:SecureTransport": "true").
  • aws:PrincipalOrgID — grant access only to identities inside your AWS Organizations organization (stops external leaks when paired with wildcard principal).
  • aws:PrincipalTag/Key and aws:ResourceTag/Key — attribute-based access control (ABAC). Tag the IAM role with Department=Finance, tag the Amazon S3 objects with Department=Finance, write one policy that allows access when aws:PrincipalTag/Department == aws:ResourceTag/Department.
  • aws:SourceArn, aws:SourceAccount — for service-to-service calls (for example, Amazon SNS publishing to Amazon SQS), prevents the confused-deputy problem.
  • sts:ExternalId — require a specific string on sts:AssumeRole calls, the standard confused-deputy mitigation for third-party vendors.
  • sts:RoleSessionName — enforce a specific session name, useful for audit trail.
  • AWS service-specific keys — s3:prefix, s3:x-amz-server-side-encryption, dynamodb:LeadingKeys, ec2:ResourceTag/Key.

Common DVA-C02 IAM Exam Traps

Trap 1 — Explicit deny doesn't require a matching allow

If any applicable IAM policy has Effect: Deny for the action, the request is denied even if nothing explicitly allowed it. An explicit deny does not need a matching allow to "cancel out".

Trap 2 — SCPs don't grant

An SCP that says Effect: Allow, Action: s3:* is not sufficient by itself to let a caller use Amazon S3. The caller's IAM policy must also grant the action.

Trap 3 — Permissions boundaries don't grant either

A permissions boundary that allows s3:* is not sufficient for the caller to use Amazon S3. The boundary only caps what the identity-based IAM policy can effectively grant.

Trap 4 — Task role vs task execution role

Runtime Amazon S3 access from the container → task role. Image pull from Amazon ECR and secret fetch from AWS Secrets Manager during launch → task execution role. If the question is "task cannot start because container image cannot be pulled", it's the execution role. If the question is "task runs fine but code throws AccessDenied on s3:GetObject", it's the task role.

Trap 5 — AssumeRole with an IAM user inside the same account for MFA

If you want to require MFA for destructive actions from your own IAM user, the idiomatic path is sts:GetSessionToken with MFA, not sts:AssumeRole. AssumeRole with MFA is also valid but adds a role abstraction that isn't needed.

Trap 6 — Resource-based policy on an AWS Lambda function vs execution role

Inbound (who may invoke) = resource-based policy. Outbound (what the function may do) = execution role. If the question is "Amazon API Gateway calls the AWS Lambda function and gets 403 AccessDenied", check the Lambda resource-based policy.

Trap 7 — IMDSv1 vs IMDSv2 and SSRF

IMDSv2 requires a session token (PUT /latest/api/token). An SSRF vulnerability in an Amazon EC2 application that only supports IMDSv1 can be used to steal the instance profile credentials. If a DVA-C02 question mentions SSRF on Amazon EC2 and credential theft, the answer is "require IMDSv2".

Trap 8 — Lambda in a VPC and the execution role

Putting an AWS Lambda function inside a VPC does not change the execution role's basic needs; the function still needs the AWSLambdaVPCAccessExecutionRole managed policy (or equivalent ec2:CreateNetworkInterface / ec2:DescribeNetworkInterfaces / ec2:DeleteNetworkInterface permissions) in addition to its application permissions.

Trap 9 — Cross-account AWS KMS

AWS KMS cross-account use always requires both the key policy in the key's account to allow the caller, and an IAM policy in the caller's account granting the AWS KMS action. AWS KMS is stricter than Amazon S3 here.

Trap 10 — AssumeRoleWithWebIdentity vs AssumeRole vs IAM user for mobile apps

A mobile app that uploads photos to Amazon S3 must never embed IAM user credentials. The right answer is AssumeRoleWithWebIdentity — usually brokered by Amazon Cognito identity pools.

Numbers and Must-Memorize Facts

  • AWS IAM is global, free of charge.
  • IAM policy Version for modern syntax: 2012-10-17.
  • sts:AssumeRole duration: 15 min to 12 hours (capped by role's MaxSessionDuration).
  • sts:GetSessionToken and sts:GetFederationToken duration: 15 min to 36 hours.
  • Amazon EC2 instance profile credentials from IMDS rotate every ~6 hours.
  • Up to 5 versions kept per customer-managed IAM policy.
  • Managed IAM policies can be attached to up to 10 identities by default (soft quota).
  • Policy sizes: 2,048 characters (inline user), 5,120 (inline group), 10,240 (inline role), 6,144 for managed.
  • Amazon ECS task = task role (runtime) + task execution role (launch).
  • Amazon EKS IRSA uses sts:AssumeRoleWithWebIdentity under the hood.
  • Access Analyzer policy generation looks back up to 90 days of AWS CloudTrail history. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
  • "Amazon ECS task cannot pull its container image from Amazon ECR" → task execution role missing ecr:*.
  • "AWS Lambda function returns AccessDeniedException when writing to Amazon DynamoDB" → execution role missing dynamodb:PutItem.
  • "Amazon EKS pod needs dedicated IAM permissions" → IRSA via sts:AssumeRoleWithWebIdentity with service account annotation.
  • "On-prem CI runner needs AWS credentials" → AWS IAM Roles Anywhere with trust anchor.
  • "Refine an overly broad IAM role after a month in production" → AWS IAM Access Analyzer policy generation from AWS CloudTrail.
  • "Cross-account access from Account A to Amazon S3 bucket in Account B" → bucket policy in B + IAM policy in A, or role in B assumed via sts:AssumeRole.
  • "Third-party vendor accesses our AWS account" → IAM role with trust policy + sts:ExternalId condition.
  • "SSRF steals Amazon EC2 credentials" → require IMDSv2.
  • "Force all developers to use MFA before destructive action" → aws:MultiFactorAuthPresent: true condition or sts:GetSessionToken + MFA.

FAQ — DVA-C02 IAM Top Questions

Q1: What's the difference between an identity-based policy and a resource-based policy, and when do I attach each?

An identity-based policy is attached to an IAM user, IAM group, or IAM role and lists what that principal may do. A resource-based policy is attached to an AWS resource (Amazon S3 bucket, AWS Lambda function, AWS KMS key, Amazon SNS topic, Amazon SQS queue, Amazon ECR repository, Amazon API Gateway resource) and lists which principals may act on it. Use identity-based policies for most everyday permissions; use resource-based policies when you need cross-account access without forcing the caller to assume a role (Amazon S3 is the classic case), when a service needs to invoke your AWS Lambda function (Amazon EventBridge, Amazon API Gateway), or when AWS KMS demands it (AWS KMS key policies are always required, they are never optional).

Q2: How does sts:AssumeRole differ from sts:AssumeRoleWithWebIdentity?

sts:AssumeRole is called by an existing IAM principal (IAM user or IAM role) with valid AWS credentials; AWS STS checks the target role's trust policy, optionally requires MFA or an ExternalId, and returns temporary credentials. sts:AssumeRoleWithWebIdentity is called by anyone holding a token from a trusted OIDC or web identity provider (Amazon Cognito, Login with Amazon, Google, Facebook, or Amazon EKS's OIDC issuer for IRSA). The caller has no AWS credentials at all; AWS STS validates the web token, checks the role's trust policy for that OIDC provider plus any conditions on the token claims, and returns credentials. AssumeRoleWithWebIdentity is what powers mobile-app-to-AWS access and Amazon EKS IRSA.

Q3: What is a permissions boundary and when should a developer use one?

A permissions boundary is an IAM policy attached to an IAM user or IAM role as a boundary. It does not grant permissions; it only caps them. The identity's effective permissions are the intersection of its identity-based policies and the boundary. You use one when you delegate the ability to create IAM roles to other developers but want to guarantee that the roles they create can never exceed a fixed ceiling — for example, "developers can create new AWS Lambda execution roles but those roles can never grant iam:* or kms:*". The boundary prevents privilege escalation.

Q4: What's the difference between the Amazon ECS task role and the task execution role?

The task role is used by your application code inside the container — it's what your AWS SDK client picks up to call Amazon DynamoDB, Amazon S3, Amazon SQS at runtime. The task execution role is used by the Amazon ECS agent on your behalf during task launch — pulling the container image from Amazon ECR, writing logs to Amazon CloudWatch Logs, and resolving secrets from AWS Secrets Manager or AWS Systems Manager Parameter Store that are referenced in the task definition. Mix them up and you'll see "task fails to start" (execution-role issue) or "task runs but API call returns AccessDenied" (task-role issue). Both also apply on AWS Fargate.

Q5: How does explicit deny interact with other IAM policy layers?

An explicit deny in any applicable IAM policy — identity-based, resource-based, permissions boundary, session policy, or SCP — is final. No allow anywhere can override it. This is the first rule the IAM policy evaluation engine applies. That is also why explicit deny is the safest guardrail mechanism: you can ship a "deny all dangerous actions" SCP at your organization root and be confident no downstream IAM policy can accidentally enable those actions in a member account.

Q6: How do AWS SDKs refresh temporary credentials?

Every AWS SDK uses a default credential provider chain. When that chain resolves temporary credentials (from AWS Lambda environment variables, from IMDSv2 on Amazon EC2, from the container credentials endpoint on Amazon ECS and AWS Fargate, from an AssumeRole provider for explicit role-switching, or from AssumeRoleWithWebIdentity for Amazon EKS IRSA), the SDK caches them along with their Expiration timestamp. Before every request, the SDK checks if the credentials are expiring within a small buffer (5 to 15 minutes) and, if so, transparently re-fetches. You should never hand-write a credential-refresh loop — if you see one in a DVA-C02 scenario, it's probably the wrong answer.

Q7: What's ExternalId and why does a third-party vendor ask for it?

sts:ExternalId is a condition key in the target IAM role's trust policy and a parameter to the sts:AssumeRole call. It prevents the confused-deputy problem when you let a third-party vendor access your AWS account via cross-account AssumeRole. The vendor generates a unique opaque string per customer; your trust policy requires Condition: {StringEquals: {sts:ExternalId: "your-unique-string"}}. If another customer of the same vendor tried to trick them into calling your role, the ExternalId would not match and the assumption would fail.

Q8: When should I use AWS IAM Roles Anywhere instead of IAM user access keys?

Almost always, in 2026. Long-term IAM user access keys stored on on-premises servers, in build agents, or in another cloud are a persistent security risk. AWS IAM Roles Anywhere lets the same workloads obtain temporary AWS credentials by presenting an X.509 certificate from a certificate authority you have registered as a trust anchor, and the credentials rotate automatically. Use IAM user access keys only when the target platform genuinely cannot do certificate-based authentication.

Q9: Why does my cross-account AWS KMS call fail even though my IAM policy allows kms:Decrypt?

Because AWS KMS requires both the caller's IAM policy AND the AWS KMS key policy in the key's account to allow the action. Unlike Amazon S3, AWS KMS cross-account access is not granted by resource-based policy alone nor by identity-based policy alone. Add a statement to the key policy that names the caller's IAM role ARN, and confirm the caller's IAM policy also grants kms:Decrypt on that key ARN.

Q10: How do I produce a least-privilege IAM policy from observed behaviour?

Deploy with a broad AWS-managed IAM policy, run the workload for at least a few days (ideally through a full business cycle), then use AWS IAM Access Analyzer policy generation to inspect up to 90 days of AWS CloudTrail history and generate a refined IAM policy containing only the actions the role actually invoked. Review the generated IAM policy, attach it in place of the broad one, redeploy, and monitor AWS CloudTrail for new AccessDenied events that indicate a missed action.

Further Reading

Official sources