<?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: Nick Thompson</title>
    <description>The latest articles on Forem by Nick Thompson (@nick_thompson).</description>
    <link>https://forem.com/nick_thompson</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%2F2106073%2Fc4f29d2b-9a8d-498c-bfbf-6398ee12955e.png</url>
      <title>Forem: Nick Thompson</title>
      <link>https://forem.com/nick_thompson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nick_thompson"/>
    <language>en</language>
    <item>
      <title>Quickly and easily filter your Amazon CloudWatch logs using Logs Insights</title>
      <dc:creator>Nick Thompson</dc:creator>
      <pubDate>Mon, 06 Jan 2025 16:05:08 +0000</pubDate>
      <link>https://forem.com/nick_thompson/quickly-and-easily-filter-your-amazon-cloudwatch-logs-using-logs-insights-3e0n</link>
      <guid>https://forem.com/nick_thompson/quickly-and-easily-filter-your-amazon-cloudwatch-logs-using-logs-insights-3e0n</guid>
      <description>&lt;p&gt;In modern cloud-native applications, monitoring and troubleshooting are critical for ensuring performance, reliability, and security. Amazon CloudWatch an AWS monitoring service, provides a powerful feature known as CloudWatch Logs Insights.&lt;/p&gt;

&lt;p&gt;This feature has allowed our teams and developers to quickly and easily search log data, helping them get to the root cause and find actionable insights quickly and efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Amazon CloudWatch Logs Insights?
&lt;/h2&gt;

&lt;p&gt;Amazon CloudWatch Logs Insights is a fully managed service that enables users to explore, query, and filter logs stored in CloudWatch.&lt;/p&gt;

&lt;p&gt;It offers an intuitive query language similar to SQL and an interactive interface to simplify log analysis. Perfect for filtering larger logs when you’re debugging an application, troubleshooting an infrastructure issue, or performing security audits. Since our team started using CloudWatch Logs Insights we have been able to make the fault resolution process faster and more precise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Amazon CloudWatch Logs Insights?
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Powerful Query Language
&lt;/h4&gt;

&lt;p&gt;Logs Insights provides a robust, SQL-like query language. With commands like fields, filter, sort, and stats, users can slice and dice logs to uncover patterns, identify anomalies, or pinpoint specific events.&lt;/p&gt;

&lt;h4&gt;
  
  
  Seamless Integration
&lt;/h4&gt;

&lt;p&gt;Logs Insights integrates seamlessly with other AWS services, including AWS Lambda, Amazon EC2, and Amazon ECS. This makes it easy to analyse logs across a wide range of AWS resources.&lt;/p&gt;

&lt;h4&gt;
  
  
  On-Demand Scalability
&lt;/h4&gt;

&lt;p&gt;The service is designed to handle log volumes of any size, scaling automatically to meet demand.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cost-Efficient
&lt;/h4&gt;

&lt;p&gt;CloudWatch Logs Insights is pay-as-you-go. You only pay for the queries you run, based on the amount of data scanned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to give Logs Insights a go?
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Step 1 - Enter the CloudWatch Dashboard
&lt;/h4&gt;

&lt;p&gt;Using an AWS account with sufficient access privilege to access your CloudWatch services log into your AWS Console and search for CloudWatch and click to arrive at the CloudWatch Services console&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2 - Select Logs Insights
&lt;/h4&gt;

&lt;p&gt;Under the Logs dropdown on the left hand pane, expand the Logs element and select Logs Insights&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%2Fwkuzr7wxi4jqk39ybo1y.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%2Fwkuzr7wxi4jqk39ybo1y.png" alt="Logs Insights Image" width="278" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3 - Choose your Log Group
&lt;/h4&gt;

&lt;p&gt;Log groups in CloudWatch represent collections of log streams, typically from a single resource type e.g a Lambda function or an EC2 instance&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4 - Write and run your Query
&lt;/h4&gt;

&lt;p&gt;In the query editor window, you can write queries to extract specific information from the logs, such as most recent entries, customer data, product id's, error codes etc.&lt;/p&gt;

&lt;p&gt;In our example below we are writing a query and selecting the fields we are interested in (timestamp, message etc) and filtering the &lt;strong&gt;message&lt;/strong&gt; field to show all logs with a string match of "level:ERROR" within the last 3 hours and limiting the response to 1000 records.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fields @timestamp, @message, @logStream, @log&lt;br&gt;
| filter @message like /level":"ERROR"/&lt;br&gt;
| sort @timestamp desc&lt;br&gt;
| limit 1000&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fn8ji697fdylaq9detj7j.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%2Fn8ji697fdylaq9detj7j.png" alt="Query Editor Image" width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once happy with your query, simply click the Run Query button and wait for the results.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5 - Analyse Results
&lt;/h4&gt;

&lt;p&gt;If your search query finds any matches, all results will be returned via a timestamped histogram graph and list of matching CloudWatch logs.&lt;/p&gt;

&lt;p&gt;From here you can visualise patterns, such as when and how often errors occurred and quickly home in on the exact CloudWatch log to take further action.&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%2F5su95vm8yvvopwd9wc11.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%2F5su95vm8yvvopwd9wc11.png" alt="Results Image" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 6 - Save and Share Queries
&lt;/h4&gt;

&lt;p&gt;Once you have crafted the perfect query, why not save it for later or share it with your team! Once you have saved a query it is available for everyone with console access to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some useful queries
&lt;/h2&gt;

&lt;h4&gt;
  
  
  List the most recent logs
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fields @timestamp, @message, @logStream, @log&lt;br&gt;
| sort @timestamp desc&lt;br&gt;
| limit 20&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Filter logs for a specific string
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fields @timestamp, @message, @logStream, @log&lt;br&gt;
| filter @message like /customer@email.com/&lt;br&gt;
| sort @timestamp desc&lt;br&gt;
| limit 1000&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Filter and count logs of matching strings (error levels etc)
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fields @timestamp, @message, @logStream, @log&lt;br&gt;
| filter @message like /ERROR/&lt;br&gt;
| stats count() by level&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Best Practices for CloudWatch Logs Insights
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Structure Your Logs&lt;/strong&gt; Use structured logging (e.g., JSON) for easier parsing and querying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Filters Efficiently&lt;/strong&gt; Reduce data scanned by filtering logs at the source level. This speeds up queries and reduces costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitor Costs&lt;/strong&gt; Regularly monitor the amount of data scanned by queries to optimise usage and manage expenses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automate with APIs&lt;/strong&gt; Use AWS SDKs or the CLI to automate log analysis and integrate Logs Insights into your CI/CD pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Combine with CloudWatch Alarms&lt;/strong&gt; Use Logs Insights in conjunction with CloudWatch Alarms to proactively monitor for specific log patterns or thresholds.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Congratulations on getting started with Amazon CloudWatch Logs Insights. In this article we covered how to access Logs Insights within the console, create our first query and analyse the results.&lt;/p&gt;

&lt;p&gt;I hope you and your teams can make use of Logs Insights effectively and start to enhance your monitoring capabilities, resolve issues faster, and make data-driven decisions to optimise your applications and infrastructure.&lt;/p&gt;

&lt;p&gt;CloudWatch Logs Insights &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AnalyzingLogData.html" rel="noopener noreferrer"&gt;Official Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CloudWatch Logs Insights &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-examples.html" rel="noopener noreferrer"&gt;Samples&lt;/a&gt; &lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudwatch</category>
      <category>logging</category>
      <category>data</category>
    </item>
    <item>
      <title>Build your next Web App using AWS Free Tier services without breaking the bank</title>
      <dc:creator>Nick Thompson</dc:creator>
      <pubDate>Fri, 13 Dec 2024 15:38:24 +0000</pubDate>
      <link>https://forem.com/nick_thompson/build-your-next-web-app-using-aws-free-tier-services-without-breaking-the-bank-1n5</link>
      <guid>https://forem.com/nick_thompson/build-your-next-web-app-using-aws-free-tier-services-without-breaking-the-bank-1n5</guid>
      <description>&lt;p&gt;When embarking on a new web project, hobby site or your next business startup, cost considerations often steer decisions about hosting options. Traditional hosting solutions, while straightforward, often come with fixed costs and maintenance responsibilities that can burden individuals and small teams. Enter &lt;strong&gt;AWS Free Tier serverless services&lt;/strong&gt;, a cost-effective, scalable, and maintenance-free alternative that offers a wealth of features with little to no costs for many workloads.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how AWS Free Tier serverless services stand out and how they can become a powerful and potentially free hosting platform for developers, startups, and businesses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the Application
&lt;/h2&gt;

&lt;p&gt;We'll architect a simple task web application that allows users to create, update, and delete tasks as well as adding authentication. The architecture will include a serverless backend, a static frontend, and a database for persistent storage. This setup is perfect for demonstrating the power of AWS’s free tier services and the benefits of a serverless first approach for your applications. Using the AWS Free Tier, this setup can likely run for free or at an extremely low cost while handling significant traffic.&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%2Fzvflds9x299vubtprlj5.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%2Fzvflds9x299vubtprlj5.png" alt="Image description" width="739" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optional Services&lt;/strong&gt;&lt;br&gt;
Every good website needs a domain, while usually an inexpensive cost ($10 a year) this is an optional service. If you already have a domain or you want to purchase one &lt;strong&gt;Amazon Route53&lt;/strong&gt; offers cost effective DNS and Domain management solutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend: Amazon S3 and CloudFront&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 (Simple Storage Service)&lt;/strong&gt;: Store and host static assets like HTML, CSS, and JavaScript. S3 is also perfect for Single Page Applications (SPA) using React or Vue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront&lt;/strong&gt;: Distribute the content globally with low latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Free Tier Limits&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3&lt;/strong&gt; 5GB of standard storage and 20,000 GET requests and 2000 PUT requests per month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront&lt;/strong&gt; 1TB of data transfer and 10 million HTTP/HTTPS requests per month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The static files of your application can be uploaded to an S3 bucket, which serves as the origin for CloudFront. CloudFront will handle global content delivery, ensuring fast load times across regions and aids in &lt;a href="https://en.wikipedia.org/wiki/Denial-of-service_attack" rel="noopener noreferrer"&gt;DDoS&lt;/a&gt; and &lt;a href="https://www.sciencedirect.com/science/article/pii/S221421262100079X" rel="noopener noreferrer"&gt;Denial of Wallet&lt;/a&gt; protection.&lt;/p&gt;

&lt;p&gt;We can secure access to your application using an Origin Access Identity which only allows CloudFront access to your S3 bucket and stops direct access to the AWS resource named bucket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend: AWS Lambda and API Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda&lt;/strong&gt;: A serverless compute service that runs your code in response to events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt;: Acts as a RESTful API interface for invoking Lambda functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Free Tier Limits&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lambda&lt;/strong&gt; 1 million requests and 400,000 GB-seconds of compute time per month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt; 1 million API calls per month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll use Lambda functions to implement the business logic for CRUD operations on tasks. API Gateway will expose endpoints via CloudFront for the frontend to interact with these functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database: Amazon DynamoDB&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB&lt;/strong&gt;: A fully managed NoSQL database ideal for handling task data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Free Tier Limits&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;25GB of storage.&lt;/li&gt;
&lt;li&gt;25 Write Capacity Units and 25 Read Capacity Units known as WCU's and RCU's respectively. Enough capacity for around 200M requests per month. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DynamoDB can store most data types which make it perfect for datasets that include ID's, title, description or status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication: Amazon Cognito&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cognito&lt;/strong&gt;: Simplifies user authentication and management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Free Tier Limits&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10,000 monthly active users&lt;/li&gt;
&lt;li&gt;10GB of cloud sync storage&lt;/li&gt;
&lt;li&gt;1M sync operations per month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cognito will provide user registration and login functionality, ensuring secure access to the web app. You can opt in for additional security such as MFA, Email verification and required user fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes AWS Free Tier Services Stand Out?
&lt;/h2&gt;

&lt;p&gt;The AWS Free Tier allows users to test and experiment with services for free up to specified limits. Among these, serverless options like &lt;strong&gt;AWS Lambda&lt;/strong&gt;, &lt;strong&gt;Amazon API Gateway&lt;/strong&gt;, &lt;strong&gt;AWS DynamoDB&lt;/strong&gt;, and &lt;strong&gt;Amazon S3&lt;/strong&gt; provide a robust toolkit for hosting web applications, APIs, and static websites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here’s why they’re worth exploring:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pay-As-You-Go Flexibility&lt;/strong&gt;: Unlike traditional hosting, AWS serverless services only charge for actual usage. The Free Tier adds another layer of affordability, often covering the needs of smaller projects entirely. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zero Maintenance Overhead&lt;/strong&gt;: Serverless services abstract away server management tasks like provisioning, scaling, and patching. Developers can focus entirely on building features rather than infrastructure management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automatic Scalability&lt;/strong&gt;: Serverless platforms scale automatically based on demand, ensuring reliable performance without overpaying for unused capacity. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As serverless services scale to zero, they incur no costs when users are not using your application or you have long periods of downtime during development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing AWS Free Tier with Traditional Hosting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Traditional Hosting&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AWS Serverless (Free Tier)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fixed monthly fee&lt;/td&gt;
&lt;td&gt;Pay-as-you-go, often free within limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited or requires manual setup&lt;/td&gt;
&lt;td&gt;Automatic, on-demand scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maintenance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires manual updates&lt;/td&gt;
&lt;td&gt;Fully managed by AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited to pre-configured plans&lt;/td&gt;
&lt;td&gt;High flexibility with more than 100 services in the free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dependent on allocated hardware&lt;/td&gt;
&lt;td&gt;Scales to meet demand&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;While traditional hosting might seem like a simple and cheap choice for websites, AWS serverless services excel in scenarios requiring dynamic scaling, low latency, and integrated workflows. While also being the perfect choice for small PoC or hobby projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Usage Limits&lt;/strong&gt;: It’s crucial to know and monitor usage to avoid exceeding free tier limits and incurring unwanted charges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;12 months free&lt;/strong&gt;: Not all AWS free tier services are always free, some are only free for 12 months, however the services used in this article are charged at very low usage costs meaning it's still a cost effective option after the 12 month period.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;To get started with AWS Free Tier Services visit the &lt;a href="https://aws.amazon.com/free/" rel="noopener noreferrer"&gt;AWS Free Tier page&lt;/a&gt; and create an account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/route53/" rel="noopener noreferrer"&gt;Amazon Route53&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/cloudfront/" rel="noopener noreferrer"&gt;Amazon CloudFront&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/s3/" rel="noopener noreferrer"&gt;Amazon S3&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/cognito/" rel="noopener noreferrer"&gt;Amazon Cognito&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html" rel="noopener noreferrer"&gt;Amazon API Gateway&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/dynamodb/" rel="noopener noreferrer"&gt;Amazon DynamoDB&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Building a web application using AWS free tier services is not only feasible but also an excellent way to learn about cloud-native development. By leveraging services like S3, Lambda, DynamoDB, and Cognito, you can create a robust, scalable application at no cost for most typical workloads. Whether you’re a budding developer or a seasoned professional, AWS’s free tier offers the tools you need to bring your ideas to life.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Create an Asset Store with a Custom Domain using AWS CDK, Route53, S3 and CloudFront</title>
      <dc:creator>Nick Thompson</dc:creator>
      <pubDate>Sun, 10 Nov 2024 19:13:46 +0000</pubDate>
      <link>https://forem.com/nick_thompson/create-an-asset-store-with-a-custom-domain-using-amazon-cdk-s3-and-cloudfront-ig7</link>
      <guid>https://forem.com/nick_thompson/create-an-asset-store-with-a-custom-domain-using-amazon-cdk-s3-and-cloudfront-ig7</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%2Fd2ubiv1qsjtl6ojx40r6.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%2Fd2ubiv1qsjtl6ojx40r6.png" alt="Image description" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating a scalable asset store with Amazon S3, CloudFront, and adding your own custom domain using Route53 is more straightforward than it might appear and is a highly effective solution for serving assets to your applications. &lt;/p&gt;

&lt;p&gt;This guide helps you setup and configure these AWS services which reliably stores your files within Amazon S3 (Simple Storage Service) distributes your assets globally using a CloudFront CDN, improves load times by having cached edge copies of your assets to your users local regions, ensures secure access through HTTPS and other added security benefits provided by having your files behind the CDN.&lt;/p&gt;

&lt;h3&gt;
  
  
  What can you host in Amazon S3?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Fonts&lt;/li&gt;
&lt;li&gt;Videos&lt;/li&gt;
&lt;li&gt;Files - S3 can store almost any type of data in most formats. JSON, Text, XML etc&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note that this guide configures your asset store for public access, make sure any files stored in S3 are OK for public view, always be careful!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To get started with this guide you will need the following&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS account with full Admin access&lt;/li&gt;
&lt;li&gt;AWS CDK installed and a basic understanding of how to create a new application. 
See &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html" rel="noopener noreferrer"&gt;Getting Started with CDK&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html" rel="noopener noreferrer"&gt;Create Your First CDK App&lt;/a&gt; for more info&lt;/li&gt;
&lt;li&gt;Recent versions of Node.js and TypeScript Installed&lt;/li&gt;
&lt;li&gt;A custom domain already registered and verified with AWS Route53&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Create your CDK application
&lt;/h3&gt;

&lt;p&gt;Make a new directory for the project and cd into the folder&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ mkdir cdk-yourprojectname&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;



&lt;p&gt;&lt;code&gt;$ cd cdk-yourprojectname&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;From the new directory create a new CDK application&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ cdk init app --language typescript&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;The CDK stack is now created and can be accessed from&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lib/cdk-yourprojectname-stack.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Make sure your local AWS environment is configured and bootstrapped as per the recommended steps in this guide &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html" rel="noopener noreferrer"&gt;Getting Started with CDK&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Set Up an S3 Bucket for Your Assets
&lt;/h3&gt;

&lt;p&gt;In this step we will import the &lt;strong&gt;aws-s3&lt;/strong&gt; module from the AWS CDK library so we can create a new instance of the construct for our S3 Bucket&lt;/p&gt;

&lt;p&gt;In your project-stack.ts file import the aws-s3 module at the top of file using&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;s3&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;aws-cdk-lib/aws-s3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within the constructor of your main cdk.Stack class we can add the constructs we require for creating our AWS services, we will use the L2 construct for S3 to create a new S3 bucket to store our files.&lt;/p&gt;

&lt;p&gt;When we create the new construct it takes in 3 arguments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A reference to the stack class (usually "this")&lt;/li&gt;
&lt;li&gt;A name for the AWS resource to be created, this is usually appended with the stack name within the AWS console but it makes sense to call it something we can easily identify. &lt;/li&gt;
&lt;li&gt;An optional {object} parameter which provides a list of attributes used to configure the construct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More information on the parameters for S3 can be found &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3-readme.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
We are using a set of sensible defaults in this 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="c1"&gt;// Create an S3 bucket to store the assets&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assetBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;S3AssetProjectBucket&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;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3-asset-project-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;publicReadAccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;removalPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DESTROY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;autoDeleteObjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;blockPublicAccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BlockPublicAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BLOCK_ACLS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;accessControl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BucketAccessControl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BUCKET_OWNER_FULL_CONTROL&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;
  
  
  Step 3: Configure Your Domain and SSL certificates (DNS Settings)
&lt;/h3&gt;

&lt;p&gt;To use a custom domain, we need to create a new DNS record within Route 53 and create an SSL certificate which we we later use with CloudFront to enable secure HTTPS access to the S3 bucket.&lt;/p&gt;

&lt;p&gt;First lets declare some variables we can use for the certificates and cloudfront.&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="c1"&gt;// define domains for route53&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yourdomain.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;assetDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CloudFront only verifies certificates issued in the &lt;strong&gt;us-east-1&lt;/strong&gt; region so depending on your local region and where you plan to deploy your stack, this effects our approach to setting up SSL certificates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1&lt;/strong&gt; Deploy the entire stack to the us-east-1 region. This means we can generate the SSL certificate as part of the main stack and use it with cloudfront without any additional configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2&lt;/strong&gt; If you still plan to deploy to your local region, such as &lt;strong&gt;eu-west-2&lt;/strong&gt; then the easiest option is to create the certificate manually using the AWS Console within the &lt;strong&gt;us-east-1&lt;/strong&gt; region and reference that certificate within the CDK stack.&lt;/p&gt;

&lt;p&gt;Lets take a look at configuring both options below:-&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1 - Deploy in the US region
&lt;/h3&gt;

&lt;p&gt;As we will be defining a new certificate using the Amazon Certificate Manager construct along with using Route53 we first need to import them from the CDK library, as before with the S3 bucket add these imports to the top of your stack.ts file&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;acm&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;aws-cdk-lib/aws-certificatemanager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;route53&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;aws-cdk-lib/aws-route53&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now create a variable which stores the hosted zone for your domain, this construct gets the information by looking up the Zone and domain name from where you declare your AWS account and region in the core app stack.&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="c1"&gt;// Get hosted zone for domain&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hostedZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;route53&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HostedZone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Zone&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;domainName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the hosted zone we can create a new certificate using the AWS Certificate Manager and the Certificate construct passing the parameters for the domain name and create a wildcard using "*" to allow for this certificate to be used with any sub-domain in the future.&lt;/p&gt;

&lt;p&gt;We pass in the hosted zone so that AWS can verify we own the domain before creating the certificate. &lt;em&gt;This process can take a few minutes to process and validate when deploying the stack&lt;/em&gt;&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="c1"&gt;// Create a new SSL cert for the entire domain&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sslCert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;acm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Certificate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourProjectSiteCertificate&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;domainName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subjectAlternativeNames&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;*.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;acm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CertificateValidation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromDns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hostedZone&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;Finally we add a removal policy to the certificate so when we tear down the CDK stack the certificate is also removed&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="c1"&gt;// Add a removal policy for the certificate&lt;/span&gt;
&lt;span class="nx"&gt;sslCert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;applyRemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DESTROY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2 - Create a manual certificate in the US region
&lt;/h3&gt;

&lt;p&gt;As we are manually creating the certificate we will need to login to the main AWS console. As an admin user with the correct permissions to create resources using &lt;a href="https://docs.aws.amazon.com/acm/latest/userguide/acm-overview.html" rel="noopener noreferrer"&gt;AWS Certificate Manager&lt;/a&gt; login and follow the steps below to create the certificate. It's important to make sure you create the certificate for both your main domain and a wildcard as this is what we will be using to setup the asset store (assets.yourdomain.com). As the domain is hosted within AWS route53 we can validate the certificate using DNS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the certificate&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open AWS Certificate Manager Console: Go to AWS Certificate Manager (ACM) and ensure you're in the &lt;strong&gt;us-east-1 region&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select Request a certificate. &amp;gt; Choose Request a public certificate &amp;gt; click Next.&lt;/li&gt;
&lt;li&gt;Specify Domain Names &amp;gt; Enter the domain name(s) for the certificate (e.g., yourdomain.com and *.yourdomain.com for wildcard) &amp;gt; Click Next.&lt;/li&gt;
&lt;li&gt;Select Validation Method &amp;gt; Choose DNS Validation (preferred as you control DNS in Route 53)&lt;/li&gt;
&lt;li&gt;Review your settings and request the certificate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the certificate has been verified and is available to view in the console. We need to note down the certificate ARN (Amazon Resource Name) so we can use it within the CDK app. To get this make sure you're in the correct &lt;strong&gt;us-east-1&lt;/strong&gt; region and then click on your certificate. Locate the ARN at the top of the page and copy the ARN data which should look something like this &lt;strong&gt;arn:aws:acm:{region}:{accountid}:certificate/{certificateid}&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now we have the ARN we can create a new variable with the CDK app using the certificate construct to create a reference to that certificate based on the ARN.&lt;/p&gt;

&lt;p&gt;In your CDK stack add the following lines of code&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usSSLCertArn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your ARN here&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UsSSLCert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;acm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromCertificateArn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourChosenCertConfigName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;usSSLCertArn&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally we need to enable a setting within the core CDK application to allow cross region resources. In your core app file located&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;bin/yourproject.ts&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 add the following line to the stack app options to enable cross region resource support. &lt;strong&gt;crossRegionReferences: true&lt;/strong&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;YourAppStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourAppStack&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="cm"&gt;/* Uncomment the next line if you know exactly what Account and Region you
   * want to deploy the stack to. */&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xxxxxxxx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xxxxxx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;crossRegionReferences&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;
  
  
  Step 3: Set Up CloudFront for Content Delivery
&lt;/h3&gt;

&lt;p&gt;Using Amazon CloudFront as a CDN will help cache and serve your assets efficiently worldwide, reducing load times for your users. It also protects against DoS service attacks and protects you from occurring high usage costs from malicious attacks such as a &lt;a href="https://academic.oup.com/cybersecurity/article/10/1/tyae004/7634012" rel="noopener noreferrer"&gt;denial of wallet attack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As with the previous constructs we need to import a few modules from the CDK library for CloudFront and Route53&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&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;aws-cdk-lib/aws-cloudfront&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;targets&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;aws-cdk-lib/aws-route53-targets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cloudfront_origins&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;aws-cdk-lib/aws-cloudfront-origins&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a CloudFront Distribution&lt;/strong&gt;:&lt;br&gt;
To create the CloudFront distribution we need to create a new instance of the construct and pass in our configuration and settings which we have created so far along with some default behaviors. More information on these parameters can be found &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront-readme.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CDNdistribution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Distribution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourProjectAssetCDN&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;certificate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sslCert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;domainNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;assetDomain&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;minimumProtocolVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SecurityPolicyProtocol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TLS_V1_2_2021&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;defaultBehavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cloudfront_origins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3Origin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetBucket&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AllowedMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALLOW_GET_HEAD_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;viewerProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ViewerProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIRECT_TO_HTTPS&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;p&gt;&lt;strong&gt;What have we configured?&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;certificate&lt;/strong&gt; - Depending on the option you chose in the certificate section this will be the variable output from either Option1 (sslCert) or Option2 (UsSSLCert)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;domainNames&lt;/strong&gt; - We set this to the asset domain variable we declared earlier in the stack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;origin&lt;/strong&gt; - Here we added a reference to the S3 bucket we created so that when anyone accesses the domain this is the default content served via the CDN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set Viewer Protocol Policy&lt;/strong&gt;: “Redirect HTTP to HTTPS” to ensure secure access to assets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally we need to create the A record for the custom domain we plan to use for the asset store (assets.yourdomain.com) and pass in the CloudFront distribution as the target which we created in the previous step.&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="c1"&gt;// Create the A record for the asset store URL&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;route53&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ARecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourProjectAssetStore&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;zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hostedZone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;recordName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assetDomain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;route53&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RecordTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAlias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloudFrontTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CDNdistribution&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;
  
  
  Step 4: Deploy and Test the Setup
&lt;/h3&gt;

&lt;p&gt;Now you should have a complete stack configured that looks like this (assuming you opted for Option 1 in the certificate section):&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt; &lt;span class="p"&gt;}&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;constructs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&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;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;route53&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;aws-cdk-lib/aws-route53&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;s3&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;aws-cdk-lib/aws-s3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;acm&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;aws-cdk-lib/aws-certificatemanager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&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;aws-cdk-lib/aws-cloudfront&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;targets&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;aws-cdk-lib/aws-route53-targets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cloudfront_origins&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;aws-cdk-lib/aws-cloudfront-origins&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YourAppStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// define domains for route53&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yourdomain.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;assetDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Get hosted zone for domain (Needs to have region set in the env param in the stack)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hostedZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;route53&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HostedZone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Zone&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;domainName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Create a new SSL cert for the entire domain&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sslCert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;acm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Certificate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourProjectSiteCertificate&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;domainName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;subjectAlternativeNames&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;*.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;acm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CertificateValidation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromDns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hostedZone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Add a removal policy for the cert&lt;/span&gt;
    &lt;span class="nx"&gt;sslCert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;applyRemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DESTROY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create an S3 bucket to store the assets&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assetBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;S3AssetProjectBucket&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;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3-asset-project-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;publicReadAccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;removalPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DESTROY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;autoDeleteObjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;blockPublicAccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BlockPublicAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BLOCK_ACLS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;accessControl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BucketAccessControl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BUCKET_OWNER_FULL_CONTROL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Create a cloudfront CDN distribution for serving the s3 bucket&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CDNdistribution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Distribution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourProjectAssetCDN&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;certificate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sslCert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;domainNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;assetDomain&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;minimumProtocolVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SecurityPolicyProtocol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TLS_V1_2_2021&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;defaultBehavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cloudfront_origins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3Origin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetBucket&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AllowedMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALLOW_GET_HEAD_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;viewerProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cloudfront&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ViewerProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIRECT_TO_HTTPS&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;// Create the A record for the asset store URL&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;route53&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ARecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourProjectAssetStore&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;zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hostedZone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;recordName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assetDomain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;route53&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RecordTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAlias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloudFrontTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CDNdistribution&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test your stack configuration before deployment&lt;/strong&gt;&lt;br&gt;
You can use the command &lt;strong&gt;cdk synth&lt;/strong&gt; to test how the real deployment will perform and this will report any issues such as misconfigurations or incompatible settings etc. &lt;/p&gt;

&lt;p&gt;Run the command in your terminal&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;$ cdk synth&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 and agree to any prompts, make sure to review the output file for any errors and address them as required. Assuming there are no errors, proceed to the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy the stack&lt;/strong&gt;&lt;br&gt;
Now we have confirmed the stack is going to deploy successfully we should be able to deploy our stack with confidence. To deploy run&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;$ cdk deploy&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 and agree to any prompts etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upload Your Assets&lt;/strong&gt;:&lt;br&gt;
You can now upload files (images, fonts, videos, CSS etc.) to the S3 bucket either through the AWS console, CLI, or SDK.&lt;/p&gt;

&lt;p&gt;Once your CloudFront distribution is deployed and DNS is propagated, you should be able to access your assets via &lt;code&gt;https://assets.yourdomain.com/path-to-your-asset&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Congratulations!
&lt;/h3&gt;

&lt;p&gt;You have now successfully created your asset store using your own domain which sits behind a globally distributed network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lets review what we built:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We created a custom SSL certificate using AWS Certificate Manager&lt;/li&gt;
&lt;li&gt;Setup a custom domain assets.yourdomain.com using Route53&lt;/li&gt;
&lt;li&gt;Configured an object storage bucket using Amazon S3&lt;/li&gt;
&lt;li&gt;Securely Distributed the content using Amazon CloudFront&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GitHub Repo for this project &lt;a href="https://github.com/nickthompson69/cdk-asset-store-demo" rel="noopener noreferrer"&gt;cdk-asset-store-demo&lt;/a&gt;
&lt;/h3&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>s3</category>
      <category>cloudfront</category>
    </item>
  </channel>
</rss>
