how to allow AWS Textract access to a protected S3 bucket - amazon-web-services

I have bucket policy which allows access only from a VPC:
{
"Version": "2012-10-17",
"Id": "aksdhjfaksdhf",
"Statement": [
{
"Sid": "Access-only-from-a-specific-VPC",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::zzzz",
"arn:aws:s3:::zzzz/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpc": "vpc-xxxx"
}
}
}
]
}
I'd like to allow traffic coming from AWS Textract to this bucket as well. I've tried various methods but because of the absolute precedence of 'explicit deny' (which I require), I cannot make it work.
Is there a different policy formulation or a different method altogether to restrict the access to this S3 Bucket to traffic from the VPC AND from Textract service exclusively?

This will not be possible.
In general, it's a good idea to avoid Deny policies since they override any Allow policy. They can be notoriously hard to configure correctly.
One option would be to remove the Deny and be very careful in who is granted Allow access to the bucket.
However, if this is too hard (eg Admins are given access to all buckets by default), then a common practice is to move sensitive data to an S3 bucket in a different AWS Account and only grant cross-account access to specific users.

Related

How can I find what external S3 buckets (AWS-owned) are being accessed?

I'm using WorkSpaces Web (not WorkSpaces!) with an S3 VPC endpoint. I would like to be able to restrict S3 access via the S3 endpoint policy to only the buckets required by WorkSpaces Web. I cannot find any documentation with the answers, and AWS support does not seem to know what these buckets are. How can I find out what buckets the service is talking to? I see the requests in VPC flow logs, but that obviously doesn't show what URL or bucket it is trying to talk to. I have tried the same policy used for WorkSpaces (below), but it was not correct (or possibly not enough). I have confirmed that s3:GetObject is the only action needed.
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "Access-to-specific-bucket-only",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::aws-windows-downloads-us-east-1/*",
"arn:aws:s3:::amazon-ssm-us-east-1/*",
"arn:aws:s3:::amazon-ssm-packages-us-east-1/*",
"arn:aws:s3:::us-east-1-birdwatcher-prod/*",
"arn:aws:s3:::aws-ssm-distributor-file-us-east-1/*",
"arn:aws:s3:::aws-ssm-document-attachments-us-east-1/*",
"arn:aws:s3:::patch-baseline-snapshot-us-east-1/*",
"arn:aws:s3:::amazonlinux.*.amazonaws.com/*",
"arn:aws:s3:::repo.*.amazonaws.com/*",
"arn:aws:s3:::packages.*.amazonaws.com/*"
]
}
]
}

AWS policy to prevent hotlinking

I am trying to set up things on S3 to prevent hotlinking.
I've taken advice from here: How do I prevent hotlinking on Amazon S3 without using signed URLs?
And also this one: https://kinsta.com/blog/hotlinking/
However, I can't get it to work.
First, I prevent all public access to the bucket so the settings on the Permissions tab are like this:
I have set the policy like this:
{
"Version": "2008-10-17",
"Id": "HTTP referer policy example",
"Statement": [
{
"Sid": "prevent hotlinking",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mybucket/*",
"Condition": {
"StringLike": {
"aws:Referer": [
"http://example.co.uk/*",
"http://www.example.co.uk/*",
"https://example.co.uk/*",
"https://www.example.co.uk/*",
"http://localhost/01-example/*"
]
}
}
}
]
}
However, when I try to access content from the bucket from the referring site, I cannot see the S3 content.
What am I doing wrong?
I prevent all public access to the bucket so the settings on the Permissions tab are like this.
That's why it does not work. Your policy allows for public/anonymous access ("Principal": {"AWS": "*"}), but at the same time you explicitly "prevent all public access". You have to enable the public access. From docs:
Before you use a bucket policy to grant read-only permission to an anonymous user, you must disable block public access settings for your bucket.
Blocking public access options will override any other configuration you're using, for this reason your bucket policy will not take effect.
To allow your policy to work you will need to disable this, you might choose to keep several of the options enabled to prevent further changes being made to the bucket policy.
On a related note to your policy, the Referer header can be faked to still access these assets so it should not be treated as a silver bullet.
Another solution to use would be to either use an S3 signed URL or to take a look at using a CloudFront distribution in front of your S3 bucket and then making use of a signed cookie.

Why some AWS IAM actions require all resources

when creating a IAM policy, if I choose ListAllMyBuckets, the resource become "*", rather than "arn:aws:s3:::*". I do not understand it. How can ListAllMyBuckets requires resources not in s3? Doesn't "Bucket" mean S3 bucket?
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
}
]
}
Since s3:ListAllMyBuckets only applies to S3 and no other AWS resource, "" is shorthand for "arn:aws:s3:::". In this case both statements are exactly the same.
The actions in IAM policies have direct relation with AWS API. For example, the AWS S3 API has a ListAllMyBuckets call that serve to, surprise: List All Buckets of your account. There is no point in give permission to "List All Your Buckets" and at the same time do not allow list some of then.
The same happens with DescribeInstances API for EC2. If you need to create limitation in your policies, you must use Conditions. (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html). But they are not available in all cases.

Allow S3 Bucket access from either specific VPC or console

I have some app configuration stored in a file in an S3 bucket (api keys). I have the S3 bucket configured to only allow access via a specific VPC endpoint, which ties the keys to specific environments, and prevents e.g. production keys being accidentally used in a staging or test environment.
However occasionally I need to amend these keys, and it's a pain. Currently the bucket policy prevents console access, so I have to remove the bucket policy, update the file, then replace the policy.
How can I allow access from the console, a specific VPC endpoint, and no where else?
Current policy, where I've tried and failed already:
{
"Version": "2012-10-17",
"Id": "Policy12345",
"Statement": [
{
"Sid": "Principal-Access",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::account-id:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-keys-staging",
"arn:aws:s3:::my-keys-staging/*"
]
},
{
"Sid": "Access-to-specific-VPCE-only",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-keys-staging",
"arn:aws:s3:::my-keys-staging/*"
],
"Condition": {
"StringNotEquals": {
"aws:sourceVpce": "vpce-vpceid"
}
}
}
]
}
As mentioned in the comments, having an explicit Deny cannot be overridden. By including the Deny tied to a particular VPC, you cannot add any other Allow elements to counteract that Deny statement.
Option 1
One option is to change your "deny if not from VPC abc" statement to "allow if from VPC abc". This would allow you to add additional Allow statements to your policy to allow you to access the bucket from elsewhere.
However, there are 2 very important caveats that goes along with doing that:
Any user with "generic" S3 access via IAM policies would have access to the bucket, and
Any role/user from said VPC would be allowed into your bucket.
So by changing Deny to Allow, you will no longer have a VPC-restriction at the bucket level.
This may or may not be within your organization's security requirements.
Option 2
Instead, you can amend your existing Deny to add additional conditions which will work in an AND situation:
"Condition": {
"StringNotEquals": {
"aws:sourceVpce": "vpce-vpceid",
"aws:username": "your-username"
}
}
This type of condition will deny the request if:
The request is not coming from your magic VPC, AND
The request is not coming from YOUR username
So you should be able to maintain the restriction of limiting requests to your VPC with the exception that your user sign-in would be allowed access to the bucket from anywhere.
Note the security hole you are opening up by doing this. You should ensure you restrict the username to one that (a) does not have any access keys assigned, and (b) has MFA enabled.

S3 IAM Policy to access other account

We need to create an IAM user that is allowed to access buckets in our client's S3 accounts (provided that they have allowed us access to those buckets as well).
We have created an IAM user in our account with the following inline policy:
{
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:PutObjectAcl",
"s3:ListMultipartUploadParts",
"s3:PutObject",
"s3:ListBucketMultipartUploads",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::*"
}
]
}
In addition to this, we will request that our clients use the following policy and apply it to their relevant bucket:
{
"Version": "2008-10-17",
"Id": "Policy1416999097026",
"Statement": [
{
"Sid": "Stmt1416998971331",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::229569340673:user/our-iam-user"
},
"Action": [
"s3:AbortMultipartUpload",
"s3:PutObjectAcl",
"s3:ListMultipartUploadParts",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::client-bucket-name/*"
},
{
"Sid": "Stmt1416999025675",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::229569340673:user/our-iam-user"
},
"Action": [
"s3:ListBucketMultipartUploads",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::client-bucket-name"
}
]
}
Whilst this all seems to work fine, the one major issue that we have discovered is our own internal inline policy seems to give full access to our-iam-user to all of our own internal buckets.
Have we mis-configured something, or are we missing something else obvious here?
According to AWS support, this is not the right way to approach the problem:
https://forums.aws.amazon.com/message.jspa?messageID=618606
I am copying the answer from them here.
AWS:
The policy you're using with your IAM user grants access to any Amazon S3 bucket. In this case this will include any S3 bucket in your account and any bucket in any other account, where the account owner has granted your user access. You'll want to be more specific with the policy of your IAM user. For example, the following policy will limit your IAM user access to a single bucket.
You can also grant access to an array of buckets, if the user requires access to more than one.
Me
Unfortunately, we don't know beforehand all of our client's bucket names when we create the inline policy. As we get more and more clients to our service, it would be impractical to keep adding new client bucket names to the inline policy.
I guess another option is to create a new AWS account used solely for the above purpose - i.e. this account will not itself own anything, and will only ever be used for uploading to client buckets.
Is this acceptable, or are there any other alternatives options open to us?
AWS
Having a separate AWS account would provide clear security boundaries. Keep in mind that if you ever create a bucket in that other account, the user would inherit access to any bucket if you grant access to "arn:aws:s3:::*".
Another approach would be to use blacklisting (note whitelisting as suggested above is a better practice).
As you can see, the 2nd statement explicitly denies access to an array of buckets. This will override the allow in the first statment. The disadvantage here is that by default the user will inherit access to any new bucket. Therefore, you'd need to be diligent about adding new buckets to the blacklist. Either approach will require you to maintain changes to the policy. Therefore, I recommend my previous policy (aka whitelisting) where you only grant access to the S3 buckets that the user requires.
Conclusion
For our purposes, the white listing/blacklisting approach is not acceptable because we don't know before all the buckets that will be supplied by our clients. In the end, we went the route of creating a new AWS account with a single user, and that user does not have of its own s3 buckets
The policy you grant to your internal user gives this user access to all S3 bucket for the API listed (the first policy in your question). This is unnecessary as your client's bucket policies will grant your user required privileges to access to client's bucket.
To solve your problem, remove the user policy - or - explicitly your client's bucket in the list of allowed [Resources] instead of using "*"