Initial commit: Terraform infrastructure, pipelines, docs and scripts
This commit is contained in:
@@ -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)*
|
||||
Reference in New Issue
Block a user