DevOps

Route53, CloudFront e ACM: Rede e Entrega de Conteúdo Já leu

17 min de leitura

Route53, CloudFront e ACM: Rede e Entrega de Conteúdo
Uma aplicação pode estar perfeitamente construída — código limpo, banco de dados otimizado, infraestrutura resiliente — e ainda assim oferecer uma experiência ruim ao usuário se a camada de entrega não estiver bem config

Uma aplicação pode estar perfeitamente construída — código limpo, banco de dados otimizado, infraestrutura resiliente — e ainda assim oferecer uma experiência ruim ao usuário se a camada de entrega não estiver bem configurada. Latência alta por distância geográfica, certificados SSL expirados, DNS mal configurado, ausência de cache para conteúdo estático — esses problemas são invisíveis para quem desenvolve localmente e devastadores para quem usa o sistema em produção.

Os três serviços abordados neste artigo formam a camada de entrega da AWS: o Route53 gerencia o DNS, o CloudFront distribui o conteúdo globalmente com baixa latência, e o ACM provê e renova certificados SSL/TLS automaticamente. Juntos, eles fazem com que uma requisição de São Paulo para uma aplicação hospedada em us-east-1 seja respondida com baixa latência, com HTTPS e com os headers de segurança corretos.


Route53: DNS como Infraestrutura

O Route53 é o serviço de DNS da AWS — altamente disponível, distribuído globalmente e integrado nativamente com os demais serviços AWS. A diferença fundamental entre o Route53 e um provedor de DNS tradicional é a capacidade de usar alias records — registros que apontam diretamente para recursos AWS como load balancers, distribuições CloudFront e buckets S3, resolvendo automaticamente para os IPs corretos sem custo de query.

Conceitos Fundamentais

Hosted Zone — o container que agrupa todos os registros DNS de um domínio. Uma hosted zone pública é acessível pela internet. Uma hosted zone privada é acessível apenas dentro de uma VPC — útil para nomes de serviços internos.

Record Types — os tipos de registro mais relevantes na AWS:

A — mapeia um nome para um endereço IPv4. Usado para apontar diretamente para IPs.

AAAA — mapeia um nome para um endereço IPv6.

CNAME — mapeia um nome para outro nome (canonical name). Não pode ser usado na raiz do domínio — empresa.com não pode ter um CNAME, mas www.empresa.com pode.

ALIAS — extensão proprietária do Route53 que se comporta como um CNAME mas pode ser usado na raiz do domínio e não gera custo de query quando aponta para recursos AWS.

MX — registros de email, apontando para servidores de correio.

TXT — texto livre, usado para verificação de domínio (Google Search Console, SPF, DKIM).

Configurando DNS com Terraform

# dns.tf

# Hosted Zone pública para o domínio principal
resource "aws_route53_zone" "principal" {
  name    = var.domain_name
  comment = "Hosted zone principal — ${var.project_name}"

  tags = local.tags_comuns
}

# Registro raiz apontando para o CloudFront
resource "aws_route53_record" "raiz" {
  zone_id = aws_route53_zone.principal.zone_id
  name    = var.domain_name
  type    = "A"

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

# Registro www com redirect para raiz
resource "aws_route53_record" "www" {
  zone_id = aws_route53_zone.principal.zone_id
  name    = "www.${var.domain_name}"
  type    = "A"

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

# Registro de API apontando para o ALB
resource "aws_route53_record" "api" {
  zone_id = aws_route53_zone.principal.zone_id
  name    = "api.${var.domain_name}"
  type    = "A"

  alias {
    name                   = aws_lb.aplicacao.dns_name
    zone_id                = aws_lb.aplicacao.zone_id
    evaluate_target_health = true
  }
}

# Registro para ambiente de staging
resource "aws_route53_record" "staging" {
  zone_id = aws_route53_zone.principal.zone_id
  name    = "staging.${var.domain_name}"
  type    = "A"

  alias {
    name                   = aws_lb.staging.dns_name
    zone_id                = aws_lb.staging.zone_id
    evaluate_target_health = true
  }
}

# Hosted Zone privada para serviços internos
resource "aws_route53_zone" "interna" {
  name = "interno.${var.domain_name}"

  vpc {
    vpc_id = module.vpc.vpc_id
  }

  tags = local.tags_comuns
}

# Registro interno para o banco de dados
# Permite trocar o endpoint real sem alterar a configuração das aplicações
resource "aws_route53_record" "banco_dados" {
  zone_id = aws_route53_zone.interna.zone_id
  name    = "db.interno.${var.domain_name}"
  type    = "CNAME"
  ttl     = 60

  records = [aws_db_instance.principal.address]
}

# Registro interno para o Redis
resource "aws_route53_record" "redis" {
  zone_id = aws_route53_zone.interna.zone_id
  name    = "cache.interno.${var.domain_name}"
  type    = "CNAME"
  ttl     = 60

  records = [aws_elasticache_replication_group.redis.primary_endpoint_address]
}

Roteamento Avançado do Route53

O Route53 oferece políticas de roteamento que vão além do DNS simples. Para arquiteturas de alta disponibilidade e distribuição geográfica:

# Roteamento por latência — direciona para a região com menor latência
resource "aws_route53_record" "api_latencia_us" {
  zone_id        = aws_route53_zone.principal.zone_id
  name           = "api.${var.domain_name}"
  type           = "A"
  set_identifier = "us-east-1"

  latency_routing_policy {
    region = "us-east-1"
  }

  alias {
    name                   = aws_lb.api_us_east.dns_name
    zone_id                = aws_lb.api_us_east.zone_id
    evaluate_target_health = true
  }
}

resource "aws_route53_record" "api_latencia_eu" {
  zone_id        = aws_route53_zone.principal.zone_id
  name           = "api.${var.domain_name}"
  type           = "A"
  set_identifier = "eu-west-1"

  latency_routing_policy {
    region = "eu-west-1"
  }

  alias {
    name                   = aws_lb.api_eu_west.dns_name
    zone_id                = aws_lb.api_eu_west.zone_id
    evaluate_target_health = true
  }
}

# Health Check para failover automático
resource "aws_route53_health_check" "api_principal" {
  fqdn              = "api.${var.domain_name}"
  port              = 443
  type              = "HTTPS"
  resource_path     = "/health"
  failure_threshold = 3
  request_interval  = 30

  tags = merge(local.tags_comuns, {
    Name = "api-health-check"
  })
}

# Registro primário com health check
resource "aws_route53_record" "api_primario" {
  zone_id        = aws_route53_zone.principal.zone_id
  name           = "api.${var.domain_name}"
  type           = "A"
  set_identifier = "primario"

  failover_routing_policy {
    type = "PRIMARY"
  }

  health_check_id = aws_route53_health_check.api_principal.id

  alias {
    name                   = aws_lb.aplicacao.dns_name
    zone_id                = aws_lb.aplicacao.zone_id
    evaluate_target_health = true
  }
}

# Registro secundário — ativa automaticamente se o primário falha
resource "aws_route53_record" "api_secundario" {
  zone_id        = aws_route53_zone.principal.zone_id
  name           = "api.${var.domain_name}"
  type           = "A"
  set_identifier = "secundario"

  failover_routing_policy {
    type = "SECONDARY"
  }

  alias {
    name                   = aws_lb.dr_region.dns_name
    zone_id                = aws_lb.dr_region.zone_id
    evaluate_target_health = true
  }
}

ACM: Certificados SSL/TLS Gerenciados

O AWS Certificate Manager provê certificados SSL/TLS gratuitos para uso com serviços AWS. Os certificados são renovados automaticamente — sem o processo manual de renovação anual que historicamente causava incidentes por certificados expirados.

# acm.tf

# Certificado para o domínio principal e subdomínios
resource "aws_acm_certificate" "principal" {
  domain_name       = var.domain_name
  validation_method = "DNS"

  subject_alternative_names = [
    "*.${var.domain_name}",           # Todos os subdomínios
    "api.${var.domain_name}",
    "staging.${var.domain_name}",
  ]

  lifecycle {
    create_before_destroy = true
  }

  tags = local.tags_comuns
}

# Registros DNS para validação do certificado
resource "aws_route53_record" "acm_validacao" {
  for_each = {
    for dvo in aws_acm_certificate.principal.domain_validation_options :
    dvo.domain_name => {
      name   = dvo.resource_record_name
      type   = dvo.resource_record_type
      record = dvo.resource_record_value
    }
  }

  zone_id         = aws_route53_zone.principal.zone_id
  name            = each.value.name
  type            = each.value.type
  ttl             = 60
  records         = [each.value.record]
  allow_overwrite = true
}

# Aguarda a validação ser concluída
resource "aws_acm_certificate_validation" "principal" {
  certificate_arn         = aws_acm_certificate.principal.arn
  validation_record_fqdns = [for record in aws_route53_record.acm_validacao : record.fqdn]
}

# Certificado em us-east-1 — obrigatório para CloudFront
# CloudFront aceita apenas certificados criados em us-east-1
resource "aws_acm_certificate" "cloudfront" {
  provider          = aws.us_east_1
  domain_name       = var.domain_name
  validation_method = "DNS"

  subject_alternative_names = [
    "*.${var.domain_name}",
  ]

  lifecycle {
    create_before_destroy = true
  }

  tags = local.tags_comuns
}

resource "aws_acm_certificate_validation" "cloudfront" {
  provider                = aws.us_east_1
  certificate_arn         = aws_acm_certificate.cloudfront.arn
  validation_record_fqdns = [for record in aws_route53_record.acm_validacao : record.fqdn]
}

CloudFront: CDN Global com Edge Locations

O CloudFront é a CDN da AWS com mais de 600 pontos de presença (edge locations) distribuídos globalmente. Quando um usuário em São Paulo acessa um conteúdo servido pelo CloudFront, a requisição vai para o edge mais próximo — não para us-east-1 diretamente. O edge verifica se tem o conteúdo em cache; se sim, responde localmente; se não, busca na origem e armazena para requisições futuras.

Para aplicações web, o CloudFront serve múltiplos propósitos além do cache: terminação SSL, proteção contra DDoS via AWS Shield Standard (gratuito), georestrição de conteúdo, redirects HTTPS forçados e adição de headers de segurança.

# cloudfront.tf

# Origin Access Control — acesso seguro ao S3 pelo CloudFront
resource "aws_cloudfront_origin_access_control" "s3" {
  name                              = "${var.project_name}-${var.environment}-s3-oac"
  description                       = "OAC para acesso ao S3"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

# Cache Policy para assets estáticos — cache longo
resource "aws_cloudfront_cache_policy" "assets_estaticos" {
  name        = "${var.project_name}-assets-estaticos"
  comment     = "Cache de longa duração para assets com hash no nome"
  default_ttl = 86400     # 1 dia
  max_ttl     = 31536000  # 1 ano
  min_ttl     = 0

  parameters_in_cache_key_and_forwarded_to_origin {
    cookies_config {
      cookie_behavior = "none"
    }
    headers_config {
      header_behavior = "none"
    }
    query_strings_config {
      query_string_behavior = "none"
    }
    enable_accept_encoding_brotli = true
    enable_accept_encoding_gzip   = true
  }
}

# Cache Policy para a API — sem cache por padrão
resource "aws_cloudfront_cache_policy" "api_sem_cache" {
  name        = "${var.project_name}-api-sem-cache"
  comment     = "Sem cache para respostas dinâmicas da API"
  default_ttl = 0
  max_ttl     = 0
  min_ttl     = 0

  parameters_in_cache_key_and_forwarded_to_origin {
    cookies_config {
      cookie_behavior = "none"
    }
    headers_config {
      header_behavior = "none"
    }
    query_strings_config {
      query_string_behavior = "none"
    }
  }
}

# Origin Request Policy — headers a encaminhar para a origem
resource "aws_cloudfront_origin_request_policy" "api" {
  name    = "${var.project_name}-api-origin-policy"
  comment = "Encaminha headers relevantes para a API"

  cookies_config {
    cookie_behavior = "none"
  }

  headers_config {
    header_behavior = "whitelist"
    headers {
      items = [
        "Authorization",
        "Content-Type",
        "X-Request-ID",
        "X-Forwarded-For",
        "CloudFront-Viewer-Country",
      ]
    }
  }

  query_strings_config {
    query_string_behavior = "all"
  }
}

# Response Headers Policy — headers de segurança
resource "aws_cloudfront_response_headers_policy" "seguranca" {
  name    = "${var.project_name}-security-headers"
  comment = "Headers de segurança HTTP aplicados em todas as respostas"

  security_headers_config {
    content_security_policy {
      content_security_policy = join("; ", [
        "default-src 'self'",
        "script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net",
        "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
        "font-src 'self' https://fonts.gstatic.com",
        "img-src 'self' data: https:",
        "connect-src 'self' https://api.${var.domain_name}",
        "frame-ancestors 'none'",
      ])
      override = true
    }

    content_type_options {
      override = true
    }

    frame_options {
      frame_option = "DENY"
      override     = true
    }

    referrer_policy {
      referrer_policy = "strict-origin-when-cross-origin"
      override        = true
    }

    strict_transport_security {
      access_control_max_age_sec = 31536000
      include_subdomains         = true
      preload                    = true
      override                   = true
    }

    xss_protection {
      mode_block = true
      protection = true
      override   = true
    }
  }

  custom_headers_config {
    items {
      header   = "Permissions-Policy"
      value    = "camera=(), microphone=(), geolocation=()"
      override = true
    }
  }
}

# Distribuição CloudFront principal
resource "aws_cloudfront_distribution" "principal" {
  enabled             = true
  is_ipv6_enabled     = true
  comment             = "${var.project_name} ${var.environment}"
  default_root_object = "index.html"
  price_class         = "PriceClass_All"
  aliases             = [var.domain_name, "www.${var.domain_name}"]
  web_acl_id          = aws_wafv2_web_acl.cloudfront.arn

  # ── Origem 1: Assets estáticos no S3 ──────────────
  origin {
    origin_id                = "s3-assets"
    domain_name              = aws_s3_bucket.frontend.bucket_regional_domain_name
    origin_access_control_id = aws_cloudfront_origin_access_control.s3.id
  }

  # ── Origem 2: API no ALB ───────────────────────────
  origin {
    origin_id   = "alb-api"
    domain_name = aws_lb.aplicacao.dns_name

    custom_origin_config {
      http_port              = 80
      https_port             = 443
      origin_protocol_policy = "https-only"
      origin_ssl_protocols   = ["TLSv1.2"]

      origin_keepalive_timeout = 60
      origin_read_timeout      = 30
    }

    custom_header {
      name  = "X-CloudFront-Secret"
      value = var.cloudfront_origin_secret
    }
  }

  # ── Comportamento padrão: S3 com cache longo ───────
  default_cache_behavior {
    allowed_methods        = ["GET", "HEAD", "OPTIONS"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = "s3-assets"
    viewer_protocol_policy = "redirect-to-https"
    compress               = true

    cache_policy_id            = aws_cloudfront_cache_policy.assets_estaticos.id
    response_headers_policy_id = aws_cloudfront_response_headers_policy.seguranca.id
  }

  # ── Comportamento para a API: sem cache, encaminha tudo ─
  ordered_cache_behavior {
    path_pattern           = "/api/*"
    allowed_methods        = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = "alb-api"
    viewer_protocol_policy = "redirect-to-https"
    compress               = true

    cache_policy_id            = aws_cloudfront_cache_policy.api_sem_cache.id
    origin_request_policy_id   = aws_cloudfront_origin_request_policy.api.id
    response_headers_policy_id = aws_cloudfront_response_headers_policy.seguranca.id
  }

  # ── Comportamento para assets com hash: cache máximo ─
  ordered_cache_behavior {
    path_pattern     = "/static/*"
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "s3-assets"

    viewer_protocol_policy = "redirect-to-https"
    compress               = true

    cache_policy_id            = aws_cloudfront_cache_policy.assets_estaticos.id
    response_headers_policy_id = aws_cloudfront_response_headers_policy.seguranca.id
  }

  # SPA: redireciona 404 e 403 do S3 para index.html
  custom_error_response {
    error_code            = 404
    response_code         = 200
    response_page_path    = "/index.html"
    error_caching_min_ttl = 10
  }

  custom_error_response {
    error_code            = 403
    response_code         = 200
    response_page_path    = "/index.html"
    error_caching_min_ttl = 10
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    acm_certificate_arn      = aws_acm_certificate_validation.cloudfront.certificate_arn
    ssl_support_method       = "sni-only"
    minimum_protocol_version = "TLSv1.2_2021"
  }

  logging_config {
    include_cookies = false
    bucket          = "${aws_s3_bucket.cloudfront_logs.id}.s3.amazonaws.com"
    prefix          = "cloudfront/${var.environment}/"
  }

  tags = local.tags_comuns
}

# Bucket S3 para o frontend
resource "aws_s3_bucket" "frontend" {
  bucket = "${var.project_name}-${var.environment}-frontend"
  tags   = local.tags_comuns
}

resource "aws_s3_bucket_public_access_block" "frontend" {
  bucket                  = aws_s3_bucket.frontend.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# Política do bucket — permite acesso apenas pelo CloudFront OAC
resource "aws_s3_bucket_policy" "frontend" {
  bucket = aws_s3_bucket.frontend.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Sid    = "AllowCloudFrontOAC"
      Effect = "Allow"
      Principal = {
        Service = "cloudfront.amazonaws.com"
      }
      Action   = "s3:GetObject"
      Resource = "${aws_s3_bucket.frontend.arn}/*"
      Condition = {
        StringEquals = {
          "AWS:SourceArn" = aws_cloudfront_distribution.principal.arn
        }
      }
    }]
  })
}

Deploy do Frontend no CloudFront

O pipeline de deploy do frontend sincroniza os arquivos com o S3 e invalida o cache do CloudFront para que a nova versão seja servida imediatamente:

# .github/workflows/deploy-frontend.yml
name: Deploy Frontend

on:
  push:
    branches: [main]
    paths: ['frontend/**']

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

    defaults:
      run:
        working-directory: frontend

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: frontend/package-lock.json

      - name: Instala dependências
        run: npm ci

      - name: Build de produção
        run: npm run build
        env:
          VITE_API_URL: https://api.${{ vars.DOMAIN_NAME }}
          VITE_APP_VERSION: ${{ github.sha }}

      - name: Configura credenciais AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
          aws-region: us-east-1

      - name: Sincroniza assets estáticos com cache longo
        run: |
          # Assets com hash no nome — cache de 1 ano
          aws s3 sync dist/assets/ \
            s3://${{ vars.FRONTEND_BUCKET }}/assets/ \
            --cache-control "public, max-age=31536000, immutable" \
            --delete

      - name: Sincroniza HTML e arquivos de configuração
        run: |
          # HTML e outros arquivos sem hash — sem cache
          aws s3 sync dist/ \
            s3://${{ vars.FRONTEND_BUCKET }}/ \
            --exclude "assets/*" \
            --cache-control "no-cache, no-store, must-revalidate" \
            --delete

      - name: Invalida cache do CloudFront
        run: |
          INVALIDATION_ID=$(aws cloudfront create-invalidation \
            --distribution-id ${{ vars.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*" \
            --query 'Invalidation.Id' \
            --output text)

          echo "Invalidação criada: $INVALIDATION_ID"

          # Aguarda a invalidação completar
          aws cloudfront wait invalidation-completed \
            --distribution-id ${{ vars.CLOUDFRONT_DISTRIBUTION_ID }} \
            --id $INVALIDATION_ID

          echo "Cache invalidado com sucesso"

      - name: Verifica deploy
        run: |
          sleep 10
          STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
            https://${{ vars.DOMAIN_NAME }})

          if [ "$STATUS" != "200" ]; then
            echo "ERRO: Site retornou status $STATUS"
            exit 1
          fi

          echo "Deploy verificado — status $STATUS"

WAF: Proteção da Camada de Aplicação

O AWS WAF (Web Application Firewall) protege o CloudFront contra ataques comuns na camada de aplicação — SQL injection, XSS, bots maliciosos, requisições de IPs com reputação ruim:

# waf.tf

resource "aws_wafv2_web_acl" "cloudfront" {
  provider = aws.us_east_1  # WAF para CloudFront deve ser em us-east-1
  name     = "${var.project_name}-${var.environment}-waf"
  scope    = "CLOUDFRONT"

  default_action {
    allow {}
  }

  # ── Regras gerenciadas pela AWS ────────────────────

  # Proteção contra ameaças comuns (OWASP Top 10)
  rule {
    name     = "aws-managed-common-rules"
    priority = 10

    override_action { none {} }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesCommonRuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "aws-managed-common"
      sampled_requests_enabled   = true
    }
  }

  # Proteção contra bots maliciosos
  rule {
    name     = "aws-managed-bot-control"
    priority = 20

    override_action { none {} }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesBotControlRuleSet"
        vendor_name = "AWS"

        managed_rule_group_configs {
          aws_managed_rules_bot_control_rule_set {
            inspection_level = "COMMON"
          }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "aws-managed-bot-control"
      sampled_requests_enabled   = true
    }
  }

  # ── Regras customizadas ────────────────────────────

  # Rate limiting global — máximo de 1000 req/5min por IP
  rule {
    name     = "rate-limit-global"
    priority = 30

    action { block {} }

    statement {
      rate_based_statement {
        limit              = 1000
        aggregate_key_type = "IP"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "rate-limit-global"
      sampled_requests_enabled   = true
    }
  }

  # Rate limiting agressivo no endpoint de autenticação
  rule {
    name     = "rate-limit-auth"
    priority = 25

    action { block {} }

    statement {
      rate_based_statement {
        limit              = 50
        aggregate_key_type = "IP"

        scope_down_statement {
          byte_match_statement {
            field_to_match {
              uri_path {}
            }
            positional_constraint = "STARTS_WITH"
            search_string         = "/api/auth"
            text_transformation {
              priority = 0
              type     = "LOWERCASE"
            }
          }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "rate-limit-auth"
      sampled_requests_enabled   = true
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "${var.project_name}-waf"
    sampled_requests_enabled   = true
  }

  tags = local.tags_comuns
}

Outputs e Configurações para a Aplicação

# outputs.tf

output "cloudfront_url" {
  description = "URL da distribuição CloudFront"
  value       = "https://${aws_cloudfront_distribution.principal.domain_name}"
}

output "url_producao" {
  description = "URL pública de produção"
  value       = "https://${var.domain_name}"
}

output "nameservers" {
  description = "Nameservers do Route53 — configurar no registrador de domínio"
  value       = aws_route53_zone.principal.name_servers
}

output "cloudfront_distribution_id" {
  description = "ID da distribuição CloudFront — necessário para invalidação de cache"
  value       = aws_cloudfront_distribution.principal.id
}

output "frontend_bucket" {
  description = "Nome do bucket S3 do frontend"
  value       = aws_s3_bucket.frontend.id
}

Encerrando o Módulo 7

Com este artigo encerra-se o Módulo 7 — AWS em Profundidade. Foram cobertos os serviços fundamentais de computação, banco de dados, cache e rede que formam a espinha dorsal de qualquer aplicação de produção na AWS: EC2 com suas famílias e ciclo de vida, ECS e Lambda para computação gerenciada, RDS e ElastiCache para dados e caching, e Route53, CloudFront e ACM para entrega e segurança.

O Módulo 8 aborda Kubernetes — o orquestrador de containers que, quando a escala e a complexidade justificam, oferece controle e flexibilidade além do que os serviços gerenciados da AWS proporcionam isoladamente.


Referências para Aprofundamento

Documentação oficial AWS - Amazon Route53 Documentation — docs.aws.amazon.com — Documentação completa do Route53, incluindo tipos de registros, políticas de roteamento e health checks. - Amazon CloudFront Documentation — docs.aws.amazon.com — Referência completa do CloudFront, cobrindo origens, behaviors, cache policies e funções Lambda@Edge. - AWS Certificate Manager — docs.aws.amazon.com — Documentação do ACM com guia de validação DNS, renovação automática e integração com serviços AWS.

Segurança - AWS WAF Documentation — docs.aws.amazon.com — Documentação completa do WAF, incluindo regras gerenciadas, rate limiting e integração com CloudFront e ALB. - OWASP Secure Headers Project — owasp.org — Referência completa dos headers de segurança HTTP recomendados pelo OWASP, com valores recomendados e explicações de cada header.

Performance - CloudFront Cache Optimization — docs.aws.amazon.com — Guia oficial para maximizar o cache hit ratio do CloudFront, incluindo configuração de TTLs, compressão e cache policies.

Comentários

Mais em DevOps

Semantic Versioning e Tags de Release
Semantic Versioning e Tags de Release

Imagine receber uma mensagem de um colega dizendo: "o bug está na vers...

Capstone: Provisionando a Infraestrutura Completa
Capstone: Provisionando a Infraestrutura Completa

Em projetos reais, a infraestrutura raramente é provisionada de uma vez. Ela...

Escrevendo um Dockerfile do Zero
Escrevendo um Dockerfile do Zero

Usar imagens prontas do Docker Hub é o ponto de partida. O passo seguinte — e...