tutoriales.com

Gestionando Certificados TLS/SSL con Terraform y AWS Certificate Manager (ACM)

Este tutorial te guiará a través del proceso de aprovisionar y gestionar certificados TLS/SSL utilizando Terraform y AWS Certificate Manager (ACM). Cubriremos la creación de certificados, la validación de dominios y la integración con servicios como Load Balancers y CloudFront. Automatiza la seguridad de tus aplicaciones web.

Intermedio20 min de lectura4 views
Reportar error

🚀 Introducción a los Certificados TLS/SSL y ACM

En el mundo digital actual, la seguridad es primordial. Los certificados TLS/SSL son esenciales para establecer conexiones seguras entre los navegadores de los usuarios y tus aplicaciones web, protegiendo los datos en tránsito mediante cifrado. AWS Certificate Manager (ACM) simplifica la gestión de estos certificados, ofreciendo certificados públicos y privados de forma gratuita para usar con otros servicios de AWS.

Tradicionalmente, la gestión de certificados implica generar CSRs (Certificate Signing Requests), comprarlos de una CA (Certificate Authority), subirlos y renovarlos manualmente. Este proceso puede ser tedioso y propenso a errores. Con Terraform y ACM, podemos automatizar completamente el ciclo de vida de nuestros certificados, garantizando que nuestras aplicaciones siempre operen bajo HTTPS de manera eficiente y segura.

¿Por qué Terraform para ACM?

La infraestructura como código (IaC) con Terraform nos permite definir, versionar y desplegar nuestra infraestructura de certificados de manera declarativa. Esto aporta múltiples beneficios:

  • Automatización: Elimina tareas manuales repetitivas.
  • Consistencia: Asegura que los certificados se desplieguen de la misma manera en todos los entornos.
  • Versionamiento: Permite rastrear cambios y revertir a versiones anteriores si es necesario.
  • Colaboración: Facilita el trabajo en equipo en la gestión de la seguridad.
  • Auditoría: Ofrece un registro claro de cómo se gestionan los certificados.
💡 Consejo: Usar Terraform para ACM no solo simplifica la gestión, sino que también reduce el riesgo de errores humanos y mejora la postura de seguridad de tu infraestructura.

📋 Prerrequisitos

Antes de empezar, asegúrate de tener lo siguiente:

  • Una cuenta de AWS activa con credenciales configuradas.
  • Terraform instalado en tu máquina local (versión 0.13 o superior).
  • Conocimientos básicos de AWS y Terraform.
  • Un dominio registrado en Route 53 (o cualquier otro registrador de dominios si puedes gestionar sus registros DNS).

🛠️ Configuración Inicial de Terraform y AWS

Primero, necesitamos configurar nuestro archivo main.tf para indicar a Terraform que utilice el proveedor de AWS.

# main.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
  required_version = ">= 1.0.0"
}

provider "aws" {
  region = "us-east-1"
}

variable "domain_name" {
  description = "El nombre de dominio principal para el certificado."
  type        = string
}

variable "alternative_names" {
  description = "Una lista de nombres de dominio alternativos (SANs)."
  type        = list(string)
  default     = []
}

variable "validation_method" {
  description = "Método de validación del certificado (DNS o EMAIL)."
  type        = string
  default     = "DNS"
  validation {
    condition     = contains(["DNS", "EMAIL"], var.validation_method)
    error_message = "El método de validación debe ser 'DNS' o 'EMAIL'."
  }
}

output "certificate_arn" {
  description = "El ARN del certificado SSL/TLS emitido."
  value       = aws_acm_certificate.my_certificate.arn
}

output "certificate_status" {
  description = "El estado actual del certificado."
  value       = aws_acm_certificate.my_certificate.status
}

Este main.tf establece el proveedor de AWS en la región us-east-1 (ACM es un servicio regional y muchos de sus usos, como con CloudFront, requieren que esté en us-east-1). Define variables para el nombre de dominio principal, nombres alternativos y el método de validación. También exporta el ARN y el estado del certificado.

⚠️ Advertencia: Para CloudFront, los certificados ACM DEBEN ser creados en la región `us-east-1` (N. Virginia), independientemente de la región donde se despliegue tu CloudFront. Para otros servicios como ELB/ALB, pueden estar en la misma región que el balanceador de carga.

🔑 Creación del Certificado ACM

El primer paso es solicitar el certificado a ACM. Añade el siguiente bloque de recursos a tu main.tf.

# Solicitar un certificado ACM
resource "aws_acm_certificate" "my_certificate" {
  domain_name               = var.domain_name
  subject_alternative_names = var.alternative_names
  validation_method         = var.validation_method

  lifecycle {
    create_before_destroy = true
  }

  tags = {
    Environment = "Production"
    Project     = "MyWebApp"
  }
}
  • domain_name: El dominio principal para el cual solicitas el certificado (ej. example.com).
  • subject_alternative_names: Una lista opcional de dominios adicionales (SANs) que el certificado cubrirá (ej. *.example.com, app.example.com).
  • validation_method: Cómo se validará la propiedad del dominio. DNS es el método preferido para automatización con Terraform.
  • lifecycle { create_before_destroy = true }: Esta es una configuración crucial. Asegura que Terraform cree un nuevo certificado antes de destruir el antiguo. Esto es vital para evitar interrupciones del servicio al renovar o reemplazar certificados.

🌐 Validación del Dominio con DNS

Para que ACM emita un certificado, debe verificar que eres el propietario o tienes control sobre el dominio para el que solicitas el certificado. El método de validación DNS es el más automatizable y robusto. Si tu dominio está gestionado en Route 53, Terraform puede crear automáticamente los registros DNS de validación.

Caso 1: Dominio en Route 53

Si tu dominio está en Route 53, puedes usar aws_route53_zone y aws_route53_record para crear los registros CNAME necesarios para la validación.

Primero, necesitamos obtener la zona de Route 53 para nuestro dominio.

# Data source para obtener la Hosted Zone de Route 53
data "aws_route53_zone" "selected_zone" {
  name         = "${var.domain_name}."
  private_zone = false
}

Luego, creamos los registros CNAME de validación. ACM generará un registro CNAME por cada dominio/subdominio que deba ser validado.

# Creación de registros DNS para la validación de ACM
resource "aws_route53_record" "acm_validation" {
  for_each = {
    for dvo in aws_acm_certificate.my_certificate.domain_validation_options : dvo.domain_name => dvo
  }

  allow_overwrite = true
  name            = each.value.resource_record_name
  type            = each.value.resource_record_type
  records         = [each.value.resource_record_value]
  ttl             = 60
  zone_id         = data.aws_route53_zone.selected_zone.zone_id
}

El for_each itera sobre domain_validation_options que ACM proporciona. Cada opción contiene el resource_record_name (el nombre del CNAME), resource_record_type (CNAME) y resource_record_value (el valor al que apunta el CNAME).

Finalmente, necesitamos un recurso para esperar a que el certificado esté completamente validado y emitido.

# Esperar la validación del certificado
resource "aws_acm_certificate_validation" "certificate_validation" {
  certificate_arn         = aws_acm_certificate.my_certificate.arn
  validation_record_fqdns = [for record in aws_route53_record.acm_validation : record.fqdn]

  # Depende de los registros DNS para asegurar que se creen antes de la validación
  depends_on = [
    aws_route53_record.acm_validation
  ]
}

Este recurso aws_acm_certificate_validation esperará hasta que el estado del certificado sea ISSUED, lo que significa que la validación se ha completado con éxito y el certificado está listo para usar.

Caso 2: Dominio fuera de Route 53

Si tu dominio no está en Route 53, tendrás que crear los registros CNAME manualmente en el registrador DNS de tu dominio. Terraform solicitará el certificado y te proporcionará los detalles del registro CNAME, pero no podrá crearlos por ti.

El bloque aws_acm_certificate sigue siendo el mismo. Para obtener los valores CNAME necesarios, puedes usar un output o inspeccionar el estado de Terraform después de terraform apply:

output "cname_records_for_manual_validation" {
  description = "Registros CNAME para configurar manualmente si el dominio no está en Route 53."
  value = [
    for dvo in aws_acm_certificate.my_certificate.domain_validation_options : {
      name  = dvo.resource_record_name
      type  = dvo.resource_record_type
      value = dvo.resource_record_value
    }
  ]
}

Una vez que hayas añadido estos registros CNAME en tu registrador DNS, ACM detectará los registros y validará el dominio automáticamente. No necesitarías el recurso aws_acm_certificate_validation en este caso, ya que Terraform no puede interactuar con un registrador DNS externo para confirmar la validación.


🔗 Integración del Certificado con Servicios AWS

Una vez que el certificado ha sido emitido, puedes asociarlo con varios servicios de AWS para habilitar HTTPS.

1. Con un Application Load Balancer (ALB)

La forma más común de usar certificados ACM es con un balanceador de carga (ALB/NLB) para terminar el TLS. Aquí tienes un ejemplo de cómo configurar un Listener HTTPS para un ALB.

# Ejemplo de integración con un Application Load Balancer

# Asume que ya tienes un ALB y Target Group definidos
resource "aws_lb" "example_lb" {
  name               = "my-example-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = ["sg-xxxxxxxx"]
  subnets            = ["subnet-xxxxxxxx", "subnet-yyyyyyyy"]
  enable_deletion_protection = false

  tags = {
    Name = "MyExampleALB"
  }
}

resource "aws_lb_target_group" "example_tg" {
  name     = "my-example-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = "vpc-xxxxxxxx"
}

resource "aws_lb_listener" "https_listener" {
  load_balancer_arn = aws_lb.example_lb.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = aws_acm_certificate_validation.certificate_validation.certificate_arn # Usa el ARN del certificado validado

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.example_tg.arn
  }
}

# (Opcional) Redireccionar HTTP a HTTPS
resource "aws_lb_listener" "http_listener" {
  load_balancer_arn = aws_lb.example_lb.arn
  port              = 80
  protocol          = "HTTP"

  default_action {
    type        = "redirect"
    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}
🔥 Importante: La `ssl_policy` define los protocolos TLS y cifrados que el ALB permitirá. Es crucial elegir una política moderna y segura. `ELBSecurityPolicy-2016-08` es un buen punto de partida, pero revisa siempre las últimas recomendaciones de seguridad de AWS.

2. Con Amazon CloudFront

Para sitios web servidos globalmente, CloudFront es la elección ideal. Los certificados ACM asociados a distribuciones de CloudFront deben crearse en la región us-east-1 (N. Virginia). Ya hemos configurado nuestro provider y aws_acm_certificate para usar esta región.

# Ejemplo de integración con CloudFront Distribution

# Asume que ya tienes un bucket S3 para tu origen o un ALB como origen
resource "aws_s3_bucket" "origin_bucket" {
  bucket = "my-cloudfront-origin-bucket-${random_string.suffix.result}"
  tags = {
    Name = "MyCloudFrontOriginBucket"
  }
}

resource "random_string" "suffix" {
  length  = 8
  special = false
  upper   = false
}

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.origin_bucket.bucket_regional_domain_name
    origin_id   = "S3-my-origin"

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.default.cloudfront_access_identity_path
    }
  }

  enabled             = true
  is_ipv6_enabled     = true
  comment             = "My S3 CloudFront distribution"
  default_root_object = "index.html"

  aliases = [var.domain_name] # Aquí se asocia tu dominio personalizado

  default_cache_behavior {
    allowed_methods        = ["GET", "HEAD", "OPTIONS"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = "S3-my-origin"
    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }
  }

  # Configuración SSL/TLS para CloudFront
  viewer_certificate {
    cloudfront_default_certificate = false
    acm_certificate_arn            = aws_acm_certificate_validation.certificate_validation.certificate_arn # ARN del certificado validado
    ssl_support_method             = "sni-only"
    minimum_protocol_version       = "TLSv1.2_2021"
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  tags = {
    Environment = "Production"
  }
}

resource "aws_cloudfront_origin_access_identity" "default" {
  comment = "OAI for S3 bucket"
}

# (Opcional) Crear un registro ALIAS en Route 53 para apuntar al CloudFront Distribution
resource "aws_route53_record" "domain_to_cloudfront" {
  zone_id = data.aws_route53_zone.selected_zone.zone_id
  name    = var.domain_name
  type    = "A"

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

En la sección viewer_certificate de la distribución de CloudFront, especificamos acm_certificate_arn con el ARN de nuestro certificado validado. ssl_support_method = "sni-only" es el método más común y recomendado.


🔄 Renovación y Ciclo de Vida del Certificado

Una de las mayores ventajas de usar ACM es su capacidad de renovar automáticamente los certificados antes de que expiren. Esto es transparente para el usuario final y para Terraform, siempre y cuando la validación DNS se mantenga vigente. Si usaste la validación DNS con Route 53 y Terraform, los registros necesarios para la renovación se mantienen y ACM se encarga del resto.

📌 Nota: Para la renovación automática, es crucial que los registros CNAME de validación permanezcan en tu configuración DNS. Si los eliminas, ACM no podrá revalidar el dominio para la renovación.

El lifecycle { create_before_destroy = true } en el recurso aws_acm_certificate es fundamental para una renovación o reemplazo manual sin interrupciones. Cuando un certificado está a punto de expirar o necesitas reemplazarlo por cualquier motivo (por ejemplo, añadir un nuevo SAN), si modificas el recurso aws_acm_certificate en Terraform, éste solicitará un nuevo certificado y lo validará, y solo una vez que el nuevo certificado esté listo, Terraform lo asociará a los servicios dependientes y eliminará el certificado antiguo.

📊 Diagrama de Flujo del Proceso

Veamos un diagrama que ilustra el flujo de trabajo completo.

1. Iniciar Terraform Apply Recurso: aws_acm_certificate 2. ACM emite Opciones de Validación Atributo: domain_validation_options 3. Terraform crea Registros DNS Recurso: aws_route53_record (CNAME) 4. Validación de Propagación ACM detecta y valida registros CNAME 5. aws_acm_certificate_validation Terraform espera estado: ISSUED 6. Certificado Validado Disponible para su uso en AWS 7. Actualización de Recursos Asignación de certificate_arn a ALB/CloudFront

🗑️ Limpieza de Recursos

Para evitar cargos inesperados, es importante limpiar los recursos de AWS una vez que hayas terminado con este tutorial. Puedes hacerlo ejecutando:

terraform destroy

Este comando eliminará todos los recursos de AWS que Terraform ha creado.

⚠️ Advertencia: Asegúrate de revisar el plan de `terraform destroy` cuidadosamente antes de confirmar, para evitar eliminar recursos que no deseas.

✅ Conclusión

Hemos recorrido el proceso completo para gestionar certificados TLS/SSL con Terraform y AWS Certificate Manager. Desde la solicitud inicial del certificado y la automatización de la validación DNS con Route 53, hasta la integración con servicios clave como Application Load Balancers y CloudFront. Esta aproximación garantiza una gestión de certificados eficiente, segura y totalmente automatizada, eliminando la carga de las tareas manuales y reduciendo el riesgo de errores.

La infraestructura como código no es solo para servidores y redes; es una práctica fundamental para cada componente de tu arquitectura en la nube, incluida la seguridad y los certificados.

Tutorial Completado

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!