Este directorio contiene la infraestructura como código (IaC) para el sitio web de Python CDMX usando AWS.
┌──────────────────────┐
│ Route53 Hosted │
│ pythoncdmx.org │
└──────────┬───────────┘
│
┌──────────────┴──────────────┐
│ │
┌───────────▼──────────┐ ┌───────────▼──────────┐
│ pythoncdmx.org │ │ staging.pythoncdmx.org│
│ www.pythoncdmx.org │ │ (Testing) │
└───────────┬──────────┘ └───────────┬───────────┘
│ │
│ HTTPS (TLS 1.2+) │ HTTPS (TLS 1.2+)
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ CloudFront PROD │ │ CloudFront STAGING │
│ - ACM Certificate │ │ - ACM Certificate │
│ - Cache: 1h-24h │ │ - Cache: 5min-2h │
│ - Gzip/Brotli │ │ - Shorter TTL │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
│ OAC (SigV4) │ OAC (SigV4)
│ │
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ S3: pythoncdmx- │ │ S3: pythoncdmx- │
│ website (PROD) │ │ website-staging │
│ - Private │ │ - Private │
│ - Versioning │ │ - Versioning │
│ - AES256 │ │ - AES256 │
└──────────────────────┘ └──────────────────────┘
- Hosted Zone: pythoncdmx.org (existente, solo se agregan registros)
- Registros Production:
- A/AAAA:
pythoncdmx.org→ CloudFront PROD - A/AAAA:
www.pythoncdmx.org→ CloudFront PROD
- A/AAAA:
- Registros Staging:
- A/AAAA:
staging.pythoncdmx.org→ CloudFront STAGING
- A/AAAA:
- Validación ACM: Registros CNAME automáticos para certificados
- Nombre:
pythoncdmx-website - Acceso: Privado (solo CloudFront puede acceder)
- Características:
- ✅ Versioning habilitado
- ✅ Encriptación AES256
- ✅ Lifecycle: 90 días versiones antiguas
- ✅ CORS configurado
- Dominios: pythoncdmx.org, www.pythoncdmx.org
- Características:
- ✅ Certificado SSL/TLS (ACM)
- ✅ HTTP/2 y HTTP/3 habilitado
- ✅ Compresión Gzip/Brotli
- ✅ Cache optimizado (HTML: 10min, Assets: 24h, Images: 7d)
- ✅ IPv6 habilitado
- ✅ Origin Access Control (OAC)
- Región: us-east-1 (requerido para CloudFront)
- Validación: DNS automática vía Route53
- Dominios cubiertos:
- pythoncdmx.org
- www.pythoncdmx.org
- Nombre:
pythoncdmx-website-staging - Acceso: Privado (solo CloudFront puede acceder)
- Características:
- ✅ Versioning habilitado
- ✅ Encriptación AES256
- ✅ Lifecycle: 30 días versiones antiguas (más agresivo)
- ✅ CORS configurado
- Dominio: staging.pythoncdmx.org
- Características:
- ✅ Certificado SSL/TLS (ACM)
- ✅ Cache más corto (HTML: 1min, Assets: 30min, Images: 1h)
- ✅ IPv6 habilitado
- ✅ Banner "STAGING" en todas las páginas
- Región: us-east-1
- Validación: DNS automática vía Route53
- Dominio: staging.pythoncdmx.org
- OIDC Provider: GitHub Actions sin credenciales long-lived
- Permisos:
- S3: Read/Write en ambos buckets (prod y staging)
- CloudFront: Invalidación de cache en ambas distribuciones
- Scope: Repositorio PythonMexico/pythonCDMX
- S3 Bucket:
pythoncdmx-terraform-state - DynamoDB:
pythoncdmx-terraform-locks - Encriptación: Habilitada
-
Terraform >= 1.0
brew install terraform # macOS -
AWS CLI configurado
aws configure
-
Route53 Hosted Zone ya creada para
pythoncdmx.org# Verificar hosted zone existente aws route53 list-hosted-zones -
Permisos AWS requeridos:
- S3: Crear/modificar buckets
- CloudFront: Crear/modificar distribuciones
- ACM: Solicitar/validar certificados
- Route53: Crear/modificar registros DNS
- IAM: Crear roles y políticas
# Crear bucket para Terraform state
aws s3 mb s3://pythoncdmx-terraform-state --region us-east-1
# Habilitar versioning
aws s3api put-bucket-versioning \
--bucket pythoncdmx-terraform-state \
--versioning-configuration Status=Enabled
# Habilitar encriptación
aws s3api put-bucket-encryption \
--bucket pythoncdmx-terraform-state \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}]
}'
# Crear tabla DynamoDB para locks
aws dynamodb create-table \
--table-name pythoncdmx-terraform-locks \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--region us-east-1✅ AUTOMÁTICO: La validación DNS se hace automáticamente vía Route53. Terraform crea los registros CNAME necesarios y espera la validación.
Si necesitas verificar el estado:
# Ver certificados y su estado
aws acm list-certificates --region us-east-1
# Ver detalles de validación
terraform output certificate_validation_recordsTiempo de validación: 5-30 minutos (automático)
cd terraform
terraform initterraform planterraform applyTerraform creará:
- ✅ 2 S3 buckets privados (production + staging)
- ✅ 2 CloudFront distributions
- ✅ 2 Certificados ACM (validación DNS automática)
- ✅ Registros DNS en Route53
- ✅ IAM Role con OIDC para GitHub Actions
- ✅ Políticas de acceso
- ✅ Cache behaviors optimizados
⏱️ Tiempo estimado: 15-30 minutos (mayoría es validación de certificados)
terraform outputOutputs importantes:
- Production:
website_url: https://pythoncdmx.orgcloudfront_distribution_id: ID para invalidación de cachewebsite_bucket_name: pythoncdmx-website
- Staging:
staging_website_url: https://staging.pythoncdmx.orgstaging_cloudfront_distribution_id: ID para invalidación de cache stagingstaging_bucket_name: pythoncdmx-website-staging
- Route53:
hosted_zone_id: ID de la hosted zonehosted_zone_name_servers: Name servers (para verificación)
El deploy automático requiere configurar secretos en GitHub:
# Ver terraform/iam-github.tf (crear este archivo)
terraform applyEn el repositorio, ir a Settings > Secrets and variables > Actions:
# Obtener valores de Terraform
terraform output
# Configurar estos secrets:
AWS_ROLE_ARN: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
CLOUDFRONT_DISTRIBUTION_ID: E1234ABCDEF567 (production)
CLOUDFRONT_DISTRIBUTION_ID_STAGING: E7890GHIJKL123 (staging)Production (.github/workflows/deploy-aws.yml):
- Trigger: Push a
main - Destino: pythoncdmx.org
- S3 Bucket: pythoncdmx-website
- Cache: Agresivo (1h-24h)
Staging (.github/workflows/deploy-staging.yml):
- Trigger: Push a
develop/stagingo PR amain - Destino: staging.pythoncdmx.org
- S3 Bucket: pythoncdmx-website-staging
- Cache: Corto (1min-2h)
- Banner: "🚧 STAGING ENVIRONMENT" en todas las páginas
aws cloudfront create-invalidation \
--distribution-id E1234ABCDEF567 \
--paths "/*"aws cloudfront create-invalidation \
--distribution-id E1234ABCDEF567 \
--paths "/index.html" "/css/*"aws cloudfront get-invalidation \
--distribution-id E1234ABCDEF567 \
--id I1234ABCDEF567- Cache: 10 minutos
- Header:
Cache-Control: public, max-age=600, must-revalidate
- Cache: 24 horas
- Header:
Cache-Control: public, max-age=86400
- Cache: 7 días
- Header:
Cache-Control: public, max-age=604800
- Cache: Sin cache
- Header:
Cache-Control: public, max-age=0, must-revalidate
- S3: 5GB de almacenamiento
- CloudFront: 50GB de transferencia
- ACM: Certificados gratuitos
- S3: ~$0.50 (20GB)
- CloudFront: ~$2-5 (dependiendo del tráfico)
- Total: ~$3-6/mes
Problema: El certificado ACM no se valida automáticamente.
Solución:
- Verifica que Route53 tenga los registros de validación:
aws route53 list-resource-record-sets --hosted-zone-id ZXXXXX
- Los registros deben ser tipo CNAME con nombres
_abc123.pythoncdmx.org - Terraform crea estos automáticamente, pero puede tardar 5-30 minutos
- Si persiste el error después de 45 minutos, revisar permisos de Route53
Problema: El nombre del bucket ya está en uso.
Solución:
# Cambiar nombre en variables.tf
bucket_name = "pythoncdmx-website-prod"Problema: Permisos insuficientes del IAM role.
Solución:
- Verificar políticas del role:
terraform/iam-github.tf - Confirmar trust relationship con GitHub OIDC
- Revisar logs de CloudWatch
Problema: Cache no invalidado.
Solución:
aws cloudfront create-invalidation \
--distribution-id $DISTRIBUTION_ID \
--paths "/*"✅ S3 Bucket privado: No acceso público directo ✅ Origin Access Control: CloudFront usa firma SigV4 ✅ Encriptación en reposo: AES256 en S3 ✅ TLS 1.2+: Protocolo mínimo seguro ✅ Versioning: Protección contra eliminación accidental ✅ IAM Roles: Sin credenciales hardcoded ✅ OIDC GitHub: Autenticación sin long-lived tokens
- Backend state encriptado
- S3 bucket policy restrictiva
- CloudFront usa HTTPS únicamente
- Certificado SSL válido
- IAM roles con least privilege
- Logs de acceso habilitados (opcional)
- AWS WAF configurado (opcional para producción)
cd terraform
terraform plan
terraform apply# Descargar state actual
aws s3 cp s3://pythoncdmx-terraform-state/website/terraform.tfstate ./backup-$(date +%Y%m%d).tfstate# ⚠️ Esto eliminará TODOS los recursos
terraform destroy| Aspecto | Production | Staging |
|---|---|---|
| Dominio | pythoncdmx.org | staging.pythoncdmx.org |
| S3 Bucket | pythoncdmx-website | pythoncdmx-website-staging |
| Cache HTML | 10 minutos | 1 minuto |
| Cache Assets | 24 horas | 30 minutos |
| Cache Images | 7 días | 1 hora |
| Lifecycle S3 | 90 días | 30 días |
| Deploy Trigger | Push a main |
Push a develop/staging |
| Banner | No | Sí ("STAGING ENV") |
- Desarrollo: Crear branch de feature
- Testing: Merge a
develop→ Deploy a staging - QA: Probar en https://staging.pythoncdmx.org
- Producción: PR a
main→ Review → Merge → Deploy automático
- Terraform AWS Provider
- CloudFront con S3
- ACM Certificate Validation
- Route53 Records
- GitHub OIDC con AWS
Para problemas con la infraestructura:
- Revisar esta documentación
- Consultar logs de CloudWatch
- Verificar estado de recursos:
terraform show - Abrir issue en el repositorio
- Contactar al equipo de infraestructura
Última actualización: 2025-01-11 Mantenido por: Equipo Python CDMX Versión: 2.0 (Route53 + Staging Environment)