This chapter covers the critical difference between resource-based policies and identity-based policies in AWS, a core concept for the DVA-C02 exam. You will learn how each type works, when to use which, and how they interact during authorization. Approximately 10-15% of exam questions touch on IAM policies, and understanding this distinction is essential for correctly answering questions about cross-account access, service-to-service permissions, and S3 bucket policies. Mastery of this topic will help you eliminate wrong answers quickly and confidently select the right solution.
Jump to a section
Imagine an apartment building with a central mailroom. Each apartment has its own mailbox (the identity of the resident). The mailroom has a rule: 'Only the resident with the key can open their mailbox.' This is an identity-based policy — the permission is attached to the resident (the IAM user/role). Now, the building manager installs a package delivery locker in the lobby. The locker has its own rule: 'Any delivery driver can leave a package here, but only the locker's key can open it to retrieve packages.' This is a resource-based policy — the permission is attached to the locker (the S3 bucket, SQS queue, etc.). Crucially, the locker can also grant access to specific residents: 'Resident of apartment 3B can take packages from this locker.' That's a resource-based policy granting cross-account access. In AWS, identity policies are attached to IAM users, groups, or roles and specify what actions that identity can perform on which resources. Resource-based policies are attached to the resource itself (like an S3 bucket policy) and specify who (which principal) can perform what actions on that specific resource. They are evaluated independently: if either policy allows the action, the action is allowed (unless an explicit deny overrides). The exam tests your ability to choose which type to use for cross-account access, service-to-service permissions, and when to use service-linked roles vs. resource policies.
What Are Identity-Based Policies?
Identity-based policies are JSON policy documents attached to an IAM entity: a user, group, or role. They define what actions that entity is allowed or denied on which AWS resources. For example, an IAM policy attached to a developer role might allow s3:GetObject on a specific bucket. The policy says: "This role can read objects from this bucket." The policy is evaluated when the entity makes a request. The key characteristic is that the policy is tied to the identity, not the resource. Identity-based policies can be managed (created and attached by you) or inline (embedded directly in the user/group/role). The default is an implicit deny: if no policy explicitly allows an action, it is denied. An explicit deny in any policy overrides any allow.
What Are Resource-Based Policies?
Resource-based policies are JSON policy documents attached directly to an AWS resource, such as an S3 bucket, SQS queue, SNS topic, Lambda function, or KMS key. They specify which principals (AWS accounts, IAM users, roles, or federated users) can perform what actions on that resource. For example, an S3 bucket policy might grant s3:GetObject to an IAM role in another account. The policy says: "This bucket allows that role to read its objects." Resource-based policies are evaluated when the resource receives a request. They allow cross-account access without needing to create IAM roles. The resource owner controls access directly. Resource-based policies can also include conditions based on source IP, VPC, or time.
How Authorization Works
When an IAM principal makes a request to an AWS service, the authorization engine evaluates all applicable policies. The evaluation logic is: 1. If there is an explicit deny in any policy (identity-based or resource-based), the request is denied. 2. If there is an explicit allow in either the identity-based policy or the resource-based policy (or both), the request is allowed. 3. If neither policy explicitly allows the action, the default is an implicit deny.
This is often summarized as "allow by default" combined with "deny overrides." However, the default is actually deny; an allow must exist somewhere. The key point is that an allow from either the identity policy OR the resource policy is sufficient. This is crucial for cross-account access: the resource-based policy can allow a principal from another account, even if that principal's own identity policy does not explicitly allow the action (though the principal's identity policy must not deny it).
Cross-Account Access Patterns
There are two primary ways to grant cross-account access:
- Resource-based policy: Attach a policy to the resource that specifies the external principal. This is simpler and does not require the external account to create a role. Example: S3 bucket policy granting s3:GetObject to an IAM user in another account.
- Role-based access: The resource owner creates an IAM role that the external principal can assume. The external principal's identity policy must allow sts:AssumeRole. This is more flexible but requires the external account to manage role assumption.
The exam frequently asks which method to use for a given scenario. Resource-based policies are preferred when the resource service supports them (S3, SQS, SNS, Lambda, KMS, etc.) and you want to grant access to many users across accounts without managing roles. Role-based access is required when the resource does not support resource-based policies (e.g., EC2, RDS) or when you need fine-grained control over session permissions.
Services That Support Resource-Based Policies
Not all AWS services support resource-based policies. Common services that do: - Amazon S3 – bucket policies - Amazon SQS – queue policies - Amazon SNS – topic policies - AWS Lambda – function policies (resource-based) - AWS KMS – key policies - Amazon S3 Glacier – vault policies - Amazon API Gateway – resource policies - AWS Secrets Manager – secret policies (resource-based) - Amazon ECR – repository policies
Services that do NOT support resource-based policies (require role-based access):
Amazon EC2
Amazon RDS
Amazon DynamoDB (except for fine-grained access via IAM, but not resource-based policies)
AWS Elastic Beanstalk
Policy Structure
Both identity-based and resource-based policies use the same JSON structure with the following elements:
- Version – policy language version, always "2012-10-17"
- Statement – array of statements, each containing:
- Effect – "Allow" or "Deny"
- Action – one or more AWS actions (e.g., "s3:GetObject")
- Resource – ARN of the resource (in identity policies) or "*" (in resource policies, where the resource is implicit)
- Principal – only in resource-based policies; specifies who is allowed/denied (e.g., "AWS": "arn:aws:iam::123456789012:user/Alice")
- Condition – optional conditions
Principal Element
The Principal element is exclusive to resource-based policies. It specifies the entity that is allowed or denied access. Values can be:
- "AWS" – an IAM user, role, or AWS account (e.g., "arn:aws:iam::123456789012:root" for the entire account)
- "Service" – an AWS service (e.g., "lambda.amazonaws.com")
- "Federated" – a federated identity provider
- "*" – everyone (anonymous access)
In identity-based policies, the principal is implicit (the entity the policy is attached to).
Example: S3 Bucket Policy (Resource-Based)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/CrossAccountRole"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
]
}Example: IAM Policy (Identity-Based)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}When to Use Each
Identity-based policies: Use when you want to define permissions for a specific user, group, or role. They are the standard way to grant permissions to IAM entities. They are required for services that do not support resource-based policies.
Resource-based policies: Use when you want to grant cross-account access without creating roles, or when you want to control access to a resource centrally. They are also useful for granting permissions to AWS services (e.g., allowing SNS to invoke a Lambda function).
Policy Evaluation Logic
The AWS authorization engine evaluates policies in the following order: 1. Identity-based policies (user, group, role) 2. Resource-based policies 3. IAM permissions boundaries 4. Organizations service control policies (SCPs) 5. Session policies (for assumed roles)
If any policy explicitly denies the action, the request is denied. Otherwise, if any policy explicitly allows the action, the request is allowed. If no policy explicitly allows, the request is implicitly denied.
Common Exam Scenarios
Cross-account S3 access: Use a bucket policy (resource-based) to grant access to an IAM user in another account. The user's identity policy must not deny the action, but does not need to explicitly allow it.
Lambda invocation by S3: Use a Lambda resource-based policy (also called a function policy) to allow S3 to invoke the function. The S3 service principal is s3.amazonaws.com.
SQS queue access from another account: Use a queue policy (resource-based) to allow an external IAM role to send messages.
KMS key sharing: Use a key policy (resource-based) to grant permissions to IAM users in another account.
Permissions Boundaries
Permissions boundaries are an advanced feature that sets the maximum permissions an identity-based policy can grant. They are not resource-based policies. They are attached to an IAM user or role and define the maximum set of actions that the entity can perform, even if its identity policy allows more. The exam may test the interaction between boundaries and resource-based policies: a resource-based policy cannot grant permissions that exceed the boundary of the principal's role.
Service Control Policies (SCPs)
SCPs are used in AWS Organizations to set permission guardrails for accounts. They are not resource-based policies; they are identity-based policies applied at the organization level. SCPs restrict what actions the account's IAM entities can do, but they do not grant permissions. Resource-based policies are still evaluated after SCPs.
Summary of Differences
Attachment point: Identity policies attach to IAM entities; resource policies attach to resources.
Principal: Identity policies have implicit principal; resource policies have explicit Principal.
Cross-account: Resource policies enable direct cross-account access; identity policies require role assumption.
Services: Identity policies work for all services; resource policies only for supported services.
Evaluation: Both are evaluated; an allow from either suffices.
Exam Tips
Memorize which services support resource-based policies (S3, SQS, SNS, Lambda, KMS).
For cross-account access, if the service supports resource-based policies, that is often the simplest answer.
If a question mentions "allow anonymous access" or "public access," look for a resource-based policy with "Principal": "*".
Be aware that resource-based policies can have conditions; identity policies can too.
Understand that an explicit deny in any policy (identity or resource) always overrides an allow.
Remember that resource-based policies can grant access to AWS services using service principals (e.g., s3.amazonaws.com).
Identify the Resource Type
Determine whether the AWS resource you want to secure supports resource-based policies. The exam-relevant services that do: Amazon S3 (bucket policies), Amazon SQS (queue policies), Amazon SNS (topic policies), AWS Lambda (function policies), AWS KMS (key policies), Amazon API Gateway (resource policies), and Amazon ECR (repository policies). If the resource does not support resource-based policies (e.g., EC2, RDS, DynamoDB), you must use identity-based policies and IAM roles for cross-account access. This step is crucial because choosing the wrong policy type will not work.
Define the Principal
For resource-based policies, specify the principal that should have access. The principal can be an AWS account (e.g., `"AWS": "123456789012"`), an IAM role or user ARN, an AWS service (e.g., `"Service": "s3.amazonaws.com"`), or a federated identity. For identity-based policies, the principal is implicit — the IAM entity the policy is attached to. In cross-account scenarios using resource-based policies, you must specify the external account's root or a specific IAM entity. Avoid using `"*"` unless you intend public access, which is often a security risk.
Write the Policy Statement
Construct a JSON policy statement with `Effect`, `Action`, `Resource`, and optionally `Condition`. For identity-based policies, the `Resource` is the ARN of the target resource. For resource-based policies, the `Resource` is usually `"*"` because the policy is attached to the resource itself, so the resource is implicit. However, you can restrict the resource to specific sub-resources (e.g., `arn:aws:s3:::my-bucket/*`). Use the minimum set of actions needed (least privilege). Remember that an explicit `Deny` overrides any `Allow`.
Attach the Policy
Attach the policy to the appropriate entity. For identity-based policies, attach to an IAM user, group, or role using the AWS Management Console, CLI (`aws iam attach-user-policy`), or SDK. For resource-based policies, attach directly to the resource. For example, an S3 bucket policy is attached via the S3 console or `aws s3api put-bucket-policy`. A Lambda resource policy is attached using `aws lambda add-permission`. Ensure the policy is valid JSON; invalid syntax will cause attachment failure.
Test and Validate Access
After attaching the policy, test that the intended principal can perform the allowed actions. Use the AWS CLI with appropriate credentials to verify. For example, if you granted `s3:GetObject` to a role in another account, assume that role and run `aws s3 cp s3://my-bucket/file.txt .`. If access is denied, check for explicit denies in any policy, verify the principal ARN, and ensure conditions are met. Use IAM Access Analyzer to validate policies against best practices. For cross-account access, ensure the resource-based policy allows the principal and the principal's identity policy does not deny the action.
Enterprise Scenario 1: Cross-Account S3 Data Sharing
A large enterprise has multiple AWS accounts: a central data lake account and several analytics accounts. The data lake team wants to allow analysts in the analytics accounts to read specific prefixes in an S3 bucket. The simplest solution is to attach a bucket policy (resource-based) to the data lake bucket that grants s3:GetObject to the IAM roles in the analytics accounts. This avoids the need for the analytics accounts to assume a role in the data lake account, reducing complexity. The bucket policy includes a condition to restrict access to specific VPC endpoints for security. Misconfiguration often occurs when the principal ARN is incorrect (e.g., using the account ID instead of the role ARN) or when the bucket policy does not include the s3:ListBucket action for the prefix, causing "Access Denied" errors when listing objects. Performance is not an issue because S3 bucket policies are evaluated at request time with minimal overhead.
Enterprise Scenario 2: Lambda Invocation from S3
A company uses S3 to store images and a Lambda function to generate thumbnails. The S3 bucket is configured to trigger the Lambda function on new object creation. To allow S3 to invoke the Lambda function, the company attaches a resource-based policy to the Lambda function (also called a function policy) that grants lambda:InvokeFunction to the S3 service principal (s3.amazonaws.com). This is more secure than making the Lambda function public. A common mistake is forgetting to add the condition that restricts invocation to the specific bucket ARN, which could allow any S3 bucket in the same account to invoke the function. The function policy also includes the source account ID to prevent cross-account abuse. At scale, with thousands of invocations per second, the Lambda resource policy evaluation adds negligible latency.
Enterprise Scenario 3: SQS Queue Cross-Account Messaging
A microservices architecture spans two AWS accounts: Account A runs a producer service, and Account B runs a consumer service. The producer sends messages to an SQS queue in Account B. To allow Account A to send messages, Account B attaches a queue policy (resource-based) that grants sqs:SendMessage to the IAM role used by the producer in Account A. The queue policy also includes a condition to restrict the source IP range. The producer's IAM role does not need to explicitly allow sqs:SendMessage in its identity policy; the queue policy alone is sufficient. However, if the producer's identity policy has an explicit deny on sqs:SendMessage, the request will fail. A common pitfall is not including the sqs:SendMessage action in the queue policy, leading to "Access Denied" errors. For high-throughput queues (thousands of messages per second), the queue policy evaluation is a minor overhead.
The DVA-C02 exam tests this topic under Domain 2: Security, Objective 2.1: "Implement resource-based policies." Specifically, you must understand when to use resource-based policies vs. identity-based policies, how to write them, and how they interact. The exam will present scenarios requiring cross-account access, service-to-service permissions, or public access control.
Most Common Wrong Answers
"Create an IAM role in the target account and have the user assume that role." This is often the wrong answer when the service supports resource-based policies. The exam will test whether you know that S3, SQS, SNS, and Lambda support resource-based policies, which are simpler for cross-account access. If the question mentions S3 bucket access, the correct answer is usually a bucket policy (resource-based), not a role.
"Attach a policy to the IAM user granting access to the resource." This is insufficient for cross-account access because the resource is in a different account. The user's identity policy only applies within their own account. The resource owner must also grant access via a resource-based policy or a role. Candidates often forget the resource side.
"Use an SCP to allow access." SCPs are for AWS Organizations and only restrict permissions; they cannot grant access. They are not a solution for cross-account access. Candidates confuse SCPs with resource-based policies.
"The request will be denied because there is no explicit allow in the identity policy." This is false for resource-based policies. An allow in the resource-based policy is sufficient, even if the identity policy has no explicit allow (as long as no explicit deny exists).
Specific Numbers and Terms
The Principal element is only in resource-based policies.
Services that support resource-based policies: S3, SQS, SNS, Lambda, KMS, API Gateway, ECR.
Default policy version: "2012-10-17".
Service principal names: s3.amazonaws.com, sqs.amazonaws.com, sns.amazonaws.com, lambda.amazonaws.com.
For public access: "Principal": "*".
For cross-account: "Principal": {"AWS": "arn:aws:iam::ACCOUNT-ID:root"}.
Edge Cases and Exceptions
Resource-based policies cannot be used for services that do not support them (e.g., EC2, RDS). For those, you must use IAM roles.
Even with a resource-based policy, the principal's account must not have an explicit deny in its identity policy or SCP.
Permissions boundaries can limit the effective permissions even if the resource-based policy allows more.
When using a resource-based policy to grant access to a service principal, you can condition on aws:SourceArn or aws:SourceAccount to prevent confused deputy problems.
How to Eliminate Wrong Answers
If the question involves S3, SQS, SNS, Lambda, or KMS and cross-account access, look for an answer that uses a resource-based policy. Eliminate answers that suggest creating a role in the target account unless the resource does not support resource-based policies.
If the question involves anonymous access to S3, the answer should mention bucket policy with "Principal": "*".
If the answer mentions SCP, it is likely wrong because SCPs do not grant permissions.
Remember that identity policies are attached to users/roles; resource policies are attached to resources. If the answer says "attach a policy to the S3 bucket," that is a resource-based policy.
Resource-based policies are attached to resources and include a `Principal` element; identity-based policies are attached to IAM entities and have an implicit principal.
For cross-account access, if the service supports resource-based policies (S3, SQS, SNS, Lambda, KMS), use that instead of creating a role.
An allow from either an identity policy or a resource policy is sufficient for access, as long as no explicit deny exists.
Services that do NOT support resource-based policies (EC2, RDS, DynamoDB) require IAM roles for cross-account access.
Resource-based policies can grant permissions to AWS service principals (e.g., `s3.amazonaws.com`) for service-to-service communication.
Always use the `aws:SourceArn` or `aws:SourceAccount` condition in resource-based policies to prevent the confused deputy problem.
Permissions boundaries and SCPs can limit the effective permissions even if a resource-based policy allows more.
The default policy version is `"2012-10-17"`; always include it.
These come up on the exam all the time. Here's how to tell them apart.
Resource-Based Policies
Attached to the resource (e.g., S3 bucket, SQS queue).
Includes explicit `Principal` element specifying who can access.
Supports cross-account access directly without role assumption.
Only available for certain AWS services (S3, SQS, SNS, Lambda, KMS, etc.).
The resource is implicit; `Resource` in statement often `"*"`.
Identity-Based Policies
Attached to an IAM user, group, or role.
No `Principal` element; principal is implicit.
Cross-account access requires assuming an IAM role in the target account.
Available for all AWS services when combined with IAM roles.
`Resource` explicitly specifies the target resource ARN.
Mistake
Resource-based policies are just like identity policies but attached to resources.
Correct
While they share JSON structure, resource-based policies include a `Principal` element that identity policies lack. Identity policies have an implicit principal (the entity they are attached to). Resource-based policies explicitly specify who can access the resource. Additionally, resource-based policies are evaluated independently and can grant cross-account access without role assumption.
Mistake
To grant cross-account access, you must always create an IAM role in the target account.
Correct
No. For services that support resource-based policies (S3, SQS, SNS, Lambda, KMS), you can simply attach a resource-based policy to the resource that specifies the external principal. This is often simpler and does not require the external account to manage role assumption. Role-based access is only necessary when the resource does not support resource-based policies.
Mistake
An identity-based policy must explicitly allow an action for the request to succeed, even if a resource-based policy allows it.
Correct
False. The authorization engine checks both identity and resource policies. If either policy allows the action, the request is allowed (provided no explicit deny). So a resource-based policy alone can allow access, even if the identity policy has no explicit allow. However, the identity policy must not contain an explicit deny.
Mistake
Resource-based policies can only be used for cross-account access.
Correct
Resource-based policies are also used for same-account access, granting permissions to AWS services (e.g., allowing S3 to invoke a Lambda function), and for public access. They are not limited to cross-account scenarios.
Mistake
You can use a resource-based policy to grant access to any AWS service.
Correct
Only services that support resource-based policies can have such policies attached. EC2, RDS, DynamoDB, and many others do not support resource-based policies. For those, you must use IAM roles.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
Resource-based policies are attached directly to an AWS resource (like an S3 bucket) and specify which principals can access that resource. They include a `Principal` element. Identity-based policies are attached to IAM users, groups, or roles and define what actions that identity can perform on which resources. They do not have a `Principal` element. Both are evaluated during authorization; an allow from either is sufficient.
No. EC2 does not support resource-based policies. To grant cross-account access to an EC2 instance, you must use an IAM role and allow the external principal to assume that role. The role's trust policy controls who can assume it, and the role's permissions policy defines what actions the assumed role can perform.
Attach a bucket policy (resource-based) to the S3 bucket in Account A that grants the desired actions (e.g., `s3:GetObject`) to the IAM user or role in Account B. The policy must specify the principal as the ARN of the user or role in Account B. The user in Account B must not have an explicit deny on the action. No role assumption is needed.
A service principal is an identifier for an AWS service, such as `s3.amazonaws.com` or `lambda.amazonaws.com`. You use it in the `Principal` element of a resource-based policy to grant the service permission to access the resource. For example, to allow S3 to invoke a Lambda function, you set `"Principal": {"Service": "s3.amazonaws.com"}` in the Lambda function policy.
No. SCPs are applied at the organization level and set maximum permissions. Even if a resource-based policy allows an action, if an SCP denies it, the action is denied. SCPs act as a filter: the effective permissions are the intersection of the SCP allow and the identity/resource policy allows.
The action is allowed. The authorization engine is designed so that an allow from either policy is sufficient. There is no conflict; the request proceeds. However, if either policy explicitly denies the action, the request is denied regardless of allows.
Yes, but it is often set to `"*"` because the policy is attached to the resource itself, making the resource implicit. However, you can specify a sub-resource ARN (e.g., `arn:aws:s3:::my-bucket/*`) to restrict the policy to specific objects or prefixes. For S3 bucket policies, the `Resource` must match the bucket ARN or a subset.
You've just covered Resource-Based Policies vs Identity Policies — now see how well it sticks with free DVA-C02 practice questions. Full explanations included, no account needed.
Done with this chapter?