How to create private buckets with Lambda access
1. Why are VPC endpoints useful?
VPC endpoints make it possible to privately connect to AWS services from a VPC.
It means that traffic won’t leave the AWS network and won’t go via the public internet.
When we normally want our application to connect to services, like S3, using SDK, traffic goes through the internet via an encrypted channel (TLS).
In some cases (for compliance or legal reasons), we don’t want resources (a bucket, for example) to be accessible through the internet. Instead, it would be much better, if we routed all traffic to the private bucket via AWS’s private network.
VPC endpoints provide a solution to this problem.
2. Gateway endpoints
AWS provides two types of endpoints: Gateway endpoints and Interface endpoints.
Gateway endpoints enables us to privately connect to S3 and DynamoDB. Interface endpoints provide private connections to other services.
These two endpoint types work differently.
Gateway endpoints use route tables to direct traffic through them. They are highly available and fully managed.
Interface endpoints, on the other hand, utilize elastic network interfaces (ENIs), and they are not highly available by default.
3. Architecture
The following diagram pictures a part of a bigger service, where a Lambda function uploads objects to an S3 bucket.
3.1. Lambda in a VPC
To achieve the above, we need to deploy the function in a VPC. In this case, we create two of them in two private subnets.
When we deploy Lambda functions in a VPC, AWS will create a new ENI in each subnet, and as such, each ENI and subnet combination will result in a new security group. To reduce the number of security groups, we can create one and attach it to both ENIs.
3.2. Private bucket
The S3 bucket will become private by adding a bucket policy to it. The bucket policy denies all traffic unless it comes from the VPC endpoint:
{
"Effect": "Deny",
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-0da40659846fa09f5"
}
}
}
We can try to upload an object via the Console - it won’t work. We can create another Lambda function, which has s3:PutObject
permissions to upload to the bucket - it won’t work if we don’t deploy it inside the VPC.
The bucket policy makes the bucket private, and only resources in the VPC can access it. Private buckets are an excellent way to protect sensitive data.
3.3. Route table entries
By specifying the service name (com.amazonaws.us-east-1.s3
) in the Destination
field of the route table, where the target is the VPC Gateway endpoint, all traffic destined to S3 will flow through the endpoint and not via the Internet Gateway.
4. Some notes
4.1 Truly private bucket
A real private bucket has the following bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Principal": "*",
"Action": "s3:*",
"Effect": "Deny",
"Resource": [
"arn:aws:s3:::BUCKET_NAME",
"arn:aws:s3:::BUCKET_NAME/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "VPC_ENDPOINT_ID"
}
}
}
]
}
I used s3:PutObject
and s3:PutObjectTagging
in the Action
field instead of all S3 operations to avoid getting locked out of my bucket. In real life, the above policy snippet should replace the one in the template.
4.2. ENI permissions
Because we deploy the Lambda function in a VPC, it will need the ec2:CreateNetworkInterface
permission.
The AWSLambdaVPCAccessExecutionRole
managed policy comes with this permission along with ec2:DeleteNetworkInterface
, which allows us to delete the stack entirely.
4.3. UploadViaInternetFn
This function is only there to prove that it cannot upload anything to the bucket because it’s not in the VPC.
This function is not necessary for real-life systems.
4.4. Inline code
The template contains inline code for the functions. Real-life services are more complicated, and a separate folder in the project will have the code.
5. Conclusion
We can create private buckets using a VPC Gateway endpoint and a bucket policy.
The CloudFormation template can be downloaded from my GitHub repo, where you can find more information about this project.
Thanks for reading and see you next time.