Table of contents
Intro to Resource Policies
AWS resource policies are powerful tools that control access to AWS service resources in an account. You apply resource policies directly to a resource. They establish connectivity and authorize principals to use resources within and across accounts, making them ideal for implementing least privilege for critical data resources.
They are also quirky, which we’ll dive into shortly.
When a principal makes a request, the AWS security system evaluates organization, resource, and identity policies:

Figure 1. AWS IAM policy evaluation logic
Resource policies grant permissions to other AWS accounts or services on a per-resource basis, enabling cross-account and public access.
Resource policy is expressed with the same json IAM policy language syntax as other AWS security policies. However, resource policy provides an opportunity for the AWS service team to implement their own rules for how service resources can be accessed. This is, at times, weird, wild, and fun.
To start with, a service may or may not support resource policies. There are at least 35 AWS services with some resource policy support. When resource policy is supported, the service may or may not require a policy for the resource. You’ll have to read the docs.
General Resource Policy Rules
Here are some general rules for how resource policy works in AWS:
First, a resource policy can generally grant a principal in the same account the ability to use the resource by Allowing the relevant actions without requiring any permissions to be granted to the principal via identity policy (Exceptions to follow). This is often the simplest and most maintainable way to manage access to a resource.
Second, when a resource policy in account 111 grants access to another account 222, that authorizes the other account (222) to determine which of its principals can access the resource via Identity policy.
Third, when a resource policy in account 111 grants access to a specific principal, role A in another account 222, then that principal will be able to access the resource in 111 if its Identity policies also grant access. And only that account 222 principal may have direct access to the resource. Account 222 cannot grant access to arbitrary principals in the account. However, account 222 can grant arbitrary principals to use the principal that was granted access. For example, it can grant role B and C the ability to assume role A.
Fourth, a resource policy can Deny access by unintended principals (without exceptions) by explicitly denying all but the intended principals using a statement like:
{
"Sid": "DenyEveryoneElse",
"Effect": "Deny",
"Action": "dynamodb:*",
"Principal": {
"AWS": [
"*"
]
},
"Resource": "*",
"Condition": {
"Bool": {
"aws:PrincipalIsAWSService": [
"false"
]
},
"ArnNotEquals": {
"aws:PrincipalArn": [
"arn:aws:iam::111122223333:role/ci",
"arn:aws:iam::111122223333:role/auditor",
"arn:aws:iam::111122223333:role/admins"
]
}
}
}
When added to a DynamoDB resource policy, this statement will deny all access to IAM principals that are not one of the explicitly-permitted roles in account 111122223333: ci, auditor, admins.
But there are exceptions to these general rules. We’ll call them ‘quirks.’
Let’s explore some of the more interesting and useful quirks of AWS resource policy and notable exceptions to standard behavior.
KMS Key Policy
Required? Yes
Size limit: 32,768 bytes
AWS KMS Key Policy is arguably the most powerful of all resource policies. A key starts with absolutely no implicit or default access. Not even the root user of the account that owns a key has access unless it is explicitly granted. KMS requires that every key must have a policy that grants some access. Key policy can grant access to the full range of AWS principal types.
An interesting key policy quirk is that granting access to the owning account’s root user identity does two things:
- allows the root user permission to use the key
- enables Identity policies within the account to grant access to the key
Here is the default policy for a KMS key (created programmatically):
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:root"
},
"Action": "kms:*",
"Resource": "*"
}
This policy enables Identity policies in the account, called ‘IAM policies’ in the KMS docs.
But enabling Identity policies makes it very difficult to deny access from unintended principals, especially once AWS service principals for data services are involved. (The DenyEveryoneElse trick above breaks down with key grants for certain data services.)
Fortunately, this ‘quirk’ opens up the technique of implementing least privilege access to data protected by the key solely through key policy (c.f. Secure data in AWS with KMS (Effective IAM). Key policy allows you to grant (only) the permissions a principal needs to encrypt or decrypt data using that key. And if the grantee principal is in the same account as the key, then the grantee can now use the key without those permissions being granted by an identity policy. Here is an example:
{
"Version": "2012-10-17",
"Id": "AllowAccessOnlyToSpecificIAMPrincipals",
"Statement": [
{
"Sid": "AllowFullAccess",
"Effect": "Allow",
"Action": "kms:*",
"Resource": "*",
"Principal": {
"AWS": [
"arn:aws:iam::111122223333:role/ci"
]
}
},
{
"Sid": "AllowReadAndWrite",
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:Encrypt",
],
"Resource": "*",
"Principal": {
"AWS": [
"arn:aws:iam::111122223333:role/appA"
]
}
}
]
}
When this policy is attached to a KMS key, only the following access will be allowed:
cirole will have full permissions on the keyappArole will have the ability to encrypt and decrypt data with the key
No other principals will have access, not even the root user of the 111122223333 account. Note that if you lose access to the key because, e.g. the ci role is deleted, then you must contact AWS Support to regain access.
Additional KMS key policy resources:
- Key policies in AWS KMS
- k9 Security’s KMS key generators (CDK, Terraform)
- Effective IAM: Secure data in AWS with KMS
IAM Role Trust Policy
Required? Yes
Size limit: 2,048 (default) / 4,096 (max) bytes
AWS IAM Role Trust Policy allows a role to be assumed (used) by another AWS principal, whether an IAM role, user, AWS service principal, etc. IAM trust policy is used to allow use of a role both within an AWS account and across accounts. Every IAM role must have a trust policy.
An interesting difference between IAM role trust policy and other resource policies is that both the Trust policy of the ‘target’ role and the identity policies of the principal using the ‘target’ role must grant access. i.e.
- IAM roles do not implicitly trust other principals in the account; those permissions need to be explicitly defined in trust policy.
- Principals that assume roles must be granted those permissions via Identity policies.
Sort of like a double-check.
Suppose you want the ops role to be able to assume the admin role.
You could do that with a trust policy on the admin role of:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:role/ops"
},
"Action": "sts:AssumeRole"
}
]
}
Then the ops role would need an identity policy like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": [
"arn:aws:iam::111122223333:role/admin"
]
}
]
}
Additional IAM Trust policy resources:
S3 Bucket Policy
Required? No
Size limit: 20,480 bytes
Amazon S3 Bucket Policy can manage permissions for principals both within and between accounts.
Bucket policies are optional. That means access to a bucket can be granted solely by Identity policies attached to an IAM user or role in the same account.
But an Identity policy is not required for identities in the bucket owner account. Bucket policy can grant access directly to a principal in the same account and they will be able to use the bucket.
The Resource element of Bucket policy is a bit quirky. The bucket resource is distinct from object resources in the bucket. So the Resource element needs to address both kinds of resources:
{
"Sid": "Allow full access to the bucket and its objects",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam111122223333:role/ops"
},
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::bucket-a",
"arn:aws:s3:::bucket-a/*"
]
}
Additional S3 bucket policy resources:
- Official docs: Bucket policies for Amazon S3
- S3 Bucket policy examples
- k9 Security’s Bucket policy generators (CDK, Terraform)
Lambda Function Policy
Required? No
Character limit: 20,480 bytes
Lambda supports (optional) resource-based permissions policies for Lambda functions and layers. You can use Lambda resource policies to grant access to principals within your account or other AWS accounts, organizations, or services.
What you can’t do is explicitly Deny access to a function using a statement like the DenyEveryoneElse trick to prevent unintended access by principals in the account with an identity policy that allows lambda:Invoke on * resources.
This is because Lambda only supports adding permissions that Allow to a function’s resource policy with the AddPermission API.
The lambda:AddPermission API grants a principal permission to use a function this request syntax:
POST /2015-03-31/functions/FunctionName/policy?Qualifier=Qualifier HTTP/1.1
Content-type: application/json
{
"Action": "string",
"EventSourceToken": "string",
"FunctionUrlAuthType": "string",
"Principal": "string",
"PrincipalOrgID": "string",
"RevisionId": "string",
"SourceAccount": "string",
"SourceArn": "string",
"StatementId": "string"
}
The lambda:AddPermission API adds a statement to the resource policy for the function. And it’s the only way you can add statements to a Lambda resource policy. There’s no lambda:PutPolicy.
Notice you cannot specify an Effect. When AddPermission adds a statement to the function’s resource policy, the Effect is always Allow.
So there is no way to specify a Deny.
You can remove statements by StatementId using the Lambda RemovePermission API. You can read the full policy like normal with the GetPolicy API.
So what can you do to control access to a sensitive Lambda function?
Some potential solutions are to:
- Deploy app/function into a dedicated account
- Use Service Control policies to deny unintended / unauthorized principals
- Implement app-level AuthZ and enforce that in the Lambda function
The right solution is highly context dependent as Lambdas often work best co-located with the workflows and data they integrate with.
Additional Lambda resource policies resources:
SQS Queue Policy
Required? No
Size limit: 8,192 bytes
SQS Queue Policy is used to manage permissions directly on an SQS queue.
Queue policies are optional. That means access to a queue can be granted solely by Identity policies attached to an IAM user or role in the same account.
A surprising quirk of SQS queue policy is that a maximum of 7 actions are allowed in a queue policy statement.

Try to add more than 7 actions to a statement and and you’ll get an error like:
OverLimit: 10 actions were found in a statement from the submitted policy, max allowed is 7
There are also limits on the number of statements (20), principals (50), and conditions (10) you can have in a queue policy, c.f. SQS queue policy quotas.
Additional SQS queue policy resources:
- SQS queue policy examples
- SQS queue policy limitations
- SQS queue policy quotas
- k9 Security’s Queue policy generator (CDK)
EFS Filesystem Policy
Required? No
Character limit: 20,000
You can use either or both IAM identity policies and resource policies to control client access to Amazon EFS filesystems. An “allow” in either an identity or file system resource policy is enough to allow the action.
IAM-based auth is totally optional! This is NFS, after all. The default EFS file system policy does not use IAM to authenticate, and grants full access to any anonymous client that can connect to the file system using a mount target available on the network. So by default, an EFS file system is available to any client on the same network.
Additional EFS file system policy resources:
Use more resource policy
We compiled these resource policy quirks to help you (and us) remember and navigate the differences in resource policy so that you can use them effectively. Resource policy is often the simplest and most effective way to implement least privilege to critical resources. It’s tough to beat a security policy applied directly to the resource you’re trying to protect.
If you have any quirks, questions, or corrections that you’d like to share, please send them to [email protected]. We’d love to hear them and capture them here.
Recent Comments