2023-01-30 00:00:00
In one of Airwalk Reply's projects there was a requirement from the cybersecurity team to enforce network segregation and limit inbound internet traffic to trusted sources. In this case the Application Load Balancer (ALB) in the ‘external zone’ was to only accept traffic from CloudFront, which is defined as the ‘perimeter zone’.
However the issue is that CloudFront IP ranges are not static and AWS can add or remove IPs at any time, which may cause service disruption if the whitelist in ALB Security Group is not up to date. Three solutions are noted below to facilitate this.
In the very beginning Airwalk Reply developed a home-grown solution for this as we found that AWS provided the current CloudFront IP ranges in a json file. We created a lambda that is triggered regularly by CloudWatch EventBridge to fetch the latest values from that file, and update the list of IP ranges in the ALB Security Group if needed.
{ "ip_prefix": "130.176.88.0/21", "region": "GLOBAL", "service": "CLOUDFRONT_ORIGIN_FACING", "network_border_group": "GLOBAL" },code snippet of the json file
But there are some caveats to this solution: the SNS topic cannot trigger the lambda that is located in an opt-in region (such as Hong Kong ap-east-1). In this case you will need to put the lambda in non opt-in region and do a cross region update to the ALB Security Group, this increases the complexity of the cloud infrastructure. This solution does however introduce extra cost to the client due to the lambda triggers.
In 2022, AWS provided the 'AWS-managed prefix list' for CloudFront that solves this problem perfectly. The list is managed and updated by AWS with no triggers, no IP range extraction from a remote json file and no lambda required.
Here is the Terraform example:
locals { cloudfront_alb_sg_from_ports = [80, 443] cloudfront_alb_sg_to_ports = [80, 443] cloudfront_alb_sg_protocols = ["tcp", "tcp"] } data "aws_ec2_managed_prefix_list" "cloudfront_prefix_list" { name = "com.amazonaws.global.cloudfront.origin-facing" } resource "aws_security_group" "cloudfront_security_groups_from_prefix_list" { count = length(local.cloudfront_alb_sg_protocols) vpc_id =ingress { from_port = element(local.cloudfront_alb_sg_from_ports, count.index) to_port = element(local.cloudfront_alb_sg_to_ports, count.index) protocol = element(local.cloudfront_alb_sg_protocols, count.index) prefix_list_ids = [data.aws_ec2_managed_prefix_list.cloudfront_prefix_list.id] } }
The prefix list counts as 55 rules in a Security Group. If you want to allow both HTTP and HTTPS request in the inbound rules, it counts as 110 rules which is greater than the default limit of 60 rules per Security Group. In this case you will need to submit a request to AWS for a limit increase.
You may notice that the number of IP ranges in the prefix list is fewer than those you found in the json file. It is because the prefix list only provides the CloudFront origin facing server IP ranges, not the edge servers IPs.
I hope you find this solution useful. Happy AWSing!
https://aws.amazon.com/blogs/networking-and-content-delivery/limit-access-to-your-origins-using-the-aws-managed-prefix-list-for-amazon-cloudfront
https://aws.amazon.com/blogs/security/automatically-update-security-groups-for-amazon-cloudfront-ip-ranges-using-aws-lambda/
https://aws.amazon.com/premiumsupport/knowledge-center/sns-not-invoking-lambda/
Sending Amazon SNS messages to an Amazon SQS queue or AWS Lambda function in a different Region - Amazon Simple Notification Service
Our people are absolutely crucial to our success. We pride ourselves on hiring the best people in the market and giving them all the support and guidance they need to develop and grow their career.
Join us