AWS - How to limit Amazon S3 access to a VPC - amazon-web-services

I would like to create a policy and attach it to the user, which will only allow them to access to Amazon S3 from an EC2 instance that is on specific VPC. Tried below logic, but, it is not allowing user to access Amazon S3 even the EC2 instance is running on vpc-35test12.
Is there a way to block user from accessing Amazon S3 but allow them only from specific vpc or subnet ?
{
"Effect": "Allow",
"NotAction": [
"iam:*",
"organizations:*",
"account:*",
"s3:*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::*",
"Condition": {
"StringLike": {
"aws:SourceVpc": "vpc-35test12"
}
}

The condition aws:SourceVpc works when you have a VPC endpoint for s3. because all the traffic to S3 goes through the public internet only even if the request is originated from the VPC. If you want the VPC to access the S3 privately via internal amazon network (without going through public internet), You will need to create a VPC endpoint for s3 and then use the aws:SourceVpc condition to restrict access only to the VPC.
If you just want to allow access to S3 from an EC2 instance, As #Ervin suggested:
Block public access on S3
Associate an IAM role to the EC2 instance
assign an IAM policy to the Role allowing access to S3

I think you are better off creating a specific IAM role and assign it to the instances you want to allow accessing the S3 bucket. After that block all other access to the bucket with an explicit Deny for "Principal" : "*" and aws:userId or aws:PrincipalArn. Here an example policy
{
"Sid":"ItIsOkToDoThis",
"Effect":"Deny",
"Action":"*",
"Principal":"*",
"Resource":[
"arn:aws:s3:::ACCESSIBLE_S3_BUCKET/*",
"arn:aws:s3:::ACCESSIBLE_S3_BUCKET"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"UNIQUE_ROLE_ID:*"
]
}
}
}
Have a look at this article for more details https://levelup.gitconnected.com/how-i-locked-the-whole-company-out-of-an-amazon-s3-bucket-1781de51e4be
Best,
Stefan

Related

Cross account S3 static website access over VPN only

I'm trying to allow access to s3 bucket static website over VPN from network aws account , bucket in prod account.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": "account-prod",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*",
"Condition": {
"StringEquals": {
"aws:SourceVpc": "vpc-1"
}
}
}
{
"Sid": "",
"Effect": "Allow",
"Principal": "account-network",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*",
"Condition": {
"StringEquals": {
"aws:SourceVpc": "vpc-2" <<<>>> tried SourceVpce as well
}
}
}
]
}
I used VPC endpoint interface in the account where VPN is setup , I tried using Condition SourceVpc and SourceVpce but non worked.
I'm using transit gateway and aws client vpn and allowed s3 endpoint IPs on the vpn endpoint + SGs + auth rules. (tgw is used and s3 prefix list, route entry from s3 prefix list via tgw)
bucket uses object owner + private ACL + bucket policy and I tried adding grantee with the canonical account id.
Any ideas what am I doing wrong here ?
This currently works in the prod account as we have another VPN solution that runs there, we are trying to migrate everything to network account and move to aws client vpn.
Any ideas what am I doing wrong here ?
Yes. s3 bucket static website can only be accesses over the Internet. You can't access them using private IP addresses from VPC or VPN. If you use VPN, you have to setup some proxy which will access the website using the internet, and then pass it back to your host.
Make sure that your VPC Subnet route table has a route to the S3 endpoint, and the policy for the endpoint is giving access.
https://tomgregory.com/when-to-use-an-aws-s3-vpc-endpoint/
next, setup your bucket policy as below, try to give access from the source of your VPC Endpoint, and not the VPC itself. (note the vpce in the policy doc).
https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies-vpc-endpoint.html

What is the difference between S3 bucket policies and S3 VPC endpoints?

I was curious to know what the functional difference is for creating an S3 bucket with a bucket policy like:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Access-to-specific-VPC-only",
"Principal": "*",
"Action": "s3:*",
"Effect": "Deny",
"Resource": ["arn:aws:s3:::example-bucket",
"arn:aws:s3:::example-bucket/*"],
"Condition": {
"StringNotEquals": {
"aws:sourceVpc": "vpc-111bbb22"
}
}
}
]
}
versus creating a VPC endpoint like:
{
"Name": "example-vpc-ap",
"Bucket": "example-bucket",
"NetworkOrigin": "VPC",
"VpcConfiguration": {
"VpcId": "vpc-111bbb22"
},
"CreationDate": "2019-11-27T00:00:00Z"
}
Are they functionally equivalent? Is one being depricated or a best practice? It is not clear what the answer is after referencing:
https://docs.aws.amazon.com/AmazonS3/latest/dev/creating-access-points.html#access-points-vpc
VPC access policy for S3 buckets
S3 VPC end point Bucket policy
Thanks
I think that aws:sourceVpc can only be used in conjunction with a VPC Endpoint.
From Example Bucket Policies for VPC Endpoints for Amazon S3 - Amazon Simple Storage Service:
You can create a bucket policy that restricts access to a specific VPC by using the aws:SourceVpc condition. This is useful if you have multiple VPC endpoints configured in the same VPC, and you want to manage access to your Amazon S3 buckets for all of your endpoints.
The VPC Endpoint definition shown in your Question is simply saying that the Endpoint is connected to a specific VPC. It does not restrict bucket access to only that Endpoint. Users could still access the bucket via the Internet or another endpoint.
I will, however, admit that all these endpoints and configurations are quite confusing!

S3 is not detecting the bucket policies

I have created an Amazon S3 bucket and I want to provide access to all my corporate users, which means anybody can access the S3 bucket and download objects.
I have written a Bucket Policy for IP restriction:
{
"Version": "2012-10-17",
"Id": "S3PolicyIPRestrict",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Allow",
"Principal": "",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mybucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"10.0.8.10"
]
}
}
}
]
}
When I add ACL permission as everyone "read" then only I am able to access the object. But the bucket policy is not applying. Anybody can access from outside the network also. What I am doing wrong?
Your bucket policy is granting permission for a source IP address of 10.0.8.10. This is a private IP address.
However, Amazon S3 is a public service sitting on the Internet. When accessing Amazon S3, requests go across the Internet (or at least to the AWS edge of the Internet) and your request will appear to be coming from a Public IP address. Therefore, the policy is not permitting access, since your address does not match the one in the policy.
You should change the policy to use the Public IP address that is used when your corporate traffic access the Internet. You could discover this address via http://checkip.amazonaws.com.
Also, if you are granting access via a Bucket Policy, you should not grant access via the ACLs.

Only allow EC2 instance to access static website on S3

I have a static website hosted on S3, I have set all files to be public.
Also, I have an EC2 instance with nginx that acts as a reverse proxy and can access the static website, so S3 plays the role of the origin.
What I would like to do now is set all files on S3 to be private, so that the website can only be accessed by traffic coming from the nginx (EC2).
So far I have tried the following. I have created and attached a new policy role to the EC2 instance with
Policies Granting Permission: AmazonS3ReadOnlyAccess
And have rebooted the EC2 instance.
I then created a policy in my S3 bucket console > Permissions > Bucket Policy
{
"Version": "xxxxx",
"Id": "xxxxxxx",
"Statement": [
{
"Sid": "xxxxxxx",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::XXXXXXXXXX:role/MyROLE"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::XXX-bucket/*"
}
]
}
As principal I have set the ARN I got when I created the role for the EC2 instance.
"Principal": {
"AWS": "arn:aws:iam::XXXXXXXXXX:role/MyROLE"
},
However, this does not work, any help is appreciated.
If the Amazon EC2 instance with nginx is merely making generic web requests to Amazon S3, then the question becomes how to identify requests coming from nginx as 'permitted', while rejecting all other requests.
One method is to use a VPC Endpoint for S3, which allows direct communication from a VPC to Amazon S3 (rather than going out an Internet Gateway).
A bucket policy can then restrict access to the bucket such that it can only be accessed via that endpoint.
Here is a bucket policy from Example Bucket Policies for VPC Endpoints for Amazon S3:
The following is an example of an S3 bucket policy that allows access to a specific bucket, examplebucket, only from the VPC endpoint with the ID vpce-1a2b3c4d. The policy uses the aws:sourceVpce condition key to restrict access to the specified VPC endpoint.
{
"Version": "2012-10-17",
"Id": "Policy",
"Statement": [
{
"Sid": "Access-to-specific-VPCE-only",
"Action": "s3:*",
"Effect": "Allow",
"Resource": ["arn:aws:s3:::examplebucket",
"arn:aws:s3:::examplebucket/*"],
"Condition": {
"StringEquals": {
"aws:sourceVpce": "vpce-1a2b3c4d"
}
},
"Principal": "*"
}
]
}
So, the complete design would be:
Object ACL: Private only (remove any current public permissions)
Bucket Policy: As above
IAM Role: Not needed
Route Table configured for VPC Endpoint
Permissions in Amazon S3 can be granted in several ways:
Directly on an object (known as an Access Control List or ACL)
Via a Bucket Policy (which applies to the whole bucket, or a directory)
To an IAM User/Group/Role
If any of the above grant access, then the object can be accessed publicly.
Your scenario requires the following configuration:
The ACL on each object should not permit public access
There should be no Bucket Policy
You should assign permissions in the Policy attached to the IAM Role
Whenever you have permissions relating to a User/Group/Role, it is better to assign the permission in IAM rather than on the Bucket. Use Bucket Policies for general access to all users.
The policy on the Role would be:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowBucketAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::my-bucket/*"
]
}
]
}
This policy is directly applied to the IAM Role, so there is no need for a principal field.
Please note that this policy only allows GetObject -- it does not permit listing of buckets, uploading objects, etc.
You also mention that "I have set all files to be public". If you did this by making each individual object publicly readable, then anyone will still be able to access the objects. There are two ways to prevent this -- either remove the permissions from each object, or create a Bucket Policy with a Deny statement that stops access, but still permits the Role to get access.
That's starting to get a bit tricky and hard to maintain, so I'd recommend removing the permissions from each object. This can be done via the management console by editing the permissions on each object, or by using the AWS Command-Line Interface (CLI) with a command like:
aws s3 cp s3://my-bucket s3://my-bucket --recursive --acl private
This copies the files in-place but changes the access settings.
(I'm not 100% sure whether to use --acl private or --acl bucket-owner-full-control, so play around a bit.)

Amazon S3 Bucket Policy: How to lock down access to only your EC2 Instances

I am looking to lock down an S3 bucket for security purposes - i'm storing deployment images in the bucket.
What I want to do is create a bucket policy that supports anonymous downloads over http only from EC2 instances in my account.
Is there a way to do this?
An example of a policy that I'm trying to use (it won't allow itself to be applied):
{
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::[my bucket name]",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:ec2:us-east-1:[my account id]:instance/*"
}
}
}
]
}
Just to clarify how this is normally done. You create a IAM policy, attach it to a new or existing role, and decorate the ec2 instance with the role. You can also provide access through bucket policies, but that is less precise.
Details below:
S3 buckets are default deny except for my the owner. So you create your bucket and upload the data. You can verify with a browser that the files are not accessible by trying https://s3.amazonaws.com/MyBucketName/file.ext. Should come back with error code "Access Denied" in the xml. If you get an error code of "NoSuchBucket", you have the url wrong.
Create an IAM policy based on arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess. Starts out looking like the snip below. Take a look at the "Resource" key, and note that it is set to a wild card. You just modify this to be the arn of your bucket. You have to do one for the bucket and its contents so it becomes: "Resource": ["arn:aws:s3:::MyBucketName", "arn:aws:s3:::MyBucketName/*"]
Now that you have a policy, what you want to do is to decorate your instances with a IAM Role that automatically grants it this policy. All without any authentication keys having to be in the instance. So go to Role, create new role, make an Amazon EC2 role, find the policy you just created, and your Role is ready.
Finally you create your instance, and add the IAM role you just created. If the machine already has its own role, you just have to merge the two roles into a new one for the machine. If the machine is already running, it wont get the new role until you restart.
Now you should be good to go. The machine has the rights to access the s3 share. Now you can use the following command to copy files to your instance. Note you have to specify the region
aws s3 cp --region us-east-1 s3://MyBucketName/MyFileName.tgz /home/ubuntu
Please Note, the term "Security through obscurity" is only a thing in the movies. Either something is provably secure, or it is insecure.
I used something like
{
"Version": "2012-10-17",
"Id": "Allow only My VPC",
"Statement": [
{
"Sid": "Allow only My VPC",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject", "s3:ListBucket",
"Resource": [
"arn::s3:::{BUCKET_NAME}",
"arn::s3:::{BUCKET_NAME}/*"
],
"Condition": {
"StringLike": {
"aws:sourceVpc": "{VPC_ID}" OR "aws:sourceVpce": "{VPCe_ENDPOINT}"
}
}
}
]
}