Initial commit: Terraform infrastructure, pipelines, docs and scripts

This commit is contained in:
Evert Daniel Romero Garrido
2026-04-14 14:53:05 -06:00
commit 85297b12a2
31 changed files with 4015 additions and 0 deletions
+322
View File
@@ -0,0 +1,322 @@
# 07 - Terraform (IaC)
> Cómo creamos la infraestructura de `proyectosacc` con código.
---
## 1. ¿Qué es Terraform?
**Terraform** es una herramienta que permite crear infraestructura en la nube escribiendo código en lugar de hacer clic en la consola de AWS.
A esto se le llama **IaC** (Infrastructure as Code) o "Infraestructura como Código".
### Ventajas de usar Terraform
-**Repetible**: puedes crear la misma infraestructura 10 veces y siempre será idéntica.
-**Versionable**: el código se guarda en Git, así que sabes quién hizo qué cambio y cuándo.
-**Rápido**: un solo comando crea servidor, base de datos, DNS y seguridad.
-**Sin sorpresas**: todo está documentado en archivos de texto.
---
## 2. ¿Qué crea Terraform en proyectosacc?
Terraform se encarga de crear todos estos recursos en AWS:
1. **VPC y subredes**: la red virtual donde vive todo.
2. **Security Groups**: las reglas de firewall.
3. **EC2 T3.small**: el servidor de la **API backend**.
4. **RDS MariaDB**: la base de datos gestionada.
5. **S3 Bucket (artefactos)**: el almacén de archivos de la API.
6. **S3 Bucket (frontend)**: el sitio web estático que sirve el React app.
7. **CloudFront Distribution**: la CDN que distribuye el frontend globalmente con HTTPS.
8. **Route 53 Record**: el dominio `sacc.ccsoft.mx` apunta a CloudFront.
9. **ACM Certificate**: certificado SSL para CloudFront.
10. **IAM Role**: permisos para que la EC2 y CloudFront accedan a S3.
---
## 3. Archivos principales de Terraform
### `main.tf`
Este es el archivo central. Aquí se definen los recursos que Terraform va a crear.
Ejemplo de la EC2 para la API:
```hcl
resource "aws_instance" "sacc_api" {
ami = "ami-0c02fb55956c7d316" # Ubuntu 22.04
instance_type = "t3.small"
vpc_security_group_ids = [aws_security_group.sacc_sg.id]
user_data = file("user-data.sh")
tags = {
Name = "proyectosacc-api"
Environment = "develop"
Project = "proyectosacc"
}
}
```
Ejemplo del bucket S3 para el frontend React:
```hcl
resource "aws_s3_bucket" "sacc_frontend" {
bucket = "ccsoft-proyectosacc-frontend"
}
resource "aws_s3_bucket_website_configuration" "sacc_frontend" {
bucket = aws_s3_bucket.sacc_frontend.id
index_document {
suffix = "index.html"
}
error_document {
key = "index.html"
}
}
```
Ejemplo de CloudFront:
```hcl
resource "aws_cloudfront_distribution" "sacc_cdn" {
enabled = true
default_root_object = "index.html"
aliases = ["sacc.ccsoft.mx"]
# Origin 1: S3 bucket para el frontend React
origin {
domain_name = aws_s3_bucket.sacc_frontend.bucket_regional_domain_name
origin_id = "saccS3Origin"
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.sacc_oai.cloudfront_access_identity_path
}
}
# Origin 2: EC2 para la API backend
origin {
domain_name = aws_instance.sacc_api.public_dns
origin_id = "saccApiOrigin"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "http-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
default_cache_behavior {
target_origin_id = "saccS3Origin"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
}
# API requests go to the EC2 origin
ordered_cache_behavior {
path_pattern = "/api/*"
target_origin_id = "saccApiOrigin"
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
viewer_protocol_policy = "redirect-to-https"
forwarded_values {
query_string = true
headers = ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"]
cookies {
forward = "all"
}
}
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.sacc_cert.arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}
}
```
> 💡 **¿Por qué dos origins?** CloudFront sirve el frontend desde S3 por defecto. Pero cuando el navegador pide algo bajo `/api/*`, CloudFront lo envía a la EC2 donde Nginx lo redirige al backend en el puerto 8080. Así todo comparte el mismo dominio `sacc.ccsoft.mx`.
---
### `variables.tf`
Aquí se definen las variables que personalizan la infraestructura.
Ejemplo:
```hcl
variable "region" {
description = "Región de AWS"
type = string
default = "us-east-1"
}
variable "instance_type" {
description = "Tipo de instancia EC2"
type = string
default = "t3.small"
}
variable "db_password" {
description = "Contraseña de la base de datos"
type = string
sensitive = true
}
```
> ⚠️ La variable `db_password` tiene `sensitive = true` para que no aparezca en los logs.
---
### `user-data.sh`
Este archivo contiene los comandos que la EC2 ejecuta la **primera vez** que se enciende.
Ejemplo de lo que hace:
1. Actualiza el sistema operativo.
2. Instala Nginx.
3. Instala Java (para correr la aplicación SACC).
4. Instala AWS CLI.
5. Crea los usuarios `thoth` y `osiris`.
6. Inyecta la **llave pública SSH dedicada** para el pipeline en `~/.ssh/authorized_keys` del usuario `thoth`.
7. Crea los directorios necesarios para el despliegue.
```bash
#!/bin/bash
set -euo pipefail
# Actualizar sistema
apt-get update -y
apt-get install -y nginx openjdk-21-jdk awscli
# Crear usuarios
useradd -m -s /bin/bash thoth || true
useradd -m -s /bin/bash osiris || true
# Crear directorios de despliegue
mkdir -p /home/thoth/deploy/artifacts/{backup,current,logs,pids}
chown -R thoth:thoth /home/thoth/deploy
# Configurar Nginx como proxy SOLO para la API (no para el frontend)
cat > /etc/nginx/sites-available/proyectosacc-api <<'EOF'
server {
listen 80;
server_name _;
location /api/ {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
EOF
ln -sf /etc/nginx/sites-available/proyectosacc-api /etc/nginx/sites-enabled/default
# Iniciar Nginx
systemctl enable nginx
systemctl start nginx
```
---
### `outputs.tf`
Aquí definimos qué información queremos que Terraform nos muestre al final.
Ejemplo:
```hcl
output "ec2_public_ip" {
description = "IP pública del servidor de la API"
value = aws_instance.sacc_api.public_ip
}
output "rds_endpoint" {
description = "Dirección de conexión a la base de datos"
value = aws_db_instance.sacc_db.endpoint
}
output "s3_artifacts_bucket" {
description = "Nombre del bucket de artefactos de la API"
value = aws_s3_bucket.artifacts.bucket
}
output "s3_frontend_bucket" {
description = "Nombre del bucket del frontend React"
value = aws_s3_bucket.sacc_frontend.bucket
}
output "cloudfront_domain" {
description = "Dominio de CloudFront"
value = aws_cloudfront_distribution.sacc_cdn.domain_name
}
```
Después de ejecutar `terraform apply`, verás estos valores en la pantalla.
---
## 4. Cómo ejecutar Terraform paso a paso
### Paso 1: Ir a la carpeta de Terraform
```bash
cd /home/evert/Servidores/Nuve/AWS/proyectosacc/terraform
```
### Paso 2: Inicializar Terraform
```bash
terraform init
```
Esto descarga los plugins necesarios para hablar con AWS.
### Paso 3: Revisar el plan
```bash
terraform plan
```
Terraform te muestra **todo lo que va a crear, modificar o destruir**. Revísalo con cuidado.
### Paso 4: Aplicar los cambios
```bash
terraform apply
```
Terraform te pedirá que escribas `yes` para confirmar. Luego empezará a crear los recursos en AWS.
### Paso 5: Ver los outputs
Al finalizar, Terraform mostrará los valores definidos en `outputs.tf`:
- IP pública de la EC2 (API backend)
- Endpoint de la base de datos
- Nombre del bucket S3 de artefactos
- Nombre del bucket S3 del frontend
- Dominio de CloudFront
---
## 5. Comandos útiles adicionales
| Comando | Para qué sirve |
|---------|----------------|
| `terraform validate` | Revisa que la sintaxis de los archivos esté correcta. |
| `terraform fmt` | Ordena y da formato a los archivos `.tf`. |
| `terraform show` | Muestra el estado actual de la infraestructura. |
| `terraform destroy` | **Elimina** todos los recursos creados. ¡Úsalo con cuidado! |
---
## 6. Checklist antes de ejecutar Terraform
- [ ] Tienes configuradas las credenciales de AWS (`aws configure`).
- [ ] La variable `db_password` no está escrita en el código, viene de un archivo seguro o variable de entorno.
- [ ] Revisaste el `terraform plan` antes de aplicar.
- [ ] Sabes en qué región de AWS se va a crear todo (`us-east-1`, `us-west-2`, etc.).
- [ ] El bucket S3 para el estado remoto ya existe (si usas backend remoto).
- [ ] El `user_data.sh` incluye la llave pública SSH dedicada para el pipeline.
- [ ] El bucket S3 del frontend tiene habilitado el versionamiento de objetos (para rollback del frontend).
- [ ] CloudFront tiene configurado el Origin Access Identity (OAI) u Origin Access Control (OAC) para leer de S3.
- [ ] Route 53 apunta a CloudFront, no a la IP de la EC2.
- [ ] CloudFront tiene un behavior `/api/*` que apunta a la EC2.
- [ ] La EC2 tiene el Security Group configurado para recibir tráfico HTTP desde CloudFront.
---
*Anterior: [`06-scripts-de-despliegue.md`](06-scripts-de-despliegue.md)*
*Siguiente: [`08-seguridad-y-secretos.md`](08-seguridad-y-secretos.md)*