Why does aws s3 bucketpolicy allow upload of objects? - amazon-web-services

I have this bucket policy( generated from policy generator).
{
"Id": "Policy1620290934586",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1620290801219",
"Action": [
"s3:PutObject"
],
"Effect": "Deny",
"Resource": "arn:aws:s3:::bucket-name/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "AES256"
},
"Null": {
"s3:x-amz-server-side-encryption": "true"
}
},
"Principal": "*"
}
]
}
This policy will allow objects to be uploaded only when there is sse-s3 header is present with aes256 value.
Also i have enabled encryption settings for bucket wide using AWS KMS.
so when i am trying to upload a file with default bucket encryption, according to policy it should not allow that because it doest not have sse-s3 header, yet file upload is successful? why?
i have followed this article
Update :-
the following policy works, means when i am using default bucket encryption settings during upload its denies. why didn't the above policy work and why the latter policy works?
{
"Version": "2012-10-17",
"Id": "PutObjectPolicy",
"Statement": [
{
"Sid": "DenyIncorrectEncryptionHeader",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::bucket-name/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "AES256"
}
}
},
{
"Sid": "DenyUnencryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::bucket-name/*",
"Condition": {
"Null": {
"s3:x-amz-server-side-encryption": "true"
}
}
}
]
}

The null statement:
"Null": {
"s3:x-amz-server-side-encryption": "true"
}
can be read as:
if s3:x-amz-server-side-encryption does not exist.
Thus, if I understand correctly the IAM logic, the situation is as follows:
First case:
Your Condition reads as:
if s3:x-amz-server-side-encryption does not exist AND is not equal to AES256.
Since you are using default encryption in the first try, there is no s3:x-amz-server-side-encryption key in the request. From docs:
A key that is not present in the request is considered a mismatch.
This means that your Condition is not satisfied and Deny does not apply.
Second case.
This one works, because by having two separate statements you are saying:
if s3:x-amz-server-side-encryption does not exist OR is not equal to AES256
So Deny will take effect in any case.

Related

AWS Organization SCP to enforce encryption based on Bucket tags

I'm writing a SCP like below.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyIncorrectEncryptionHeader",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"ForAnyValue:StringEquals": {
"aws:ResourceTag/Owner": [
"finance"
]
},
"StringNotEquals": {
"s3:x-amz-server-side-encryption": [
"AES256",
"aws:kms"
]
}
}
},
{
"Sid": "DenyUnEncryptedObjectUploads",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"ForAnyValue:StringEquals": {
"aws:ResourceTag/Owner": [
"finance"
]
},
"Null": {
"s3:x-amz-server-side-encryption": true
}
}
}
]
}
What I want to do is to only allow users to upload files to buckets own by finance with using encryption.
I use Tag Key:Value Owner:finance to identify s3 buckets enforce this policy. However this, seems to be not working and still we can upload objects into these buckets without encryption.
Note, If I remove aws:ResourceTag/Owner condition, the policy works pretty well. But that affect all buckets. But in my case, I only need to apply this policy for the buckets, which owns by finance team.

AWS CLI and MFA

I have created an IAM user (without MFA) and attached the below policy to the user. This is to make sure that the calls to the S3 use MFA. But, when I use the AccessKeys for this user via the AWS CLI, I am able to perform the S3 operation aws s3 ls with out any authorization error.
Am I doing something wrong or is it a bug in AWS?
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
Not exactly sure why the policy statement in the OP is not working. But,
I did attach the AmazonS3FullAccess policy with one of the below policy and it behaves as expected. For the long-term credentials I am not able to perform S3 operations and for the temporary credentials when authenticated with MFA I am able to perform the S3 operations.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "s3:*",
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
{
"Version": "2012-10-17",
"Id": "123",
"Statement": [
{
"Effect": "Deny",
"Resource": "*",
"Action": "s3:*",
"Condition": {
"Null": {
"aws:MultiFactorAuthAge": true
}
}
}
]
}
You are using Allow, but you should be using Deny as explained in AWS docs. Example:
{
"Version": "2012-10-17",
"Id": "123",
"Statement": [
{
"Sid": "",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/taxdocuments/*",
"Condition": { "Null": { "aws:MultiFactorAuthAge": true }}
}
]
}
Read the AWS docs carefully, as you can lock yourself out of the bucket if you use Deny incorrectly.

AWS - Permission Denied After Setting a Policy with SecureTransport:false

I was trying to enforce a policy that allows only SSL access.
However, after attaching the Policy, now I get "You don't have permissions" on every single thing in this bucket, including the Permissions tab and Bucket Policy section.
I am the admin and I do have all access permissions to S3 in IAM for my user.
This is the policy:
{
"Id": "Policy98421321896",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "MustBeEncryptedInTransit",
"Action": "s3:*",
"Effect": "Deny",
"Resource": [
"arn:aws:s3:::cf-templates-98d9d7a96z21x-us-east-1",
"arn:aws:s3:::cf-templates-98d9d7a96z21x-us-east-1/*"
],
"Condition": {
"ArnEqualsIfExists": {
"aws:SecureTransport": "false"
}
},
"Principal": "*"
}
]
}
Question is:
How do I restore permissions to this bucket?
And how should I correctly set this policy?
When you want to add a condition which checks for Boolean values then it should be "Bool" key with valid value.
"Condition": {
"Bool": {
"aws:SecureTransport": "true"
}
}
What you are trying to achieve is mentioned in this blog and you can use it according to your need.
https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-policy-for-config-rule/
{
"Id": "ExamplePolicy",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSSLRequestsOnly",
"Action": "s3:*",
"Effect": "Deny",
"Resource": [
"arn:aws:s3:::DOC-EXAMPLE-BUCKET",
"arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
},
"Principal": "*"
}
]
}
About your 2nd part of the question, you can reset the permission using your root account as it should have god level permissions. But it is strange that updating a bucket policy changes your IAM policies and you can't access certain parts of S3 config. Maybe something else is missing here..

How to limit access to an S3 bucket to a specific VPC while allowing console access

I am setting up a selection of S3 buckets and wish to restrict access to them to a VPC while still allowing access to the buckets from the AWS console.
As proposed here I have created an S3 endpoint and also added it to the main routing table. The policy on the endpoint allows full access to all resources.
I have created an S3 policy (see below) and added it to the bucket. As soon as I save the policy, access to the bucket from the console is no longer possible.
I have also tried to specifically add a user to the condition "StringNotEquals" in the form of "aws:username": "user1", to no avail.
{
"Version": "2012-10-17",
"Id": "Policy-S3-Bucket-myBucket",
"Statement": [
{
"Sid": "Access-via-VPC-only",
"Principal": "*",
"Action": "s3:*",
"Effect": "Deny",
"Resource": [
"arn:aws:s3:::myBucket",
"arn:aws:s3:::myBucket/*"
],
"Condition": {
"StringNotEquals": {
"aws:sourceVpc": "vpc-01c9d66c12345"
}
}
},
{
"Sid": "Allow-console-access",
"Action": [
"s3:*"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::myBucket",
"arn:aws:s3:::myBucket/*"
],
"Principal": {
"AWS": [
"arn:aws:iam::<account-id>:user/user1", "arn:aws:iam::<account-id>:user/user2"
]
}
}
]
}
The expected result would be that the S3 bucket is only accessible by the aforementioned VPC and via the AWS console.
The actual result is:
The bucket overview shows an "Error: Access Denied" and the permissions page(public access settings) shows: "You don't have access to view this configuration. Contact your account administrator to request access."
I have to login using the root user and delete the policy to regain access to the bucket.
I found a solution which seems to work. I have tested it in the policy simulator and it also appears to work correctly in the live environment. The following policy does the trick:
{
"Version": "2012-10-17",
"Id": "Policy-S3-Bucket-myBucket",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:ListAllMyBuckets"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:username": ["user1", "user2"]
}
}
},
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::myBucket"],
"Condition": {
"StringEquals": {
"aws:sourceVpc": "vpc-01c9d66c12345"
}
}
},
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::myBucket"],
"Condition": {
"StringEquals": {
"aws:username": ["user1", "user2"]
}
}
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": ["arn:aws:s3:::myBucket/*"],
"Condition": {
"StringEquals": {
"aws:sourceVpc": "vpc-01c9d66c12345"
}
}
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": ["arn:aws:s3:::myBucket/*"],
"Condition": {
"StringEquals": {
"aws:username": ["user1", "user2"]
}
}
}
]
}
The policy requires for either the sourceVpc string OR the username to be as listed in the condition.
Admittedly, the policy is verbose and there is a substantial amount of replication. If anyone has an idea to solve this more efficiently, I'm all ears.
This policy was tested and gives exactly what you need:
Statement": {
"Sid": "Allow-anonymous-access-from-specific-VPC",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket_name/*",
"Condition": {
"StringEquals": {
"aws:SourceVpc": "some-vpc-id"
}
}
}
This will allow anonymous access from requests coming from "some-vpc-id", while yet allowing access from AWS console.
Your VPC has to have S3 endpoint configured for it to work.
The trick seems to be on denying everything except if it comes from the user or from the VPC but it has to be in the same condition. The way policies work is that Deny rules precede over every other rule, so if you deny, you can't then allow on a subsequent rule; it's already denied and that's it.
By the way, the aws:userid of the root user is the Account Id. Probably a bad practice to use this user but oh well :P
So my bucket now only accepts traffic from the VPC and from the user I log into via the AWS web console (so I don't get access denied errors in the web console)
{
"Version": "2012-10-17",
"Id": "Policy154336817545456388",
"Statement": [
{
"Sid": "Block-if-not-from-VPC-or-Me",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::bucket-name",
"arn:aws:s3:::bucket-name/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-4598ujfjrhc",
"aws:userid": "576767373466"
}
}
}
]
}

Restrict bucket creation to an region

I want to restrict the user from creating the Amazon S3 buckets in a particular region. I wrote a policy like below and attached to the user. But it denies the user from creating any bucket.
Please help. The other Statements are written to see if the buckets are created. Unfortunately, we cannot restrict the user from listing the buckets.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RegionSpecificS3BucketCreation",
"Effect": "Allow",
"Action": "s3:CreateBucket",
"Resource": "arn:aws:s3:::*",
"Condition": {
"StringLike": {
"s3:LocationConstraint": "us-east-1"
}
}
},
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::*"
},
{
"Sid": "VisualEditor2",
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:HeadBucket"
],
"Resource": "*"
}
]
}
us-east-1 is a special case. That is the original S3 region and for backwards compatibility buckets in that region do not actually have a location constraint declared. They are still constrained to us-east-1 (the data remains in that region) but you create buckets in us-east-1 by not specifying a location constraint at the API level.
I suspect that the correct condition test for that specific region would be this:
"Condition": {
"StringLikeIfExists": {
"s3:LocationConstraint": ""
}
}
That is, if the string is present at all, it must be an empty string.
For all other regions, what you are doing should work fine.
I used the below policy to restrict the bucket creation in all region then us-east-1 and ap-south-1. Rather than using the "Allow" effect I applied a "Deny" effect for all S3 actions and added and exception for required regions.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Deny",
"Action": "s3:*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"us-east-1",
"ap-south-1"
]
}
}
}
]
}