{"id":74233,"date":"2025-08-28T00:48:57","date_gmt":"2025-08-27T19:18:57","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=74233"},"modified":"2026-01-02T18:08:26","modified_gmt":"2026-01-02T12:38:26","slug":"securing-aws-alb-behind-cloudfront-using-waf-and-security-groups","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/securing-aws-alb-behind-cloudfront-using-waf-and-security-groups\/","title":{"rendered":"Securing AWS ALB Behind CloudFront: Using WAF and Security Groups"},"content":{"rendered":"<h2><strong>Introduction<\/strong><\/h2>\n<p>A pretty common AWS setup is CloudFront in front of an Application Load Balancer (ALB). CloudFront improves performance and gives you some security features \u201cfor free.\u201d But if you leave the ALB wide open, anyone can bypass CloudFront and hit it directly &#8211; not ideal.<\/p>\n<p>This documentation outlines two effective methods for restricting direct traffic to an Application Load Balancer (ALB) and ensuring that all traffic is routed through Amazon CloudFront.<\/p>\n<div id=\"attachment_74229\" style=\"width: 310px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-74229\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-74229 size-medium\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/08\/Architecture-300x151.png\" alt=\"When deploying applications on AWS, it\u2019s common to use CloudFront, AWS\u2019s content delivery network (CDN), in front of an Application Load Balancer (ALB) to enhance performance and security. To ensure that the ALB is not directly accessible from the internet, you should configure security groups, access control lists (ACLs), and other security measures to allow traffic only through CloudFront.\" width=\"300\" height=\"151\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/08\/Architecture-300x151.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Architecture-1024x514.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Architecture-768x386.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Architecture-624x313.png 624w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Architecture.png 1282w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><p id=\"caption-attachment-74229\" class=\"wp-caption-text\">.<\/p><\/div>\n<p><strong>There are two practical ways to stop that:<\/strong><\/p>\n<ol>\n<li>Use AWS WAF with a secret header.<\/li>\n<li>Lock down the ALB\u2019s Security Group to CloudFront IPs.<\/li>\n<\/ol>\n<p>Best practice: don\u2019t pick one or the other. Use both.<\/p>\n<p><strong>Method 1<\/strong>: Restricting Direct Traffic Using AWS WAF<\/p>\n<h2><strong>Architecture Overview<\/strong><\/h2>\n<p>WAF acts like a filter for HTTP\/S traffic. The trick here is to add a hidden header in CloudFront. WAF checks for it, and if it\u2019s missing, the request gets dropped before it touches your ALB.<\/p>\n<p>Architecture Diagram<\/p>\n<h2 style=\"margin-top: 1.71429rem; margin-bottom: 1.71429rem; font-size: 1.28571rem;\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-74230 size-large\" style=\"font-size: 1.28571rem;\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-AWS-WAF-1024x824.png\" alt=\"Restricting-Direct-Traffic-Using-AWS-WAF Diagram\" width=\"625\" height=\"503\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-AWS-WAF-1024x824.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-AWS-WAF-300x241.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-AWS-WAF-768x618.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-AWS-WAF-624x502.png 624w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-AWS-WAF.png 1220w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/h2>\n<h2><strong>Implementation Steps<\/strong><\/h2>\n<ol>\n<li>Add a custom header in CloudFront<\/li>\n<\/ol>\n<ul>\n<li>Go to the <strong>CloudFront<\/strong> console \u2192 find your <strong>distribution<\/strong>.<\/li>\n<li>Edit the<strong> ALB origin<\/strong>.<\/li>\n<li>Add a <strong>header<\/strong> with a secret key\/value.<\/li>\n<li><strong>Save<\/strong> it somewhere safe; you\u2019ll need it for WAF.<\/li>\n<\/ul>\n<p>2. Set up a WAF rule<\/p>\n<ul>\n<li>Open <strong>WAF<\/strong> console, create\/choose a <strong>Web ACL<\/strong>.<\/li>\n<li>Attach it to your <strong>ALB<\/strong>.<\/li>\n<li>Add a <strong>rule<\/strong> that blocks anything without the header.<\/li>\n<li>Put it at the top priority.<\/li>\n<\/ul>\n<h2>Testing and Validation<\/h2>\n<ul>\n<li>Run curl directly against the ALB \u2192 should get blocked.<\/li>\n<li>Go via CloudFront \u2192 should work.<\/li>\n<li>Turn on WAF logging, watch in CloudWatch to confirm only valid requests pass.<\/li>\n<\/ul>\n<h2>Cost Considerations<\/h2>\n<ul>\n<li>WAF pricing = ACLs + rules + number of requests.<\/li>\n<li>Extra cost if you enable logging.<\/li>\n<li>CloudFront costs stay the same, just expect a slight bump in total spend.<\/li>\n<\/ul>\n<h2>Method 2: Restricting Direct Traffic Using Security Groups<\/h2>\n<h2>Architecture Overview<\/h2>\n<p>Security Groups are AWS\u2019s built-in firewall. You can just say: only let CloudFront IP ranges in. AWS maintains a managed prefix list for CloudFront, so you don\u2019t have to babysit changing IPs yourself.<\/p>\n<h3>Architecture Diagram<\/h3>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-74231 size-large\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-Security-Groups--1024x815.png\" alt=\"Restricting-Direct-Traffic-Using-Security-Groups Diagram\" width=\"625\" height=\"497\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-Security-Groups--1024x815.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-Security-Groups--300x239.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-Security-Groups--768x611.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-Security-Groups--624x497.png 624w, \/blog\/wp-ttn-blog\/uploads\/2025\/08\/Restricting-Direct-Traffic-Using-Security-Groups-.png 1244w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<h2>Implementation Steps<\/h2>\n<ul>\n<li>Open the <strong>EC2 console<\/strong>, go to your <strong>ALB.<\/strong><\/li>\n<li>Under Security, click the <strong>Security Group<\/strong>.<\/li>\n<li>Edit <strong>inbound<\/strong> rules.<\/li>\n<li>Remove <strong>0.0.0.0\/0<\/strong> if it\u2019s there (after adding the new rule first).<\/li>\n<li>Add a new inbound rule:<\/li>\n<li>Protocol = HTTPS (or what you need).<\/li>\n<li>Source = AWS-managed CloudFront prefix list.<\/li>\n<li><strong>Save<\/strong>.<\/li>\n<\/ul>\n<h2>Testing and Validation<\/h2>\n<ul>\n<li>Try hitting the ALB DNS directly \u2192 should fail.<\/li>\n<li>Test through CloudFront \u2192 should succeed.<\/li>\n<li>Double-check ALB access logs and CloudWatch metrics.<\/li>\n<\/ul>\n<h2>Cost Considerations<\/h2>\n<h3>Security Groups Costs:<\/h3>\n<ul>\n<li>Security Groups themselves do not incur additional costs beyond the standard AWS charges for EC2 and ALB. However, the complexity of rules may impact the management overhead.<\/li>\n<li>Regular review and optimization of security group rules can help avoid unnecessary complexity and potential performance issues.<\/li>\n<\/ul>\n<h3><strong>CloudFront Costs:<\/strong><\/h3>\n<ul>\n<li>As with AWS WAF, using CloudFront in conjunction with Security Groups will affect your overall AWS costs. Review the CloudFront pricing page to understand how it may impact your budget.<\/li>\n<\/ul>\n<h2><strong>Best Approach for Restricting Traffic :<\/strong><\/h2>\n<p><strong>Combine WAF and Security Groups<\/strong><\/p>\n<ul>\n<li>Each method has strengths. SGs work at the network layer; WAF works at the application layer. If one fails, the other is still standing.<\/li>\n<li>Think of it like: SG = locked door, WAF = alarm system. Together, your ALB is harder to reach, and CloudFront remains the only valid way in.<\/li>\n<\/ul>\n<h2><strong>Conclusion<\/strong><\/h2>\n<p>The safest option is to apply both WAF and SG restrictions. That way, your ALB isn\u2019t left exposed, and all requests have to pass through CloudFront first. It gives you performance benefits plus a solid security posture.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction A pretty common AWS setup is CloudFront in front of an Application Load Balancer (ALB). CloudFront improves performance and gives you some security features \u201cfor free.\u201d But if you leave the ALB wide open, anyone can bypass CloudFront and hit it directly &#8211; not ideal. This documentation outlines two effective methods for restricting direct [&hellip;]<\/p>\n","protected":false},"author":1606,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":33},"categories":[2348],"tags":[1216],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/74233"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1606"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=74233"}],"version-history":[{"count":6,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/74233\/revisions"}],"predecessor-version":[{"id":77285,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/74233\/revisions\/77285"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=74233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=74233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=74233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}