Allow lambda function to access S3 bucket but block external IPs - amazon-web-services

I am trying to write in a S3 bucket with the help of a lambda function but would like to have the S3 bucket accessible only to IPs inside office network.
I have used this bucket policy but this does not allow my lambda to write to the S3 bucket, when i remove the IP blocking part, lambda function works fine.
How can i change this bucket policy so that it allows lambda to write but does not allow external IPS to access the S3 bucket?
Thanks!
{
"Version": "2012-10-17",
"Id": "",
"Statement": [
{
"Sid": "AllowSESPuts",
"Effect": "Allow",
"Principal": {
"Service": "ses.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::mybucket.net/*",
"Condition": {
"StringEquals": {
"aws:Referer": "230513111850"
}
}
},
{
"Sid": "AllowECSPuts",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": [
"s3:DeleteObject",
"s3:GetObject",
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::mybucket.net/*"
},
{
"Sid": "",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:GetObjectVersion"
],
"Resource": [
"arn:aws:s3:::abc.net/*",
"arn:aws:s3:::abc.net"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AROAJIS5E4JXTWB4RTX3I:*",
"230513111751"
]
},
"NotIpAddress": {
"aws:SourceIp": [
"81.111.111.111/24" --dummy IP
]
}
}
}
]
}

As a general rule, it makes life easier if you can avoid Deny statements in policies.
Therefore, you could configure:
An Amazon S3 bucket with a Bucket Policy that permits access from the desired CIDR range
An IAM Role for the Lambda function that permits access to the Amazon S3 bucket
There should be no need for a Deny statement in the bucket policy since access is denied by default.

One typical approach is to place the lambda function inside a private VPC subnet. Then attach an S3 gateway VPC endpoint to it and set the corresponding S3 bucket policy to only allow certain actions performed from the VPC endpoint. [ref]

Related

Limit public access of bucket to vpc endpoint

So I want my S3 bucket to be publicly accessible but only if the request is sent through the VPC endpoint. I allowed public access on both my bucket level and account level and also added the following statements to my bucket policy:
{
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"${media_storage_bucket_arn}",
"${media_storage_bucket_arn}/*"
]
},
{
"Sid": "Access-to-specific-VPCE-only",
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::${current_account}:root"
},
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"${media_storage_bucket_arn}",
"${media_storage_bucket_arn}/*"
],
"Condition": {
"StringEquals": {
"aws:sourceVpce": "${vpc_endpoint}"
}
}
}
I have an EC2 server in a private subnet that needs to read images from an S3 bucket using a curl command and the object URL, so far, the easiest way to accomplish this would be to lift all the public access blocks, but this compromises the safety of the files in the bucket, so that is why I implemented the vpc endpoint statement to restrict access if the request is not sent through the endpoint, This works fine, but it still allows me to read any object in the bucket through its URL even if the request is not sent through the vpc endpoint. I'm sure there has to be an easier/better approach.

S3 bucket policy to deny all except a particular AWS service role and IAM role

Can you write an s3 bucket policy that will deny access to all principals except a particular IAM role and AWS service role (e.g. billingreports.amazonaws.com).
I have tried using 'Deny' with 'NotPrincipal', but none of the below examples work as I don't think the ability to have multiple types of principals is supported by AWS?
This allows you to save the policy but locks out the bucket (warning: only root user can then update policy to unlock)
"Effect": "Deny",
"NotPrincipal": {
"AWS": [
"arn:aws:iam::<account_id>:root",
"arn:aws:iam::<account_id>:role/specialBillingRole"
],
"Service": "billingreports.amazonaws.com"
}
Therefore I am trying to use conditions but can't find the right combinations that will work. Here is an example policy.
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "billingreports.amazonaws.com"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Sid": "",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket/*",
"arn:aws:s3:::my-bucket"
],
"Condition": {
"StringNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::<account_id>:role/specialBillingRole",
"billingreports.amazonaws.com",
"<account_id>"
]
}
}
}
]
}
UPDATED the question as per some comment suggestions.
2nd UPDATE Also tried the below, which still gives access to all roles/users in the account (can't use wildcards in the Principal).
{
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::<account_id>:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket/*",
"arn:aws:s3:::my-bucket"
],
"Condition": {
"ArnNotEquals": {
"aws:PrincipalArn": [
"arn:aws:iam::<account_id>:role/specialBillingRole",
"<account_id>"
]
}
}
}
You can certainly create a bucket policy that grants access only to a service role and an IAM role, but to be clear, a service role will still begin with "arn:aws:iam:::role...".
Are you instead trying to create a bucket policy that grants access both to a particular service and a service role? I'm asking because if you have a role created with billingreports.amazonaws.com as its trusted entity, and if that role is what's intended to access the bucket, then you do not need to list the service separately in your bucket policy (if the scenario is as I imagine).
Please do note, also, that you can indeed use wildcards with the principal, combined with a condition - I do so all the time (see my example policy below). When I want to restrict bucket access to a specific role, I simply include an Allow statement with a Principal of just the role I want to allow, and then a Deny statement with a Principal of "AWS": "*", followed by a condition, like so:
{
"Version": "2008-10-17",
"Id": "PolicyScopedToSecurity",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[accountID]:role/[roleName]",
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::[bucketName]",
"arn:aws:s3:::[bucketName]/*"
]
},
{
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::[bucketName]",
"arn:aws:s3:::[bucketName]/*"
],
"Condition": {
"StringNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::[accountID]:role/[roleName]",
"[accountID]"
]
}
}
}
]
}
If you truly need the service itself to access the bucket, the solution will be slightly different. My response assumes the service role needs access.

Can you use tags to give access to S3 Buckets?

I just tried adding tags to some buckets and then I created an inline IAM role policy that'd give that role access to the S3 buckets however that didn't work. I tried both iam:ResourceTag/tagName and s3:ResourceTag/tagName as conditionals but neither worked.
As everything looked just fine I started thinking that AWS might not have implemented this yet for S3. Is that the case? I tried reviewing documentation and indeed I didn't find anything about this use of tags working with S3.
For example the role HumanResources should have to all buckets tagged with HR, Recruitment etc. but no other buckets.
In looking at Actions, Resources, and Condition Keys for Amazon S3 - AWS Identity and Access Management, there does not appear to be the ability to specify a Bucket Tag in an IAM Policy.
One alternative is to use a wildcard in a bucket name. For example, you could grant permission to access:
acme-hr-1
You could grant permissions based on a bucket name of acme-hr-*.
Yes you can but you will need do on each S3 Resource Policy.
Here is an S3 Policy to grant access to the bucket for only IAM users and roles with a Tag department set to "hr".
To ensure HR employee only have access to these buckets you will need to remove all S3 access from their IAM user/role access polices.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyObjectOthers",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts",
"s3:DeleteObject*",
"s3:PutObject*",
"s3:GetObject*",
"s3:RestoreObject*"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME/*"
],
"Condition": {
"StringNotLike": {
"aws:PrincipalTag/department": [
"hr"
]
}
}
},
{
"Sid": "DenyListOthers",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:ListBucket*"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME"
],
"Condition": {
"StringNotLike": {
"aws:PrincipalTag/department": [
"hr"
]
}
}
},
{
"Sid": "AllowObject",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWS_ACCOUNT_NUMBER:root"
},
"Action": [
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts",
"s3:DeleteObject*",
"s3:PutObject*",
"s3:GetObject*",
"s3:RestoreObject*"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME/*"
],
"Condition": {
"StringLike": {
"aws:PrincipalTag/department": [
"hr"
]
}
}
},
{
"Sid": "AllowList",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWS_ACCOUNT_NUMBER:root"
},
"Action": [
"s3:ListBucket*"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME"
],
"Condition": {
"StringLike": {
"aws:PrincipalTag/department": [
"hr"
]
}
}
}
]
}
Previous Wrong Answer
From: IAM Policy Elements: Variables and Tags - AWS Identity and Access Management
"Resource": ["arn:aws:s3:::bucket/${aws:PrincipalTag/department}"]
Also make sure to include the version at 2012-10-17.

S3 replication: Access denied: Amazon S3 can't detect whether versioning is enabled on the destination bucket

I'm configuring a replication between two s3 buckets. but I get the error
Access denied: Amazon S3 can't detect whether versioning is enabled on
the destination bucket.
The destination bucket is in another account, different region.
Here is the bucket policy in the destination bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::destination",
"arn:aws:s3:::destination/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AROAS3AHCETXXDF5Z5GVG:*",
"AROAS3AHCETXX2DMH4JPY:*",
"AROAS3AHCEXXX4SNCNTNV:*",
"AROAVJZZXXXXXZBBR7PN6L:*"
]
}
}
},
{
"Sid": "S3ReplicationPolicyStmt1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::XXXXXXXXXXX:root"
},
"Action": [
"s3:GetBucketVersioning",
"s3:GetObjectVersionForReplication",
"s3:PutBucketVersioning",
"s3:ReplicateObject",
"s3:ReplicateDelete",
"s3:PutObjectAcl",
"s3:ObjectOwnerOverrideToBucketOwner"
],
"Resource": [
"arn:aws:s3:::destination",
"arn:aws:s3:::destination/*"
]
}
]
}
My buckets are highly confidential, so I first deny all access except for some roles: So in the condition, I have the replication role ID excluded too.
Why the replication role is still not allowed to replicate? What is wrong with this bucket policy ?
In the above policy I actually authorize the replication role twice. in both statements.
Here is the replication IAM role policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:Get*",
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::source",
"arn:aws:s3:::source/*"
]
},
{
"Action": [
"s3:ReplicateObject",
"s3:ReplicateDelete",
"s3:ReplicateTags",
"s3:GetBucketVersioning",
"s3:GetObjectVersionTagging",
"s3:ObjectOwnerOverrideToBucketOwner"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::destination/*"
}
]
}
I tried deleting the explicite deny statement and test the replication, the source bucket gets the Versioning and I had no access denied, but objects are not replicated.
For my experience, AWS S3 policies follow a white-list approach, meaning that you first need to add statements for the actions you want to allow, and then a final statement to deny everything else.
So in your case, try to just switch the statements.
The solution was to white list the replication role in the source bucket as well. Both buckets have similar policy so It was necessary to allow the replication role to access the source.

S3 Private Bucket

I'm trying to create a private S3 bucket with limited access. I only want myself as a user and an EC2 role to have access to the bucket. The purpose of the bucket is to store encrypted SSH keys that will be copied onto machines in an autoscaling group. Right now, when I run aws sync against the bucket, here is the output:
cogility#ip-10-10-200-113:~$ aws s3 sync s3://sshfolder.companycloud.com/cogility /home/cogility/.ssh
download failed: s3://sshfolder.companycloud.com/cogility/id_rsa to ../cogility/.ssh/id_rsa An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
download failed: s3://sshfolder.companycloud.com/cogility/id_rsa.pub to ../cogility/.ssh/id_rsa.pub An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
I create the EC2 instances with an EC2 role with the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"kms:List*",
"kms:Get*",
"kms:Describe*"
],
"Resource": "arn:aws:kms:us-west-2:0000000000:key/kms-id-01234567890"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sshfolder.companycloud.com/*",
"arn:aws:s3:::sshfolder.companycloud.com"
]
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:*",
"ec2:*",
"cloudwatch:*",
"autoscaling:*"
],
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"lambda:List*",
"lambda:Invoke*",
"lambda:Get*"
],
"Resource": "*"
}
]
}
And here is the bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sshfolder.companycloud.com",
"arn:aws:s3:::sshfolder.companycloud.com/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AROAXXXXXXXXXXXXXXXXX", <-- autoscaling-ec2-role user id
"AROAXXXXXXXXXXXXXXXXX",
"AIDAXXXXXXXXXXXXXXXXX",
"AIDAXXXXXXXXXXXXXXXXX"
],
"aws:sourceVpce": "vpce-abc82480d"
},
"ArnNotLike": {
"aws:SourceArn": "arn:aws:sts::000000000000:assumed-role/autoscaling-ec2-role/"
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::000000000000:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sshfolder.companycloud.com",
"arn:aws:s3:::sshfolder.companycloud.com/*"
]
}
]
}
Any idea why I'm not able to access the S3 bucket from my EC2 instance?
Amazon S3 buckets are private by default. Therefore, one approach would be:
Do not use a Bucket Policy
Add permissions to your IAM User and the IAM Role to access the bucket
Alternatively:
Use a Bucket Policy to grant access to the IAM User and IAM Role
Both would be sufficient to meet your needs.
However, if you are further paranoid that somebody might accidentally grant access to the bucket (eg with s3:* and a principal of *), then your approach of explicitly Denying access to anyone other than that User & Role is a good approach.
deny trumps allow in your bucket policy. You need to use not principal to achieve this.
"Statement": [
{
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::000000000000:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sshfolder.companycloud.com",
"arn:aws:s3:::sshfolder.companycloud.com/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AROAXXXXXXXXXXXXXXXXX", <-- autoscaling-ec2-role user id
"AROAXXXXXXXXXXXXXXXXX",
"AIDAXXXXXXXXXXXXXXXXX",
"AIDAXXXXXXXXXXXXXXXXX"
],
"aws:sourceVpce": "vpce-abc82480d"
},
"ArnNotLike": {
"aws:SourceArn": "arn:aws:sts::000000000000:assumed-role/autoscaling-ec2-role/"
}
}
}
]
It just inverts the principal element. You can similarly use NotAction and NotResource as appropriate. You could do away with your conditionals altogether and just use NotPrincipal for all of them, it's generally better practice than conditionals.
Here is a resource on it: https://aws.amazon.com/blogs/security/how-to-create-a-policy-that-whitelists-access-to-sensitive-amazon-s3-buckets/