IAM roles, policies and STS: DVA-C03 study notes and practice questions
What to know about IAM roles, policies and STS for the DVA-C03 exam, from the Security domain (26% of the exam guide), then 3 free questions to test it. Part of the DVA-C03 study guide.
These questions describe an AccessDenied error, a cross-account call that fails, or a job that loses access partway through. Find the policy that is missing or the session limit that is being hit.
Roles instead of keys
Lambda functions, ECS tasks, EC2 instances and CodeBuild projects should get credentials from an IAM role, which the SDK picks up automatically. Long-term access keys are for systems outside AWS.
A role has two policies. The trust policy says who may assume the role. The permissions policy says what the role may do. Both must allow the call, and a resource policy on the target must too when the caller is in another account.
Cross-account access
There are two patterns:
Role in the target account. The target account creates a role that trusts the caller’s account or role. The caller’s role needs sts:AssumeRole on that role’s ARN. Both sides must allow the call.
Resource policy. The target resource (an S3 bucket, an SQS queue, a KMS key) names the external principal directly. No AssumeRole is needed.
Session limits
When one assumed role is used to assume a second role (role chaining), the second session is capped at one hour, however long the role’s maximum session duration is. A three-hour batch job that loses access an hour in is a chaining problem. The fix is to remove the second hop: give the first role the access it needs, or add a resource policy on the target, such as a bucket policy, that lets the first role in directly.
Calling sts:AssumeRole when the execution role already has the permissions adds a second hop for no gain. Use sts:GetCallerIdentity to see which principal your code runs as; it needs no permissions. Remember that the SDK’s default credential chain reads environment variables before the instance or function role, so exported keys override the role. To read an encoded authorization failure message, call sts:DecodeAuthorizationMessage.
iam:PassRole
Creating or updating a Lambda function, ECS task or CloudFormation stack with a role requires iam:PassRole on that role, for the identity that makes the call. A PassRole failure is a problem for the deployer, not the function.
Narrowing permissions
Permissions boundaries cap the most a role or user can ever get.
Session policies narrow a session that is being assumed, without changing the role. The session gets only what the role’s policies, its boundary and the session policy all allow.
Tags with attribute-based access control (ABAC) let one policy cover many resources that share a tag.
Explicit deny always wins over an allow. A service control policy (SCP) in AWS Organizations can deny an action for a whole account, even when the account’s own policies allow it.
How to choose
Scenario wording
Answer
Code on AWS needs credentials
Attach an IAM role; do not add keys
Lambda role has the policy but a call still fails
Check the target’s resource policy and the trust policy
Access must cross accounts, no keys
AssumeRole into a role in the target account, or a resource policy
Job runs longer than an hour across a second role
Remove the chain or avoid the second AssumeRole
Deployment fails with PassRole
Grant iam:PassRole to the deployer
Access must never exceed a set limit
Permissions boundary or SCP
Third party assumes a role in your account
Trust policy with an sts:ExternalId condition
CI pipeline outside AWS needs credentials
OIDC federation with a scoped trust policy sub condition
Draft a least-privilege policy from real use
IAM Access Analyzer policy generation
Common traps
Adding sts:AssumeRole to code that already has the rights it needs.
Fixing an AccessDenied on the caller when the target’s resource policy is the missing part.
Creating an IAM user with access keys for a Lambda function.
Assuming a role session lasts as long as the role’s maximum session duration when it was chained.
Forgetting that an SCP can deny access no matter what the role allows.
A Lambda function in account 111111111111 saves orders to a DynamoDB table in account 222222222222.
The security team for account 222222222222 requires that the function reaches the table only through an IAM role that they own and control, and no long-term credentials may be stored anywhere. The function's code uses the AWS SDK.
Which TWO steps are required? (Choose two.)
Choose two answers.
AA. In account 222222222222, create a role with write access to the table and a trust policy that names the function's execution role.
BB. Attach a resource-based policy to the table that allows the function's execution role to call dynamodb:PutItem.
CC. Add a statement to the function's resource-based policy that allows the role in account 222222222222 to invoke the function.
DD. Allow sts:AssumeRole on the role's ARN in the execution role, and have the code call AssumeRole to get temporary credentials.
EE. Create an IAM user in account 222222222222 with table access, and keep its access key in AWS Secrets Manager for the function.
Show the answer and explanation
Answers: A, D
A. Right: Correct. The role in the table's account holds the DynamoDB permissions, and its trust policy decides who may assume it. Naming the execution role as the trusted principal lets the function, and nothing else, take on the role. Learn more: Cross-account access with IAM roles (opens in a new tab)
C. Wrong: A function's resource-based policy controls who can invoke the function, not what the function can reach. It does nothing to give the function access to a table in another account. Learn more: Lambda resource-based policies (opens in a new tab)
D. Right: Correct. The caller's own identity policy must also allow sts:AssumeRole on the target role, because a trust policy alone is not enough. The SDK then uses the temporary credentials from AssumeRole for DynamoDB calls. Learn more: Cross-account access with IAM roles (opens in a new tab)
E. Wrong: An IAM user's access key is a long-term credential, which the requirement rules out, even when stored in Secrets Manager. It also bypasses the role that the security team wants to manage. Temporary credentials from AssumeRole are the intended approach.
Explanation
Cross-account role access needs both sides: the role in the table's account must trust the function's execution role, and the execution role must be allowed to call sts:AssumeRole on that role. The code then uses the temporary credentials. A table resource policy or an IAM user's keys would reach the table but not through a role the table owner controls without stored secrets.
Both sides are needed: the role trusts the execution role, and the execution role may call sts:AssumeRole on it.
A developer defines an S3 bucket, a Lambda function and the bucket's object-created notification in one AWS CloudFormation template.
The function's execution role already has every permission the function needs at run time, but Amazon S3 is not yet allowed to start the function, so the notification cannot be set up.
What should the developer add to the template?
Choose one answer.
AA. A statement in the function's execution role that allows the S3 service to call lambda:InvokeFunction on the function's ARN.
BB. An AWS::Lambda::EventSourceMapping resource that links the bucket to the function and the event types it should handle.
CC. An AWS::Lambda::Permission resource that lets s3.amazonaws.com invoke the function, limited to this bucket and account.
DD. A bucket policy statement that allows the function's execution role to call s3:GetObject on every object in the bucket.
Show the answer and explanation
Answer: C
A. Wrong: The execution role is what the function assumes while it runs, so it controls what the function can call, not who can start it. Permission to invoke a function is granted on the function itself through a resource-based policy. Learn more: Lambda resource-based policies (opens in a new tab)
B. Wrong: Event source mappings are used for services that Lambda polls, such as SQS queues, Kinesis streams and DynamoDB streams. S3 pushes notifications to the function instead, so it needs an invoke permission rather than a mapping.
C. Right: Correct. This adds a resource-based policy statement to the function with the S3 service as principal. Adding the source ARN and account conditions means only this bucket in this account can start the function. Learn more: Lambda resource-based policies (opens in a new tab)
D. Wrong: That lets the function read objects once it is running, which is a different problem. It does not give S3 permission to start the function, so the notification is still rejected.
Explanation
S3 pushes events to Lambda, so the function needs a resource-based policy that names the S3 service as the principal; in CloudFormation that is an AWS::Lambda::Permission resource. Conditions on the source ARN and account stop other buckets from invoking the function. Execution role statements and bucket policies control other directions of access.
A developer whose role has only Amazon EC2 permissions runs a deployment script that calls ec2:RunInstances.
The call fails with UnauthorizedOperation and a long encoded authorization failure message. To fix the policy, the developer needs the decoded details, including the action, the resource and the condition values that were evaluated.
What should be done?
Choose one answer.
AA. Ask an administrator to allow sts:DecodeAuthorizationMessage for the developer's role, then call the AWS STS DecodeAuthorizationMessage API.
BB. Run the message through a Base64 decoder, because it is plain JSON that has only been Base64-encoded for transport.
CC. Paste the message into the IAM policy simulator, which accepts encoded failure messages and lists the matching statements.
DD. Find the failed call in CloudTrail event history and read the decoded message that CloudTrail stores with it.
Show the answer and explanation
Answer: A
A. Right: Correct. The message is encoded because it can contain details the caller should not see by default, so decoding is a separate permission. Once allowed, STS returns the decoded detail, including the principal, action, resource and condition values. Learn more: DecodeAuthorizationMessage (opens in a new tab)
B. Wrong: The message is not simply Base64-encoded JSON. Only STS can decode it, and only for callers that have been given permission to do so.
C. Wrong: The policy simulator tests a policy against actions that you choose; it does not accept an encoded failure message. It would not show the condition values from the failed request either.
D. Wrong: CloudTrail records API activity and can show that the call failed, but the way to decode this message is the dedicated STS API. Searching event history is not a replacement for it. Learn more: DecodeAuthorizationMessage (opens in a new tab)
Explanation
Encoded authorization failure messages are decoded with the STS DecodeAuthorizationMessage API, and the caller needs sts:DecodeAuthorizationMessage. The decoded result shows whether an explicit deny or a missing allow caused the failure, with the action, resource and condition values. Base64 tools, the policy simulator and CloudTrail do not decode the message.
Want more on IAM roles, policies and STS? The 5 full-length practice sets have 15 more IAM roles, policies and STS questions, 390 in all, none of them in the free exam. One payment of $14.99, no subscription. See the practice sets →