DEV Community

Cover image for Protect Amazon CloudFront Origins with Built-in Security Features: AWS Best Practices
Cristhian Becerra
Cristhian Becerra

Posted on

Protect Amazon CloudFront Origins with Built-in Security Features: AWS Best Practices

TL;DR: In this article, I will show you how and why you should protect Amazon CloudFront origins using multiple built-in security features that I have personally implemented, along with the use case and benefits of each, to achieve a protected and resilient origin, all aligned with the Security and Reliability pillars of the AWS Well-Architected Framework. 🌐


Table of Contents:


Introduction

If you’ve heard of Amazon CloudFront, you know it is a Content Delivery Network (CDN) service that helps us distribute static and dynamic content quickly and reliably. CloudFront delivers content to our users through a global network of data centers known as edge locations. When a user requests content you’re serving via CloudFront, the request is routed to the edge location closest to the user—or the one that provides the lowest latency—so that the content is delivered with the best possible performance.

If your content is static, CloudFront allows you to cache it so that requests are served directly from the cache and do not reach the origin, thus reducing the load on it. On the other hand, if your content is dynamic, it should not be cached, but CloudFront enables routing the user’s request to the origin through AWS’s global network infrastructure, optimizing latency and performance. 🤩

When we start getting familiar with Amazon CloudFront, it’s common not to know the recommended security best practices and inadvertently skip them, leaving our origins unprotected or vulnerable. A frequent mistake is not restricting access to origins exclusively to CloudFront, which can allow direct access to the origin through uncontrolled routes, leading to undesired behavior or security breaches. To prevent these issues, in this article I will explain why it’s important to protect Amazon CloudFront origins, as well as present multiple built-in security features that I have implemented and that align with AWS best practices.

Why Protect Amazon CloudFront Origins

In today’s world, technology advances at a rapid pace, and with it, cybersecurity threats grow exponentially. For this reason, security has become a fundamental priority.

Amazon CloudFront allows us to add an extra layer of protection between our users and the origins, which can be load balancers, servers, containers, among others. Instead of directing users straight to the origins, we redirect them through CloudFront, which acts as an intermediary to retrieve the requested content and then deliver it to the user.

By using CloudFront to create a distribution, we are adding an additional layer to our system. Even if the initial goal was only to improve performance and speed, we are incorporating a new component into our architecture that also needs protection. CloudFront offers a set of built-in security features that help protect our origins. It provides additional defense against multiple types of attacks, including DDoS attacks, and integrates directly with AWS WAF and AWS Shield. 🛡️

However, implementing multiple security measures on the CloudFront distribution is of little use if our origins are not protected or if communication to them is not restricted exclusively to CloudFront. This would leave our origins exposed to threats and vulnerabilities that could go unnoticed under the false perception that all traffic passes solely through CloudFront. For these reasons, protecting Amazon CloudFront origins is an essential step to ensure the security and integrity of our applications.


Built-in CloudFront Security Features

In the following sections, I will present various built-in security features that I have personally implemented, which are aligned with AWS best practices and that I believe you will find very useful to know. 🚀

Note: In the official resources section at the end, you will find all the corresponding AWS documentation for each of the features mentioned below.

Restrict Access to Application Load Balancers

When you use a public load balancer (ALB) as the origin of an Amazon CloudFront distribution, it remains accessible from the Internet by default, not just through CloudFront. To restrict access to the public load balancer so that it is only possible via the CloudFront distribution, you can use a custom HTTP header.

In the CloudFront distribution, for the specific origin you want to protect, add a custom HTTP header with a secret value, which must not be publicly exposed. This way, CloudFront will include this header in all requests it sends to the origin (ALB).

Then, configure the Application Load Balancer listener to only forward requests to its targets when they contain the custom HTTP header with the specified secret value. This ensures that the ALB will discard any request that does not contain this header, guaranteeing that only traffic coming from CloudFront is accepted.

It is recommended to renew the secret value of the custom HTTP header at least once a year as a precaution against potential security leaks.

Restrict Access to Application Load Balancers

Restrict Access to an Amazon S3 Origin

When you use an Amazon S3 bucket as the origin of an Amazon CloudFront distribution, it remains accessible from the Internet by default, not just through CloudFront. To restrict access to the bucket objects so that it is only possible via the CloudFront distribution, you can use Origin Access Control (OAC).

Origin Access Control (OAC) allows us to protect S3 origins and, unlike its predecessor Origin Access Identity (OAI), it is compatible with all S3 buckets in all AWS regions. Additionally, it supports encryption via AWS KMS and allows dynamic requests (such as PUT and DELETE) to Amazon S3.

To implement Origin Access Control (OAC), for the specific origin you want to protect, simply create a new origin access control instead of using a public access origin, and update the bucket policy of the S3 bucket by adding the statement provided by CloudFront, which has the following structure:

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<Bucket Name>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::<Account ID>:distribution/<Distribution ID>"
                }
            }
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Restrict Access to an Amazon S3 Origin

Restrict Access with VPC Origins

Until recently, CloudFront only allowed configuring public origins. That is, if you wanted to place a load balancer or an EC2 instance behind a CloudFront distribution, these had to have a DNS resolvable to a public IP address.

At the end of 2024, AWS introduced CloudFront Virtual Private Cloud (VPC) Origins, a feature that allows assigning private load balancers or private EC2 instances located in private subnets within a VPC as origins. They no longer need to be public!

To implement VPC Origins, simply create a new VPC Origin in CloudFront, specifying the ARN of the private ELB or the private EC2 instance. The security group associated with these private resources must continue to allow access from CloudFront IP addresses.

Although you could allow incoming access from the Internet —since it is not a public resource— if you want to prevent other private resources within the same VPC from accessing the origin and ensure that only CloudFront has access, it is highly recommended to use prefix lists. See the following section for guidance.

Restrict Access with VPC Origins

AWS-Managed Prefix Lists

When you need to allow access to the same set of IP addresses across multiple security groups, instead of manually adding each IP address to all groups, you can create a prefix list. In this case, we are talking about a customer-managed prefix list, meaning it is our responsibility to keep the list of IP addresses up to date.

On the other hand, a common need when working with resources inside a VPC is to limit incoming or outgoing traffic only to certain AWS services. Although it is possible to obtain the list of public IP addresses for each service, these change constantly, and maintaining them manually would be complex and error-prone. For this purpose, AWS offers AWS-managed prefix lists, which are automatically maintained and updated by AWS, allowing you to filter IP addresses for various services such as Amazon CloudFront, Amazon DynamoDB, Amazon S3, among others.

As mentioned in the previous section, if we want to allow traffic to our resources in a VPC only from CloudFront IP addresses, we can leverage the AWS-managed prefix list corresponding to Amazon CloudFront. To do this, simply specify the Prefix List (pl) as the source or destination in the security group rules.

This feature is extremely useful when working with origins inside a VPC. However, if the origin is On-Premises, whether with hybrid connectivity to AWS via a Site-to-Site VPN or AWS Direct Connect, or even fully disconnected from AWS and accessible via a public IP address, it is not possible to use prefix lists. For these scenarios, see the following section.

AWS-Managed Prefix Lists

AWS IP Address Ranges

As mentioned in the previous section, it is indeed possible to obtain the list of public IP addresses for each AWS service. While in a VPC we can leverage prefix lists, when working in On-Premises environments outside of AWS, we are required to use the list of AWS public IP addresses.

For this, AWS maintains its list of public IP addresses updated in JSON format in the ip-ranges.json file. Using the IP addresses from this list, you can configure your On-Premises firewall. But you might now be wondering: how will I keep my firewall updated if Amazon’s IP addresses change constantly?

Don’t worry, Amazon thought of that and created an SNS topic you can subscribe to in order to receive notifications about updates to the ip-ranges.json file. The ARN of the topic is: arn:aws:sns:us-east-1:806199016981:AmazonIpSpaceChanged. You just need to subscribe to the topic and develop a small local automation that processes the notifications and updates your On-Premises firewall rules as needed.

AWS IP Address Ranges

CloudFront Geographic Restrictions

This section is simple. You can enhance the security of your origin by configuring geographic restrictions on your distribution, as long as they fit your use case.

To do this, CloudFront allows you to implement an allow list or block list on your distribution and specify all the countries you need to allow or block.

CloudFront Geographic Restrictions

CloudFront Field-Level Encryption

This section covers a specific use case that occurs when, within the request made by the client to CloudFront, a payload is included containing multiple fields, some of which hold sensitive data. Fields with sensitive data should only be visible to the final destination, while any intermediate network or compute resources should see these fields encrypted. However, we cannot encrypt the entire request, as this use case requires that intermediate resources can still view all other non-sensitive fields without issues.

This is where field-level encryption comes into play. Suppose the client sends a request whose payload contains both non-sensitive fields and sensitive fields, such as PII, PHI, confidential information, credentials, among others. Between CloudFront and the final destination, there are multiple intermediate resources, none of which should be able to see the sensitive data, although they still need to process the non-sensitive fields. In this scenario, we implement field-level encryption provided by CloudFront.

To implement field-level encryption, we simply need to create an encryption profile in CloudFront, which should specify the data fields to encrypt and the public key that will be used for such encryption, previously stored in CloudFront. On the other hand, the final destination, for example, an application server, must have the corresponding private key and be configured to decrypt the encrypted fields. Only the final server possesses the private key, thus protecting the confidentiality of sensitive data from intermediate resources without limiting the processing of non-sensitive data in the same request.

CloudFront Field-Level Encryption

CloudFront Origin Shield

Origin Shield is an additional cache layer that can help reduce the load on your origin and, thereby, protect its availability. Primary use cases include scenarios with users across different geographic regions or when working with multiple CDNs.

Origin Shield improves cache hit rates, decreases origin load, and optimizes network performance. The flow of a request in CloudFront without Origin Shield passes through the Edge Locations, then the Regional Edge Caches, and finally reaches the origin. In this case, multiple regions might be querying the origin unnecessarily. To avoid this, by enabling Origin Shield, an additional layer is placed between the Regional Edge Caches and the origin, so that only Origin Shield sends requests to the origin, thus reducing its load.

To use Origin Shield, within your distribution select the origin, enable Origin Shield, and choose the AWS region where you want it deployed.

CloudFront Origin Shield

AWS WAF Core Protections

CloudFront has direct integration with AWS WAF and allows you to add a basic security layer with a single click, which in the background creates a Web ACL with the default protection your application needs.

The default WAF protection for CloudFront includes defense against common vulnerabilities such as those in the OWASP Top 10, SQL injections, rate limiting, and blocking traffic from malicious IP addresses based on Amazon’s threat intelligence. However, if you consider it necessary —and in fact it is recommended— customize your Web ACL according to your requirements and add additional rules you deem appropriate to strengthen your origin’s security.

AWS WAF Core Protections

CloudFront Origin Groups

This feature, technically, is not a security measure, but one of resilience, yet I want to mention it because I have tested it and find it particularly interesting.

As you know, CloudFront is a global service, but the origins probably are not. That is, in the event of a regional outage or an availability zone failure, the application could stop responding, even if the CloudFront distribution itself is unaffected.

To handle these situations, CloudFront Origin Groups allows us to configure a failover solution easily. We only need to create an Origin Group specifying multiple origins and the failover criteria, i.e., the HTTP Status Codes that CloudFront must receive to trigger failover to another origin located in a different region.

In this way, CloudFront Origin Groups allows us to maintain high availability in the event of a regional failure: the same global distribution remains active, simply redirecting requests to another origin within the group, but located in a different region.

CloudFront Origin Groups


Lessons Learned

Never forget to restrict access to origins. In most cases, when you implement CloudFront, the distribution should be the only one with access to the origin. For this reason, it is common to implement all defense mechanisms on the CloudFront distribution; however, if you do not restrict access to the origin, it will remain vulnerable to threats that you probably had not considered because you focused solely on protecting the distribution. 😶

If you need to implement AWS WAF for your application, you should almost always attach the Web ACL to the CloudFront distribution, rather than, for example, to the ALB origin. It always makes more sense to apply WAF at the distribution level so that traffic is filtered as high up as possible, thus reducing the load and cost of data processing on the ALB. 😎

I recommend using georestriction whenever possible and, of course, when it applies to your use case. In my experience, depending on your region, georestriction can be one of the simplest ways to prevent undesired traffic from scraping bots, since this type of traffic usually originates from specific countries. 🤖

Conclusion

Amazon CloudFront includes multiple built-in security features that allow us to protect origins, covering failover, firewall, georestriction, additional caching layers, field-level encryption, and most importantly, origin access restriction. All of this allows us to consolidate various perimeter-level protection mechanisms in the CloudFront distribution, thereby strengthening the security posture of our applications through a defense-in-depth strategy.

What’s Next

In the next section, you will find official AWS resources and documentation for the built-in security features of Amazon CloudFront mentioned in this article, in case you want to continue learning or dive deeper to evaluate if they really apply to your use case.

I also invite you to implement these built-in CloudFront security features in your own AWS account. Share in the comments what you thought of this article or if you discovered something interesting about any Amazon CloudFront feature during your implementation. ✍🏻

For me, a next step will be to test the integration of AWS Shield Advanced with CloudFront in the future, as I have not yet had the opportunity to see AWS Shield’s DDoS mitigation logic applied to CloudFront in action.

Official Resources

Top comments (0)