<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alexey Baltacov</title>
    <description>The latest articles on DEV Community by Alexey Baltacov (@alexeybaltacov).</description>
    <link>https://dev.to/alexeybaltacov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2826933%2Fab385ce6-4e2c-4759-a55c-4989e5e307cf.png</url>
      <title>DEV Community: Alexey Baltacov</title>
      <link>https://dev.to/alexeybaltacov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexeybaltacov"/>
    <language>en</language>
    <item>
      <title>Protect Your Web Site with AWS WAF and CloudFront</title>
      <dc:creator>Alexey Baltacov</dc:creator>
      <pubDate>Sun, 22 Mar 2026 12:58:57 +0000</pubDate>
      <link>https://dev.to/aws-builders/protect-your-web-site-with-aws-waf-and-cloudfront-2p8c</link>
      <guid>https://dev.to/aws-builders/protect-your-web-site-with-aws-waf-and-cloudfront-2p8c</guid>
      <description>&lt;h2&gt;
  
  
  Protect Your On-Premises Website with AWS WAF and Amazon CloudFront
&lt;/h2&gt;

&lt;p&gt;Protecting web applications—regardless of where they run—with a scalable, highly available, and cost-effective edge layer is a cornerstone of modern architecture. This article walks through a hands-on proof of concept (PoC) that leverages AWS WAF for security, CloudFront for global caching and performance, and a serverless pipeline for on-the-fly HTTP context modification.&lt;/p&gt;

&lt;p&gt;You’ll learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhance availability and reduce origin load by caching static and dynamic content at the edge.&lt;/li&gt;
&lt;li&gt;Secure traffic with AWS WAF rules before it ever reaches CloudFront.&lt;/li&gt;
&lt;li&gt;Offload requests from the origin to minimize connectivity and costs.&lt;/li&gt;
&lt;li&gt;Modify any part of the HTTP request or response—including headers, query strings, and body—using a Lambda-powered proxy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sensitive data and IP addresses in screenshots have been blurred.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; I understand this guide—demonstrating how to proxy and modify HTTP content—might resemble instructions used by phishing site creators. That was never my intention; these techniques are meant solely for legitimate security, performance, and reliability purposes.&lt;/p&gt;

&lt;p&gt;Traditional WAF appliances and CDNs can be expensive, rigid, and complex to manage—particularly when you need to retrofit existing on-premises applications. By combining AWS WAF and Amazon CloudFront, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Edge Security:&lt;/strong&gt; AWS WAF blocks malicious requests at AWS’s global PoPs, shielding your origin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Caching:&lt;/strong&gt; CloudFront serves cached content from locations closest to your users, reducing latency and origin hits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin Offload:&lt;/strong&gt; Less network traffic and compute on your servers, lowering TCO.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-the-Fly HTTP Manipulation:&lt;/strong&gt; Inject, strip, or rewrite headers and body content without touching origin code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll demonstrate these capabilities using a simple IP-lookup service (&lt;code&gt;noc.co.il&lt;/code&gt;) to keep the PoC lean and focused on edge mechanics.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Evaluating Origin Compatibility
&lt;/h2&gt;

&lt;p&gt;For this PoC, we chose a simple IP-lookup service (&lt;code&gt;noc.co.il&lt;/code&gt;) to isolate edge mechanics. Our goals were to verify that the origin would:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Respond over HTTPS without client interruptions.&lt;/li&gt;
&lt;li&gt;Trust and reflect standard proxy headers (&lt;code&gt;X-Forwarded-For&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Parse header values as plain text (no validation), allowing us to spoof or inject values.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.1 Initial Compatibility Test
&lt;/h3&gt;

&lt;p&gt;We first obtained the &lt;code&gt;curl&lt;/code&gt; command via the browser’s &lt;strong&gt;Copy as cURL&lt;/strong&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://noc.co.il/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Accept: text/html'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compressed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this returned the expected HTML shell of the IP lookup page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; - &lt;span class="nt"&gt;--compressed&lt;/span&gt; https://noc.co.il/
HTTP/1.1 200 OK
Content-Type: text/html&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;UTF-8
...
&amp;lt;html&amp;gt;My IP: 203.0.113.10&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.2 Testing &lt;code&gt;X-Forwarded-For&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Next, we injected a fake IP via the &lt;code&gt;X-Forwarded-For&lt;/code&gt; header to see if the service honors it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; - &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Forwarded-For: 198.51.100.24"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compressed&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://noc.co.il/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Findings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The response body included both our real IP and &lt;code&gt;198.51.100.24&lt;/code&gt;, confirming the header was trusted.&lt;/li&gt;
&lt;li&gt;No header validation errors occurred.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.3 Spoofing Non-existent Addresses
&lt;/h3&gt;

&lt;p&gt;To verify lack of validation, we added another bogus IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Forwarded-For: 198.51.100.24, 300.300.300.300"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://noc.co.il/ | &lt;span class="nb"&gt;tee &lt;/span&gt;response.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspecting &lt;code&gt;response.html&lt;/code&gt; in a browser showed the exact header text echoed in the page—demonstrating the origin parses the header as raw text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sidebar:&lt;/strong&gt; Because CloudFront automatically appends &lt;code&gt;X-Forwarded-For&lt;/code&gt;, this origin behavior is crucial for forwarding the true client IP downstream.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Solution Architecture Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Original Architecture
&lt;/h3&gt;

&lt;p&gt;In the initial approach, I fronted the origin directly with AWS WAF and CloudFront, without any additional proxy layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqy3namj1ejohgjpvk7n9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqy3namj1ejohgjpvk7n9.png" alt="Original architecture diagram" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Clients -&amp;gt; AWS WAF -&amp;gt; CloudFront -&amp;gt; Original Site (noc.co.il)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS WAF:&lt;/strong&gt; Enforces IP allow-lists and managed security rules at AWS edge locations before traffic reaches CloudFront.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront:&lt;/strong&gt; Distributes and caches content globally, forwarding only necessary headers to the origin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Original Site:&lt;/strong&gt; The unmodified &lt;code&gt;noc.co.il&lt;/code&gt; endpoint, responding directly to CloudFront requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.2 Final Architecture (With API Gateway Proxy)
&lt;/h3&gt;

&lt;p&gt;To overcome response-body limitations, I introduced an API Gateway/Lambda proxy between CloudFront and the origin. The Lambda function serves as a reverse proxy for dynamic HTML, while static assets like &lt;code&gt;favicon.ico&lt;/code&gt; are served directly from S3 via a separate behavior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz93gyapuhhipwo0kqac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz93gyapuhhipwo0kqac.png" alt="Final architecture with API Gateway proxy" width="800" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS WAF:&lt;/strong&gt; Applies IP filters and managed rules at the AWS edge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront:&lt;/strong&gt; Uses two cache behaviors:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/favicon.ico&lt;/code&gt; -&amp;gt; &lt;strong&gt;S3 origin&lt;/strong&gt; for static assets with optimized TTLs.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/*&lt;/code&gt; -&amp;gt; &lt;strong&gt;API Gateway&lt;/strong&gt; for dynamic HTML via the reverse-proxy Lambda.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway (REST API Reverse Proxy Mode):&lt;/strong&gt; Receives viewer requests for dynamic content and invokes the Lambda reverse-proxy function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lambda Function (Reverse Proxy):&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fetch:&lt;/strong&gt; Makes an HTTP request to &lt;code&gt;https://noc.co.il&lt;/code&gt; including path and query parameters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modify:&lt;/strong&gt; Reads and parses the HTML response body.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Return:&lt;/strong&gt; Sends the modified HTML back through API Gateway and CloudFront while preserving the original status code and headers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;S3 Origin:&lt;/strong&gt; Serves the custom &lt;code&gt;favicon.ico&lt;/code&gt; directly from edge caches, bypassing API Gateway.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Detailed Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Certificate Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Generate a Let’s Encrypt certificate for your custom domain (&lt;code&gt;noc.ittools.net&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9036rorh8x8wj3tb60bp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9036rorh8x8wj3tb60bp.png" alt="Certificate generation screenshot" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import it into ACM in &lt;code&gt;us-east-1&lt;/code&gt; for CloudFront.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm965xzy5smjod8e6j1ga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm965xzy5smjod8e6j1ga.png" alt="ACM import screenshot" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 AWS WAF Setup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IP Sets:&lt;/strong&gt; Define trusted IPv4/IPv6 addresses such as office and datacenter ranges.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkgr5f8ta7u0es0bhj3b7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkgr5f8ta7u0es0bhj3b7.png" alt="AWS WAF IP set screenshot 1" width="800" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="AWS WAF IP set screenshot 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web ACL:&lt;/strong&gt; Allow traffic from the IP sets and set the default action to &lt;strong&gt;Block&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76vsnikwkasubyo4r5ok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76vsnikwkasubyo4r5ok.png" alt="AWS WAF Web ACL screenshot" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rate-based rules (optional):&lt;/strong&gt; Throttle anomalous request spikes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.3 CloudFront Distribution
&lt;/h3&gt;

&lt;p&gt;Configure the CloudFront distribution with the cache behavior and origin request policy that match your proxy design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcox8stde414asnx98mu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcox8stde414asnx98mu.png" alt="CloudFront distribution screenshot" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attach your AWS WAF Web ACL to this distribution.&lt;/li&gt;
&lt;li&gt;Enable response headers policies to add HSTS, CSP, and custom headers at the edge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.4 Reducing Origin Connectivity
&lt;/h3&gt;

&lt;p&gt;Caching at CloudFront dramatically cuts down on requests to your origin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static assets (images, CSS, JS) are served from edge caches for configurable TTLs.&lt;/li&gt;
&lt;li&gt;Dynamic content hits origin only on cache misses—adjustable via cache keys (headers, cookies, query strings).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This offload not only improves performance but reduces bandwidth and compute costs on your servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.5 Full HTTP Context Access and Modification
&lt;/h3&gt;

&lt;p&gt;Neither CloudFront Functions nor Lambda@Edge allow modifying response bodies. Additionally, since both CloudFront and API Gateway automatically append their own &lt;code&gt;X-Forwarded-For&lt;/code&gt; entries, we need a reverse proxy to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch the original HTML from &lt;code&gt;https://noc.co.il&lt;/code&gt; while preserving query strings and path.&lt;/li&gt;
&lt;li&gt;Inject a custom &lt;code&gt;&amp;lt;link rel="icon" href="/favicon.ico" /&amp;gt;&lt;/code&gt; into the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Strip the two trailing IP addresses added by CloudFront and API Gateway from any comma-separated IP lists embedded in the HTML body.&lt;/li&gt;
&lt;li&gt;Return the modified HTML through API Gateway and CloudFront while preserving the origin’s headers and status codes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To achieve this, configure API Gateway in REST API reverse-proxy mode and invoke a Lambda function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;http.client&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlencode&lt;/span&gt;

&lt;span class="c1"&gt;# Configuration
&lt;/span&gt;&lt;span class="n"&gt;REMOVE_IP_COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REMOVE_IP_COUNT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;FAVICON_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAVICON_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/favicon.ico&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ORIGIN_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ORIGIN_HOST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;noc.co.il&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ORIGIN_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ORIGIN_PATH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# 1) Parse client request info
&lt;/span&gt;    &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;httpMethod&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;qs_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queryStringParameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;query_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qs_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;qs_params&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;

    &lt;span class="c1"&gt;# 2) Build the upstream path
&lt;/span&gt;    &lt;span class="n"&gt;origin_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ORIGIN_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;client_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;origin_path&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;query_str&lt;/span&gt;

    &lt;span class="c1"&gt;# 3) Copy headers except Host
&lt;/span&gt;    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# 4) Fetch from the real origin
&lt;/span&gt;    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HTTPSConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ORIGIN_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getresponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;body_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# 5) Decode HTML
&lt;/span&gt;    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body_bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 6) Inject favicon link right after &amp;lt;head&amp;gt;
&lt;/span&gt;    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(&amp;lt;head\b[^&amp;gt;]*&amp;gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\1&amp;lt;link rel=\"icon\" href=\"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;FAVICON_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\" type=\"image/png\"&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IGNORECASE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 7) Remove the last N IPv4s from every comma-separated list
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;strip_trailing_ips&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\s*,\s*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;REMOVE_IP_COUNT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;REMOVE_IP_COUNT&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b(?:\d{1,3}\.){3}\d{1,3}(?:\s*,\s*(?:\d{1,3}\.){3}\d{1,3})+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;strip_trailing_ips&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 8) Build the API Gateway Lambda-proxy response
&lt;/span&gt;    &lt;span class="n"&gt;out_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getheader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_bytes&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;isBase64Encoded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern gives you full control over outgoing responses without touching the origin code.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Final Results
&lt;/h2&gt;

&lt;p&gt;Below is a comparison of the original IP lookup page and the modified version, showing the injected favicon and response changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Original Site
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczczj4iqzkncmxyx9olq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczczj4iqzkncmxyx9olq.png" alt="Original site screenshot" width="748" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Modified Site
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0edtx7ug0zs2udpj9w0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0edtx7ug0zs2udpj9w0q.png" alt="Modified site screenshot" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. High Availability, Security, and CDN Benefits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DDoS Mitigation:&lt;/strong&gt; AWS WAF integrates with AWS Shield at no extra cost for CloudFront distributions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Failover:&lt;/strong&gt; Edge caches can continue serving content even if the origin is briefly unreachable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Efficiency:&lt;/strong&gt; Pay only for WAF rule evaluations, Lambda invocations, and data transfer—no upfront hardware.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6.1 Amazon CloudFront as a CDN
&lt;/h3&gt;

&lt;p&gt;Amazon CloudFront is AWS’s global content delivery network, designed to accelerate both static and dynamic content by caching it at edge locations worldwide. Key benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced latency:&lt;/strong&gt; Delivers content from the closest edge location to end users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizable cache behaviors:&lt;/strong&gt; Control TTLs, forwarded headers, query strings, and cookies per path pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic content support:&lt;/strong&gt; Forward dynamic requests to any HTTP origin and selectively cache or bypass content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security integrations:&lt;/strong&gt; AWS WAF, TLS termination at the edge, and Origin Access Control for private S3 buckets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invalidation and versioning:&lt;/strong&gt; Invalidate cache on demand or use versioned URLs for instant updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pay-as-you-go pricing:&lt;/strong&gt; Based on data transfer, request counts, and invalidation usage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6.2 Origin Failover with Multiple Origins
&lt;/h3&gt;

&lt;p&gt;To maximize availability, CloudFront supports &lt;strong&gt;Origin Groups&lt;/strong&gt;—a primary/secondary origin configuration that automatically fails over if the primary origin becomes unhealthy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary origin:&lt;/strong&gt; Your default origin, such as API Gateway or a custom origin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secondary origin:&lt;/strong&gt; A fallback endpoint, such as another region, an on-premises endpoint, or a static S3 bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health checks:&lt;/strong&gt; CloudFront monitors the primary origin using configurable HTTP(S) health checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failover logic:&lt;/strong&gt; On health-check failure, requests are routed to the secondary origin with minimal latency impact.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configuration steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the CloudFront distribution, create two origins.&lt;/li&gt;
&lt;li&gt;Define an origin group linking both origins and specify health-check parameters.&lt;/li&gt;
&lt;li&gt;Update cache behaviors to use the origin group as the target.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This failover capability ensures that even if your primary backend experiences downtime, CloudFront can seamlessly serve content from an alternate source.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Conclusion
&lt;/h2&gt;

&lt;p&gt;By fronting any website—on-premises or in the cloud—with AWS WAF and CloudFront, you achieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhanced availability through aggressive edge caching and failover.&lt;/li&gt;
&lt;li&gt;Robust security with customizable WAF rules at every PoP.&lt;/li&gt;
&lt;li&gt;Minimal origin load via cache offload and selective forwarding.&lt;/li&gt;
&lt;li&gt;Complete HTTP context manipulation using CloudFront Functions, Lambda@Edge, or, in very specific cases, API Gateway and Lambda for dynamic transformations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Normally the API Gateway + Lambda part is not required, since many HTML body changes can be made on the origin web server directly and these workarounds are unnecessary.&lt;/p&gt;

&lt;p&gt;This architecture transforms legacy and modern applications alike into resilient, secure, and performant cloud-edge services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appendix A: Edge Compute Options — CloudFront Functions vs Lambda@Edge
&lt;/h2&gt;

&lt;p&gt;AWS CloudFront provides two serverless compute options at the edge—CloudFront Functions and Lambda@Edge—each tailored to different use cases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiv83lo09rtuwbprcpcn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiv83lo09rtuwbprcpcn.png" alt="Edge compute options screenshot" width="800" height="906"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Parallels to F5 iRules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;F5 iRules allow TCP, UDP, and HTTP inspection and manipulation on traditional load balancers.&lt;/li&gt;
&lt;li&gt;CloudFront Functions provide similar lightweight header- and URL-based logic at the edge, executing JavaScript within milliseconds.&lt;/li&gt;
&lt;li&gt;Lambda@Edge extends these capabilities with richer runtimes and more advanced traffic steering and content transformation.&lt;/li&gt;
&lt;li&gt;Both CloudFront serverless options and F5 iRules enable granular control over HTTP flows, but CloudFront offloads compute to a global CDN with pay-as-you-go billing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudFront Functions cannot perform network calls or access request bodies.&lt;/li&gt;
&lt;li&gt;Lambda@Edge offers more runtime and compute but incurs higher latency and cost for short-lived tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This appendix clarifies compute options independently of the PoC’s specific Lambda reverse-proxy implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appendix B: Pricing Notes
&lt;/h2&gt;

&lt;p&gt;The original LinkedIn article includes AWS WAF and CloudFront pricing examples. Before publishing on DEV, verify current pricing in the official AWS pricing pages because service prices can change over time. The original article listed example monthly Web ACL, rule, request, data transfer, request, invalidation, and certificate price points. (&lt;a href="https://www.linkedin.com/pulse/protect-your-web-site-aws-waf-cloudfront-alexey-baltacov-60lgf/?trackingId=J10c9QI%2F7GB7OGQ44uQEVw%3D%3D" rel="noopener noreferrer"&gt;linkedin.com&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/waf/pricing/" rel="noopener noreferrer"&gt;AWS WAF pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cloudfront/pricing/" rel="noopener noreferrer"&gt;Amazon CloudFront pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/waf/" rel="noopener noreferrer"&gt;AWS WAF Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/" rel="noopener noreferrer"&gt;Amazon CloudFront Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/high_availability_origin_failover.html" rel="noopener noreferrer"&gt;CloudFront origin failover&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-at-edge.html" rel="noopener noreferrer"&gt;Lambda@Edge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html" rel="noopener noreferrer"&gt;CloudFront Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>waf</category>
      <category>cloudfront</category>
      <category>security</category>
    </item>
    <item>
      <title>AWS WAF Rate Limiting Based on Origin Response</title>
      <dc:creator>Alexey Baltacov</dc:creator>
      <pubDate>Sun, 22 Mar 2026 11:24:42 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-waf-rate-limiting-based-on-origin-response-1h5j</link>
      <guid>https://dev.to/aws-builders/aws-waf-rate-limiting-based-on-origin-response-1h5j</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fllugmyu3dkpwg3wjzfv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fllugmyu3dkpwg3wjzfv9.png" alt="AWS WAF Rate Limiting Based on Origin Response"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;You have a public website fronted by Amazon CloudFront that serves static files from S3. Customers access these files via direct URLs and must be able to download any file at any time without interference. At the same time, you want to stop malicious actors from crawling your entire bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; Prevent automated scanning of all URLs while still allowing legitimate customers unlimited downloads of the specific files they need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constraint:&lt;/strong&gt; No user login or authentication. Files are freely downloadable, so you cannot simply gate them behind a sign-in flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Plain AWS WAF Rate Limiting Is Not Enough
&lt;/h2&gt;

&lt;p&gt;AWS WAF lets you define rate-limit rules keyed by source IP or by fingerprinting mechanisms such as JA3 and JA4. In theory, you could set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;low limit&lt;/strong&gt; such as 10 requests per minute, which blocks scanners effectively but risks blocking legitimate high-throughput customers.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;high limit&lt;/strong&gt;, which lets scanners creep through, especially if attackers distribute requests across IPs or devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is an uncomfortable trade-off: too low hurts real users, too high fails to stop attackers.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS WAF's View of Origin Responses and ATP Rules
&lt;/h2&gt;

&lt;p&gt;By default, custom AWS WAF rules only inspect request attributes. They do not know whether your origin returned &lt;code&gt;200 OK&lt;/code&gt; or &lt;code&gt;404 Not Found&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The only built-in AWS WAF rules that inspect responses are the &lt;strong&gt;Account Takeover Prevention (ATP)&lt;/strong&gt; managed rules. Those require you to map login fields and are designed for authentication endpoints, not static file downloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Lambda@Edge Alone Cannot Solve It
&lt;/h2&gt;

&lt;p&gt;Lambda@Edge runs per request and has no built-in shared global state. It cannot maintain counters across all executions, so by itself it cannot enforce a global request threshold.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Hybrid Approach: WAF + Lambda@Edge
&lt;/h2&gt;

&lt;p&gt;You can combine WAF's global counting capabilities with Lambda@Edge's ability to modify HTTP responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Primary WAF Rate-Limit Rule (Soft Threshold)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; Rate-based statement, for example 10 requests per 5 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; &lt;code&gt;Count&lt;/code&gt; (not &lt;code&gt;Block&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom response header:&lt;/strong&gt; Insert &lt;code&gt;X-RateLimit-Exceeded: true&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWS WAF prefixes custom header names with &lt;code&gt;x-amzn-waf-&lt;/code&gt;. So if you specify &lt;code&gt;X-RateLimit-Exceeded&lt;/code&gt;, downstream components will see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x-amzn-waf-x-ratelimit-exceeded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2) Secondary WAF Rate-Limit Rule (Hard Threshold)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; Rate-based statement with a much higher threshold, for example 1,000 requests per 5 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; &lt;code&gt;Block&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This immediately stops heavy-volume attacks at the WAF layer, prevents excessive Lambda@Edge invocations, and reduces cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Lambda@Edge Function (Origin Response Trigger)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trigger:&lt;/strong&gt; CloudFront Origin Response event
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Records&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;cf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// AWS WAF prefixes headers with x-amzn-waf-&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-amzn-waf-x-ratelimit-exceeded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;200&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;429&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;statusDescription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too Many Requests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Rate Limit Reached&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Please try again later.&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Associate and Deploy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Attach your Web ACL, containing both rate-limit rules and any ATP group you choose to use, to the CloudFront distribution.&lt;/li&gt;
&lt;li&gt;Deploy the Lambda@Edge function through the CloudFront console or the AWS CLI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Legitimate Access
&lt;/h3&gt;

&lt;p&gt;Repeatedly fetch an existing file. The soft-limit counter will increment, but users will still receive the file until the hard threshold is crossed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scanning Attempts
&lt;/h3&gt;

&lt;p&gt;Request many non-existent URLs. Errors quickly hit the soft threshold, causing your custom &lt;code&gt;429&lt;/code&gt; response page. Extreme traffic volumes hit the hard threshold and are blocked at WAF before Lambda@Edge runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo video
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/FtCMrJetjWo"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of This Pattern
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Precision:&lt;/strong&gt; Rate limits are tied to actual &lt;code&gt;Not Found&lt;/code&gt; or error responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Experience:&lt;/strong&gt; Legitimate customers getting &lt;code&gt;200 OK&lt;/code&gt; responses are not blocked unless they truly exceed your thresholds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Efficiency:&lt;/strong&gt; High-volume attacks are stopped before Lambda@Edge runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS-native design:&lt;/strong&gt; Uses AWS WAF, CloudFront, and Lambda@Edge without adding external state stores or proxy layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/waf/latest/APIReference/API_RateBasedStatement.html" rel="noopener noreferrer"&gt;AWS WAF Rate-based rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/waf/latest/APIReference/API_CustomHTTPHeader.html" rel="noopener noreferrer"&gt;AWS WAF Custom HTTP headers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/waf/latest/developerguide/customizing-the-response-for-blocked-requests.html" rel="noopener noreferrer"&gt;AWS WAF Custom responses for Block actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-atp.html" rel="noopener noreferrer"&gt;AWS WAF Fraud Control ATP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on LinkedIn on May 8, 2025.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>waf</category>
      <category>cloudfront</category>
      <category>security</category>
    </item>
    <item>
      <title>Making Amazon Bedrock AgentCore Gateway Accessible (Only Through CloudFront)</title>
      <dc:creator>Alexey Baltacov</dc:creator>
      <pubDate>Mon, 16 Feb 2026 19:21:51 +0000</pubDate>
      <link>https://dev.to/aws-builders/making-amazon-bedrock-agentcore-gateway-accessible-only-through-cloudfront-ha1</link>
      <guid>https://dev.to/aws-builders/making-amazon-bedrock-agentcore-gateway-accessible-only-through-cloudfront-ha1</guid>
      <description>&lt;p&gt;tags: aws, architecture, genai, security, AWScommunity, AWScommunityBuilders&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wp6js60t0avbdylojqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wp6js60t0avbdylojqo.png" alt="aws architecture genai cloud security" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Amazon Bedrock AgentCore Gateway makes it straightforward to expose GenAI-powered APIs.&lt;/p&gt;

&lt;p&gt;AWS provides an official pattern for attaching a custom domain using CloudFront:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Client -&amp;gt; CloudFront -&amp;gt; AgentCore Gateway&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Official documentation:&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-custom-domains.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-custom-domains.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For many use cases, this approach is sufficient.&lt;/p&gt;

&lt;p&gt;But what if the requirement is stronger?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This endpoint must only be reachable through a specific CloudFront distribution.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where architectural boundaries matter.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Hidden Exposure Problem
&lt;/h2&gt;

&lt;p&gt;Even when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudFront is placed in front&lt;/li&gt;
&lt;li&gt;AWS WAF is attached&lt;/li&gt;
&lt;li&gt;A custom domain is configured&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The underlying AgentCore Gateway service endpoint remains publicly accessible.&lt;/p&gt;

&lt;p&gt;CloudFront functions as a reverse proxy, not a strict isolation boundary.&lt;/p&gt;

&lt;p&gt;AgentCore supports resource-based policies:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/resource-based-policies.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/resource-based-policies.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These policies primarily control &lt;strong&gt;who&lt;/strong&gt; can invoke the gateway (IAM principals, AWS accounts, and supported condition keys).&lt;/p&gt;

&lt;p&gt;This model works well for internal service-to-service communication.&lt;/p&gt;

&lt;p&gt;However, for public-facing APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;External consumers do not authenticate using IAM.&lt;/li&gt;
&lt;li&gt;Authentication typically relies on OAuth, JWT, API keys, or custom headers.&lt;/li&gt;
&lt;li&gt;The endpoint must remain internet-reachable for legitimate users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, even if legitimate traffic flows through CloudFront, the underlying Gateway endpoint may still be reachable directly from the internet unless additional controls are introduced.&lt;/p&gt;

&lt;p&gt;IAM-based restrictions do not remove that exposure because the service endpoint itself remains public.&lt;/p&gt;

&lt;p&gt;For environments with strict ingress isolation requirements, this becomes a critical gap.&lt;/p&gt;


&lt;h2&gt;
  
  
  Compare This to S3 + CloudFront (OAI / OAC)
&lt;/h2&gt;

&lt;p&gt;Amazon S3 provides a native enforcement primitive:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Only CloudFront can access this bucket.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With CloudFront Origin Access Identity (OAI) or Origin Access Control (OAC), an S3 bucket can be made private and restricted to a specific CloudFront distribution.&lt;/p&gt;

&lt;p&gt;Example S3 bucket policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowCloudFrontAccessOnly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E123ABC456XYZ"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-private-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The bucket is not public.&lt;/li&gt;
&lt;li&gt;Direct internet access fails.&lt;/li&gt;
&lt;li&gt;Only the CloudFront identity is permitted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AgentCore does not currently provide an equivalent isolation construct.&lt;/p&gt;

&lt;p&gt;An additional boundary must therefore be introduced.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture for Enforcing CloudFront-Only Access
&lt;/h2&gt;

&lt;p&gt;To enforce CloudFront-only reachability, the following architecture can be implemented:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg0eu0w4u8cfh5jglszi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg0eu0w4u8cfh5jglszi.png" alt="Architecture for Enforcing CloudFront-Only Access" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public entry point: &lt;code&gt;ext-clients-api-57x9abc.mycompany.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Required Host header downstream: &lt;code&gt;gw-abc123.gateway.bedrock-agentcore.us-east-1.amazonaws.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Enforcing CloudFront-Only at the Network Layer
&lt;/h2&gt;

&lt;p&gt;The Application Load Balancer (ALB) is publicly addressable, but it does not need to be publicly reachable.&lt;/p&gt;

&lt;p&gt;Inbound traffic can be restricted using &lt;strong&gt;AWS Managed Prefix Lists for CloudFront&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/working-with-aws-managed-prefix-lists.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/vpc/latest/userguide/working-with-aws-managed-prefix-lists.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS maintains a managed prefix list containing CloudFront origin-facing IP ranges.&lt;/p&gt;

&lt;p&gt;Attach this managed prefix list to the ALB security group and allow inbound HTTPS only from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;com.amazonaws.global.cloudfront.origin-facing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only CloudFront edge locations can establish TCP connections to the ALB.&lt;/li&gt;
&lt;li&gt;Direct internet traffic to the ALB is blocked at the security group level.&lt;/li&gt;
&lt;li&gt;IP spoofing cannot bypass the restriction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without CloudFront, the ALB is not reachable.&lt;/p&gt;

&lt;p&gt;This creates a true network enforcement boundary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where AWS WAF and DDoS Protection Fit
&lt;/h2&gt;

&lt;p&gt;This design enables layered protection.&lt;/p&gt;

&lt;h3&gt;
  
  
  CloudFront (Edge Layer)
&lt;/h3&gt;

&lt;p&gt;CloudFront is automatically protected by &lt;strong&gt;AWS Shield Standard&lt;/strong&gt;, which provides DDoS mitigation at the edge.&lt;/p&gt;

&lt;p&gt;AWS WAF at CloudFront can provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rate-based rules (anti-abuse and scraping protection)&lt;/li&gt;
&lt;li&gt;IP reputation filtering&lt;/li&gt;
&lt;li&gt;Geo restrictions&lt;/li&gt;
&lt;li&gt;AWS Managed Rule Groups&lt;/li&gt;
&lt;li&gt;AWS Bot Control&lt;/li&gt;
&lt;li&gt;Account Takeover Prevention (ATP)&lt;/li&gt;
&lt;li&gt;Authentication field inspection&lt;/li&gt;
&lt;li&gt;Header validation&lt;/li&gt;
&lt;li&gt;Payload size limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Malicious traffic can be filtered before reaching the infrastructure.&lt;/p&gt;




&lt;h3&gt;
  
  
  ALB (Ingress Layer)
&lt;/h3&gt;

&lt;p&gt;AWS WAF can also be attached to the ALB to enforce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verification of a secret header injected by CloudFront&lt;/li&gt;
&lt;li&gt;Strict Host header validation&lt;/li&gt;
&lt;li&gt;Additional managed rule groups&lt;/li&gt;
&lt;li&gt;Authentication flow inspection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if the ALB DNS name is discovered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct connection attempts fail due to managed prefix list restrictions.&lt;/li&gt;
&lt;li&gt;Spoofed requests fail due to header validation and WAF rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This results in three enforcement layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edge (Shield + WAF)&lt;/li&gt;
&lt;li&gt;Network (managed prefix list restriction)&lt;/li&gt;
&lt;li&gt;Application (ALB WAF + listener rules)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Technical Challenge: TLS vs Host Header
&lt;/h2&gt;

&lt;p&gt;When placing an ALB in front of AgentCore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The ALB must terminate TLS using a certificate for a custom domain, for example:&lt;br&gt;
&lt;code&gt;ext-clients-api-57x9abc.mycompany.com&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Downstream routing may require a different HTTP &lt;code&gt;Host&lt;/code&gt; header, for example:&lt;br&gt;
&lt;code&gt;gw-abc123.gateway.bedrock-agentcore.us-east-1.amazonaws.com&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These belong to different protocol layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TLS SNI hostname controls certificate validation.&lt;/li&gt;
&lt;li&gt;HTTP Host header controls routing logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AgentCore does not support accepting arbitrary custom domains inbound.&lt;/p&gt;

&lt;p&gt;This mismatch must be resolved before traffic reaches AgentCore.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: CloudFront Origin Modification
&lt;/h2&gt;

&lt;p&gt;CloudFront Functions allow modification of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;domainName&lt;/code&gt; (origin connection hostname for TLS/SNI)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hostHeader&lt;/code&gt; (HTTP Host header sent to the origin)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cf&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cloudfront&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ORIGIN_DOMAIN_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ext-clients-api-57x9abc.mycompany.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OVERRIDE_HOST_HEADER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gw-abc123.gateway.bedrock-agentcore.us-east-1.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;cf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateRequestOrigin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ORIGIN_DOMAIN_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hostHeader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OVERRIDE_HOST_HEADER&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TLS validation against the ALB certificate.&lt;/li&gt;
&lt;li&gt;ALB routing based on the required Host header.&lt;/li&gt;
&lt;li&gt;External clients to interact only with the custom domain.&lt;/li&gt;
&lt;li&gt;AgentCore to remain accessible only through the controlled CloudFront -&amp;gt; ALB -&amp;gt; PrivateLink path.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Outcome
&lt;/h2&gt;

&lt;p&gt;This architecture provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom domain support&lt;/li&gt;
&lt;li&gt;Edge-level DDoS protection (Shield Standard)&lt;/li&gt;
&lt;li&gt;Advanced WAF protections (rate limiting, ATP, bot control, managed rules)&lt;/li&gt;
&lt;li&gt;Network-level CloudFront-only enforcement&lt;/li&gt;
&lt;li&gt;Ingress validation at ALB&lt;/li&gt;
&lt;li&gt;Private connectivity via VPC endpoint&lt;/li&gt;
&lt;li&gt;Strong ingress isolation for GenAI workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The default AWS pattern is well suited for standard deployments.&lt;/p&gt;

&lt;p&gt;When strict CloudFront-only reachability is required, an architectural boundary is necessary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CloudFront + managed prefix lists + ALB + PrivateLink + layered WAF provides that boundary.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>security</category>
      <category>agentcoregateway</category>
    </item>
    <item>
      <title>AWS WAF Intro Guide</title>
      <dc:creator>Alexey Baltacov</dc:creator>
      <pubDate>Thu, 06 Feb 2025 23:00:31 +0000</pubDate>
      <link>https://dev.to/alexeybaltacov/aws-waf-intro-guide-25a3</link>
      <guid>https://dev.to/alexeybaltacov/aws-waf-intro-guide-25a3</guid>
      <description>&lt;p&gt;With this guide you will not become an AWS WAF expert, but will get a bit of taste about its capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Introduction and Overview of AWS WAF
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AWS Web Application Firewall (WAF)&lt;/strong&gt; is a managed security service designed to help protect your web applications or APIs from common web exploits and bots. AWS WAF lets you create rules to monitor (count), block, or allow traffic based on criteria such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP addresses&lt;/li&gt;
&lt;li&gt;HTTP headers&lt;/li&gt;
&lt;li&gt;URI paths&lt;/li&gt;
&lt;li&gt;Request size&lt;/li&gt;
&lt;li&gt;SQL injection attempts&lt;/li&gt;
&lt;li&gt;Cross-Site Scripting (XSS) patterns&lt;/li&gt;
&lt;li&gt;Request rate (rate-based rules)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Additionally&lt;/strong&gt;, when you use AWS WAF, you automatically get the protections of &lt;strong&gt;AWS Shield Standard&lt;/strong&gt; &lt;strong&gt;at no additional cost&lt;/strong&gt;. &lt;strong&gt;AWS Shield Standard&lt;/strong&gt; is a built-in DDoS protection service for AWS resources (including CloudFront and Route 53) that mitigates common network and transport layer attacks. Together, AWS WAF and AWS Shield Standard provide a layered defense approach: WAF focuses on Layer 7 (application layer) threats, while Shield Standard covers volumetric and SYN flood-type attacks (Layers 3 and 4).&lt;/p&gt;

&lt;h2&gt;
  
  
  1.1 Resources Protected by AWS WAF
&lt;/h2&gt;

&lt;p&gt;You can attach AWS WAF to the following AWS resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon CloudFront (for global distribution and caching)&lt;/li&gt;
&lt;li&gt;Amazon API Gateway (REST APIs)&lt;/li&gt;
&lt;li&gt;Application Load Balancer (ALB)&lt;/li&gt;
&lt;li&gt;AWS AppSync (GraphQL APIs)&lt;/li&gt;
&lt;li&gt;Amazon Cognito user pools&lt;/li&gt;
&lt;li&gt;AWS App Runner service&lt;/li&gt;
&lt;li&gt;AWS Verified Access instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, when you use &lt;strong&gt;CloudFront&lt;/strong&gt; with &lt;strong&gt;AWS WAF&lt;/strong&gt;, you can protect &lt;strong&gt;any external or internal origin behind CloudFront&lt;/strong&gt;, including &lt;strong&gt;on-premises servers or third-party cloud environments&lt;/strong&gt;. CloudFront acts as a secure reverse proxy, letting you apply WAF inspection rules to all inbound requests before they reach your origin, regardless of whether that origin is hosted inside or outside of AWS.&lt;/p&gt;

&lt;p&gt;Attaching WAF to these resources allows you to inspect and filter incoming requests based on rules you define (custom rules) or rules you enable from AWS Managed Rule Sets, all while benefiting from the baseline DDoS protections of AWS Shield Standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Applying AWS WAF: CloudFront vs. Other Resources
&lt;/h2&gt;

&lt;h2&gt;
  
  
  2.1 AWS WAF with CloudFront
&lt;/h2&gt;

&lt;p&gt;When integrated with CloudFront, AWS WAF inspects and can block traffic at the edge, before it reaches your origin. Key advantages include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global Edge Presence&lt;/strong&gt;: Requests are processed at CloudFront edge locations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN and Caching&lt;/strong&gt;: CloudFront’s CDN reduces latency and offloads your origin by caching content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure Reverse Proxy&lt;/strong&gt;: By placing CloudFront in front of your application (whether it’s hosted within AWS, on-premises, or another cloud), you effectively use it as a secure reverse proxy that can filter traffic globally.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Shield Standard&lt;/strong&gt;: Automatically protects CloudFront distributions (and other supported AWS resources) against most common DDoS attacks at no extra cost.&lt;br&gt;
If your application needs more nuanced logic than WAF alone can provide, you can extend functionality using:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CloudFront Functions&lt;/strong&gt;: Lightweight JavaScript functions for short-running tasks (up to 1ms) like inspecting headers or rewriting URIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lambda@Edge&lt;/strong&gt;: A more robust solution if you need to read or modify request/response bodies, implement complex authentication flows, or handle sophisticated transformations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;_&lt;strong&gt;Important:&lt;/strong&gt; If AWS WAF blocks a request at the edge, CloudFront Functions and Lambda@Edge will not trigger for that request.&lt;br&gt;
_&lt;/p&gt;

&lt;h2&gt;
  
  
  2.2 AWS WAF with Regional Services
&lt;/h2&gt;

&lt;p&gt;AWS WAF can also operate at a regional level by attaching to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application Load Balancer (ALB)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon API Gateway&lt;/strong&gt; (REST APIs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS AppSync&lt;/strong&gt; (GraphQL APIs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Cognito&lt;/strong&gt; user pools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS App Runner&lt;/strong&gt; service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Verified Access&lt;/strong&gt; instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is suitable for applications or microservices that do not require global edge distribution or caching. Key differences from the CloudFront approach include:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Latency and Caching
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront + WAF&lt;/strong&gt;: Security measures at the edge, lower latency, potential cost savings from caching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regional Services + WAF&lt;/strong&gt;: Traffic is inspected regionally without inherent CDN caching.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Scope and Customization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront&lt;/strong&gt; can use &lt;strong&gt;CloudFront Functions&lt;/strong&gt; or &lt;strong&gt;Lambda@Edge&lt;/strong&gt; for advanced transformations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regional Services&lt;/strong&gt; can still use custom or managed WAF rules, but do not benefit from global caching.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Protecting External Origins
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront + WAF&lt;/strong&gt; can protect &lt;strong&gt;non-AWS origins&lt;/strong&gt; by pointing the distribution to external servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regional services&lt;/strong&gt; typically secure traffic within AWS unless you design a specific pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. AWS Managed Rules
&lt;/h2&gt;

&lt;p&gt;AWS Managed Rules are pre-configured, continuously updated rule sets provided by AWS to protect against a wide range of threats. By enabling these managed rules in your AWS WAF, you can quickly cover many common web attacks without having to define every pattern or behavior manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Coverage for OWASP Top 10
&lt;/h3&gt;

&lt;p&gt;Many AWS Managed Rules are designed to help address &lt;strong&gt;OWASP Top 10&lt;/strong&gt; vulnerabilities, such as:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Injection&lt;/strong&gt; (SQLi, NoSQL, Command Injection)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;AWSManagedRulesSQLiRuleSet&lt;/strong&gt; identifies and blocks SQL injection attempts.&lt;/li&gt;
&lt;li&gt;Common malicious payloads and known injection vectors are covered.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Broken Authentication and Session Management
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Combined with &lt;strong&gt;Account Takeover Prevention (ATP)&lt;/strong&gt;, WAF can detect brute force or credential stuffing attempts on login endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Sensitive Data Exposure
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Managed Rules can flag suspicious payloads or unusual request patterns that might indicate data exfiltration (in conjunction with rate-based rules and SSL/TLS).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  XML External Entities (XXE)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Certain AWS Managed Rule Groups include checks for XML-based threats and malicious entity references.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Broken Access Control
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;While some aspects of access control are application-specific, AWS Managed Rules can detect attempts to bypass security controls using known exploit patterns, suspicious HTTP methods, or path tampering.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Security Misconfiguration
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Common Rule Sets automatically update to address vulnerabilities in common frameworks and platforms, reducing the risk of misconfiguration exposure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cross-Site Scripting (XSS)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWSManagedRulesCommonRuleSet&lt;/strong&gt; includes signatures for detecting malicious scripts and XSS payloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Insecure Deserialization
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Some advanced Managed Rule Groups check for known malicious serialization formats and exploit payloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Using Components with Known Vulnerabilities
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;AWS regularly updates the Managed Rule Sets to address newly disclosed CVEs, helping you keep pace with emerging threats.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Insufficient Logging and Monitoring
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Although logging itself is not a “rule,” AWS WAF integrates with S3, CloudWatch, and Kinesis Firehose for monitoring. Suspicious requests are clearly tagged and logged, aiding your threat detection strategy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.2 Examples of AWS Managed Rule Sets
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWSManagedRulesCommonRuleSet&lt;/strong&gt;: Covers a broad range of general vulnerabilities, including XSS, HTTP request smuggling, and some injection signatures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWSManagedRulesSQLiRuleSet&lt;/strong&gt;: Specifically targets SQL injection patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWSManagedRulesAmazonIpReputationList&lt;/strong&gt;: Blocks or labels requests from known malicious IP addresses or botnets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWSManagedRulesLinuxRuleSet&lt;/strong&gt; (or similar specialized sets): Target vulnerabilities specific to Linux-based systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.3 Complementing Managed Rules with Custom Logic
&lt;/h3&gt;

&lt;p&gt;While AWS Managed Rules provide excellent baseline coverage, you should &lt;strong&gt;monitor&lt;/strong&gt; traffic in “Count” mode initially to identify potential false positives and tune your rules. You can then add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom rules for application-specific logic (e.g., blocking certain user agents or disallowed query parameters).&lt;/li&gt;
&lt;li&gt;Rate-based rules to mitigate brute force or scraping attempts.&lt;/li&gt;
&lt;li&gt;Account Takeover Prevention (ATP) for deeper login endpoint protection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This &lt;strong&gt;layered approach&lt;/strong&gt; (managed rules plus custom refinements) helps ensure robust, OWASP-aligned protection without sacrificing application availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. AWS WAF Fraud Control – Account Takeover Prevention (ATP)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Overview of ATP
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Account Takeover Prevention (ATP)&lt;/strong&gt; is part of &lt;strong&gt;AWS WAF Fraud Control&lt;/strong&gt;, designed to detect and mitigate unauthorized login attempts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Analyzes Login Attempts&lt;/strong&gt;: Monitors login traffic to identify suspicious behavior (credential stuffing, brute force).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk-Based Scoring&lt;/strong&gt;: ATP assigns risk scores to login attempts based on factors like repeated login failures or IP reputation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with WAF&lt;/strong&gt;: You can create WAF rules to allow, count, block, or require CAPTCHA on requests flagged by ATP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By spotting anomalies in login patterns, ATP helps prevent account takeover incidents before they escalate.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Benefits of Using Email Addresses as Usernames with ATP
&lt;/h3&gt;

&lt;p&gt;When combining ATP with email-based usernames (your application should use usernames in email format), you gain several security and operational advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Easier Parsing and Validation: An email format (&lt;a href="mailto:username@domain.com"&gt;username@domain.com&lt;/a&gt;) is consistent, enabling simpler checks for malicious or disposable domains.&lt;/li&gt;
&lt;li&gt;Domain Intelligence: ATP or custom WAF rules can label or block logins from suspicious or disposable email domains.&lt;/li&gt;
&lt;li&gt;Reduced Guesswork: Attackers must guess valid email addresses, which can be less trivial than typical username formats like admin or test.&lt;/li&gt;
&lt;li&gt;Improved Logging: Email addresses provide a clearly identifiable username in the logs for investigating suspicious activity.&lt;/li&gt;
&lt;li&gt;Easier MFA and Recovery: Users often prefer logging in with an email address, simplifying password resets and integrating MFA flows.&lt;/li&gt;
&lt;li&gt;Leverage Compromised Credentials Databases:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;AWS obtains threat intelligence including email/password pairs from public data breaches to help detect credential stuffing or attempts using known compromised credentials.&lt;/li&gt;
&lt;li&gt;Because users commonly reuse email addresses across different services, ATP can cross-reference these compromised credential sets more effectively when your primary username field is an email.&lt;/li&gt;
&lt;li&gt;This synergy helps AWS WAF quickly flag suspicious login attempts, especially when an attacker attempts known leaked email/password pairs from security breaches.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Best Practices and Well-Architected Approach for Building Your Rule Base
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Start with Managed Rules, Then Layer Custom Rules
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Baseline Protections (Managed Rules)&lt;/strong&gt;: Quickly address common threats (SQLi, XSS, bad bots) by enabling relevant AWS Managed Rule Sets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Rules&lt;/strong&gt;: Tailor rules to your application’s business logic (e.g., block suspicious headers, limit request sizes, or restrict certain paths).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate-Based Rules&lt;/strong&gt;: Mitigate DDoS or brute-force attacks by capping requests from a single IP address over a specified period.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JS Challenge and Captcha&lt;/strong&gt;: Implement JS challenge and captcha in your application in order to reduce DDoS by automated browsers, CLI  and other tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.2 “Count” Mode + Labels, Then Block
&lt;/h3&gt;

&lt;p&gt;A major best practice is to start all rules in “Count” mode and add labels:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure each rule to Count rather than block initially.&lt;/li&gt;
&lt;li&gt;Assign a label to requests that match the rule (e.g., SuspiciousSQLi, XSSAttempt).&lt;/li&gt;
&lt;li&gt;Observe logs to verify these matches are legitimate threats or anomalies.&lt;/li&gt;
&lt;li&gt;Implement a final, catch-all blocking rule that blocks requests carrying labels deemed malicious.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach helps reduce false positives while ensuring you have visibility into what would be blocked before actively cutting off traffic as well as centralized control over custom block page headers and responses&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Extend with CloudFront Functions or Lambda@Edge
&lt;/h3&gt;

&lt;p&gt;In cases where AWS WAF rules do not cover a specific use case or you need more dynamic logic, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront Functions&lt;/strong&gt;: Lightweight JavaScript for short-running tasks (up to 1 ms) like inspecting headers, rewriting URIs, or adding custom headers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda@Edge&lt;/strong&gt;: A more robust solution for reading/modifying request or response bodies, implementing complex authentication flows, or dynamic transformations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: If WAF blocks a request, CloudFront Functions or Lambda@Edge will not run for that request.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5.4 Align with AWS Well-Architected Security Pillar
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Design your WAF rule base according to AWS’s Well-Architected Security Pillar:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identification&lt;/strong&gt;: Label and log events to understand potential threats.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proactive Protection&lt;/strong&gt;: Use a combination of managed and custom rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least Privilege&lt;/strong&gt;: Only allow known safe patterns or domains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: Deploy and manage WAF using Infrastructure as Code (CloudFormation, Terraform) for consistency and repeatability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Rule Groups and Rule Labels
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 Rule Groups
&lt;/h3&gt;

&lt;p&gt;A Rule Group is a container for one or more WAF rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Managed Rule Groups&lt;/strong&gt;: Quick to enable, provide coverage for broad classes of attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Rule Groups&lt;/strong&gt;: Let you organize your own rules by function (e.g., IP restrictions, user-agent blocks, country blocks).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  6.2 Rule Labels
&lt;/h4&gt;

&lt;p&gt;When a request matches a rule, WAF can attach labels for tracking or later decision-making. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;SQLiDetected&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;BadBotTraffic&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;DisallowedCountry&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can create a final rule that blocks requests carrying specific labels. Labels also appear in WAF logs, helping you analyze and correlate different rule matches.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Custom Responses in WAF Rule Actions
&lt;/h2&gt;

&lt;p&gt;AWS WAF supports custom responses for Block actions. Instead of returning a generic 403 Forbidden, you can define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom HTTP Status&lt;/strong&gt; Code (e.g., 403, 404, 502, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Headers&lt;/strong&gt; (e.g., to convey an error reason to the client)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom HTML or text Body&lt;/strong&gt; for the response
This feature is useful when you want to provide a branded or instructive error page, or add extra troubleshooting information for the user. Since the request is already blocked, no further edge functions (CloudFront Functions or Lambda@Edge) will execute for that request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: You might choose to return a 403 status with a short HTML body:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
  "Name": "MyWebACL",&lt;br&gt;
  "Scope": "CLOUDFRONT",&lt;br&gt;
  "DefaultAction": { "Allow": {} },&lt;br&gt;
  "Rules": [&lt;br&gt;
    {&lt;br&gt;
      "Name": "BlockWithCustomResponse",&lt;br&gt;
      "Priority": 1,&lt;br&gt;
      "Statement": {&lt;br&gt;
        "ByteMatchStatement": {&lt;br&gt;
          "FieldToMatch": { "SingleHeader": { "Name": "x-bad-header" } },&lt;br&gt;
          "PositionalConstraint": "EXACTLY",&lt;br&gt;
          "SearchString": "bad-value",&lt;br&gt;
          "TextTransformations": [{ "Priority": 0, "Type": "NONE" }]&lt;br&gt;
        }&lt;br&gt;
      },&lt;br&gt;
      "Action": {&lt;br&gt;
        "Block": {&lt;br&gt;
          "CustomResponse": {&lt;br&gt;
            "ResponseCode": 403,&lt;br&gt;
            "CustomResponseBodyKey": "CustomHTMLResponse",&lt;br&gt;
            "ResponseHeaders": [&lt;br&gt;
              { "Name": "X-Custom-Error", "Value": "BlockedByWAF" }&lt;br&gt;
            ]&lt;br&gt;
          }&lt;br&gt;
        }&lt;br&gt;
      },&lt;br&gt;
      "VisibilityConfig": {&lt;br&gt;
        "SampledRequestsEnabled": true,&lt;br&gt;
        "CloudWatchMetricsEnabled": true,&lt;br&gt;
        "MetricName": "BlockWithCustomResponseRule"&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  ],&lt;br&gt;
  "CustomResponseBodies": {&lt;br&gt;
    "CustomHTMLResponse": {&lt;br&gt;
      "ContentType": "TEXT_HTML",&lt;br&gt;
      "Content": "&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Access Denied&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Your request has been blocked.&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;br&gt;
    }&lt;br&gt;
  },&lt;br&gt;
  "VisibilityConfig": {&lt;br&gt;
    "SampledRequestsEnabled": true,&lt;br&gt;
    "CloudWatchMetricsEnabled": true,&lt;br&gt;
    "MetricName": "MyACLMetric"&lt;br&gt;
  }&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this example, any request including a header &lt;strong&gt;x-bad-header&lt;/strong&gt;: &lt;strong&gt;bad-value&lt;/strong&gt; is blocked, returning a &lt;strong&gt;403&lt;/strong&gt; code with a custom HTML body.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Limitations
&lt;/h2&gt;

&lt;p&gt;While AWS WAF is powerful and flexible, you should be aware of some important constraints and limitations:&lt;/p&gt;

&lt;h4&gt;
  
  
  Rule Capacity (WCU – WAF Capacity Units)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Each rule (or statement within a rule) consumes a certain number of WCUs based on its complexity. For example, ByteMatchStatement or IP match conditions generally have lower WCU usage, while Regex match statements and complex logical operators can use more.&lt;/li&gt;
&lt;li&gt;There is a maximum WCU limit for each Web ACL. If your rules exceed that limit, you cannot add them all to the same Web ACL. You may need to simplify your rules or optimize your rule groups.&lt;/li&gt;
&lt;li&gt;Monitor your rule WCU usage (in the AWS console or via the CLI) to ensure you stay within allowed capacity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Regex Complexity
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Very complex regex patterns can quickly use up available WCUs. Simplify your patterns or break them into multiple statements where possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Logging Latency
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;WAF logs are almost real time when using Cloudwatch and typically appear with a short delay in S3 or Kinesis&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Regional vs. Global
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;WAF on CloudFront is global; on ALB, API Gateway, etc., it’s regional.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cost
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Each rule, managed rule group, and request passing through WAF contributes to your monthly bill. Monitor usage carefully.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Inspection Header Size
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;WAF regional inspects up to a certain size for request headers/body (e.g., first 16 KB). &lt;/li&gt;
&lt;li&gt;WAF Global (Cloudfront) supports up to 64 KB headers/body inspection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Requests exceeding this limit may not be fully inspected.&lt;/p&gt;

&lt;h4&gt;
  
  
  Blocking Halts Edge Functions
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;If a request is blocked by WAF, CloudFront Functions or Lambda@Edge will not run for that request.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. Practical Information about Working with Labels
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Defining Labels&lt;/strong&gt;: Specify labels in your WAF rule actions (console or CLI).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combining Labels&lt;/strong&gt;: Multiple rules can label the same request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match on Labels&lt;/strong&gt;: A final rule can check if a request has any suspicious labels and block it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging&lt;/strong&gt;: Inspect WAF logs to see which labels are assigned and confirm the accuracy of your rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Protecting Resources Outside AWS Using CloudFront
&lt;/h2&gt;

&lt;p&gt;One advantage of &lt;strong&gt;CloudFront + WAF&lt;/strong&gt; is the ability to protect &lt;strong&gt;external (non-AWS) origins&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a CloudFront distribution that points to your on-premises or third-party cloud origin.&lt;/li&gt;
&lt;li&gt;Attach a WAF Web ACL to that distribution.&lt;/li&gt;
&lt;li&gt;Enable caching for static or cacheable content to reduce load on the external origin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Secure Reverse Proxy&lt;/strong&gt;: CloudFront, acting as a secure reverse proxy, inspects all traffic with WAF at the edge before forwarding it to your external servers.&lt;br&gt;
This setup provides global edge security and performance benefits even if your origin is not hosted on AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. AWS Managed Protections for OWASP Top 10
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The OWASP Top 10&lt;/strong&gt; is a standard awareness document outlining the most critical web application security risks. AWS WAF addresses several OWASP Top 10 vulnerabilities via AWS Managed Rules and additional features:&lt;/p&gt;

&lt;h4&gt;
  
  
  Injection
&lt;/h4&gt;

&lt;p&gt;(SQLi, NoSQL, Command Injection)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWSManagedRulesSQLiRuleSet&lt;/strong&gt; helps block SQL injection attempts.&lt;br&gt;
Custom rules can detect command injection patterns.&lt;br&gt;
Broken Authentication and Session Management&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ATP&lt;/strong&gt; helps mitigate brute force or credential stuffing.&lt;br&gt;
Rate-based rules can address repeated login attempts.&lt;br&gt;
Sensitive Data Exposure&lt;/p&gt;

&lt;p&gt;WAF can block suspicious payloads that may indicate data exfiltration.&lt;br&gt;
Combine with SSL/TLS for encrypted data in transit.&lt;/p&gt;

&lt;h4&gt;
  
  
  XML External Entities (XXE)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom or third-party&lt;/strong&gt; rules detect malicious XML patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Broken Access Control
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;WAF custom rules can enforce strict path or header-based controls.&lt;/li&gt;
&lt;li&gt;Labels help track role-based or token-based access attempts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Security Misconfiguration
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;AWS Managed Rule Sets automatically update to address new vulnerabilities.&lt;/li&gt;
&lt;li&gt;Custom rules detect unusual HTTP methods or suspicious headers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cross-Site Scripting (XSS)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;AWSManagedRulesCommonRuleSet&lt;/strong&gt; includes patterns for typical XSS vectors.&lt;/p&gt;

&lt;h4&gt;
  
  
  Insecure Deserialization
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Advanced rule sets can detect malicious serialization formats.&lt;/li&gt;
&lt;li&gt;Using Components with Known Vulnerabilities&lt;/li&gt;
&lt;li&gt;Regular updates to AWS Managed Rules help protect against newly disclosed CVEs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Insufficient Logging and Monitoring
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;WAF logging (to S3, CloudWatch, or Kinesis) provides robust, centralized monitoring.&lt;/li&gt;
&lt;li&gt;Combine with Athena or OpenSearch for advanced log analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. Pricing Model
&lt;/h2&gt;

&lt;h3&gt;
  
  
  12.1 AWS WAF Pricing
&lt;/h3&gt;

&lt;p&gt;AWS WAF pricing typically includes four main components:&lt;/p&gt;

&lt;h4&gt;
  
  
  Web ACLs
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You pay a monthly charge for each web ACL that you create (e.g., around USD $5 per month per web ACL, depending on the region).&lt;/li&gt;
&lt;li&gt;Rules&lt;/li&gt;
&lt;li&gt;Each rule (custom or managed) in your web ACL adds a small monthly cost - often USD $1 per rule per month.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Rule Groups
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Enabling an AWS Managed Rule Group or a third-party rule group from AWS Marketplace can incur a monthly subscription (for the group itself), plus the cost for each rule inside the group if applicable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Request Volume
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You pay for each million web requests inspected by AWS WAF. The typical rate is around USD $0.60–$1.00 per million requests (exact cost varies by region).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Important:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Prices &lt;strong&gt;vary&lt;/strong&gt; by AWS Region.&lt;/li&gt;
&lt;li&gt;Third-party managed rule groups may have higher subscription costs than AWS-managed rule sets.&lt;/li&gt;
&lt;li&gt;Overuse of large or complex rules can drive up monthly costs. Monitor usage carefully.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  12.2 CloudFront Pricing
&lt;/h3&gt;

&lt;p&gt;Amazon CloudFront has its own separate billing model. Main cost factors include:&lt;/p&gt;

&lt;h4&gt;
  
  
  Data Transfer Out
&lt;/h4&gt;

&lt;p&gt;You pay for data transferred from CloudFront edge locations to your users. Rates vary by geographic region and volume.&lt;/p&gt;

&lt;h4&gt;
  
  
  Requests
&lt;/h4&gt;

&lt;p&gt;You pay for HTTPS/HTTP requests served by CloudFront. Pricing can be on the order of USD $0.01 per 10,000 requests in many regions.&lt;/p&gt;

&lt;h4&gt;
  
  
  CloudFront Functions / Lambda@Edge
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront Functions&lt;/strong&gt;: Billed by the number of function invocations (e.g., $0.10 per 1 million invocations).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda@Edge&lt;/strong&gt;: Billed by the number of requests plus compute time (GB-seconds).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optimization Tip: Caching effectively in CloudFront can drastically reduce the number of origin fetches, which lowers data transfer costs and can also reduce Lambda@Edge invocations. However, caching does not reduce the number of WAF inspections, as every client request that hits CloudFront is still processed by WAF (unless previously blocked or allowed by another mechanism).&lt;/p&gt;

&lt;h2&gt;
  
  
  13. AWS WAF vs. Incapsula (Imperva) vs. Cloudflare vs. AWS WAF with CloudFront
&lt;/h2&gt;

&lt;p&gt;Below is a high-level comparison table, including a separate row for AWS WAF with CloudFront:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91imq2jtn7utk431nte0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91imq2jtn7utk431nte0.png" alt=" " width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Takeaways:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;AWS WAF (Regional Services): Ideal for apps that don’t require global edge caching or are purely regional.&lt;/li&gt;
&lt;li&gt;AWS WAF with CloudFront: Global edge distribution, built-in CDN and caching, extends protection to external origins. Additionally, combining AWS WAF with CloudFront Functions and Lambda@Edge provides extended customization flexibility, allowing deep control over each and every HTTP parameter within the session, from rewriting headers to injecting custom logic for advanced routing or security checks.&lt;/li&gt;
&lt;li&gt;Incapsula &amp;amp; Cloudflare: Third-party global security/CDN solutions with their own pricing, feature sets, and potential integration complexities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  14. Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AWS WAF&lt;/strong&gt; is a powerful, flexible solution for safeguarding &lt;strong&gt;both AWS-hosted and external web applications&lt;/strong&gt;. With managed rules, custom rules, labels, and a layered “count then block” strategy, you can tailor your defenses while minimizing false positives. Integrating &lt;strong&gt;CloudFront&lt;/strong&gt; adds global edge coverage, caching, and the option to use &lt;strong&gt;CloudFront Functions&lt;/strong&gt; or &lt;strong&gt;Lambda@Edge&lt;/strong&gt; for advanced logic.&lt;/p&gt;

&lt;p&gt;Furthermore, &lt;strong&gt;AWS Shield Standard&lt;/strong&gt; is included at no additional cost, protecting your AWS resources from common network and transport-layer DDoS attacks, while WAF focuses on application-layer threats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Account Takeover Prevention (ATP)&lt;/strong&gt; further boosts security by analyzing login attempts for suspicious behavior, making it especially effective when users log in with email addresses. This consistency aids in detection and labeling of potentially malicious traffic and benefits from AWS’s threat intelligence on compromised credentials from public data breaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Implementation Steps&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable AWS Managed Rules for immediate protection against common attacks, including OWASP Top 10 vulnerabilities.&lt;/li&gt;
&lt;li&gt;Add Custom Rules to address your application’s unique security needs.&lt;/li&gt;
&lt;li&gt;Leverage Rule Labels and test in “Count” mode before enforcing blocks.&lt;/li&gt;
&lt;li&gt;Adopt a Final Blocking Rule that triggers on suspicious labels (e.g., SQLiDetected, ATPHighRisk).&lt;/li&gt;
&lt;li&gt;Use CloudFront as a secure reverse proxy to protect both AWS and external origins, taking advantage of edge caching.&lt;/li&gt;
&lt;li&gt;Implement ATP to mitigate unauthorized login attempts, benefiting from standardized email-based usernames and compromised credential checks.&lt;/li&gt;
&lt;li&gt;Monitor Limitations such as WAF Capacity Units (WCU), inspection header size, and overall request volume to ensure your rules function effectively at scale.&lt;/li&gt;
&lt;li&gt;Use Custom Responses in block actions for branded or instructive error pages.&lt;/li&gt;
&lt;li&gt;Leverage AWS Shield Standard for built-in DDoS protection, covering the network and transport layers at no extra cost.&lt;/li&gt;
&lt;li&gt;Manage Costs by monitoring the number of web ACLs, rules, and request volume. Optimize with CloudFront caching to reduce origin fetches.&lt;/li&gt;
&lt;li&gt;Regularly Review OWASP Top 10 and confirm your AWS Managed Rule Sets (and custom rules) align with emerging vulnerabilities.
By following these best practices and leveraging AWS WAF’s advanced features, you can establish a well-architected, scalable, and cost-effective defense against evolving threats- both within and beyond the AWS ecosystem.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
