Question
How can you restrict access to an S3 bucket to a single AWS instance when the instances have no public IP address and you're using an S3 endpoint in your VPC?
Background and Detail
We have a VPC that has a Virtual Private Gateway, which runs a VPN back to our on-premise data center. The VPC has no internet gateway. The servers have no public IP addresses. There's an S3 endpoint and a route table set up correctly. Let's say there's one subnet with three instances. We have two S3 buckets yet to be created, which will be encrypted.
We'd like to restrict access from instance A S3 bucket A and instance B to S3 bucket B. Instance C shouldn't have access to either bucket.
We also need to be able to upload information to the buckets from the public internet. This access should only be available through specific IPs, which is easy to do using bucket policies. This could make a difference to the solution though.
This page on AWS documentation says
You cannot use an IAM policy or bucket policy to allow access from a VPC IPv4 CIDR range (the private IPv4 address range). VPC CIDR blocks can be overlapping or identical, which may lead to unexpected results. Therefore, you cannot use the aws:SourceIp condition in your IAM policies for requests to Amazon S3 through a VPC endpoint. This applies to IAM policies for users and roles, and any bucket policies. If a statement includes the aws:SourceIp condition, the value fails to match any provided IP address or range. Instead, you can do the following:
- Use your route tables to control which instances can access resources in Amazon S3 via the endpoint.
- For bucket policies, you can restrict access to a specific endpoint or to a specific VPC. For more information, see Using Amazon S3 Bucket Policies.
We can't use route tables as we have two instances that need access to different buckets.
I've also read this page, which wasn't helpful for our situation.
Option: KMS keys
I suspect if we give each bucket its own KMS key and restrict access to the keys to the appropriate instance only that instance can access the decrypted data. I think this will work, but there's some complexity there, and I'm not 100% sure as I haven't done much with KMS.
An advantage of this approach is it denies by default, grants by configuration. Because of the number of users of the account we can't rely on configuration to deny by default, as was very helpfully suggested by Alex below.
Ideas Thoughts or Suggestions
Does anyone have any other suggestions or ideas we could follow up? Or any thoughts / further detail on the KMS idea?
My suggestion would be to use instance roles. These are roles that can be assumed by applications running on specific instances by querying the metadata service - AWS tools support this natively - allowing applications running on that instance to use those credentials. More details on them here.
You would then have a unique role for instance A and another for instance B, then take a look at this post on using Bucket Policies to restrict access to a bucket based on a specific role. Here.
That should probably do what you need. Although the KMS one is also an approach, but probably more complicated. You could also move the instances into different VPCs and use an endpoint policy to restrict access based on source VPC - but that would be very messy and would bring other complications.