Roger Felipe Nsk
open main menu
blog placeholder

Criar bucket S3 com CDN na AWS utilizando OpenTofu

/ 4 min read
Last updated:

Como Criar um Bucket S3 com CDN na AWS usando OpenTofu

No meu último artigo eu mostrei como criar uma função Lambda com uma API usando Nodejs, Api Gateway e OpenTofu e percebi que os áudios que utilizei no artigo, precisavam ser armazenados em algum local, então eu criei um bucket e conectei ao Cloudfront da AWS para servir os áutios. E nesse artigo eu irei mostrar como você pode fazer o mesmo.

Pré-requisitos

Certifique-se de ter as seguintes ferramentas instaladas em seu sistema:

  1. OpenTofu
  2. AWS-Cli

Opcional: Caso você queira utilizar um domínio personalizado, você precisa ter um domínio registrado e configurado no Route53.

Passo 1: Criar o projeto e os arquivos necessários

Crie um diretório chamado tofu no seu projeto:

Windows PowerShell Unix/Mac
mkdir tofu
cd tofu
type nul > main.tf
type nul > variables.tf
mkdir tofu
cd tofu
touch main.tf
touch variables.tf

Passo 2: Configurar o arquivo variables.tf

Obs: Você pode utilizar o nome de variáveis que achar melhor, só basta lembrar de alterar no arquivo main.tf também.

Sobre as variáveis:
variable "region" {
  description = "The AWS region to deploy resources in"
  type        = string
  default     = "us-east-1" # Altere para a região que deseja
}

variable "profile" {
  description = "Default AWS profile to use for deployment"
  type        = string
  default     = "meu_profile" # Altere para o seu profile
}

variable "blog_bucket_name" {
  description = "The name of the S3 bucket to create"
  type        = string
  default     = "meu_bucket" # Altere para o nome do seu bucket
}

variable "use_custom_domain" {
  description = "Determines whether to use a custom domain for the CloudFront distribution"
  type        = bool
  default     = true # Altere para false se não deseja utilizar um domínio personalizado
}

variable "route_53_zone_id" {
  description = "The Route 53 zone ID to use for the CloudFront distribution"
  type        = string
  default     = "zone_id" # Altere para o ID da sua zona no Route53
}

variable "audio_blog_alias" {
  description = "The alias to use for the CloudFront distribution"
  type        = string
  default     = "meu_sub_dominio" # Altere para o subdomínio que deseja
}

variable "certificate_acm_id" {
  description = "The ARN of the ACM certificate to use for the CloudFront distribution"
  type        = string
  default     = "acm_certificate_id" # Altere para o ID do certificado ACM
}

Passo 3: Configurar o arquivo main.tf

Sobre o arquivo principal:

Crie um arquivo main.tf com o seguinte conteúdo:

provider "aws" {
  region  = var.region
  profile = var.profile
}
data "aws_caller_identity" "current" {}

resource "aws_s3_bucket" "blog_bucket" {
  bucket = var.blog_bucket_name

  force_destroy = true

  tags = {
    Name = var.blog_bucket_name
  }
}

resource "aws_s3_bucket_public_access_block" "public_access_block" {
  bucket = aws_s3_bucket.blog_bucket.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
  comment = "OAI para o S3"
}

resource "aws_s3_bucket_policy" "blog_bucket_policy" {
  bucket = aws_s3_bucket.blog_bucket.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          AWS = aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn
        }
        Action   = "s3:GetObject"
        Resource = "${aws_s3_bucket.blog_bucket.arn}/*"
      },
    ]
  })
}
resource "aws_cloudfront_distribution" "blog_audios_distribution" {
  origin {
    domain_name = aws_s3_bucket.blog_bucket.bucket_regional_domain_name
    origin_id   = aws_s3_bucket.blog_bucket.bucket

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path
    }
  }

  enabled         = true
  is_ipv6_enabled = true
  comment         = "Distribuição CloudFront para os audios do blog"
  aliases         = var.use_custom_domain ? [var.audio_blog_alias] : []

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD", "OPTIONS"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = aws_s3_bucket.blog_bucket.bucket

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    acm_certificate_arn            = var.use_custom_domain ? "arn:aws:acm:${var.region}:${data.aws_caller_identity.current.account_id}:certificate/${var.certificate_acm_id}" : null
    ssl_support_method             = var.use_custom_domain ? "sni-only" : null
    minimum_protocol_version       = "TLSv1.2_2021"
    cloudfront_default_certificate = var.use_custom_domain ? null : true
  }
}

resource "aws_route53_record" "my_cloudfront_alias" {
  count = var.use_custom_domain ? 1 : 0

  depends_on = [aws_cloudfront_distribution.blog_audios_distribution]
  zone_id    = var.route_53_zone_id
  name       = var.audio_blog_alias
  type       = "A"

  alias {
    name                   = aws_cloudfront_distribution.blog_audios_distribution.domain_name
    zone_id                = aws_cloudfront_distribution.blog_audios_distribution.hosted_zone_id
    evaluate_target_health = false
  }
}

output "cloudfront_domain_name" {
  value = aws_cloudfront_distribution.blog_audios_distribution.domain_name
}

Passo 3: Deploy

Dentro da pasta tofu, execute os seguintes comandos para fazer o deploy:

tofu init
tofu plan
tofu apply

Após o deploy, você verá a URL da Distribuição do Cloudformation que está servindo os arquivos do seu bucket.

Algo parecido com cloudfront_id.cloudfront.net

Passo 4: Testando a distribuição

Para testar vamos subir um arquivo para o bucket e acessar a URL da distribuição.

aws s3 cp <caminho_do_arquivo> s3://<nome_do_bucket> --profile meu_profile

Após subir o arquivo, acesse a URL da distribuição no navegador.

Vamos supor que você realizou o upload de uma foto para o S3, ao acessar a url da distribuição, você verá a foto que subiu.

Passo 5: Destruindo a Infraestrutura após os testes

Para destruir a infraestrutura, execute o seguinte comando:

tofu destroy

Conclusão

Com isso agora posso servir meus arquivos de áudio de forma segura e rápida.