<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tiago Boeing</title>
    <description>The latest articles on DEV Community by Tiago Boeing (@tiagoboeing).</description>
    <link>https://dev.to/tiagoboeing</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%2F341609%2F6384bbc3-38d8-48af-ae3b-fc225a6e058d.jpeg</url>
      <title>DEV Community: Tiago Boeing</title>
      <link>https://dev.to/tiagoboeing</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tiagoboeing"/>
    <language>en</language>
    <item>
      <title>CDN de alta disponibilidade na AWS com Terraform: um guia para reduzir a latência e aumentar a performance de seu site</title>
      <dc:creator>Tiago Boeing</dc:creator>
      <pubDate>Sun, 26 Mar 2023 01:35:32 +0000</pubDate>
      <link>https://dev.to/aws-builders/cdn-de-alta-disponibilidade-na-aws-com-terraform-um-guia-para-reduzir-a-latencia-e-aumentar-a-performance-de-seu-site-pj8</link>
      <guid>https://dev.to/aws-builders/cdn-de-alta-disponibilidade-na-aws-com-terraform-um-guia-para-reduzir-a-latencia-e-aumentar-a-performance-de-seu-site-pj8</guid>
      <description>&lt;p&gt;Este artigo é uma continuação do &lt;a href="https://dev.to/aws-builders/cdn-de-alta-disponibilidade-na-aws-com-s3-cloudfront-e-route53-3bh9"&gt;primeiro sobre o mesmo assunto que foi escrito há algum tempo&lt;/a&gt;, mas sem abordar a utilização de Infrastructure as Code (IaC). Neste artigo, será apresentado um guia de como criar sua própria CDN de alta disponibilidade na AWS usando IaC com Terraform.&lt;/p&gt;

&lt;p&gt;Utilize a CDN para hospedar um website estático e/ou servir arquivos estáticos com baixa latência e alta disponibilidade. Além de melhorar o desempenho do website, as CDNs garantem que o usuário sempre será servido do servidor mais próximo, o que reduz ainda mais a latência e garante uma experiência de navegação rápida e suave. Isso pode levar a um aumento de tráfego e conversões.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ Para explicação dos serviços envolvidos, precificação e outras informações, leia o &lt;a href="https://medium.com/@tiagoboeing/cdn-de-alta-disponibilidade-na-aws-com-s3-cloudfront-e-route53-d08da8fab0ab" rel="noopener noreferrer"&gt;primeiro artigo sobre o mesmo assunto&lt;/a&gt; que demonstra a configuração via Console da AWS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É necessário conhecimento do funcionamento do Terraform e da AWS. Não serão abordados aqui conceitos introdutórios sobre essas tecnologias.&lt;/p&gt;

&lt;h2&gt;
  
  
  Objetivos
&lt;/h2&gt;

&lt;p&gt;Criar automaticamente toda a infraestrutura necessária dentro da AWS em poucos minutos e com alguns comandos, incluindo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuração dos serviços necessários;&lt;/li&gt;
&lt;li&gt;Criação dos registros DNS para validar o certificado e um alias para o CloudFront;&lt;/li&gt;
&lt;li&gt;Geração do certificado SSL para servir conteúdo utilizando protocolo HTTPS;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pré-requisitos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Conta AWS;&lt;/li&gt;
&lt;li&gt;AWS CLI devidamente configurado;&lt;/li&gt;
&lt;li&gt;Terraform devidamente instalado e configurado;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Composição da infraestrutura
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;S3 como fonte dos arquivos;&lt;/li&gt;
&lt;li&gt;CloudFront para distribuir os arquivos;&lt;/li&gt;
&lt;li&gt;Route53 para criar os registros DNS no domínio próprio;&lt;/li&gt;
&lt;li&gt;Certificate Manager (ACM) para gerenciar os certificados SSL/TLS para a distribuição do CloudFront.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fx8d4h651xhmspi11exe1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx8d4h651xhmspi11exe1.png" alt="Mermaid diagram with IaC structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  IaC - Infrastructure as Code
&lt;/h3&gt;

&lt;p&gt;É uma prática de gerenciamento de infraestrutura de TI em que a infraestrutura é gerenciada por meio de código, em vez de configurações manuais. Com IaC, a infraestrutura é definida em arquivos de configuração que podem ser versionados, testados e implementados automaticamente, permitindo que os desenvolvedores gerenciem a infraestrutura de maneira mais eficiente e consistente. Ferramentas populares de IaC incluem o Terraform, o AWS CloudFormation e o Ansible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform
&lt;/h3&gt;

&lt;p&gt;O Terraform é uma ferramenta de IaC que permite definir e provisionar infraestrutura em nuvem de forma declarativa, utilizando arquivos de configuração para descrever os recursos necessários. Com o Terraform, é possível criar, modificar e excluir recursos em diversos provedores de nuvem, como AWS, Azure e Google Cloud Platform, de forma consistente e replicável. Além disso, o Terraform possui recursos avançados, como a possibilidade de criar módulos reutilizáveis e gerenciar o estado da infraestrutura, permitindo uma gestão mais eficiente e segura da infraestrutura em nuvem.&lt;/p&gt;

&lt;p&gt;Para mais informações, consulte a &lt;a href="https://www.terraform.io/docs/index.html" rel="noopener noreferrer"&gt;documentação oficial do Terraform&lt;/a&gt;.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;ℹ️ Se desejar apenas o código-fonte para provisionar a infraestrutura &lt;a href="https://github.com/tiagoboeing/terraform-aws/tree/master/cloudfront-cdn" rel="noopener noreferrer"&gt;acesse o repositório no GitHub.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Código-fonte
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/tiagoboeing/terraform-aws/tree/536e087e6604da759f5b56f9ca82e09a773231d5/cloudfront-cdn" rel="noopener noreferrer"&gt;Link permanente com snapshot do repositório no momento que o artigo foi escrito.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;O projeto Terraform será dividido em vários arquivos para facilitar compreensão:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;provider.tf&lt;/code&gt;: Especifica com qual cloud e versões estamos trabalhando;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main.tf&lt;/code&gt;: Arquivo principal que centraliza configurações comuns do Terraform, &lt;code&gt;data&lt;/code&gt;, &lt;code&gt;locals&lt;/code&gt;, etc;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outputs.tf&lt;/code&gt;: Define as saídas dos recursos criados pelo Terraform;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;inputs.tf&lt;/code&gt;: Define as variáveis de entrada para o Terraform;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;s3.tf&lt;/code&gt;: Configurações do bucket, políticas e outros;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;certificate.tf&lt;/code&gt;: Configurações do certificado SSL para servir conteúdo utilizando HTTPS;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cloudfront.tf&lt;/code&gt;: Criação e configuração do CloudFront;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test-cdn.tf&lt;/code&gt;: Apenas para demonstração e teste do funcionamento, este arquivo fará upload de um arquivo HTML para o bucket e invalidará o cache do CloudFront para que as alterações sejam refletidas rapidamente. Remova após validar a implementação;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;terraform.tfvars&lt;/code&gt;: Arquivo onde o valor das variáveis pode ser especificado.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Para visualizar o conteúdo dos arquivos, &lt;a href="https://www.notion.so/CDN-de-alta-disponibilidade-na-AWS-utilizando-IaC-bf8b7053bca349e3bfe4291fa39b37d9" rel="noopener noreferrer"&gt;confira o repositório no momento que o artigo foi escrito.&lt;/a&gt; As seções abaixo abordarão apenas arquivos chave para facilitar a compreensão.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Definição do provedor (&lt;code&gt;provider.tf&lt;/code&gt;)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform &lt;span class="o"&gt;{&lt;/span&gt;
  required_providers &lt;span class="o"&gt;{&lt;/span&gt;
    aws &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/aws"&lt;/span&gt;
      version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"4.59.0"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

provider &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  skip_credentials_validation &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Variáveis locais e queries (&lt;code&gt;main.tf&lt;/code&gt;)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;locals &lt;span class="o"&gt;{&lt;/span&gt;
  service              &lt;span class="o"&gt;=&lt;/span&gt; var.service
  stage                &lt;span class="o"&gt;=&lt;/span&gt; var.stage
  resource_prefix_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.service&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.stage&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  route53_private_zone &lt;span class="o"&gt;=&lt;/span&gt; var.route53_private_zone
  route53_base_domain  &lt;span class="o"&gt;=&lt;/span&gt; var.route53_zone_domain
  cdn_domain           &lt;span class="o"&gt;=&lt;/span&gt; var.cdn_domain
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Get AWS Account ID&lt;/span&gt;
data &lt;span class="s2"&gt;"aws_caller_identity"&lt;/span&gt; &lt;span class="s2"&gt;"current"&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c"&gt;# Get Route53 Zone&lt;/span&gt;
data &lt;span class="s2"&gt;"aws_route53_zone"&lt;/span&gt; &lt;span class="s2"&gt;"domain_zone"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.route53_base_domain&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
  private_zone &lt;span class="o"&gt;=&lt;/span&gt; local.route53_private_zone
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;São definidas algumas variáveis locais para utilizar nos demais arquivos;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.terraform.io/docs/providers/aws/d/caller_identity.html" rel="noopener noreferrer"&gt;aws_caller_identity&lt;/a&gt;: consulta usada para obter o ID da conta e concatená-lo com o nome do bucket do S3 para garantir que o nome seja único na AWS e tentar evitar falhas na criação do bucket.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.terraform.io/docs/providers/aws/d/route53_zone.html" rel="noopener noreferrer"&gt;aws_route53_zone&lt;/a&gt;: consulta uma Hosted Zone no Route53 que possua o domínio informado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Definição das &lt;code&gt;inputs&lt;/code&gt; (&lt;code&gt;inputs.tf&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Na infraestrutura teremos as seguintes &lt;code&gt;inputs&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;service&lt;/code&gt;: nome com que os recursos serão criados dentro da AWS;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stage&lt;/code&gt;: estágio da aplicação caso desejar criar mais de uma CDN para o mesmo serviço (dev, test, prod). Nota: é possível utilizar &lt;a href="https://docs.aws.amazon.com/pt_br/AmazonCloudFront/latest/DeveloperGuide/continuous-deployment.html" rel="noopener noreferrer"&gt;a implantação contínua do próprio CloudFront&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;route53_private_zone&lt;/code&gt;: define se a zona DNS é privada ou não;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;route53_zone_domain&lt;/code&gt;: domínio da zona DNS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cdn_domain&lt;/code&gt;: nome do domínio para a CDN, pode ser deixado em branco para utilizar o domínio base (Hosted Zone do Route53);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cloudfront_allowed_methods&lt;/code&gt;: métodos HTTP permitidos no CloudFront;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cloudfront_cached_methods&lt;/code&gt;: métodos HTTP que serão mantidos em cache no CloudFront;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cloudfront_default_root_object&lt;/code&gt;: arquivo raiz padrão no CloudFront;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cloudfront_http_version&lt;/code&gt;: versão do protocolo HTTP no CloudFront.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;variable &lt;span class="s2"&gt;"service"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-cdn"&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; string
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Service name"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"stage"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; string
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Stage (dev, test, prod)"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"route53_private_zone"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false
  type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; bool
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"route53_zone_domain"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; string
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Route53 zone domain (base domain)"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"cdn_domain"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; string
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Domain name (Where you want to deploy the CloudFront distribution. Leave empty to deploy inside base domain)"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"cloudfront_allowed_methods"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;, &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;, &lt;span class="s2"&gt;"OPTIONS"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; list&lt;span class="o"&gt;(&lt;/span&gt;string&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"cloudfront_cached_methods"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;, &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;, &lt;span class="s2"&gt;"OPTIONS"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; list&lt;span class="o"&gt;(&lt;/span&gt;string&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"cloudfront_default_root_object"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.html"&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; string
&lt;span class="o"&gt;}&lt;/span&gt;

variable &lt;span class="s2"&gt;"cloudfront_http_version"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  default &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http2"&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; string
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Passando valores para as variáveis criadas (&lt;code&gt;terraform.tfvars&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Existem várias formas de passar valores para as variáveis do Terraform, incluindo a utilização de arquivos JSON, variáveis de ambiente ou a passagem de valores diretamente pela linha de comando no momento da execução do Terraform. Consulte a &lt;a href="https://www.terraform.io/docs/language/values/variables.html" rel="noopener noreferrer"&gt;documentação oficial do Terraform&lt;/a&gt; para mais informações.&lt;/p&gt;

&lt;p&gt;Neste exemplo será utilizado um arquivo com a extensão &lt;code&gt;.tfvars&lt;/code&gt;, então basta criar um arquivo &lt;code&gt;terraform.tfvars&lt;/code&gt; e definir o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;route53_zone_domain &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tiagoboeing.com"&lt;/span&gt;
cdn_domain          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-cdn.tiagoboeing.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste caso o domínio (Hosted Zone no Route53) é &lt;code&gt;tiagoboeing.com&lt;/code&gt; e a CDN será implantada em um subdomínio.&lt;/p&gt;

&lt;p&gt;A propriedade &lt;code&gt;route53_zone_domain&lt;/code&gt; serve como base para o Terraform obter a Hosted Zone no Route53.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criação do bucket no S3 (&lt;code&gt;s3.tf&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;O primeiro passo é criar um bucket no S3 e definir uma política de segurança que restrinja o acesso público direto a qualquer conteúdo. Isso impedirá que um objeto seja tornado público diretamente via S3. O CloudFront será a única maneira de acessar os arquivos.&lt;/p&gt;

&lt;p&gt;Crie um arquivo chamado &lt;code&gt;s3.tf&lt;/code&gt; e adicione o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"bucket"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  bucket &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.resource_prefix_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-bucket-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.aws_caller_identity.current.account_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  tags &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    Stage   &lt;span class="o"&gt;=&lt;/span&gt; local.stage,
    Service &lt;span class="o"&gt;=&lt;/span&gt; local.service
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

resource &lt;span class="s2"&gt;"aws_s3_bucket_acl"&lt;/span&gt; &lt;span class="s2"&gt;"bucket_acl"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  bucket &lt;span class="o"&gt;=&lt;/span&gt; aws_s3_bucket.bucket.id
  acl    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"private"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

resource &lt;span class="s2"&gt;"aws_s3_bucket_public_access_block"&lt;/span&gt; &lt;span class="s2"&gt;"bucket_public_access"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  bucket &lt;span class="o"&gt;=&lt;/span&gt; aws_s3_bucket.bucket.id

  block_public_acls       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;block_public_policy     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;ignore_public_acls      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;restrict_public_buckets &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

resource &lt;span class="s2"&gt;"aws_s3_bucket_policy"&lt;/span&gt; &lt;span class="s2"&gt;"bucket_policy"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  bucket &lt;span class="o"&gt;=&lt;/span&gt; aws_s3_bucket.bucket.id

  policy &lt;span class="o"&gt;=&lt;/span&gt; jsonencode&lt;span class="o"&gt;({&lt;/span&gt;
    &lt;span class="s2"&gt;"Version"&lt;/span&gt; : &lt;span class="s2"&gt;"2008-10-17"&lt;/span&gt;,
    &lt;span class="s2"&gt;"Statement"&lt;/span&gt; : &lt;span class="o"&gt;[&lt;/span&gt;
      &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"Sid"&lt;/span&gt; : &lt;span class="s2"&gt;"AllowCloudFrontServicePrincipalReadOnly"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Effect"&lt;/span&gt; : &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Principal"&lt;/span&gt; : &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"Service"&lt;/span&gt; : &lt;span class="s2"&gt;"cloudfront.amazonaws.com"&lt;/span&gt;,
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"Action"&lt;/span&gt; : &lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Resource"&lt;/span&gt; : &lt;span class="s2"&gt;"arn:aws:s3:::&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.bucket.bucket&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/*"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Condition"&lt;/span&gt; : &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"StringEquals"&lt;/span&gt; : &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"aws:SourceArn"&lt;/span&gt; : aws_cloudfront_distribution.cloudfront.arn
          &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;})&lt;/span&gt;

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    aws_s3_bucket.bucket
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Estamos definindo os seguintes recursos:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket" rel="noopener noreferrer"&gt;aws_s3_bucket&lt;/a&gt;: Cria o bucket que o CloudFront utilizará como &lt;code&gt;origin&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy" rel="noopener noreferrer"&gt;aws_s3_bucket_policy&lt;/a&gt;: Define uma política de acesso para que o CloudFront seja capaz de obter os objetos do bucket no S3 (necessário quando trabalhamos com buckets privados)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_acl" rel="noopener noreferrer"&gt;aws_s3_bucket_acl&lt;/a&gt;: Define o controle de acesso ao bucket no S3 como privado.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block" rel="noopener noreferrer"&gt;aws_s3_bucket_public_access_block&lt;/a&gt;: Define os parâmetros de acesso público para o bucket no S3 da AWS, bloqueando a criação de buckets públicos, políticas públicas, listagens públicas e controle de acesso público.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Criação e validação do certificado SSL (&lt;code&gt;certificate.tf&lt;/code&gt;)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_acm_certificate"&lt;/span&gt; &lt;span class="s2"&gt;"certificate"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  domain_name       &lt;span class="o"&gt;=&lt;/span&gt; local.cdn_domain &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; ? local.cdn_domain : data.aws_route53_zone.domain_zone.name
  validation_method &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"DNS"&lt;/span&gt;

  tags &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    Stage   &lt;span class="o"&gt;=&lt;/span&gt; local.stage,
    Service &lt;span class="o"&gt;=&lt;/span&gt; local.service
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

resource &lt;span class="s2"&gt;"aws_acm_certificate_validation"&lt;/span&gt; &lt;span class="s2"&gt;"certificate_validation"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  certificate_arn         &lt;span class="o"&gt;=&lt;/span&gt; aws_acm_certificate.certificate.arn
  validation_record_fqdns &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;record &lt;span class="k"&gt;in &lt;/span&gt;aws_route53_record.certificate_records : record.fqdn]

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    aws_acm_certificate.certificate
  &lt;span class="o"&gt;]&lt;/span&gt;

  timeouts &lt;span class="o"&gt;{&lt;/span&gt;
    create &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10m"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Add Certificate Validation Records on Route53&lt;/span&gt;
resource &lt;span class="s2"&gt;"aws_route53_record"&lt;/span&gt; &lt;span class="s2"&gt;"certificate_records"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  for_each &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;dvo &lt;span class="k"&gt;in &lt;/span&gt;aws_acm_certificate.certificate.domain_validation_options : dvo.domain_name &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      name   &lt;span class="o"&gt;=&lt;/span&gt; dvo.resource_record_name
      record &lt;span class="o"&gt;=&lt;/span&gt; dvo.resource_record_value
      &lt;span class="nb"&gt;type&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; dvo.resource_record_type
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  allow_overwrite &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;name            &lt;span class="o"&gt;=&lt;/span&gt; each.value.name
  records         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;each.value.record]
  ttl             &lt;span class="o"&gt;=&lt;/span&gt; 60
  &lt;span class="nb"&gt;type&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; each.value.type
  zone_id         &lt;span class="o"&gt;=&lt;/span&gt; data.aws_route53_zone.domain_zone.zone_id
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Estamos definindo os seguintes recursos:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate" rel="noopener noreferrer"&gt;aws_acm_certificate&lt;/a&gt;: criação do certificado SSL para a CDN utilizando o AWS Certificate Manager (ACM);&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation" rel="noopener noreferrer"&gt;aws_acm_certificate_validation&lt;/a&gt;: Define que a validação do certificado será realizada via DNS;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record" rel="noopener noreferrer"&gt;aws_route53_record&lt;/a&gt;: adiciona registros no Route53 para validar o certificado SSL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Criação do CloudFront (&lt;code&gt;cloudfront.tf&lt;/code&gt;)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_cloudfront_origin_access_control"&lt;/span&gt; &lt;span class="s2"&gt;"cloudfront_acl"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ACL - &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.resource_prefix_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  origin_access_control_origin_type &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt;
  signing_behavior                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"always"&lt;/span&gt;
  signing_protocol                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sigv4"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

resource &lt;span class="s2"&gt;"aws_cloudfront_distribution"&lt;/span&gt; &lt;span class="s2"&gt;"cloudfront"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  enabled             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;is_ipv6_enabled     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;comment             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CDN for &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.resource_prefix_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  default_root_object &lt;span class="o"&gt;=&lt;/span&gt; var.cloudfront_default_root_object
  http_version        &lt;span class="o"&gt;=&lt;/span&gt; var.cloudfront_http_version

  aliases &lt;span class="o"&gt;=&lt;/span&gt; local.cdn_domain &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; ? &lt;span class="o"&gt;[&lt;/span&gt;local.cdn_domain] : local.route53_base_domain &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; ? &lt;span class="o"&gt;[&lt;/span&gt;local.route53_base_domain] : &lt;span class="o"&gt;[]&lt;/span&gt;

  origin &lt;span class="o"&gt;{&lt;/span&gt;
    origin_id                &lt;span class="o"&gt;=&lt;/span&gt; aws_s3_bucket.bucket.id
    origin_access_control_id &lt;span class="o"&gt;=&lt;/span&gt; aws_cloudfront_origin_access_control.cloudfront_acl.id
    domain_name              &lt;span class="o"&gt;=&lt;/span&gt; aws_s3_bucket.bucket.bucket_regional_domain_name
  &lt;span class="o"&gt;}&lt;/span&gt;

  default_cache_behavior &lt;span class="o"&gt;{&lt;/span&gt;
    target_origin_id &lt;span class="o"&gt;=&lt;/span&gt; aws_s3_bucket.bucket.id

    compress        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
    &lt;/span&gt;allowed_methods &lt;span class="o"&gt;=&lt;/span&gt; var.cloudfront_allowed_methods
    cached_methods  &lt;span class="o"&gt;=&lt;/span&gt; var.cloudfront_cached_methods

    forwarded_values &lt;span class="o"&gt;{&lt;/span&gt;
      query_string &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false

      &lt;/span&gt;cookies &lt;span class="o"&gt;{&lt;/span&gt;
        forward &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"none"&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    viewer_protocol_policy &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"redirect-to-https"&lt;/span&gt;
    min_ttl                &lt;span class="o"&gt;=&lt;/span&gt; 0
    default_ttl            &lt;span class="o"&gt;=&lt;/span&gt; 3600
    max_ttl                &lt;span class="o"&gt;=&lt;/span&gt; 86400
  &lt;span class="o"&gt;}&lt;/span&gt;

  restrictions &lt;span class="o"&gt;{&lt;/span&gt;
    geo_restriction &lt;span class="o"&gt;{&lt;/span&gt;
      restriction_type &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"none"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  viewer_certificate &lt;span class="o"&gt;{&lt;/span&gt;
    cloudfront_default_certificate &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false

    &lt;/span&gt;minimum_protocol_version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"TLSv1.2_2021"&lt;/span&gt;
    ssl_support_method       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sni-only"&lt;/span&gt;

    acm_certificate_arn &lt;span class="o"&gt;=&lt;/span&gt; aws_acm_certificate_validation.certificate_validation.certificate_arn
  &lt;span class="o"&gt;}&lt;/span&gt;

  tags &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    Stage   &lt;span class="o"&gt;=&lt;/span&gt; local.stage,
    Service &lt;span class="o"&gt;=&lt;/span&gt; local.service
  &lt;span class="o"&gt;}&lt;/span&gt;

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    aws_s3_bucket.bucket
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Create Route53 Record to CloudFront&lt;/span&gt;
resource &lt;span class="s2"&gt;"aws_route53_record"&lt;/span&gt; &lt;span class="s2"&gt;"domain_record"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name    &lt;span class="o"&gt;=&lt;/span&gt; local.cdn_domain &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; ? local.cdn_domain : data.aws_route53_zone.domain_zone.name
  &lt;span class="nb"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"A"&lt;/span&gt;
  zone_id &lt;span class="o"&gt;=&lt;/span&gt; data.aws_route53_zone.domain_zone.zone_id

  &lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    name                   &lt;span class="o"&gt;=&lt;/span&gt; aws_cloudfront_distribution.cloudfront.domain_name
    zone_id                &lt;span class="o"&gt;=&lt;/span&gt; aws_cloudfront_distribution.cloudfront.hosted_zone_id
    evaluate_target_health &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    aws_cloudfront_distribution.cloudfront
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Estamos definindo os seguintes recursos:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_identity" rel="noopener noreferrer"&gt;aws_cloudfront_origin_access_control&lt;/a&gt;: Cria uma política de acesso para o S3;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution" rel="noopener noreferrer"&gt;aws_cloudfront_distribution&lt;/a&gt;: Cria e configura a distribuição do CloudFront;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record" rel="noopener noreferrer"&gt;aws_route53_record&lt;/a&gt;: Adiciona um registro DNS no Route53 como alias para o CloudFront.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Teste da infraestrutura (&lt;code&gt;test-cdn.tf&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Aqui será a etapa onde um arquivo HTML será enviado para o bucket S3 e então o cache do CloudFront invalidado para garantir que as alterações reflitam imediatamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#############################&lt;/span&gt;
&lt;span class="c"&gt;# Only for tests purposes&lt;/span&gt;
&lt;span class="c"&gt;# Upload one HTML file to S3&lt;/span&gt;
&lt;span class="c"&gt;#############################&lt;/span&gt;
resource &lt;span class="s2"&gt;"aws_s3_object"&lt;/span&gt; &lt;span class="s2"&gt;"public_folder"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  for_each     &lt;span class="o"&gt;=&lt;/span&gt; fileset&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"public/"&lt;/span&gt;, &lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  bucket       &lt;span class="o"&gt;=&lt;/span&gt; aws_s3_bucket.bucket.id
  key          &lt;span class="o"&gt;=&lt;/span&gt; each.value
  &lt;span class="nb"&gt;source&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"public/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.value&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  etag         &lt;span class="o"&gt;=&lt;/span&gt; filemd5&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"public/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.value&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  content_type &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"text/html"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;#############################&lt;/span&gt;
&lt;span class="c"&gt;# Only for tests purposes&lt;/span&gt;
&lt;span class="c"&gt;# Invalidate index.html from CloudFront cache&lt;/span&gt;
&lt;span class="c"&gt;#############################&lt;/span&gt;
resource &lt;span class="s2"&gt;"null_resource"&lt;/span&gt; &lt;span class="s2"&gt;"cache_invalidation"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="c"&gt;# prevent invalidating cache before new s3 file is uploaded&lt;/span&gt;
  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    aws_s3_object.public_folder
  &lt;span class="o"&gt;]&lt;/span&gt;

  for_each &lt;span class="o"&gt;=&lt;/span&gt; fileset&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.module&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/public/"&lt;/span&gt;, &lt;span class="s2"&gt;"**"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  triggers &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; filemd5&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"public/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.value&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  provisioner &lt;span class="s2"&gt;"local-exec"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# sleep is necessary to prevent throttling when invalidating many files; a dynamic sleep time would be more reliable&lt;/span&gt;
    &lt;span class="c"&gt;# possible way of dealing with parallelism (though would lose the indiviual triggers): https://discuss.hashicorp.com/t/specify-parallelism-for-null-resource/20884/2&lt;/span&gt;
    &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sleep 1; aws cloudfront create-invalidation --distribution-id &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;aws_cloudfront_distribution&lt;/span&gt;&lt;span class="p"&gt;.cloudfront.id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; --paths '/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.value&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crie uma pasta chamada &lt;code&gt;public&lt;/code&gt; e adicione um arquivo &lt;code&gt;index.html&lt;/code&gt; com qualquer conteúdo apenas para teste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provisionar infraestrutura
&lt;/h2&gt;

&lt;p&gt;Com os recursos configurados, é hora de provisionar a infraestrutura.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Valide o plano de criação&lt;/span&gt;
terraform plan

&lt;span class="c"&gt;# Se tudo estiver correto, aplique o plano para iniciar a criação&lt;/span&gt;
terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O provisionamento inicial normalmente leva alguns minutos e a distribuição do CloudFront pode demorar mais alguns minutos para ficar disponível.&lt;/p&gt;

&lt;p&gt;Aguarde o tempo necessário. Ao finalizar, acesse o domínio configurado e valide se o arquivo HTML foi apresentado corretamente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No exemplo do artigo o subdomínio onde a CDN foi provisionada é &lt;a href="https://terraform-cdn.tiagoboeing.com/" rel="noopener noreferrer"&gt;&lt;code&gt;terraform-cdn.tiagoboeing.com&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Parabéns! Você agora possui uma CDN de alta disponibilidade na AWS utilizando IaC. Não hesite em explorar outras soluções e recursos da AWS e continue aprendendo!&lt;/p&gt;

&lt;h2&gt;
  
  
  Links do artigo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/tiagoboeing/terraform-aws/tree/536e087e6604da759f5b56f9ca82e09a773231d5/cloudfront-cdn" rel="noopener noreferrer"&gt;Link permanente do repositório no momento que o artigo foi escrito&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tiagoboeing/terraform-aws/tree/master/cloudfront-cdn" rel="noopener noreferrer"&gt;Repositório no GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://terraform-cdn.tiagoboeing.com/" rel="noopener noreferrer"&gt;Demonstração da CDN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Leia também
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tiagoboeing.medium.com/cdn-de-alta-disponibilidade-na-aws-com-s3-cloudfront-e-route53-d08da8fab0ab" rel="noopener noreferrer"&gt;CDN de alta disponibilidade na AWS com S3, CloudFront e Route53&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tiagoboeing.medium.com/execucao-agendada-de-funcoes-em-serverless-2bc7506cfcaf" rel="noopener noreferrer"&gt;Execução agendada de funções utilizando AWS e Serverless Framework&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  English
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tiagoboeing.medium.com/serverless-framework-aws-automatically-creating-certificate-and-domain-for-your-app-98cd5e31b66c" rel="noopener noreferrer"&gt;Serverless Framework + AWS: automatically creating certificate and domain for your app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Redes sociais
&lt;/h2&gt;

&lt;p&gt;Quer saber mais sobre mim, o autor deste artigo? Então dê uma olhada nas minhas redes sociais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/tiagoboeing/" rel="noopener noreferrer"&gt;Perfil no LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tiagoboeing.medium.com/" rel="noopener noreferrer"&gt;Perfil no Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tiagoboeing" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.instagram.com/tiagoboeing/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Espero que tenha gostado do artigo e encontrado informações úteis. Se tiver alguma dúvida ou sugestão, deixe nos comentários.&lt;/p&gt;




&lt;p&gt;Você sabia que pode se tornar um Community Builder da AWS? Como Community Builder, você terá a oportunidade de se conectar com outros profissionais da área de tecnologia e aprender com especialistas da AWS. Além disso, você poderá compartilhar seus conhecimentos e experiências com outros membros da comunidade. Não perca a chance de se tornar um líder na sua área e se juntar a uma comunidade global de entusiastas da AWS! Saiba mais em &lt;a href="https://aws.amazon.com/developer/community/community-builders/" rel="noopener noreferrer"&gt;aws.amazon.com/developer/community/community-builders&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>iac</category>
      <category>cloudfront</category>
    </item>
    <item>
      <title>Serverless Framework + AWS: automatically creating certificate and domain for your app</title>
      <dc:creator>Tiago Boeing</dc:creator>
      <pubDate>Fri, 04 Mar 2022 10:16:30 +0000</pubDate>
      <link>https://dev.to/aws-builders/serverless-framework-aws-automatically-creating-certificate-and-domain-for-your-app-5832</link>
      <guid>https://dev.to/aws-builders/serverless-framework-aws-automatically-creating-certificate-and-domain-for-your-app-5832</guid>
      <description>&lt;p&gt;This is a guide showing how you can automatically create an SSL certificate on Amazon Certificate Manager (ACM) and configure a subdomain on Route 53 Hosted Zone using Serverless Framework with some wonderful plugins.&lt;/p&gt;

&lt;p&gt;Before start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need an AWS account;&lt;/li&gt;
&lt;li&gt;Have a &lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/CreatingHostedZone.html"&gt;Hosted Zone configured on Route53&lt;/a&gt; with some domain name;&lt;/li&gt;
&lt;li&gt;Have a little bit of knowledge of using Serverless Framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Firstly, you need to know that we'll use some Serverless Framework plugins to turn our life easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.serverless.com/plugins/serverless-domain-manager"&gt;Serverless Domain Manager&lt;/a&gt; to control Route53 rules and API Gateway custom domain configs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/schwamster/serverless-certificate-creator#readme"&gt;Serverless Certificate Creator&lt;/a&gt; to create certificates on Amazon Certificate Manager and confirm by DNS method.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I’ll show some scripts using NodeJS, but Serverless Framework can be used on almost any language (to not say literally anywhere).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;With this in mind, let's go ahead! Start installing dependencies:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install serverless-domain-manager serverless-certificate-creator —-save-dev&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a custom domain section
&lt;/h2&gt;

&lt;p&gt;I usually separate domains to allow customization for each one, it would be like this in my stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# serverless.yml&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;domains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# References to 'prod' stage&lt;/span&gt;
    &lt;span class="na"&gt;prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.tiagoboeing.com&lt;/span&gt;
      &lt;span class="na"&gt;certificateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.tiagoboeing.com&lt;/span&gt;

    &lt;span class="c1"&gt;# References to 'dev' stage  &lt;/span&gt;
    &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-dev.tiagoboeing.com&lt;/span&gt;
      &lt;span class="na"&gt;certificateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-dev.tiagoboeing.com&lt;/span&gt;

    &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, the certificate name is chosen by you. I only like to use the same name of the domain to keep easier to locate on ACM.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the way how I organize my apps, take this as an example to customize/start.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See our &lt;code&gt;custom&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Amazon Certificate Manager&lt;/span&gt;
  &lt;span class="na"&gt;customCertificate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Route 53 Hosted Zone name&lt;/span&gt;
    &lt;span class="c1"&gt;# don't forget the dot on the end!&lt;/span&gt;
    &lt;span class="na"&gt;hostedZoneNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tiagoboeing.com."&lt;/span&gt;

    &lt;span class="c1"&gt;# Here we get our certificate name inside custom.domain.STAGE.certificateName&lt;/span&gt;
    &lt;span class="c1"&gt;# STAGE will be automatically filled with the value from "provider &amp;gt; stage"&lt;/span&gt;
    &lt;span class="na"&gt;certificateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.domains.${self:provider.stage}.certificateName}&lt;/span&gt;

    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:provider.region}&lt;/span&gt;

  &lt;span class="c1"&gt;# Route53&lt;/span&gt;
  &lt;span class="na"&gt;customDomain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Get value from "domains" section using stage that is being deployed&lt;/span&gt;
    &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.domains.${self:provider.stage}.domainName}&lt;/span&gt;

    &lt;span class="c1"&gt;# Same case of certificaName inside customCertificate&lt;/span&gt;
    &lt;span class="na"&gt;certificateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.domains.${self:provider.stage}.certificateName}&lt;/span&gt;

    &lt;span class="c1"&gt;# Enable plugin to create an A Alias and AAAA Alias records in Route53&lt;/span&gt;
    &lt;span class="c1"&gt;# mapping the domainName to the generated distribution domain name.&lt;/span&gt;
    &lt;span class="na"&gt;createRoute53Record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="c1"&gt;# Enable plugin to autorun create_domain/delete_domain as part of sls deploy/remove&lt;/span&gt;
    &lt;span class="na"&gt;autoDomain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy
&lt;/h2&gt;

&lt;p&gt;Take the following tips and tricks:&lt;/p&gt;

&lt;h3&gt;
  
  
  To create the certificate on ACM run:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;serverless create-cert

# or

npx serverless create-cert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the certificate on the deploying stage, you can change the stage using &lt;code&gt;--stage prod&lt;/code&gt; flag or &lt;code&gt;STAGE=prod&lt;/code&gt; env.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create domain - simply run
&lt;/h3&gt;

&lt;p&gt;To create domain on Route 53, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;serverless create_domain

# or

npx serverless create_domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that &lt;code&gt;createRoute53Record&lt;/code&gt; and &lt;code&gt;autoDomain&lt;/code&gt; were enabled on &lt;code&gt;serverless.yml&lt;/code&gt;, a simple &lt;code&gt;serverless deploy&lt;/code&gt; will start automatically this step.&lt;/p&gt;

&lt;p&gt;Deploying to another stage (not on the default: &lt;strong&gt;dev&lt;/strong&gt;) you need to use the option &lt;code&gt;--stage&lt;/code&gt; (&lt;a href="https://www.serverless.com/framework/docs/providers/aws/cli-reference/deploy"&gt;read more here&lt;/a&gt;). As an example for the first time you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# First deploy PROD stage

serverless create-cert --stage=prod

serverless deploy --stage=prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s possible to manually generate a domain using serverless-domain-manager, you can do it using the command &lt;code&gt;serverless create_domain&lt;/code&gt;, this isn’t needed if you have the &lt;code&gt;autoDomain&lt;/code&gt; flag enabled (as mentioned earlier).&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete stack
&lt;/h2&gt;

&lt;p&gt;See the complete Serverless stack below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sls-my-app&lt;/span&gt;

&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-domain-manager&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-certificate-creator&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs14.x&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:stage, 'dev'}&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:region, 'us-east-1'}&lt;/span&gt;
  &lt;span class="na"&gt;apiGateway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;shouldStartNameWithService&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

  &lt;span class="c1"&gt;# passing base domain name and stage to our functions&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DOMAIN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.customDomain.domainName}&lt;/span&gt;
    &lt;span class="na"&gt;STAGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:provider.stage}&lt;/span&gt;

&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;authenticate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/functions/hello.handler&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Return&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;world"&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
          &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;domains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.tiagoboeing.com&lt;/span&gt;
      &lt;span class="na"&gt;certificateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.tiagoboeing.com&lt;/span&gt;
    &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-dev.tiagoboeing.com&lt;/span&gt;
      &lt;span class="na"&gt;certificateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-dev.tiagoboeing.com&lt;/span&gt;

  &lt;span class="c1"&gt;# Amazon Certificate Manager&lt;/span&gt;
  &lt;span class="na"&gt;customCertificate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hostedZoneNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tiagoboeing.com."&lt;/span&gt; &lt;span class="c1"&gt;# don't forget the dot on the end - is required by Route53&lt;/span&gt;
    &lt;span class="na"&gt;certificateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.domains.dev.certificateName}&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:provider.region}&lt;/span&gt;

  &lt;span class="c1"&gt;# Route53&lt;/span&gt;
  &lt;span class="na"&gt;customDomain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.domains.${self:provider.stage}.domainName}&lt;/span&gt;
    &lt;span class="na"&gt;certificateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.domains.dev.certificateName}&lt;/span&gt;
    &lt;span class="na"&gt;createRoute53Record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;autoDomain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;📝 Thanks, Paulo Weber by the review this text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tiagoboeing.medium.com/automating-changelog-in-your-nodejs-project-c54bdbb56e57"&gt;Automating changelogs in your NodeJS project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PT-BR:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tiagoboeing.medium.com/cdn-de-alta-disponibilidade-na-aws-com-s3-cloudfront-e-route53-d08da8fab0ab"&gt;CDN de alta disponibilidade na AWS com S3, CloudFront e Route53&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.toAutomatizando%20gera%C3%A7%C3%A3o%20de%20changelogs%20em%20seus%20projetos%20NodeJS"&gt;Automatizando geração de changelogs em seus projetos NodeJS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>certificate</category>
      <category>domain</category>
    </item>
    <item>
      <title>CDN de alta disponibilidade na AWS com S3, CloudFront e Route53</title>
      <dc:creator>Tiago Boeing</dc:creator>
      <pubDate>Tue, 30 Nov 2021 03:06:08 +0000</pubDate>
      <link>https://dev.to/aws-builders/cdn-de-alta-disponibilidade-na-aws-com-s3-cloudfront-e-route53-2528</link>
      <guid>https://dev.to/aws-builders/cdn-de-alta-disponibilidade-na-aws-com-s3-cloudfront-e-route53-2528</guid>
      <description>&lt;p&gt;Este é um guia sem enrolações (prometo entrar no detalhe apenas do que for essencial) sobre como provisionar uma rede de distribuição de conteúdo (CDN) na AWS. Os passos são executados via console (GUI/interface) e &lt;strong&gt;as capturas de tela tendem a ficar obsoletas com o passar do tempo, podendo não representar o estado atual da interface à medida que as soluções evoluem.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em outra ocasião abordarei a criação utilizando IaC (Infrastructure as Code)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pressuponho que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;já possua uma conta na AWS, se não tiver &lt;a href="https://portal.aws.amazon.com/billing/signup#/start"&gt;crie e logo de início ganhe 12 meses de nível gratuito&lt;/a&gt; (as ferramentas envolvidas no artigo são privilegiadas);&lt;/li&gt;
&lt;li&gt;tem um domínio (hosted zone) cadastrado no Route53 (caso preferir utilizar o seu).&lt;/li&gt;
&lt;li&gt;está buscando distribuir conteúdo de maneira replicada pelo mundo e com baixa latência. Caso os usuários forem de uma única região e não existir preocupação com futuras expansões, é possível utilizar apenas o S3 com a &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html"&gt;opção static website&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  O que são conteúdos estáticos?
&lt;/h3&gt;

&lt;p&gt;São arquivos em que o conteúdo não é criado dinamicamente, embora possa mudar com determinada frequência, em sua essência ele permanecerá o mesmo até a próxima alteração e, no momento que ela (alteração) ocorrer podemos realizar diversas operações para garantir que o novo conteúdo seja distribuído para os clientes através de práticas como a invalidação de cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplos de arquivos estáticos:&lt;/strong&gt; Imagens, aplicações SPAs (já que são compostas de arquivos de texto/scripts), tipografias, vídeos (você até pode, mas o tipo da distribuição do CloudFront deste artigo não tem este propósito — assunto para outra ocasião) e outros.&lt;/p&gt;

&lt;h2&gt;
  
  
  CDN
&lt;/h2&gt;

&lt;p&gt;Content Delivery Network (Rede de distribuição de conteúdo) — tem como principal motivo contribuir para a melhora do tempo de carregamento de páginas e aumentar a disponibilidade do conteúdo ao redor do mundo, normalmente esta inclui diversos servidores de borda (edge) que são próximos do usuário (e isto é o que garante a baixa latência).&lt;/p&gt;

&lt;h2&gt;
  
  
  S3
&lt;/h2&gt;

&lt;p&gt;O S3 é o serviço da AWS voltado ao armazenamento de arquivos, nele criamos diversos buckets (baldes) que são os espaços onde iremos realizar o upload. Um bucket pode ser organizado por pastas e conter configurações de vida útil de um objeto/arquivo (tais como expiração), permissões, CORS e uma infinidade de outros.&lt;/p&gt;

&lt;h2&gt;
  
  
  CloudFront
&lt;/h2&gt;

&lt;p&gt;O CloudFront é um serviço vital para inúmeros outros dentro da nuvem da AWS, muitas das vezes você o utiliza sem perceber. É ele quem garante a disponibilidade ao redor do mundo e melhores taxas de latência com base na localização do cliente. Embora este artigo trate de arquivos estáticos, não é só para isto que o CloudFront serve, podendo distribuir APIs através de &lt;a href="https://aws.amazon.com/pt/lambda/edge/"&gt;Lambda@Edge&lt;/a&gt;, transmissão ao vivo e sob demanda de vídeo, distribuição de atualizações para dispositivos IoT e outros.&lt;/p&gt;

&lt;p&gt;Podemos adicionar um nome de domínio para uma distribuição (nome dado a instância do CloudFront) utilizando o Route53 (serviço para gerenciamento de DNS da AWS), configurar regras de proxy adicionando uma Lambda à frente para controlar CSP — Content Security Policies [assunto para próximos artigos, mas se tiver pressa, &lt;a href="https://aws.amazon.com/pt/blogs/networking-and-content-delivery/adding-http-security-headers-using-lambdaedge-and-amazon-cloudfront/"&gt;veja esse artigo do Jake Wells&lt;/a&gt;], revalidação de cache, monitorar tráfego e uma infinidade de cenários.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Antes de provisionar qualquer recurso cloud é importante analisar os custos envolvidos para evitar surpresas, se estiver em uma conta de nível gratuito trate de certificar quais os limites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Definição de preço
&lt;/h3&gt;

&lt;p&gt;A AWS oferece no nível gratuito (de 12 meses), a cada mês: 50 GB de transferência de dados para fora, 2 milhões de solicitações HTTP ou HTTPS e 2 milhões de invocações do CloudFront Functions. Para mais detalhes, &lt;a href="https://aws.amazon.com/pt/cloudfront/pricing/?nc=sn&amp;amp;loc=3"&gt;consulte a definição de preço&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se não estiver no nível gratuito, faça uma simulação &lt;a href="https://calculator.aws/#/createCalculator/CloudFront"&gt;utilizando a calculadora de preços&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cenário hipotético de um CloudFront com as seguintes características e seus respectivos custos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Região us-east-1 (N. Virginia)&lt;/li&gt;
&lt;li&gt;10 GB por mês de tráfego de saída para a internet = 0.85 USD&lt;/li&gt;
&lt;li&gt;10 GB por mês de transferência para o servidor de origem (solicitações POST e PUT) = 0.20 USD&lt;/li&gt;
&lt;li&gt;100.000 requisições HTTPS por mês = 0.10 USD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;0.85 USD + 0.20 USD + 0.10 USD = 1.15 USD (Custo total por mês)&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vamos lá…
&lt;/h2&gt;

&lt;p&gt;Meu console se encontra em inglês para facilitar o entendimento e evitar traduzir alguns termos técnicos (mesmo que sua conta estiver em português é comum o console não ser 100% traduzido e ainda aparecer termos em inglês).&lt;/p&gt;

&lt;h3&gt;
  
  
  S3 Bucket
&lt;/h3&gt;

&lt;p&gt;O S3 é o local onde vamos armazenar os conteúdos da CDN, para isto precisamos criar um bucket (balde). Localize o S3 na busca de serviços:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Duw_UieY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hb7gw904d5zo6q02ozpj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Duw_UieY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hb7gw904d5zo6q02ozpj.png" alt="Image description" width="880" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clique em Create Bucket:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ojn1Zrby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/czcrxkid000bv2pdkoww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ojn1Zrby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/czcrxkid000bv2pdkoww.png" alt="Image description" width="713" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com base em minha experiência em determinado momento você pode desejar ativar alguns recursos no bucket que dependem de requisitos que sigam boas práticas de nomenclatura, como o &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/transfer-acceleration.html"&gt;Transfer acceleration&lt;/a&gt; e para isto &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html"&gt;obrigatoriamente o nome não pode conter&lt;/a&gt; &lt;code&gt;.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mais sobre convenção de nomes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html"&gt;Boas práticas de nomes para buckets do AWS S3&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/transfer-acceleration.html"&gt;Requisitos para utilizar Transfer acceleration&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seguindo as boas práticas, vamos utilizar hífen &lt;code&gt;—&lt;/code&gt; para separar as palavras, preencha os dados para a criação do bucket:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VkHd0sJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/067pv8dpax83k2fgcepq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VkHd0sJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/067pv8dpax83k2fgcepq.png" alt="Image description" width="880" height="758"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bucket name&lt;/strong&gt;: deve ser um nome único em toda a AWS;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Region&lt;/strong&gt;: como o CloudFront ficará à frente do nosso bucket e esta será a única maneira de acessar os conteúdos, preferi utilizar &lt;code&gt;us-east-1&lt;/code&gt; porque os custos são inferiores à São Paulo &lt;code&gt;sa-east-1&lt;/code&gt; — &lt;a href="https://aws.amazon.com/pt/s3/pricing/"&gt;Mais sobre custos do S3&lt;/a&gt;. (dependendo de seus planos, verifique a legislação quanto ao local de armazenamento dos dados);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block Public Access settings for this bucket&lt;/strong&gt;: mantenha o padrão;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bucket Versioning&lt;/strong&gt;: fica a critério, isto criará novas versões caso o documento enviado tenha o mesmo nome e facilitará rollback em caso de sobrescritas acidentais, em contrapartida tende a aumentar o consumo de armazenamento do bucket ao longo do tempo &lt;a href="https://docs.aws.amazon.com/pt_br/AmazonS3/latest/userguide/object-lifecycle-mgmt.html"&gt;se não for configurada uma rotina automática de limpeza&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Mantenha as demais opções sem alterar e crie o bucket clicando em &lt;strong&gt;Create bucket&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Após isto seu bucket estará criado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZGp2pb4H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wj7cc441895n4uivwxqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZGp2pb4H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wj7cc441895n4uivwxqq.png" alt="Image description" width="880" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No S3 por enquanto não há mais o que fazer, já existe um local para armazenar os arquivos. O próximo passo é criar a distribuição do CloudFront.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distribuição do CloudFront
&lt;/h3&gt;

&lt;p&gt;Localize o CloudFront na busca de serviços:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pj8ZH_29--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7mnwpcj9ektslzbnxqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pj8ZH_29--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7mnwpcj9ektslzbnxqb.png" alt="Pesquisa pelo CloudFront na busca por serviços." width="880" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clique em &lt;strong&gt;Create Distribution&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GzQzfh_N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u4mn53320sh52tne1er7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GzQzfh_N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u4mn53320sh52tne1er7.png" alt="Image description" width="880" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora a lista de configurações começa a ficar um pouco extensa, esta etapa é de extrema importância, resolvi numerar os passos iniciais para facilitar o entendimento:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hBUFKglI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xblhife54z181b6tn5s1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hBUFKglI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xblhife54z181b6tn5s1.png" alt="Image description" width="880" height="702"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Origin domain (1)&lt;/strong&gt;: é o bucket do S3 a ser utilizado pelo CloudFront, pesquise pelo nome criado na seção anterior, no meu caso é &lt;code&gt;tiagoboeing-cdn-article.s3.us-east-1.amazonaws.com&lt;/code&gt; ;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin path&lt;/strong&gt;: é opcional, ao deixar em branco o CloudFront estará utilizando a raiz do bucket como caminho relativo, mas se preferir é possível especificar uma determinada subpasta como raiz;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name (2)&lt;/strong&gt;: por padrão este campo será preenchido com o nome do bucket, defina o valor que preferir para facilitar a identificação da distribuição, costumo utilizar o domínio associado à mesma;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;S3 bucket access&lt;/strong&gt;: como deixamos nosso bucket privado (de maneira proposital para evitar acesso direto à ele), vamos configurar uma política que permita ao CloudFront ler os arquivos que lá estão;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(3) — Marque &lt;strong&gt;Yes use OAI (bucket can restrict access to only CloudFront)&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;(4) — Vamos criar a access identity, clique em &lt;strong&gt;Create new OAI&lt;/strong&gt;, preencha com o nome desejado conforme o padrão que preferir, costumo utilizar o prefixo sugerido (&lt;code&gt;access-identity-&lt;/code&gt;) + domínio da CDN, clique em criar e a &lt;strong&gt;Origin access identity&lt;/strong&gt; será preenchida automaticamente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L6fzI8IV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tuib6eg6vcuclsfk0mwm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L6fzI8IV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tuib6eg6vcuclsfk0mwm.png" alt="Image description" width="880" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(5) — Marque a caixa &lt;strong&gt;Bucket policy → Yes, update the bucket policy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Para facilitar, um resumo apenas do que alterei mais abaixo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Em Default cache behavior — Viewer → Viewer protocol policy&lt;/strong&gt;: Redirect HTTP to HTTPS;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Em Settings — Alternate domain name (CNAME)&lt;/strong&gt;: adicionei o domínio que pretendo usar e vou configurar no Route53 posteriormente;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Em Settings — Custom SSL certificate&lt;/strong&gt;: clique em &lt;strong&gt;Request certificate&lt;/strong&gt; e na nova aba será aberto o &lt;a href="https://aws.amazon.com/pt/certificate-manager/?nc=sn&amp;amp;loc=1"&gt;AWS Certificate Manager&lt;/a&gt; (o certificado SSL é gratuito), os passos são auto-guiados:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request a public certificate&lt;/strong&gt; → em &lt;strong&gt;Fully qualified domain name&lt;/strong&gt; coloque o domínio que irá utilizar na CDN → escolha como pretende verificar o domínio (se estiver configurado no Route53 use DNS validation pois a validação é automática) → Clique em &lt;strong&gt;Request&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Via DNS: Após solicitar, acesse o certificado e em &lt;strong&gt;Domains&lt;/strong&gt; clique em &lt;strong&gt;Create records in Route 53 → Create records&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Em Settings — Default root object&lt;/strong&gt;: se for utilizar a CDN para hospedar páginas estáticas (SPAs) defina index.html&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Em Settings — Description&lt;/strong&gt;: opcionalmente preencha com a observação que preferir.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crie a distribuição e aguarde, o status ficará como &lt;strong&gt;Deploying&lt;/strong&gt; e isto pode levar alguns minutos.&lt;/p&gt;

&lt;p&gt;Abaixo o resultado de todas as alterações realizadas para não restar dúvidas, em vermelho os locais modificados:&lt;/p&gt;

&lt;p&gt;Após alguns minutos… Pronto! Temos a distribuição criada! 🚀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oqe1GXR1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ntzrurlo47nf74yamow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oqe1GXR1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ntzrurlo47nf74yamow.png" alt="Image description" width="880" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicando no título é possível verificar as configurações:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--05MNsMq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2x1gbwsr4zv5vjy0jrgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--05MNsMq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2x1gbwsr4zv5vjy0jrgx.png" alt="Image description" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Criar registro no Route53 para o CloudFront
&lt;/h3&gt;

&lt;p&gt;Como ao longo do artigo optei por utilizar o subdomínio &lt;code&gt;cdn-article.tiagoboeing.com&lt;/code&gt; para exemplo, resta apenas criar este registro no Route53. Copie o domínio de &lt;strong&gt;Distribution domain name&lt;/strong&gt; (inclusive se ignorar esta etapa, este será o endereço de acesso da CDN).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O passo é opcional, mas leve em conta que ao utilizar o domínio padrão do CloudFront as alterações nas propriedades do domínio durante a criação da distribuição e o certificado não devem ser realizadas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vou ser breve nesta etapa.&lt;/p&gt;

&lt;p&gt;Estou presumindo que já existe uma hosted zone configurada. Acesse o Route53 buscando na lista de serviços; Clique na &lt;strong&gt;Hosted zone&lt;/strong&gt; do seu domínio e vá para &lt;strong&gt;Create record&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WcJu_wan--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c2r2n8qfkq25un9auxxn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WcJu_wan--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c2r2n8qfkq25un9auxxn.gif" alt="Image description" width="880" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Record name&lt;/strong&gt;: coloque o subdomínio utilizado durante a criação do CloudFront, no meu caso &lt;code&gt;cdn-article&lt;/code&gt; ;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Record type&lt;/strong&gt;: A — Routes traffic to an IPv4 address and some AWS resources;&lt;/li&gt;
&lt;li&gt;Marque a caixa de seleção &lt;strong&gt;Alias&lt;/strong&gt; e escolha &lt;strong&gt;Route traffic to → Alias to CloudFront distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;E na caixa &lt;strong&gt;Choose distribution&lt;/strong&gt; se tiver sorte tente localizar sua distribuição. (Aqui há uma incógnita, às vezes a AWS simplesmente não encontra a distribuição, por isso a dica de copiar a &lt;strong&gt;Distribution domain name&lt;/strong&gt; anteriormente) — se não conseguir localizar pela caixa basta colar o valor.&lt;/li&gt;
&lt;li&gt;Mantenha as demais opções com os valores padrões.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Hora da diversão, vamos aos testes
&lt;/h2&gt;

&lt;p&gt;Recapitulando…&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Criamos o bucket no S3 para armazenar os arquivos da CDN;&lt;/li&gt;
&lt;li&gt;Criamos a distribuição do CloudFront, definimos um nome de domínio, solicitamos um certificado SSL e anexamos nela;&lt;/li&gt;
&lt;li&gt;Apontamos um subdomínio para a distribuição.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vamos tentar acessar o subdomínio criado, no meu caso &lt;code&gt;cdn-article.tiagoboeing.com&lt;/code&gt; (para você estará inacessível pois removi após finalizar o artigo).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ruTuS0H3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ptucs6ip5pyz4q1nygg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ruTuS0H3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ptucs6ip5pyz4q1nygg.png" alt="Image description" width="804" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sem pânico! Não há conteúdo no bucket do S3 e neste caso haverá erro mesmo, mas perceba que ao digitar &lt;code&gt;http://&lt;/code&gt; automaticamente será alterado o endereço para utilizar HTTPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adicione qualquer arquivo no S3
&lt;/h3&gt;

&lt;p&gt;Adicionei um arquivo HTML chamado &lt;code&gt;index.html&lt;/code&gt; para testar a propriedade &lt;strong&gt;Default root object&lt;/strong&gt; que configuramos durante a criação do CloudFront. Basta arrastar e soltar o arquivo no bucket (não customizei nenhuma configuração, apenas fiz upload).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WCZJM63J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eylq4l37j739biap0qib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WCZJM63J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eylq4l37j739biap0qib.png" alt="Image description" width="880" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E… vamos testar novamente recarregando a página.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pl2zImev--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qixnn8k0jzwtk6z24ko.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pl2zImev--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qixnn8k0jzwtk6z24ko.png" alt="Image description" width="880" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tudo certo! A CDN está pronta para ser utilizada.&lt;/p&gt;

&lt;p&gt;Por segurança vamos tentar acessar o S3 diretamente sem passar pelo CloudFront, o endereço será &lt;code&gt;https://tiagoboeing-cdn-article.s3.us-east-1.amazonaws.com/index.html&lt;/code&gt; e é esperado um erro de permissão, isto indica que o bucket realmente está privado e apenas acessível via domínio do CloudFront:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Eer_Al1n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fvinstgiueo2y2otyfuv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Eer_Al1n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fvinstgiueo2y2otyfuv.png" alt="Tudo certo, o bucket está privado." width="880" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Invalidação de cache
&lt;/h3&gt;

&lt;p&gt;O CloudFront possui um cache configurável, a distribuição que criamos utiliza as políticas padrões recomendadas, isto significa que o &lt;strong&gt;CloudFront entregará ao usuário o conteúdo que estiver em seu cache quando disponível e não expirado/invalidado&lt;/strong&gt;. Esta é a razão pela qual ao realizar upload de um novo arquivo e/ou modificar um existente as alterações não são refletidas automaticamente, você precisar criar uma invalidação de cache!&lt;/p&gt;

&lt;p&gt;No momento que uma invalidação for criada, assim que houver uma requisição para a distribuição o CloudFront verificará por novos arquivos e criará o cache novamente.&lt;/p&gt;

&lt;p&gt;Esta foi a configuração de cache que utilizamos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CDfqzT7u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjjqqrm7c5iqm776glo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CDfqzT7u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjjqqrm7c5iqm776glo9.png" alt="Image description" width="721" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E aqui as políticas associadas a ela. Temos um TTL padrão de 24 horas (86.400 segundos).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JBAO8IOF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xn0uwjrwieynu1nkyj0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JBAO8IOF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xn0uwjrwieynu1nkyj0e.png" alt="Image description" width="880" height="896"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Modifiquei o título do arquivo HTML para demonstrar o cache.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MQz4-9uS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbywuj7s7ewsd6algm9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MQz4-9uS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbywuj7s7ewsd6algm9r.png" alt="Image description" width="650" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Realiza upload ao S3 e sobrescrito o &lt;code&gt;index.html&lt;/code&gt; existente… Ao voltar no browser e recarregar a página ainda visualizamos o conteúdo antigo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y5l_Rygn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9stuvjt1bijavbtg7ai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y5l_Rygn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9stuvjt1bijavbtg7ai.png" alt="Image description" width="880" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O motivo? Bem! O santo cache. Vamos criar uma invalidação. Volte ao CloudFront e clique na distribuição, depois acesse a aba &lt;strong&gt;Invalidations&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--33laMguj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/089wzqec6fmwgx1xv8d3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--33laMguj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/089wzqec6fmwgx1xv8d3.png" alt="Image description" width="880" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clique em &lt;strong&gt;Create invalidation&lt;/strong&gt; → na caixa &lt;strong&gt;Add object paths&lt;/strong&gt; é possível:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FIIhi0AB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pt3prtwbwph5m4t7346p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FIIhi0AB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pt3prtwbwph5m4t7346p.png" alt="Image description" width="880" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;escolher objetos (arquivos) individualmente: &lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;pasta/arquivo.txt&lt;/code&gt;, etc;&lt;/li&gt;
&lt;li&gt;invalidar tudo de uma pasta específica: &lt;code&gt;pasta/*&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;invalidar todo o conteúdo de todo o CloudFront: &lt;code&gt;/*&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como no S3 temos apenas um arquivo chamado &lt;code&gt;index.html&lt;/code&gt; e para exemplificar vou invalidar todo o conteúdo de todo o CloudFront informando: &lt;code&gt;/*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tente ser o mais restritivo possível, evite criar invalidações usando &lt;code&gt;/*&lt;/code&gt; pois isto tende a exigir maior tempo à medida que o conteúdo aumenta e fim do mês haverá uma surpresa ao verificar a fatura 😁, já que &lt;a href="https://aws.amazon.com/pt/cloudfront/pricing/"&gt;cada invalidação possui um custo.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Não há cobrança adicional para os primeiros 1.000 caminhos solicitados para invalidação a cada mês. Acima desse limite, será cobrado 0,005 USD por solicitação de invalidação de caminho.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Invalidação finalizada:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d5zSs3Ul--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0b0byhhilyeabqza0be7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d5zSs3Ul--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0b0byhhilyeabqza0be7.png" alt="Image description" width="880" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora é simples, basta voltar ao endereço da CDN, atualizar a página e o novo conteúdo será entregue ao cliente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--__z51-Z4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c7dzh9rt9mxzemzizfa6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--__z51-Z4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c7dzh9rt9mxzemzizfa6.png" alt="Image description" width="880" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/d31w24psGYeekCZy/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/d31w24psGYeekCZy/giphy.gif" width="480" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ideias de próximos passos:
&lt;/h2&gt;

&lt;p&gt;E talvez até mesmo artigo futuro… 🤔 O que acha?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatize via CI/CD o fluxo de upload dos arquivos para o S3 e invalidação do cache do CloudFront, utilize-o para entregar suas funcionalidades e correções com agilidade e/ou testar as MRs/PRs durante o desenvolvimento;&lt;/li&gt;
&lt;li&gt;Configure a segurança utilizando Lambda@Edge para definir CSP — Content Security Policy. Duas ferramentas úteis para auxiliar na depuração: &lt;a href="https://observatory.mozilla.org/"&gt;Mozila Observatory&lt;/a&gt; e &lt;a href="https://csp-evaluator.withgoogle.com/"&gt;Google CSP Evaluator&lt;/a&gt;;
Configure a distribuição para navegar corretamente entre as rotas de um SPA;&lt;/li&gt;
&lt;li&gt;Crie uma stack IaC (Infrastructure as Code) e evite configurações manuais via console da AWS sempre que precisar de uma nova CDN, faça deploy em poucos minutos com apenas alguns comandos. Ferramentas que podem auxiliar: &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt;, &lt;a href="https://www.serverless.com/"&gt;Serverless Framework&lt;/a&gt; ou &lt;a href="https://aws.amazon.com/pt/cloudformation/"&gt;AWS CloudFormation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Fique por dentro das novidades
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UCSVbLbpdFImwC9T7v7FH3hg"&gt;Se inscreva em meu canal do Youtube para acompanhar tutoriais.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>cloudnative</category>
      <category>cdn</category>
    </item>
  </channel>
</rss>
