2.1 IAM for Developers
Key Takeaways
- IAM evaluation always follows the same order: an explicit Deny overrides every Allow, and with no matching Allow the default is an implicit deny
- Identity-based policies attach to users, groups, or roles; resource-based policies (S3 bucket, SQS queue, KMS key, Lambda) attach to the resource and name a Principal
- Grant AWS access to running code with roles (EC2 instance profiles, Lambda execution roles, ECS task roles), never long-lived access keys baked into the app
- STS AssumeRole returns short-lived credentials and is the basis for cross-account access; use an External ID to prevent the confused-deputy problem with third parties
- Permission boundaries, SCPs, and session policies set a ceiling on permissions but never grant access on their own
Why IAM Matters on DVA-C02
Security accounts for 26% of the DVA-C02 exam (the second-largest domain, behind Development with AWS Services at 32%, on a 65-question, 130-minute test scored 100–1000 with a 720 passing line), and Identity and Access Management (IAM) questions dominate it. Most are scenarios: an application throws an AccessDeniedException, or you must pick the most secure way to grant a permission. The correct answer almost always involves an IAM role with least privilege, not a hard-coded access key.
Identities: Users, Groups, Roles
- IAM user — a long-term identity (a person or service) with a console password and/or access keys. Discouraged for application code because the keys are static and easily leaked.
- IAM group — a collection of users; attach a policy once and every member inherits it. Groups cannot be assumed and cannot be nested inside other groups.
- IAM role — an identity assumed temporarily that hands out short-lived credentials with no embedded secret. This is the preferred mechanism for EC2, Lambda, ECS, and any cross-account access.
Anatomy of a Policy Statement
Every JSON policy statement combines Effect (Allow/Deny), Action (e.g. s3:GetObject), Resource (an ARN), and optional Principal and Condition blocks. Wildcards (s3:*, arn:aws:s3:::bucket/*) widen scope; least privilege narrows it. The exam expects you to read a statement and predict the outcome.
Identity Policy vs Resource Policy
This distinction is a favorite trap. Both are JSON, but they answer different questions.
| Identity-based policy | Resource-based policy | |
|---|---|---|
| Attached to | User, group, or role | The resource (S3 bucket, SQS queue, KMS key, Lambda) |
Names a Principal? | No | Yes — defines who may act |
| Cross-account | Needs a role + AssumeRole | Can grant another account directly |
For same-account access you only need an Allow on either side. Across accounts you typically need an Allow on both sides — the resource policy permits the external principal, and the principal's identity policy permits the action.
Policy Evaluation: Deny Wins
IAM gathers every applicable policy — identity, resource, permission boundary, Service Control Policy (SCP), and session policy — and applies one rule:
- Explicit Deny anywhere → request denied. Nothing overrides it.
- No explicit Deny + at least one Allow → request allowed.
- No Allow at all → implicit deny (the default starting state).
Roles, STS, and Least Privilege
AWS Security Token Service (STS) issues temporary credentials when an identity calls AssumeRole. A role carries two policies: a trust policy (the Principal allowed to assume it) and a permissions policy (what the session may do). EC2 uses an instance profile, Lambda an execution role, and ECS a task role — the SDK fetches and auto-rotates the credentials, so no keys touch your code.
For third-party (cross-account) access, add an External ID as a Condition (sts:ExternalId) in the trust policy to block the confused-deputy problem. The confused deputy occurs when a trusted intermediary (for example, a monitoring SaaS) is tricked into using its access on behalf of an attacker; the External ID is a secret only you and the legitimate partner know, so a third party cannot impersonate them even if they learn your role ARN. Use policy variables like ${aws:username} and Condition keys such as aws:SourceIp, aws:SecureTransport, or aws:MultiFactorAuthPresent to scope access tightly.
Permission Boundaries vs SCPs vs Session Policies
The exam often layers several guardrails and asks for the effective permission. Keep them straight:
- Permission boundary — an advanced policy attached to a user or role that caps its maximum permissions. Effective permission is the intersection of the identity policy and the boundary. It grants nothing on its own.
- Service Control Policy (SCP) — an AWS Organizations guardrail applied to whole accounts/OUs. It also only filters; it never grants. An action must be allowed by the identity policy and not blocked by any SCP.
- Session policy — passed inline during
AssumeRole/GetFederationTokento further restrict that one session.
The golden rule across all of them: a guardrail can only narrow, never widen. For an action to succeed it must be Allowed by an identity (or resource) policy and survive every boundary, SCP, and session policy, with no explicit Deny anywhere.
Practical Least-Privilege Workflow
Developers are expected to start narrow and widen only as needed. Use IAM Access Analyzer to generate a policy from CloudTrail activity, scope Resource to specific ARNs instead of *, prefer roles over users, and rotate or eliminate any long-lived access keys. When code runs on AWS compute, the SDK's default credential provider chain automatically discovers role credentials from the instance profile, ECS task metadata endpoint, or Lambda environment — so correct code never needs an embedded key at all.
Debugging AccessDenied Errors
Many DVA-C02 questions hand you an AccessDeniedException and a set of policies, then ask which fix is correct. Work the evaluation logic in order: first scan every attached policy (identity, resource, boundary, SCP, session) for an explicit Deny — if one matches the action and resource, that is the cause, and no Allow can save it. If there is no Deny, confirm at least one Allow matches the exact Action and Resource ARN; a wildcard mismatch (granting s3:GetObject on bucket but not bucket/*) is a frequent trap. For cross-account calls, verify the Allow exists on both the identity side and the resource side.
Finally, confirm the request satisfies every Condition (such as a required source IP, MFA, or SecureTransport) — a failed condition turns an apparent Allow into an effective deny.
A Lambda function's identity-based execution role contains an Allow for s3:GetObject on a bucket. The bucket policy contains an explicit Deny for that same Lambda role. Can the function read the object?
A developer must let a partner's separate AWS account assume a role in your account, but only when the partner supplies a shared secret value. Which element of the role's trust policy addresses the confused-deputy risk?
An EC2-based application authenticates to DynamoDB using an IAM user's access keys stored in a config file. What is the most secure way to grant the same access?