DVA-C02Chapter 7 of 101Objective 2.1

IAM for Developers: Roles and Policies

This chapter covers IAM (Identity and Access Management) from a developer's perspective, focusing on roles and policies—the core mechanisms for controlling access to AWS resources. For the DVA-C02 exam, approximately 10–15% of questions touch on IAM-related topics, often in scenarios involving cross-account access, temporary credentials, or least privilege. Understanding how policies are evaluated, how roles differ from users, and how to write effective policies is essential for both the exam and real-world development. This chapter will give you the precise knowledge needed to tackle these questions confidently.

25 min read
Intermediate
Updated May 31, 2026

IAM: The Security Guard with a Checklist

Imagine a large corporate building with many rooms, each containing sensitive documents. The building is your AWS account, and the rooms are services like S3, DynamoDB, or Lambda. There is a security guard at the entrance (IAM) who controls access. Every person (IAM user or role) must present an ID card (credentials) to enter. The guard does not decide on the spot who gets in; instead, he has a massive binder (policy) that lists exactly who can access which rooms and what they can do inside (read, write, delete). If the binder says 'Alice can read Room 12 and write to Room 15,' Alice can only do those actions. If she tries to enter Room 20, the guard stops her, even if she has a key. The binder can also grant temporary access to contractors (roles) by giving them a visitor badge that expires after a few hours. Importantly, the guard never asks 'should this person be allowed?'—he just checks the binder. If the binder is missing a page (no policy), the person is denied by default. This is exactly how IAM works: policies are the rules, and the guard (IAM service) enforces them without any 'maybe'—it's always explicit allow or implicit deny.

How It Actually Works

What is IAM and Why Does It Exist?

AWS Identity and Access Management (IAM) is a web service that helps you securely control access to AWS resources. It is the single point of control for authentication (who can sign in) and authorization (what they can do). Before IAM, AWS accounts had only one root user with unlimited access—a major security risk. IAM was introduced to allow granular, least-privilege access. For developers, IAM is crucial because every AWS API call is authenticated and authorized by IAM. Whether you are using the AWS CLI, SDK, or console, IAM is in the background checking every request.

How IAM Works Internally

When an entity (user, role, or service) makes an AWS API request, the request flows through the IAM policy evaluation engine. The process is: 1. Authentication: The requester provides credentials (access key ID and secret access key for API calls, or username/password for console). IAM verifies these against stored credentials. 2. Authorization: IAM evaluates all applicable policies to determine if the request is allowed or denied. The default is implicit deny (no explicit allow = deny). The evaluation logic uses a set of rules:

- By default, all requests are implicitly denied. - An explicit allow overrides an implicit deny. - An explicit deny overrides any allow. - The order of policies does not matter; all policies are evaluated together. 3. Decision: IAM returns either allow or deny. If denied, the API call fails with an AccessDenied error.

Key Components

Users: A permanent identity for a person or application. Users have long-term credentials (password for console, access keys for API). Users are best for humans who need ongoing access.

Groups: A collection of users. You attach policies to groups, and all users in the group inherit those policies. Groups simplify management—you manage policies once, not per user.

Roles: An identity that can be assumed by anyone who needs it, including AWS services, users from other accounts, or federated users. Roles have no permanent credentials; instead, they provide temporary security credentials (via AWS STS) that expire (default 1 hour, max 12 hours). Roles are the preferred way to grant permissions to applications running on EC2, Lambda, or other services.

Policies: JSON documents that define permissions. There are two types: identity-based policies (attached to users, groups, or roles) and resource-based policies (attached to resources like S3 buckets or SQS queues). Policies consist of statements with Effect (Allow or Deny), Action (e.g., s3:GetObject), Resource (e.g., arn:aws:s3:::my-bucket/*), and optional Condition (e.g., IP address range).

Defaults and Important Values

Maximum policy size: 6,144 characters for identity-based policies, 20,480 characters for resource-based policies.

Maximum number of policies per IAM role: 10 (can be increased via support request).

Maximum number of roles per AWS account: 1,000 (soft limit, can be increased).

STS token expiration: Default 1 hour, configurable from 15 minutes to 12 hours for roles (via the API). For assumed role sessions, the max is 12 hours.

IAM best practices: Use roles for EC2 instances, use groups for users, enable MFA, rotate access keys regularly, use conditions for extra security.

How Policies Are Evaluated

The evaluation logic is often tested on the exam. The key rule: Explicit Deny always wins. If there is any policy that explicitly denies an action, that action is denied regardless of any allows. If there is no explicit deny but at least one explicit allow, the action is allowed. If there is no explicit allow and no explicit deny, the action is implicitly denied. This is known as the 'deny override' principle.

For example, consider a user who has an S3 bucket policy that allows s3:GetObject on a bucket, but also has an IAM policy that denies s3:GetObject on that same bucket. The deny wins—the user cannot read objects. This is a common exam trap: candidates think an allow in the bucket policy overrides the IAM deny, but it does not.

Writing Policies: The ARN Structure

Every AWS resource has an Amazon Resource Name (ARN). The format is:

arn:partition:service:region:account-id:resource

Example: arn:aws:s3:::my-bucket/* for all objects in my-bucket.

Policies use ARNs to specify which resources the policy applies to. The Resource field can be a specific ARN or a wildcard * for all resources. However, using * is dangerous and should be avoided—always scope to the least permissive resource.

Service-Linked Roles

Some AWS services require permissions to call other services on your behalf. AWS creates service-linked roles automatically, preconfigured with the necessary permissions. For example, Amazon EC2 Auto Scaling creates a service-linked role named AWSServiceRoleForAutoScaling. You cannot delete these roles unless you first delete the service that uses them. This is a common exam topic: knowing that service-linked roles are predefined and cannot be modified by the user.

Cross-Account Roles

To grant access to resources in one account from another account, you use cross-account roles. The process: 1. Account A creates an IAM role with a trust policy that allows Account B's users to assume the role. 2. Account B's admin grants its users permission to call sts:AssumeRole on that role. 3. Users in Account B assume the role and receive temporary credentials to access Account A's resources.

Cross-account roles are preferred over resource-based policies when you need to delegate access across accounts without sharing long-term credentials. The exam often asks which method to use for cross-account access: roles vs. resource-based policies. The rule: if the resource supports resource-based policies (e.g., S3, SQS, SNS), you can use them for cross-account access directly; otherwise, use roles.

IAM Permissions Boundaries

A permissions boundary is an advanced feature that sets the maximum permissions an identity-based policy can grant. It acts as a 'ceiling.' For example, if a user has a permissions boundary that allows only S3 actions, even if you attach a policy that allows EC2 actions, the user cannot perform EC2 actions because the boundary denies them. The effective permissions are the intersection of the identity-based policy and the permissions boundary. This is a high-difficulty exam topic.

IAM Policy Conditions

Conditions allow you to add extra constraints to a policy. Common condition keys: - aws:SourceIp: restrict access to a specific IP range. - aws:RequestedRegion: restrict API calls to a specific region. - aws:MultiFactorAuthPresent: require MFA for sensitive actions. - s3:x-amz-server-side-encryption: require encryption when uploading to S3.

Conditions are evaluated during authorization. If the condition is not met, the policy statement does not apply (the action is implicitly denied).

IAM for Developer Workflows

Developers often need to grant permissions to applications running on EC2 or Lambda. The correct approach is to create an IAM role and attach it to the EC2 instance (via instance profile) or to the Lambda function. The service then retrieves temporary credentials from the instance metadata service (for EC2) or from the Lambda runtime environment. Never store access keys in code or on disk—this is a security anti-pattern that the exam heavily penalizes.

CLI and SDK Usage

When using the AWS CLI, you configure credentials via aws configure, which stores them in ~/.aws/credentials. However, for EC2 roles, you do not need to configure credentials—the CLI automatically retrieves them from the instance metadata. The order of credential resolution is: 1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) 2. Shared credentials file (~/.aws/credentials) 3. CLI config file (~/.aws/config) 4. Instance metadata service (for EC2 roles) 5. Container credentials (for ECS tasks)

Knowing this order is critical for troubleshooting and exam questions.

IAM Best Practices for Developers

Use roles instead of users for applications.

Apply least privilege: start with a minimal policy and add permissions as needed.

Use groups to manage permissions for multiple users.

Enable MFA for privileged users.

Rotate access keys regularly.

Use conditions to restrict access based on network, time, or MFA.

Monitor IAM activity with CloudTrail.

Common Exam Scenarios

1.

EC2 accessing S3: Create an IAM role with S3 permissions, attach it to the EC2 instance profile. Do not use access keys.

2.

Lambda accessing DynamoDB: Attach a role to the Lambda function with DynamoDB permissions.

3.

Cross-account S3 access: Use bucket policy (resource-based) or cross-account role. The exam often asks which is simpler.

4.

Federated access: Use IAM roles with SAML or Web Identity Federation (Cognito).

5.

Service-linked roles: Recognize that AWS creates them automatically and you cannot modify them.

Policy Evaluation Example

Consider the following scenario:

An IAM user has an inline policy that allows ec2:DescribeInstances on all resources.

The same user is in a group that has a policy denying ec2:DescribeInstances on all resources.

What happens? The deny wins—the user cannot describe instances.

This is because explicit deny overrides explicit allow. The exam loves this pattern.

Walk-Through

1

Create an IAM Role

Navigate to the IAM console, select 'Roles', then 'Create role'. Choose the trusted entity type: for AWS services, select 'AWS service' and choose the service (e.g., EC2). This sets up the trust policy, which defines who can assume the role. The trust policy is a JSON document that specifies the principal (e.g., ec2.amazonaws.com) that is allowed to call sts:AssumeRole. By default, the trust policy allows the service to assume the role, but you can restrict it further with conditions. After selecting the service, click 'Next: Permissions'.

2

Attach Permissions Policy

On the permissions step, you attach one or more managed policies or create an inline policy that defines what the role can do. For example, attach 'AmazonS3ReadOnlyAccess' to allow read-only S3 access. You can also create a custom policy to scope permissions to specific buckets or actions. The policies attached here are identity-based policies for the role. After attaching policies, click 'Next: Tags' (optional) and then 'Next: Review'.

3

Name and Create the Role

Give the role a meaningful name, such as 'EC2-S3-ReadOnly-Role'. Optionally, add a description. Review the trust policy and permissions policies. Click 'Create role'. The role is now available in the account. Note the role's ARN, which looks like 'arn:aws:iam::123456789012:role/EC2-S3-ReadOnly-Role'. This ARN is used when you need to reference the role in other policies or when granting cross-account access.

4

Attach Role to EC2 Instance

When launching an EC2 instance, you can specify an IAM role under 'Configure Instance Details' > 'IAM role'. Alternatively, you can attach a role to an existing instance by selecting the instance, then 'Actions' > 'Security' > 'Modify IAM role'. This creates an instance profile (a container for the role) and associates it with the instance. The instance profile name is automatically generated based on the role name. Once attached, the EC2 instance can retrieve temporary credentials from the instance metadata service at http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name.

5

Test Access from EC2

SSH into the EC2 instance and use the AWS CLI to test access. For example, run 'aws s3 ls' to list S3 buckets. The CLI automatically retrieves credentials from the instance metadata service—no need to configure access keys. If the role has S3 read-only access, the command succeeds. If you try an action not allowed (e.g., 'aws s3 cp file.txt s3://bucket/'), it fails with an AccessDenied error. This confirms that the role is working and the permissions are correctly scoped.

What This Looks Like on the Job

Scenario 1: Microservices on ECS Accessing DynamoDB

A company runs a microservices architecture on Amazon ECS (Fargate). Each microservice needs to access specific DynamoDB tables. The naive approach would be to create one IAM user per service and embed access keys in environment variables. This is insecure and hard to manage. Instead, the team creates an IAM role for each ECS task definition, with a policy that allows only the required DynamoDB actions on specific tables. For example, the 'order-service' role has a policy allowing dynamodb:GetItem and dynamodb:PutItem on the Orders table only. The ECS task definition specifies the task role ARN. When the container starts, the ECS agent retrieves temporary credentials from the task metadata endpoint and injects them into the container via environment variables (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI). The SDK uses these credentials automatically. This setup ensures least privilege and eliminates hardcoded secrets. A common misconfiguration is attaching too broad a policy (e.g., DynamoDB full access) to all tasks, which violates least privilege and increases blast radius. The team monitors CloudTrail logs to detect any unexpected access patterns.

Scenario 2: Cross-Account Access for Data Analytics

A data analytics team in Account A needs to read data from an S3 bucket in Account B. The security team wants to avoid sharing long-term IAM users. The solution is to use a cross-account role. In Account B, an IAM role named 'DataAnalystRole' is created with a trust policy that allows Account A's root user or a specific IAM group to assume it. The permissions policy grants s3:GetObject and s3:ListBucket on the analytics bucket. In Account A, the team leader is granted permission to call sts:AssumeRole on the role ARN. When a data scientist needs access, they assume the role using the AWS CLI: 'aws sts assume-role --role-arn arn:aws:iam::AccountB:role/DataAnalystRole --role-session-name analytics-session'. This returns temporary credentials (access key, secret key, session token) valid for 1 hour (configurable up to 12 hours). The scientist then uses these credentials to access the S3 bucket. A common pitfall is forgetting to set the session token—if omitted, the request fails with an invalid access key error. Also, if the trust policy incorrectly specifies the principal (e.g., using the wrong account ID), the assume-role call fails with AccessDenied.

Scenario 3: Federated Access with Cognito

A mobile app uses Amazon Cognito for user authentication. Users sign in via Facebook or Google, and then need to access AWS resources (e.g., upload photos to S3). The app uses Cognito Identity Pools to exchange the social token for temporary AWS credentials. The developer creates an identity pool and configures an IAM role for authenticated users. The role's policy allows s3:PutObject on a specific S3 bucket prefixed with the user's identity ID (e.g., 'my-app-uploads/${cognito-identity.amazonaws.com:sub}/*'). This ensures each user can only upload to their own folder. The Cognito service assumes the role on behalf of the user and returns credentials. The app uses these credentials to make API calls directly. A common misconfiguration is using a single IAM user for all app users, which breaks auditability and least privilege. Cognito Identity Pools solve this by providing unique credentials per user. The exam tests understanding of the Cognito-to-IAM flow and the use of condition keys like ${cognito-identity.amazonaws.com:sub}.

How DVA-C02 Actually Tests This

The DVA-C02 exam tests IAM roles and policies under Domain 2: Security, Objective 2.1: 'Manage IAM roles and policies.' Expect 5–8 questions that directly assess your understanding of policy evaluation logic, temporary credentials, cross-account access, and best practices. The most common wrong answers stem from misunderstanding the deny-override principle and the difference between identity-based and resource-based policies.

Common Wrong Answers: 1. 'An explicit allow in a resource-based policy overrides an explicit deny in an identity-based policy.' This is false—explicit deny always wins regardless of policy type. Candidates confuse the fact that resource-based policies can grant cross-account access without requiring a role, but they do not override denies. 2. 'To allow an EC2 instance to access S3, create an IAM user and store access keys on the instance.' This is a security anti-pattern. The correct answer is to use an IAM role attached to the instance profile. The exam will present this as an option—always eliminate it. 3. 'IAM roles have permanent credentials.' Roles have temporary credentials via STS. Candidates might think roles are like users with long-term keys. 4. 'A service-linked role can be edited to add more permissions.' Service-linked roles are predefined and cannot be modified. You can only attach additional policies to the role, but you cannot change the trust policy or the core permissions.

Specific Numbers and Values: - STS token default expiration: 1 hour, max 12 hours. - Maximum policy size: 6,144 characters (identity-based), 20,480 (resource-based). - Maximum roles per account: 1,000. - Maximum policies per role: 10. - The condition key for MFA: 'aws:MultiFactorAuthPresent' (boolean). - The condition key for source IP: 'aws:SourceIp'.

Edge Cases: - When a role is assumed from a service like EC2, the session name is automatically generated. For cross-account roles, you can specify a session name. - If a policy has a condition that fails, the statement does not apply—it is not denied, just not evaluated. This means if there is another statement that allows the action without the condition, it could still allow. But if the only allow statement has a condition that fails, the action is implicitly denied. - Permissions boundaries: the effective permissions are the intersection of the identity-based policy and the boundary. This is a high-difficulty topic—rare but appears.

How to Eliminate Wrong Answers: - If the question involves 'permanent credentials' for an EC2 instance, eliminate that option. - If the question involves cross-account access and the resource supports resource-based policies (S3, SQS, SNS), look for the option that uses the resource-based policy directly. Otherwise, look for cross-account roles. - If the question mentions 'least privilege', look for the option that scopes actions and resources narrowly. - If the question asks about 'temporary credentials', think STS and roles, not users. - If the question includes 'service-linked role', remember that it is created by AWS and cannot be modified.

Key Takeaways

Explicit deny always overrides any allow—this is the cardinal rule of IAM policy evaluation.

IAM roles use temporary credentials from AWS STS; default expiration is 1 hour, max 12 hours.

Use IAM roles for EC2, Lambda, and ECS instead of storing access keys in code or on disk.

Cross-account access: use resource-based policies if the resource supports them; otherwise use cross-account roles.

Service-linked roles are predefined by AWS and cannot be modified—you can only attach additional policies.

Permissions boundaries set the maximum permissions an identity-based policy can grant; effective permissions are the intersection.

Maximum policy size: 6,144 characters for identity-based, 20,480 for resource-based.

The condition key 'aws:MultiFactorAuthPresent' can enforce MFA for sensitive actions.

IAM groups simplify permission management for users; attach policies to groups, not individual users.

Always apply least privilege: start with minimal permissions and add only what is necessary.

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

IAM User

Has long-term credentials (password and/or access keys).

Best for humans or applications that need persistent access.

Cannot be assumed by AWS services directly (except via STS).

Credentials can be rotated manually.

Not suitable for cross-account access (requires resource-based policies or roles).

IAM Role

Has temporary credentials via STS (default 1 hour, max 12 hours).

Best for applications running on AWS services (EC2, Lambda, ECS).

Can be assumed by AWS services, IAM users, or federated identities.

Credentials are automatically rotated by AWS.

Ideal for cross-account access via sts:AssumeRole.

Identity-Based Policy

Attached to a user, group, or role.

Controls what actions the identity can perform on which resources.

Cannot grant access to principals from other accounts directly (except via cross-account roles).

Evaluated along with other policies for the identity.

Works for all AWS services.

Resource-Based Policy

Attached to a resource (e.g., S3 bucket, SQS queue).

Controls which principals can access the resource and what actions they can perform.

Can grant access to principals in other accounts directly (no role needed).

Evaluated separately from identity-based policies.

Only supported by certain services (S3, SQS, SNS, Lambda, etc.).

Watch Out for These

Mistake

IAM roles have long-term access keys like users.

Correct

IAM roles do not have permanent credentials. They provide temporary security credentials via AWS STS, which expire after a configurable period (default 1 hour, max 12 hours). You cannot download a secret access key for a role.

Mistake

An explicit allow in a bucket policy overrides an explicit deny in an IAM policy.

Correct

Explicit deny always overrides any allow, regardless of where the deny is defined. The policy evaluation order is: explicit deny > explicit allow > implicit deny. So an IAM policy that denies s3:GetObject will prevent access even if the bucket policy allows it.

Mistake

You can edit a service-linked role to add custom permissions.

Correct

Service-linked roles are predefined by AWS and cannot be modified. You cannot change their trust policy or their core permissions. However, you can attach additional customer-managed policies to a service-linked role to grant extra permissions, but you cannot remove the predefined permissions.

Mistake

Using an IAM user with access keys on an EC2 instance is a best practice.

Correct

Storing access keys on EC2 instances is a security risk. The best practice is to create an IAM role and attach it to the EC2 instance via an instance profile. The instance then retrieves temporary credentials from the instance metadata service automatically.

Mistake

Resource-based policies cannot be used for cross-account access.

Correct

Resource-based policies (like S3 bucket policies) can grant access to principals in other AWS accounts directly. They do not require a role. However, not all services support resource-based policies (e.g., DynamoDB does not; you must use cross-account roles).

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

What is the difference between an IAM role and an IAM user?

An IAM user is a permanent identity with long-term credentials (password and access keys), typically used for humans or applications that need persistent access. An IAM role is an identity that provides temporary credentials via AWS STS, and can be assumed by users, applications, or AWS services. Roles are preferred for EC2, Lambda, and cross-account access because they eliminate the need to manage long-term keys and automatically rotate credentials.

How do I allow an EC2 instance to access an S3 bucket?

Create an IAM role with a policy that grants the necessary S3 permissions (e.g., s3:GetObject). Attach the role to the EC2 instance via an instance profile (during launch or by modifying the instance). The EC2 instance will automatically retrieve temporary credentials from the instance metadata service at http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name. No access keys need to be stored on the instance.

What is the difference between identity-based and resource-based policies?

Identity-based policies are attached to an IAM user, group, or role and define what actions that identity can perform on which resources. Resource-based policies are attached directly to a resource (e.g., S3 bucket, SQS queue) and define which principals can access the resource and what actions they can perform. Resource-based policies can grant cross-account access directly, while identity-based policies require a cross-account role to grant access to another account.

Can I modify a service-linked role?

You cannot modify the trust policy or the core permissions of a service-linked role. However, you can attach additional customer-managed policies to a service-linked role to grant extra permissions. You cannot delete a service-linked role until you delete the service that created it.

How do I grant cross-account access to an S3 bucket?

You have two options: (1) Use a resource-based policy (bucket policy) on the S3 bucket that grants access to the other account's root user or a specific IAM principal. (2) Create a cross-account IAM role in the bucket owner's account, and allow the other account's users to assume that role. The bucket policy approach is simpler and does not require the other account to assume a role. The exam often expects you to choose the bucket policy if the question involves S3.

What happens if a policy has an explicit deny and an explicit allow for the same action?

The explicit deny wins. IAM policy evaluation uses the rule 'explicit deny overrides any allow.' So even if there is an allow statement, if there is any deny statement that applies to the action, the action is denied. This is a common exam trap.

How long do temporary credentials from STS last?

By default, temporary credentials from sts:AssumeRole last 1 hour. You can configure the duration from 15 minutes up to a maximum of 12 hours when you create the role or call assume-role. For roles assumed by AWS services (like EC2), the duration is typically 6 hours but can vary.

Terms Worth Knowing

Ready to put this to the test?

You've just covered IAM for Developers: Roles and Policies — now see how well it sticks with free DVA-C02 practice questions. Full explanations included, no account needed.

Done with this chapter?