support CalledVia athena condition with white-listed IP address - amazon-iam

This works as expected. It allows Athena to access the bucket along with other 4 white listed IP addresses.
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::athenadata162",
"arn:aws:s3:::athenadata162/*"
],
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"123.456.789.120/32",
"234.567.889.120/32",
"456.789.123.456/32",
"567.890.123.456/32"
]
}
}
},
{
"Sid": "CrossAccountAccessAthena",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::athenadata162",
"arn:aws:s3:::athenadata162/*"
],
"Condition": {
"ForAnyValue:StringEquals": {
"aws:CalledVia": "athena.amazonaws.com"
}
}
}
]
}
But if I change the * in the second statement to point to another user from some other account, then I get access denied error.
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/readwriteuser"
},
It is possible to use "CalledVia" condition with white-listed IP addresses.
But is it possible to use the condition for some other account and also white list IP addresses?
If I keep only the second condition, then it works as expected and allow athena from another account to read data from current bucket. I am trying to allow certain known IP addresses along with Athena from another account. That does not seem to be possible. In other words...
IP addresses + Athena from current account = Possible
NO IP addresses + Athena from another account = Possible
IP addresses + Athena from another account = ??
More info:
https://aws.amazon.com/about-aws/whats-new/2020/03/amazon-athena-support-querying-data-s3-buckets-aws-iam-condition-key/

Related

AWS Bucket Policy to Allow Lambda but block all other external IPs

I need to create a AWS Bucket Policy which blocks all external IP addresses, except our office IP, but still allows Lambda functions to access the Bucket.
I know how to make this work using a AWS VPC and NAT, however due to the high costs involved the client doesn't want to activate those.
So far this how my bucket policy looks like, but it's not working:
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "GiveSESPermissionToWriteEmail",
"Effect": "Allow",
"Principal": {
"Service": "ses.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::files-dev/*"
},
{
"Sid": "SourceIP",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::files-dev/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"81.111.111.111/24"
]
}
}
},
{
"Sid": "GiveLambdaPermisssion",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::6XXXXXX:role/app-backend-dev-lambdaFunctionRole-1XXXX"
],
"Service": "lambda.amazonaws.com"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::files-dev/*"
}
]
}
I've think I read all of AWS documentation I could find related to this, but I couldn't find what I was looking for. It might be because their docs, are so confusing and do not cover all the functionality. And I have also searched for solutions here on StackOverflow and other forums but nothing worked.
You won't be able to whitelist the Lambda function's IP addresses without having them go through a NAT gateway. To do so would require whitelisting every IP address at AWS, which is not only a hugely unmanageable list of IPs, but also entirely insecure since it would whitelist anyone with an AWS account.
The problem is that the "NotIpAddress" rule you currently have is always going to apply, so it is always going to deny your Lambda functions. I believe the way to fix this is to add a NotPrincipal clause to the SourceIP rule, so that it doesn't apply to Lambda function calls. Something like the following:
{
"Sid": "SourceIP",
"Effect": "Deny",
"NotPrincipal": {"AWS": [
"arn:aws:iam::6XXXXXX:role/app-backend-dev-lambdaFunctionRole-1XXXX"
]},
"Action": "s3:*",
"Resource": "arn:aws:s3:::files-dev/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"81.111.111.111/24"
]
}
}
},
This is heavily inspired by Mark B's answer, but fixed to include the assumed role principal.
Please note that the assumed role is sts instead of iam!
{
"Sid": "SourceIP",
"Effect": "Deny",
"NotPrincipal": {"AWS": [
"arn:aws:iam::6XXXXXX:role/app-backend-dev-lambdaFunctionRole-1XXXX",
"arn:aws:sts::6XXXXXX:assumed-role/app-backend-dev-lambdaFunctionRole-1XXXX/lambda-name"
]},
"Action": "s3:*",
"Resource": "arn:aws:s3:::files-dev/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"81.111.111.111/24"
]
}
}
},

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"
}
}
}
]
}

How to allow Amazon S3 access from specific IPs

I am trying this policy to allow users to Put and List object access with a particular IP (56.160.12.114) only and all the rest should have only Get access. But this policy is not working for me:
{
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "IPDeny",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-wicked-awesome-bucket/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "56.160.12.114/28"
}
}
}
]
}
This policy is saying: Deny access to anyone who is not using this range of IP addresses
That's fine, but you will also need a policy that Allows access, because the default behaviour is Deny. Thus, you are Denying people who are already denied by default.
A better way would be:
Have default Deny access (happens automatically)
Allow access based on IP
Something like this:
{
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-wicked-awesome-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "56.160.12.114/28"
}
}
}
]
}
Please note, however, that this is granting s3:* access to any system that is coming from that range of IP addresses (including whatever is connected to that network range). Make sure you're okay with that.
Update:
If you only want to grant the user the ability to Put and List the object, then use:
{
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::jstack-b",
"arn:aws:s3:::jstack-b/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "56.160.12.114/28"
}
}
}
]
}

s3 policy allow multiple IPs at the same statement

I am trying to allow connection to a bucket from 3 specified ip addresses. When I add them this way:
{
"Version": "2008-10-17",
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "IPDeny",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::bucket/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "ip1",
"aws:SourceIp": "ip2",
"aws:SourceIp": "ip3"
}
}
}
]
}
Upon saving only one line of the three will be kept and so I can only have one IP set. Any idea how can I do it without going to long adding new statements and workarounds?
{
"Version": "2008-10-17",
"Id": "testPolicy",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucketname/subfolder/subfolder2/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"xxx.xxx.xxx.xxx/32",
"xxx.xxx.xxx.xxx/32"
]
}
}
}
]
}
You've to provide IP's in the form of subnet like
wrong: 1.2.3.4
Right: 1.2.3.4/32
It isn't mandatory to apply the routing prefix for the specific IP address. According to the official AWS Documentation,
If you specify an IP address without the associated routing prefix, IAM uses the default prefix value of /32.
I've tested it at my end and it works even after not specifying /32 after the IP address.

Amazon S3 - add local computer to list of allowed referers

I have a bucket policy in place (below) that only allows access to S3 from our remote website (to prevent hotlinking). I'd like to also be able to access the files when working from our local computer. I've tried adding my ip address, local ip, and localhost to aws:Referer but that hasn't worked.
For the task I'm trying to accomplish, I'd like to be able to directly access the files in my browser using the direct link: https://s3.amazonaws.com/[bucket]/[filename]
Any suggestions? Thanks!
{
"Version": "2012-10-17",
"Id": "http referer policy example",
"Statement": [
{
"Sid": "Allow get requests referred by www.mysite.com and mysite.com",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::[bucketname]/*",
"Condition": {
"StringLike": {
"aws:Referer": [
"http://www.[mysite].com/*",
"http://192.168.1.6/*",
"http://foundwaves.com/*",
"http://[ip]/*",
"http://localhost/*"
]
}
}
},
{
"Sid": "Explicit deny to ensure requests are allowed only from specific referer.",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::foundwaves/*",
"Condition": {
"StringNotLike": {
"aws:Referer": [
"http://www.[mysite].com/*",
"http://192.168.1.6/*",
"http://foundwaves.com/*",
"http://[ip]/*",
"http://localhost/*"
]
}
}
}
]
}