<?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>Forem: Piero Bozzolo</title>
    <description>The latest articles on Forem by Piero Bozzolo (@petecocoon).</description>
    <link>https://forem.com/petecocoon</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%2F891462%2F40d9df65-0335-4d71-b3e6-c2c7dab21995.jpeg</url>
      <title>Forem: Piero Bozzolo</title>
      <link>https://forem.com/petecocoon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/petecocoon"/>
    <language>en</language>
    <item>
      <title>Configuring API Gateway for Secure S3 File Uploads: A Step-by-Step Guide</title>
      <dc:creator>Piero Bozzolo</dc:creator>
      <pubDate>Mon, 26 Aug 2024 13:42:34 +0000</pubDate>
      <link>https://forem.com/petecocoon/configuring-api-gateway-for-secure-s3-file-uploads-a-step-by-step-guide-8ng</link>
      <guid>https://forem.com/petecocoon/configuring-api-gateway-for-secure-s3-file-uploads-a-step-by-step-guide-8ng</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a reviewed version of the same previously published article on my medium page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To allow an API Gateway to upload files directly to S3, you need to create an IAM role that can be assumed by the API Gateway and has the necessary permissions to write objects to S3.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create the IAM Role
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--einoxcEx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5888/1%2AhF1yCsZUUjAVVmLCq8-Z0Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--einoxcEx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5888/1%2AhF1yCsZUUjAVVmLCq8-Z0Q.png" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the IAM service in your AWS console.&lt;/li&gt;
&lt;li&gt;Navigate to “Roles” and click “Create role.”&lt;/li&gt;
&lt;li&gt;Select “AWS service” under “Trusted entity type,” then choose “API Gateway” under “Use cases for other AWS services.”&lt;/li&gt;
&lt;li&gt;Click “Next” to proceed.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IixTKubs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5568/1%2AkqVI6E1dqeOzYVH_1brHRw.png" width="800" height="445"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Set Permissions for the Role
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;After creating the role, name it (e.g., “api-gateway-s3-upload”) and click “Create role.”&lt;/li&gt;
&lt;li&gt;To add permissions, open the newly created role from the IAM Roles list.&lt;/li&gt;
&lt;li&gt;Under the “Permissions” tab, click “Add permissions” -&amp;gt; “Attach policies.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RIFgwncc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4644/1%2AydcP7RPXiGtp6DzLpjb79Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RIFgwncc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4644/1%2AydcP7RPXiGtp6DzLpjb79Q.png" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Filter by “S3” and select &lt;strong&gt;AmazonS3FullAccess&lt;/strong&gt;.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k5VJcwgQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5520/1%2A9G6G9LzFpwvn72uvCzJiwA.png" width="800" height="400"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While &lt;strong&gt;AmazonS3FullAccess&lt;/strong&gt; grants full S3 access, it does not adhere to the principle of least privilege. Consider creating a custom policy that only allows the &lt;code&gt;PutObject&lt;/code&gt; action on the specific S3 bucket.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O3jHaWlJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4468/1%2Ach-YwDKLuhSuRPgkQxx0Hw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O3jHaWlJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4468/1%2Ach-YwDKLuhSuRPgkQxx0Hw.jpeg" width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3: Fine-Tuning the Permissions
&lt;/h3&gt;

&lt;p&gt;To ensure compliance with the least privilege principle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove the &lt;strong&gt;AmazonS3FullAccess&lt;/strong&gt; policy by selecting it and clicking “Remove.”&lt;/li&gt;
&lt;li&gt;Add a new inline policy by clicking “Add Permissions” -&amp;gt; “Create inline policy.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ajlXAkem--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5524/1%2AScj3jbMJDz0ZgOmdiekiWQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ajlXAkem--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5524/1%2AScj3jbMJDz0ZgOmdiekiWQ.png" width="800" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the JSON tab, insert the following policy:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y8B-pTr7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4862/1%2A1mN2OgzlSXCr1hNQ1WzwTg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y8B-pTr7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4862/1%2A1mN2OgzlSXCr1hNQ1WzwTg.jpeg" width="800" height="130"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&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="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;"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:PutObject"&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:::your-bucket-name/*"&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;/li&gt;
&lt;li&gt;&lt;p&gt;Review the policy, assign it a unique name, and create it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;You've successfully created an IAM role with a custom policy that allows API Gateway to upload files to S3 securely. In the next part of this series, we'll explore how to configure an API that leverages this role for S3 operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KpLhBUVx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2514/1%2Ar7hbEmkP-toG_h-IGme-ng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KpLhBUVx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2514/1%2Ar7hbEmkP-toG_h-IGme-ng.png" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>apigateway</category>
    </item>
    <item>
      <title>Extreme Programming Meets the Cloud: How Serverless Would Have Been XP's BFF</title>
      <dc:creator>Piero Bozzolo</dc:creator>
      <pubDate>Thu, 15 Aug 2024 15:33:34 +0000</pubDate>
      <link>https://forem.com/petecocoon/extreme-programming-meets-the-cloud-how-serverless-would-have-been-xps-bff-m11</link>
      <guid>https://forem.com/petecocoon/extreme-programming-meets-the-cloud-how-serverless-would-have-been-xps-bff-m11</guid>
      <description>&lt;p&gt;Last weekend, I was getting ready for a trip in my camper, knowing I'd be without an internet connection. As I passed by my bookshelf, I quickly grabbed an old book to have something to read, and I happened to pick up &lt;em&gt;"Extreme Programming Explained"&lt;/em&gt; by Kent Beck. Over the weekend, I reread after almost 15 years the first few chapters and couldn't help but think about how perfectly the serverless world aligns with an XP approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Serverless is Perfect for Extreme Programming&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In recent years, Extreme Programming (XP) has become a cornerstone of agile development, thanks to its focus on code quality and its ability to quickly adapt to changes. But if you want to truly maximize the benefits of XP, choosing the right infrastructure is key. And that's where serverless comes in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rapid Feedback:&lt;/strong&gt; One of the core aspects of XP is getting continuous feedback through frequent, short release cycles. With serverless, you can deploy new features in real-time and get immediate feedback from users. You don’t have to worry about the infrastructure, which means you can release updates more often and at a lower cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Focus on Code:&lt;/strong&gt; XP promotes simple design and constant code refactoring. Serverless lets you focus entirely on developing features without thinking about the underlying infrastructure. This reduces complexity, keeping the code clean and easy to manage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Continuous Integration Made Easier:&lt;/strong&gt; Continuous integration is a cornerstone of XP, and serverless is the perfect ally here. Thanks to the modularity of serverless functions, you can isolate and test each part of the code independently, reducing the risk of bugs. Moreover, many serverless platforms come with built-in support for CI/CD (Continuous Integration/Continuous Deployment) pipelines, allowing you to automate testing and code deployment. This speeds up development and ensures consistent quality over time. The best part is you don't have to worry about managing the infrastructure—serverless takes care of it all, leaving you free to focus on features and business logic. This makes for a smoother workflow and lets you quickly adapt to changes, in true XP fashion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic Scalability:&lt;/strong&gt; One of XP's strengths is its ability to quickly adapt to change. With serverless, your applications automatically scale based on demand, with no manual intervention needed, which translates to tremendous flexibility in tackling new challenges or adding features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduced Complexity:&lt;/strong&gt; XP loves simplicity, and serverless is perfect for that. The modular solutions provided by serverless reduce architectural complexity, improve code quality, and make it easier to continuously enhance the system.&lt;/p&gt;

&lt;p&gt;In conclusion, if you're using Extreme Programming, serverless is the ideal companion. It helps you stay agile, improve code quality, and respond quickly to changes, perfectly embodying the principles of XP. And let’s be honest, if serverless had been available during XP's heyday, I'm sure it would have become one of the favorite tools of early XP enthusiasts, thanks to its ability to support a fast, iterative development approach.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>xp</category>
    </item>
    <item>
      <title>Dynamically Choosing Origin Based on Host Header and Path with AWS CloudFront and Lambda@Edge</title>
      <dc:creator>Piero Bozzolo</dc:creator>
      <pubDate>Thu, 27 Jun 2024 17:41:42 +0000</pubDate>
      <link>https://forem.com/petecocoon/dynamically-choosing-origin-based-on-host-header-and-path-with-aws-cloudfront-and-lambdaedge-1c3p</link>
      <guid>https://forem.com/petecocoon/dynamically-choosing-origin-based-on-host-header-and-path-with-aws-cloudfront-and-lambdaedge-1c3p</guid>
      <description>&lt;p&gt;In a recent project for our customer &lt;a href="https://www.skillgym.com/" rel="noopener noreferrer"&gt;Skillgym&lt;/a&gt;, I faced the challenge of serving content from different origins based on specific conditions, like the host subdomain. The goal was to leverage AWS CloudFront to distribute content efficiently while ensuring the flexibility to choose between multiple origins based on the host header and request path. This post will walk you through the solution, highlighting the differences between CloudFront Functions and Lambda@Edge, and how we used Lambda@Edge to dynamically select origins based on subdomains.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Challenge
&lt;/h3&gt;

&lt;p&gt;The primary challenge was to configure CloudFront to serve content from different origins based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Specific domains or subdomains&lt;/li&gt;
&lt;li&gt;Different paths within each domain/subdomain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, we needed to route traffic to an S3 bucket for static assets on a specific path for a particular domain. This means that requests to &lt;a href="http://www.example.com/images/test.png" rel="noopener noreferrer"&gt;www.example.com/images/test.png&lt;/a&gt; should be directed to the S3 object at s3://my-bucket/example.com-content/public/images/test.png. At the same time, we used an Application Load Balancer (ALB) to handle dynamic content. So, requests to &lt;a href="http://www.company-website.com/images/dynamic-image.png" rel="noopener noreferrer"&gt;www.company-website.com/images/dynamic-image.png&lt;/a&gt; should be directed to the API served by the ALB.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution Overview
&lt;/h3&gt;

&lt;p&gt;The solution involves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configuring an S3 bucket and CloudFront distribution.&lt;/li&gt;
&lt;li&gt;Writing Lambda@Edge functions to dynamically choose the origin.&lt;/li&gt;
&lt;li&gt;Setting up CloudFront Functions for lightweight request manipulation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  CloudFront Functions vs. Lambda@Edge
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CloudFront Functions&lt;/strong&gt; are designed for lightweight, short-duration tasks such as simple HTTP header manipulation. They execute very quickly and are cost-effective for simple tasks. CloudFront Functions are priced based on the number of function invocations.&lt;/p&gt;

&lt;p&gt;As of the current pricing model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First 2,000,000 invocations each month&lt;/strong&gt; are free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$0.10 per 1,000,000 invocations&lt;/strong&gt; thereafter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are limited to basic transformations and do not support accessing external services or executing complex logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lambda@Edge&lt;/strong&gt;, on the other hand, offers more power and flexibility. It allows for more complex logic and can interact with external services, making it suitable for tasks such as dynamically choosing origins based on request attributes.&lt;/p&gt;

&lt;p&gt;Lambda@Edge functions are priced based on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Invocations&lt;/strong&gt;: $0.60 per 1,000,000 invocations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duration&lt;/strong&gt;: $0.00000625125 for every GB-second used.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;If the requested content is already cached and the cache is still valid, the &lt;code&gt;origin-request&lt;/code&gt; Lambda@Edge function will not be invoked.&lt;/strong&gt; This means Lambda@Edge only executes when CloudFront needs to go to the origin to fetch the content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation Details
&lt;/h3&gt;

&lt;p&gt;We will define two origins, but only one cache behavior. In the function associated with the viewer-request trigger, we will manipulate the incoming request. Then, in the function associated with the origin-request trigger, we will change the origin based on the host header. This setup allows us to dynamically select the appropriate origin for each request while maintaining a consistent caching strategy.&lt;/p&gt;

&lt;h4&gt;
  
  
  Terraform Configuration
&lt;/h4&gt;

&lt;p&gt;Here's the Terraform configuration to set up the necessary AWS resources.&lt;/p&gt;

&lt;p&gt;It’s important to note that the provided Terraform code is far from complete. Additional configurations are required to fully set up the S3 bucket, Origin Access Control (OAC), and other distribution parameters. Specifically, detailed bucket definitions, complete OAC settings, and comprehensive CloudFront distribution parameters must be included to ensure a fully functional and secure content delivery setup. These additional configurations are crucial for properly managing permissions, securing access, and optimizing the performance of the CloudFront distributions.&lt;/p&gt;

&lt;p&gt;Since the origin request function is executed on the S3 cache behaviour, CloudFront automatically replaces the host header with the S3 host header. To preserve the original host header, we need to save it in a custom header, such as x-original-host. When the origin request function determines that the origin should be the ALB, we can use the value stored in x-original-host to restore the original host header. This allows us to continue using the host header as a rule to select the target group in the ALB, ensuring proper routing and origin selection based on the original request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_cloudfront_distribution"&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;distribution_bucket&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;domain_name&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;distribution_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_regional_domain_name&lt;/span&gt;
    &lt;span class="nx"&gt;origin_access_control_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_cloudfront_origin_access_control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="nx"&gt;origin_id&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_origin_id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;domain_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_target_origin&lt;/span&gt;
    &lt;span class="nx"&gt;origin_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main_origin&lt;/span&gt;
    &lt;span class="nx"&gt;custom_origin_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;origin_protocol_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"match-viewer"&lt;/span&gt;
      &lt;span class="nx"&gt;http_port&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
      &lt;span class="nx"&gt;https_port&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
      &lt;span class="nx"&gt;origin_ssl_protocols&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"TLSv1.2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;enabled&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;is_ipv6_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;aliases&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host_subdomains&lt;/span&gt;

  &lt;span class="nx"&gt;default_cache_behavior&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... &lt;/span&gt;
    &lt;span class="nx"&gt;target_origin_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_origin_id&lt;/span&gt;
    &lt;span class="nx"&gt;cache_policy_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_cache_policy&lt;/span&gt;

    &lt;span class="nx"&gt;viewer_protocol_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"redirect-to-https"&lt;/span&gt;

    &lt;span class="nx"&gt;function_association&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;event_type&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"viewer-request"&lt;/span&gt;
      &lt;span class="nx"&gt;function_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_cloudfront_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace-s3-view-path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;lambda_function_association&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;event_type&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"origin-request"&lt;/span&gt;
      &lt;span class="nx"&gt;lambda_arn&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;select-origin-function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;qualified_arn&lt;/span&gt;
      &lt;span class="nx"&gt;include_body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&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;h4&gt;
  
  
  Lambda@Edge and CloudFront Functions
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Viewer Request Function&lt;/strong&gt;: This CloudFront function rewrites the URL path based on subdomain mappings and saves the original host header in the x-original-host header.
&lt;/li&gt;
&lt;/ol&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;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;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;request&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;uri&lt;/span&gt; &lt;span class="o"&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;uri&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;host&lt;/span&gt; &lt;span class="o"&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;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;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-original-host&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Add logic to manipulate URI based on subdomain&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;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/old-path&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/old-path&lt;/span&gt;&lt;span class="dl"&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;/new-path&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;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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Origin Request Function&lt;/strong&gt;: This Lambda@Edge function routes requests to different origins based on the subdomain and path.
&lt;/li&gt;
&lt;/ol&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;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;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;request&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;request&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hostHeader&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="nx"&gt;host&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="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalHost&lt;/span&gt; &lt;span class="o"&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;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-original-host&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subdomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hostHeader&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&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="c1"&gt;// You can add your logic here&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;subdomain&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;static&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="nx"&gt;request&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;host&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;Host&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;your-s3-bucket.s3.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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Store the original host header in a custom header&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalHost&lt;/span&gt; &lt;span class="o"&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;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-original-host&lt;/span&gt;&lt;span class="dl"&gt;'&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="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;origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-alb.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;port&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="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;sslProtocols&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;TLSv1.2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;readTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;keepaliveTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;customHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="c1"&gt;// Set the host header to the original request host&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;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;host&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;host&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="nx"&gt;originalHost&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;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;h3&gt;
  
  
  Bucket security
&lt;/h3&gt;

&lt;p&gt;This approach leverages the Origin Access Control (OAC) feature, as it is the only method that works with this configuration (during the implementation I tested OAI without success). &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Selecting the right CDN origin and using Lambda@Edge with CloudFront Functions gives you the flexibility to select the origin with complex logic. Lambda@Edge enables advanced logic execution closer to users, while CloudFront Functions handle lightweight tasks like URL rewrites efficiently. &lt;/p&gt;

</description>
      <category>cloudfront</category>
      <category>aws</category>
      <category>serverless</category>
      <category>lambda</category>
    </item>
    <item>
      <title>The Secrets of AWS API Gateway</title>
      <dc:creator>Piero Bozzolo</dc:creator>
      <pubDate>Tue, 14 May 2024 15:07:24 +0000</pubDate>
      <link>https://forem.com/petecocoon/the-secrets-of-aws-api-gateway-480o</link>
      <guid>https://forem.com/petecocoon/the-secrets-of-aws-api-gateway-480o</guid>
      <description>&lt;h2&gt;
  
  
  The Secrets of AWS API Gateway
&lt;/h2&gt;

&lt;p&gt;How can an API be secured and exposed to the internet? How the underlying API resource access can be controlled? Is it possible to make an AWS service accessible to external users? Let’s see how API Gateway helps us answer those questions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dm6UWfHa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A7U9GhamSsGpqykAOtq64Wg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dm6UWfHa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A7U9GhamSsGpqykAOtq64Wg.png" alt="" width="401" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generally speaking, an API Gateway is a management service that lies between an API client and a bunch of backend services. That service can be a container running NGINX, a Lambda function, a general HTTPS server running on EC2, or a group of legacy APIs.&lt;/p&gt;

&lt;p&gt;Although the service can centralize and manage many APIs under a unique endpoint, somehow like Application Load Balancer, API Gateway can solve many other contour problems. Let’s see some examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;Authentication&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;API Gateway can be configured to filter out unauthorized requests. API Gateway-managed API can be connected to &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html"&gt;AWS Cognito&lt;/a&gt; to handle authentication. This method involves the use of a &lt;a href="https://swagger.io/docs/specification/authentication/bearer-authentication/"&gt;bearer token&lt;/a&gt; included in every HTTP request.&lt;/p&gt;

&lt;p&gt;Cognito is not the only option for authentication. A lambda function that checks the token and allows or denies every request can be set as a custom authenticator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Throttling
&lt;/h2&gt;

&lt;p&gt;How the number of API invocations can be limited per user or per region? Throttling is the right feature and put a limit on invocations preventing overwhelming the application. Also, different thresholds can be set for every consumer using &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html#apigateway-how-throttling-limits-are-applied"&gt;usage plans and API keys&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Transformations
&lt;/h2&gt;

&lt;p&gt;Sometimes, when a legacy or a 3rd-party service is used, the request body must be remapped in another format before processing. The same can happen backward: the answer sent from the service to the customer should be changed for compatibility purposes. Using the &lt;a href="https://velocity.apache.org/engine/devel/index.html"&gt;Velocity Template Language&lt;/a&gt; engine, mapping templates are responsible to reconstruct and transform request/response data. Request parameters can be transformed too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expose HTTP APIs.
&lt;/h2&gt;

&lt;p&gt;Exposing HTTP API is the core feature of API Gateway. In the microservice era, this is the fundamental feature of a modern cloud-native application, where the architecture consists of lowly coupled and highly specialized services. Every application service can be written in different languages, by different teams or vendors, with custom development and release cycle. API Gateway exposes a unique endpoint for all of them. Moreover, every AWS service can be consumed as an HTTP request, so many of them can be served from API Gateway to your customer, even Lambda Function!&lt;/p&gt;

&lt;h2&gt;
  
  
  Body validations
&lt;/h2&gt;

&lt;p&gt;One rule exists from ancient times: never trust inputs. When APIs are implemented an input validation technology must be chosen. In the previous paragraph, we highlighted that a modern application can be written in many languages with its validations library. API Gateway can validate inputs on your behalf, keeping the validations in one single point, using one only syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other features
&lt;/h2&gt;

&lt;p&gt;API Gateway can work also as a cache for HTTP APIs and can mock API for development purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS API Gateway types
&lt;/h2&gt;

&lt;p&gt;There are three variants of API Gateway available, what is the right choice for your application?&lt;/p&gt;

&lt;p&gt;HTTP API&lt;br&gt;
If a gateway is needed without special features the HTTP API is the right choice. It doesn't support i.e. body transformation, throttling, and many other features BUT is the lowest latency and cheapest solution.&lt;/p&gt;

&lt;p&gt;WebSocket API&lt;br&gt;
If a full-duplex communication between the application and clients is needed, WebSocket is the cutting-edge technology that permits that.&lt;/p&gt;

&lt;p&gt;REST API&lt;br&gt;
This is the most used variant. Has all the features listed and more. When the developer wants to test API Gateway functionality this can be a good choice due to the advanced testing capability and the ability to import &lt;a href="https://en.wikipedia.org/wiki/OpenAPI_Specification"&gt;OpenAPI&lt;/a&gt; specifications.&lt;br&gt;
REST API can be deployed in three modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Edge endpoint. Every request to the gateway will be routed to CloudFront Point of Presence making the application available with low latency all around the world.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regional endpoint (you can start with this option). The endpoint will be deployed in your application region&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Private regional endpoint. Same as Regional Endpoint, but the application will be available only in your &lt;a href="https://aws.amazon.com/vpc/"&gt;Virtual Private Cloud&lt;/a&gt; (your network inside AWS)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information on what kind of API Gateway should be chosen &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html"&gt;this&lt;/a&gt; documentation page contains a sum of all differences.&lt;/p&gt;

&lt;p&gt;In the following post, we will see how to integrate API Gateway with an AWS Service like S3.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Accelerate serverless development cycle with SAM Accelerate</title>
      <dc:creator>Piero Bozzolo</dc:creator>
      <pubDate>Tue, 14 May 2024 15:06:52 +0000</pubDate>
      <link>https://forem.com/petecocoon/accelerate-serverless-development-cycle-with-sam-accelerate-309</link>
      <guid>https://forem.com/petecocoon/accelerate-serverless-development-cycle-with-sam-accelerate-309</guid>
      <description>&lt;h2&gt;
  
  
  Accelerate serverless development cycle with SAM Accelerate
&lt;/h2&gt;

&lt;p&gt;One of the most common objections about serverless is that the development cycle and the test release can be extremely slow.&lt;/p&gt;

&lt;p&gt;When you start with a serverless test project the first releases are fast and streamlined, but one may encounter problems once resources are added.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NFBiEEo7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Ahe1pkHiNvbyQzpxXr_aucg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NFBiEEo7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Ahe1pkHiNvbyQzpxXr_aucg.jpeg" alt="" width="640" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the project expands we will probably start to need a CI / CD environment. This is an excellent method to release the application code in a staging or production environment. Still, when we have to run the pipeline just for test or to update one single function it can be uncomfortable, awkward, and a time-wasting activity. The pipeline steps can be executed locally from your machine, but you will only save a few seconds. The deployment time grew with the project.&lt;/p&gt;

&lt;p&gt;We would need a feature in serverless frameworks that streamlines this process in the &lt;em&gt;development phase&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For some time this feature has existed in the AWS Serverless Application Framework (hereinafter AWS SAM) framework in the form of a beta feature and is now available to everyone.&lt;/p&gt;

&lt;p&gt;Let’s take a short step back and try to understand what SAM is and how it works. If you already know SAM you can go directly to the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless Application Model
&lt;/h2&gt;

&lt;p&gt;A serverless application is made up of code and configurations. How can we manage the project and how can we describe my applications so that can be released in multiple environments? We need a tool that packages my code and all his stuff and releases it in the cloud.&lt;/p&gt;

&lt;p&gt;In AWS one tool is AWS SAM. AWS SAM is strictly related to AWS CloudFormation with whom it shares syntax and introduces an easy way to create and configure serverless resources (i.e. Lambda Function, Bucket S3, or DynamoDB tables).&lt;/p&gt;

&lt;p&gt;Let’s see an example: We need a lambda function invoked when an object is created on an S3 bucket.&lt;/p&gt;

&lt;p&gt;Our code folder will contain the following files:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template.yaml #application definitions
onupload_function/app.js #application code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The content of the *template.yam*l will be:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31Resources:ArticlesS3Bucket:
  Type: AWS::S3::BucketOnUploadFunction:
  Type: AWS::Serverless::Function
  Properties:
    Handler: app.lambdaHandler
    Runtime: nodejs14.x
    CodeUri: onupload_function/
    Events:
      OnFileCreated:
        Type: S3
        Properties:
          Bucket: !Ref ArticlesS3Bucket
          Events: s3:ObjectCreated:*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the onupload_function/app.js we will write a function that reacts to the upload event on the S3 bucket. In the example, we will just log the event payload:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.lambdaHandler = async (event, context) =&amp;gt;{
 console.log(JSON.stringify(event));
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To release our application it will be enough from the console to run the following commands:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sam build
$ sam deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see many seconds are needed before having the whole infrastructure released. In the deployment phase, you will also choose a CloudFormation stack name to which the application belongs. Keep it noted.&lt;/p&gt;

&lt;p&gt;This is a mandatory step that must be completed one time also with the new feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to streamline the deployment phase
&lt;/h2&gt;

&lt;p&gt;As we saw the deployment phase is easy and not complex, but it can only &lt;em&gt;become slow&lt;/em&gt;. Every time we add or make changes in the infrastructure the whole code is packaged, uploaded, and released. The build and deployment process can last 20 minutes.&lt;/p&gt;

&lt;p&gt;For speeding up the deployment process we can use the new &lt;em&gt;“sam sync”&lt;/em&gt; feature which, unlike “&lt;em&gt;sam deploy”&lt;/em&gt;, can release &lt;em&gt;only the differences&lt;/em&gt; that we have done to the code and to the infrastructure. If we want to use that feature we &lt;em&gt;must&lt;/em&gt; complete at least one time the “sam deploy” phase.&lt;/p&gt;

&lt;p&gt;Sync also comes with a very handy file watcher that is able to monitor our template and apply the changes when we save the file.&lt;/p&gt;

&lt;p&gt;To use sync and its watcher file we need to run this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sam sync --stack-name sam-app --watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;the stack name will be the name we gave to the stack in the deployment phase.&lt;/p&gt;

&lt;p&gt;Our application will be updated in seconds and resources such as Lambda function, API definitions in API Gateway, Step Function and other infrastructure components will be ready to be truly tested in the AWS infrastructure.&lt;/p&gt;

&lt;p&gt;If you are interested in the serverless world, don’t miss the Claranet live shows on Twitch &lt;a href="https://www.twitch.tv/claranet_it"&gt;https://www.twitch.tv/claranet_it&lt;/a&gt; and the videos on my YouTube channel &lt;a href="https://www.youtube.com/channel/UCSC2n9Q4fRacTr0jGOdcO0g"&gt;https://www.youtube.com/channel/UCSC2n9Q4fRacTr0jGOdcO0g&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Accelerare il ciclo di sviluppo serverless con SAM Accelerate</title>
      <dc:creator>Piero Bozzolo</dc:creator>
      <pubDate>Tue, 14 May 2024 15:04:01 +0000</pubDate>
      <link>https://forem.com/petecocoon/accelerare-il-ciclo-di-sviluppo-serverless-con-sam-accelerate-2pp6</link>
      <guid>https://forem.com/petecocoon/accelerare-il-ciclo-di-sviluppo-serverless-con-sam-accelerate-2pp6</guid>
      <description>&lt;h2&gt;
  
  
  Accelerare il ciclo di sviluppo serverless con SAM Accelerate
&lt;/h2&gt;

&lt;p&gt;Una delle più importati obbiezioni che mi vengono fatte quando parlo di serverless è che il ciclo di sviluppo e rilascio in test delle app può risultare piuttosto lento.&lt;/p&gt;

&lt;p&gt;Spesso si parte con le prime prove nel serverless con un progetto di piccole dimensioni che é semplice e veloce da rilasciare, magari anche dalla propria macchina.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NFBiEEo7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Ahe1pkHiNvbyQzpxXr_aucg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NFBiEEo7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Ahe1pkHiNvbyQzpxXr_aucg.jpeg" alt="" width="640" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Man mano che il progetto cresce sorge la necessità di fare build e implementare pipeline secondo i principi di CI/CD. Questo è un ottimo modo per rilasciare il codice e l’applicativo, ma può risultare scomodo se devo fare test continui sul codice o se devo validare le modifiche fatte all’infrastruttura. Questo perchè devo attendere che la pipeline compia i passi di test, build, package e deploy dell’applicativo serverless e della sua infrastruttura. Anche senza passare da una pipeline questi passi possono essere eseguiti localmente dalla nostra macchina se stiamo rilasciando l’&lt;em&gt;ambiente di sviluppo&lt;/em&gt;. Purtroppo più il progetto cresce più lenta diventa la fase di deploy.&lt;/p&gt;

&lt;p&gt;Servirebbe una &lt;em&gt;feature&lt;/em&gt; nei framework serverlesss che snellisca questo processo nella &lt;em&gt;fase di sviluppo.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Da qualche tempo questa feature esiste nel framework AWS SAM sotto forma di beta feature e da oggi è disponibile a tutti.&lt;/p&gt;

&lt;p&gt;Facciamo un breve passo indietro e cerchiamo di capire cos’è e come funziona SAM. Se già conosci SAM puoi andare direttamente alla sezione successiva.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless Application Model
&lt;/h2&gt;

&lt;p&gt;Un’applicazione serverless è costituita generalmente da codice e configurazioni.&lt;br&gt;
Come gestisco il progetto e come posso descrivere il mio applicativo in modo che possa essere rilasciato su più ambienti? Ho bisogno di uno strumento che pacchettizza il mio codice e tutto il suo contorno e che lo rilasci nel cloud.&lt;/p&gt;

&lt;p&gt;In AWS uno degli strumenti a disposizione è SAM o Serverless Application Model. SAM è fortemente imparentato con AWS CloudFormation che ne condivide la sintassi ed introduce la possibilità di configurare risorse serverless (es. Lambda Function, Bucket S3 o tabelle DynamoDB) in modo più semplice.&lt;/p&gt;

&lt;p&gt;Facciamo un esempio: vorrei che al caricamento di un file su un bucket S3 venga invocata una funzione lambda.&lt;/p&gt;

&lt;p&gt;La cartella del nostro codice sarà popolata con due file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template.yaml #definizione dell'applicativo
onupload_function/app.js #codice applicativo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Il contenuto del file template.yaml è il seguente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:

ArticlesS3Bucket:
  Type: AWS::S3::Bucket

OnUploadFunction:
  Type: AWS::Serverless::Function
  Properties:
    Handler: app.lambdaHandler
    Runtime: nodejs14.x
    CodeUri: onupload_function/
    Events:
      OnFileCreated:
        Type: S3
        Properties:
          Bucket: !Ref ArticlesS3Bucket
          Events: s3:ObjectCreated:*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;il contenuto di onupload_function/app.js è una funzione che risponde all’evento di caricamento di un file sul bucket S3. Nell’esempio loggeremo semplicemente il contenuto dell’evento:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.lambdaHandler = async (event, context) =&amp;gt;{
  console.log(JSON.stringify(event));
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Per rilasciare il nostro applicativo basterà da console impartire il comando:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sam build
$ sam deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Come potrete vedere sono necessari diversi secondi prima di aver il codice e l’infrastruttura rilasciata. Nella fase di deploy sceglierete anche il nome dello stack CloudFormation a cui apparterrà l’applicativo. Segnamolo da parte perchè ci servirà dopo. &lt;br&gt;
Questo è un passaggio obbligatorio anche in presenza della nuova feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Come velocizzare il processo di deploy
&lt;/h2&gt;

&lt;p&gt;Come abbiamo visto il processo di rilascio non è complicatissimo, ma può &lt;em&gt;rallentare&lt;/em&gt; quando aggiungo molte risorse perchè, ad esempio, vengono pacchettizzate ogni volta tutte le funzioni lambda e ne viene creata una nuova versione. Spesso possono trascorrere anche alcuni minuti prima di poter provare il nuovo codice sul cloud.&lt;/p&gt;

&lt;p&gt;Per velocizzare il processo possiamo utilizzare la feature &lt;em&gt;sync&lt;/em&gt; che a differenza di &lt;em&gt;deploy&lt;/em&gt; è in grado di rilasciare &lt;em&gt;solo le modifiche&lt;/em&gt; che noi abbiamo fatto al codice o all’infrastruttura. Per poter utilizzare sync &lt;em&gt;dobbiamo&lt;/em&gt; aver portato a termine un deploy con successo almeno una volta.&lt;/p&gt;

&lt;p&gt;Sync ha anche in dotazione un comodissimo file watcher che è in grado di monitorare il nostro template e applicare le modifiche quando salviamo il file.&lt;/p&gt;

&lt;p&gt;Per utilizzare sync e il suo file watcher dobbiamo dare questo comando:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sam sync --stack-name sam-app --watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;lo stack name sarà il nome che abbiamo dato allo stack nella fase di deploy.&lt;/p&gt;

&lt;p&gt;Il nostro applicativo sarà aggiornato in pochi secondi e risorse come Lambda function, definizioni di API in API Gateway, Step Function e altri componenti infrastrutturali saranno pronti per essere testati realmente nell’infrastruttura AWS.&lt;/p&gt;

&lt;p&gt;Se ti interessa il mondo serverless non perderti le live di Claranet su Twich &lt;br&gt;
&lt;a href="https://www.twitch.tv/claranet_it"&gt;https://www.twitch.tv/claranet_it&lt;/a&gt;&lt;br&gt;
i video su &lt;br&gt;
&lt;a href="https://www.youtube.com/channel/UCSC2n9Q4fRacTr0jGOdcO0g"&gt;https://www.youtube.com/channel/UCSC2n9Q4fRacTr0jGOdcO0g&lt;/a&gt;&lt;/p&gt;

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