Dominio y certificado
Al final de este módulo producción sirve en tu subdominio, con HTTPS y un certificado que se renueva solo.
Con participante = "p01", el sitio queda en p01.workshop.v0x.site.
Paso 7.1 · Aplicar producción sin dominio
Sección titulada «Paso 7.1 · Aplicar producción sin dominio»Objetivo: comprobar que el stack completo funciona antes de meter DNS en la ecuación.
cd taskflow-p01-infra/envs/prodcp terraform.tfvars.example terraform.tfvarsCambia dos valores y deja base_domain vacío por ahora:
participante = "p01"deploy_role_name = "taskflow-p01-deploy-prod"base_domain = ""Inicializa con el mismo bucket de estado que dev, y aplica:
cd ../..make init ENV=prod STATE_BUCKET=taskflow-p01-tfstate-123456789012make apply ENV=prodmake output ENV=prodQué deberías ver: otra site_url de CloudFront, distinta de la de dev. Ahora tienes
dos entornos completamente separados: distinto bucket, distinta distribución, distinto
rol y distinto estado.
Paso 7.2 · Activar el dominio
Sección titulada «Paso 7.2 · Activar el dominio»Objetivo: decirle a Terraform cuál es tu subdominio y en qué zona de Route 53 vive.
La zona workshop.v0x.site ya existe en Route 53 (la creó el instructor). Con
dns_mode = "route53", Terraform administra todo el DNS por ti: crea los registros de
validación del certificado, espera a que ACM lo emita y crea el alias del subdominio.
base_domain = "workshop.v0x.site"dns_mode = "route53"route53_zone_id = "Z0123456789ABCDEFGHIJ" # el instructor te lo daQué deberías ver: nada todavía, es solo configuración.
Paso 7.3 · Aplicar con el dominio
Sección titulada «Paso 7.3 · Aplicar con el dominio»Objetivo: emitir el certificado, validarlo y asociarlo a la distribución, en un solo paso.
make apply ENV=prodTerraform crea el certificado ACM, escribe el registro CNAME de validación en la zona
de Route 53, y se queda esperando en aws_acm_certificate_validation a que ACM
compruebe el registro. Suele tardar entre dos y diez minutos. No tienes que crear ningún
registro a mano: al estar la zona en Route 53, todo el flujo es automático.
Qué deberías ver: el apply termina; el certificado queda emitido y asociado a la distribución, y el alias de tu subdominio ya apunta a CloudFront.
Paso 7.4 · Comprobar el subdominio
Sección titulada «Paso 7.4 · Comprobar el subdominio»Objetivo: confirmar que tu subdominio resuelve a CloudFront.
make output ENV=prodVerás site_url con tu subdominio (https://p01.workshop.v0x.site) y dns_target con
el dominio de la distribución. El alias ya lo creó Terraform, así que el subdominio debe
resolver en pocos minutos (propagación del cambio en Route 53).## Paso 7.7 · Comprobar
Objetivo: verificar HTTPS, cabeceras de seguridad y el fallback de rutas.
curl -sI https://p01.workshop.v0x.site | head -12Qué deberías ver:
HTTP/2 200strict-transport-securitypresentex-content-type-options: nosniff- una cabecera
x-cachede CloudFront
Y en el navegador, recargar https://p01.workshop.v0x.site/tareas/<id> tiene que
funcionar. Si da 403, el arreglo del paso 6.6 no está aplicado en producción: revisa que
descomentaste los bloques en el módulo, que es compartido por los dos entornos, y que
aplicaste ENV=prod.
Ver el stack de producción completo
locals { # Tu subdominio. Cada participante obtiene el suyo bajo el mismo dominio de # prueba: p01.workshop.v0x.site, aperez.workshop.v0x.site, y así. # # Si base_domain está vacío, producción también cae al dominio por defecto de # CloudFront. Sirve para probar el stack completo antes de tener DNS listo. domain_name = var.base_domain == "" ? "" : "${var.participante}.${var.base_domain}"}
module "hosting" { source = "../../modules/spa-hosting"
providers = { aws = aws aws.us_east_1 = aws.us_east_1 }
project = var.project participante = var.participante environment = "prod"
domain_name = local.domain_name dns_mode = var.dns_mode route53_zone_id = var.route53_zone_id
price_class = var.price_class
tags = var.tags}
# ---------------------------------------------------------------------------# Permisos del rol de despliegue de producción## Idéntico en forma al de dev, pero apuntando a otro bucket y otra distribución.# Son dos roles distintos precisamente para que el pipeline de dev no pueda# escribir en producción por error ni por descuido.# ---------------------------------------------------------------------------
data "aws_iam_policy_document" "deploy" { statement { sid = "SincronizarSitio" effect = "Allow"
actions = [ "s3:PutObject", "s3:DeleteObject", "s3:GetObject", ]
resources = ["${module.hosting.bucket_arn}/*"] }
statement { sid = "ListarBucket" effect = "Allow"
actions = ["s3:ListBucket"] resources = [module.hosting.bucket_arn] }
statement { sid = "InvalidarCache" effect = "Allow"
actions = [ "cloudfront:CreateInvalidation", "cloudfront:GetInvalidation", ]
resources = [module.hosting.distribution_arn] }}
resource "aws_iam_role_policy" "deploy" { name = "${var.project}-${var.participante}-prod-deploy" role = var.deploy_role_name policy = data.aws_iam_policy_document.deploy.json}El subdominio se compone en un local, no se escribe a mano:
domain_name = var.base_domain == "" ? "" : "${var.participante}.${var.base_domain}"Con base_domain vacío, producción también cae al dominio por defecto de CloudFront.
Eso es lo que permitió el paso 7.1.
Qué te dio el certificado
Sección titulada «Qué te dio el certificado»Con domain_name configurado, el módulo activa además HSTS. Es dinámico a propósito: el
dominio por defecto de CloudFront es compartido entre muchos clientes, y fijarle una
política HSTS afectaría a terceros. Con dominio propio, en cambio, tiene todo el
sentido.
Y la renovación es automática mientras el registro de validación siga existiendo en el DNS. Nadie tiene que acordarse de renovar nada, que es el otro recordatorio de por qué salimos de nginx en una instancia.
Resumen de comandos
Sección titulada «Resumen de comandos»# producción sin dominiocd envs/prod && cp terraform.tfvars.example terraform.tfvars # editarcd ../.. && make init ENV=prod STATE_BUCKET=<bucket-de-estado>make apply ENV=prod
# activar el dominio: en envs/prod/terraform.tfvars poner# base_domain = "workshop.v0x.site"# dns_mode = "route53"# route53_zone_id = "<zona que te dio el instructor>"make apply ENV=prod # crea validación + alias y espera a ACMmake output ENV=prod # site_url y dns_target
curl -sI https://p01.workshop.v0x.site | head -12Ahora automatizamos el despliegue.