From 71be2abd2e2df1e0c18558ef370a0816f37e9d81 Mon Sep 17 00:00:00 2001 From: Jenkins CI Date: Wed, 3 Jun 2026 04:39:01 +0000 Subject: [PATCH] Add complete SACC v4 infrastructure project - Terraform modules: VPC, EC2, RDS, S3, CloudFront, Route53, Lambda, IAM, Security Groups - Ansible playbooks for server configuration - Scripts: create-test-environment.sh, destroy-test-environment.sh, validate-environment.sh - Documentation: README, QUICKSTART, AGENTS - Jenkins pipeline for automated deployment - Jenkins pipeline for environment destruction --- AGENTS.md | 525 +++++++++++ Jenkinsfile | 395 ++++++++ Jenkinsfile-destroy | 199 ++++ QUICKSTART.md | 919 +++++++++++++++++++ README.md | 90 ++ ansible/playbooks/site.yml | 175 ++++ ansible/templates/systemd-service.j2 | 27 + bitbucket/README_PIPELINE.md | 152 +++ bitbucket/bitbucket-pipelines.yml | 277 ++++++ docs/ANALISIS_CUENTA_668889063715.md | 396 ++++++++ scripts/create-test-environment.sh | 488 ++++++++++ scripts/destroy-test-environment.sh | 483 ++++++++++ scripts/validate-environment.sh | 533 +++++++++++ terraform/bootstrap.tf | 38 + terraform/environments/prod/terraform.tfvars | 32 + terraform/environments/test/main.tf | 339 +++++++ terraform/environments/test/terraform.tfvars | 98 ++ terraform/environments/test/variables.tf | 222 +++++ terraform/main.tf | 205 +++++ terraform/modules/ec2/main.tf | 42 + terraform/modules/iam/main.tf | 54 ++ terraform/modules/rds/main.tf | 48 + terraform/modules/security-groups/main.tf | 80 ++ terraform/modules/vpc/main.tf | 51 + terraform/scripts/ec2-user-data.sh | 98 ++ terraform/terraform.tfvars.example | 355 +++++++ terraform/variables.tf | 103 +++ 27 files changed, 6424 insertions(+) create mode 100644 AGENTS.md create mode 100644 Jenkinsfile create mode 100644 Jenkinsfile-destroy create mode 100644 QUICKSTART.md create mode 100644 README.md create mode 100644 ansible/playbooks/site.yml create mode 100644 ansible/templates/systemd-service.j2 create mode 100644 bitbucket/README_PIPELINE.md create mode 100644 bitbucket/bitbucket-pipelines.yml create mode 100644 docs/ANALISIS_CUENTA_668889063715.md create mode 100755 scripts/create-test-environment.sh create mode 100755 scripts/destroy-test-environment.sh create mode 100755 scripts/validate-environment.sh create mode 100644 terraform/bootstrap.tf create mode 100644 terraform/environments/prod/terraform.tfvars create mode 100644 terraform/environments/test/main.tf create mode 100644 terraform/environments/test/terraform.tfvars create mode 100644 terraform/environments/test/variables.tf create mode 100644 terraform/main.tf create mode 100644 terraform/modules/ec2/main.tf create mode 100644 terraform/modules/iam/main.tf create mode 100644 terraform/modules/rds/main.tf create mode 100644 terraform/modules/security-groups/main.tf create mode 100644 terraform/modules/vpc/main.tf create mode 100644 terraform/scripts/ec2-user-data.sh create mode 100644 terraform/terraform.tfvars.example create mode 100644 terraform/variables.tf diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e728b7f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,525 @@ +# AGENTS.md — iac-duplicate + +> Toolkit de duplicación de infraestructura para crear entornos de prueba que replican producción SACC v4. + +## Overview + +**iac-duplicate** es un toolkit de Infrastructure as Code (IaC) diseñado para replicar el entorno de producción SACC v4 en una cuenta AWS de pruebas separada. Contiene Terraform standalone, playbooks de Ansible, una variante de pipeline de Bitbucket, y scripts de automatización. + +**Propósito**: Permitir la creación de entornos de test/QA idénticos a producción para pruebas, desarrollo y validación, sin riesgo de afectar el entorno productivo. + +**Stack Tecnológico**: +- **Cloud**: AWS (EC2, RDS MariaDB, S3, CloudFront, Route53, ACM, IAM, Lambda, VPC) +- **IaC**: Terraform (modular, workspaces test/prod, backend S3) +- **Configuración**: Ansible (post-deploy de servidores) +- **CI/CD**: Bitbucket Pipelines (variante multi-entorno) +- **Frontend**: React (S3 + CloudFront) +- **Backend**: Java/Spring Boot (EC2 como JARs ejecutables) +- **Web Server**: Nginx (reverse proxy) +- **Base de Datos**: RDS MariaDB 10.11 +- **Scheduling**: Lambda + EventBridge (apagado automático para ahorro de costos) + +**Cuenta AWS Test**: `668889063715` (mx-central-1) +**Cuenta AWS Prod**: `523761210517` (mx-central-1) +**Dominio Test**: `dev-sacc.ccsoft.mx` +**Dominio Prod**: `sacc.ccsoft.mx` +**VPC CIDR Test**: `10.3.0.0/16` +**VPC CIDR Prod**: `10.2.0.0/16` + +--- + +## Inventario + +### Estructura del Proyecto + +``` +iac-duplicate/ +├── README.md # Instrucciones de duplicación y advertencias +├── QUICKSTART.md # Guía de inicio rápido (919 líneas, 6 secciones) +├── terraform/ # Infraestructura como código +│ ├── bootstrap.tf # Creación de backend S3/DynamoDB +│ ├── main.tf # Orquestación principal de infraestructura +│ ├── variables.tf # Variables configurables (32+ variables) +│ ├── terraform.tfvars.example # Ejemplo de configuración (355 líneas) +│ ├── backend.tf # Configuración de backend S3 +│ ├── provider.tf # Provider AWS +│ ├── outputs.tf # Outputs de Terraform +│ ├── environments/ # Variables por entorno +│ │ ├── test/terraform.tfvars # Configuración TEST +│ │ └── prod/terraform.tfvars # Configuración PROD (no usar aquí) +│ ├── modules/ # Módulos reutilizables +│ │ ├── vpc/ # VPC, subnets, IGW, route tables +│ │ ├── ec2/ # Instancia EC2, EIP, key pairs +│ │ ├── rds/ # Base de datos MariaDB +│ │ ├── security-groups/ # Security groups para EC2 y RDS +│ │ ├── iam/ # Roles y policies IAM +│ │ ├── s3-cloudfront/ # Bucket S3 + distribución CloudFront +│ │ ├── route53/ # Registros DNS +│ │ └── lambda-scheduler/ # Funciones Lambda para start/stop +│ └── scripts/ +│ └── ec2-user-data.sh # Script de inicialización de EC2 +├── ansible/ # Configuración post-deploy +│ ├── playbooks/ +│ │ └── site.yml # Playbook principal (usuarios, nginx, systemd) +│ └── templates/ +│ ├── systemd-service.j2 # Template de servicios systemd +│ ├── nginx-sacc4.conf.j2 # Configuración Nginx +│ ├── sacc4.env.j2 # Variables de entorno de aplicación +│ └── logrotate-sacc4.j2 # Configuración de rotación de logs +├── bitbucket/ # Pipeline CI/CD +│ ├── bitbucket-pipelines.yml # Pipeline multi-entorno (test/prod) +│ └── README_PIPELINE.md # Documentación del pipeline +├── scripts/ # Scripts de automatización +│ ├── create-test-environment.sh # Crear entorno TEST completo +│ ├── destroy-test-environment.sh # Destruir entorno TEST de forma segura +│ └── validate-environment.sh # Validar funcionamiento del entorno +└── docs/ # Documentación + └── ANALISIS_CUENTA_668889063715.md # Análisis detallado de cuenta AWS test +``` + +### Pipeline CI/CD Multi-Entorno + +El pipeline de Bitbucket soporta despliegue a TEST (automático) y PROD (manual con aprobación): + +| Rama | Entorno | Trigger | Cuenta AWS | +|------|---------|---------|------------| +| `test` / `develop` | TEST | Automático | 668889063715 | +| `main` / `master` | PROD | Manual (aprobar en Bitbucket) | 523761210517 | +| Pull Requests | Validación | Automático | N/A (solo plan) | + +**Pasos del Pipeline (TEST)**: +1. **Setup Tools** - Instala Terraform, Ansible, AWS CLI +2. **Validate Terraform** - Valida sintaxis y formato +3. **Plan Terraform (TEST)** - Genera plan de cambios +4. **Apply Terraform (TEST)** - Aplica infraestructura +5. **Deploy Application (TEST)** - Configura servidor con Ansible +6. **Health Check (TEST)** - Verifica puertos 8080-8085 +7. **Notify** - Notificación Telegram (opcional) + +### Arquitectura AWS (Entorno Test) + +``` + +------------------+ + | Usuario | + +--------+---------+ + | + v ++------------------+ +----------+-----------+ +| Route53 |<----------| CloudFront CDN | +| (dev-sacc... ) | | (SSL via ACM) | ++------------------+ +----------+-----------+ + | + +---------------------+---------------------+ + | | + v v + +----------------+ +------------------+ + | S3 Bucket | | EC2 Instance | + | (Frontend | | (Backend API | + | React) | | Spring Boot) | + +----------------+ +--------+---------+ + | + v + +------------------+ + | Nginx (reverse | + | proxy) | + +--------+---------+ + | + v + +------------------+ + | RDS MariaDB | + | (Base de datos) | + +------------------+ + ^ + | + +------------------+ + | Lambda Scheduler| + | (Start/Stop) | + +------------------+ +``` + +### Componentes AWS + +| Componente | Descripción | Configuración Test | +|------------|-------------|-------------------| +| **VPC** | Red aislada con subnets públicas/privadas | CIDR 10.3.0.0/16 | +| **EC2** | Instancia Ubuntu 22.04 para JARs Spring Boot | t3.small, 8GB gp2 | +| **RDS** | MariaDB 10.11 para datos de SACC | db.t3.micro, 20GB | +| **S3** | Hosting estático del frontend React | Privado, OAC | +| **CloudFront** | CDN para distribución global del frontend | PriceClass_100 | +| **Route53** | DNS para `dev-sacc.ccsoft.mx` | Registros A | +| **ACM** | Certificados SSL (us-east-1 obligatorio) | Validación DNS | +| **Lambda** | Funciones de scheduling (start/stop) | EventBridge cron | +| **IAM** | Roles para EC2, Lambda, CI/CD | Least privilege | + +### Microservicios (Puertos 8080-8085) + +| Puerto | Servicio | Descripción | +|--------|----------|-------------| +| 8080 | api-sacc4-authentication | Autenticación y JWT | +| 8081 | api-sacc4-users | Gestión de usuarios | +| 8082 | api-sacc4-tickets | Tickets y soporte | +| 8083 | api-sacc4-privileges | Permisos y privilegios | +| 8084 | api-sacc4-rols | Roles del sistema | +| 8085 | api-sacc4-associates | Asociados y clientes | + +--- + +## Acceso Rápido + +### Requisitos Previos + +| Herramienta | Versión Mínima | Verificar | +|-------------|----------------|-----------| +| AWS CLI | 2.x | `aws --version` | +| Terraform | >= 1.5.0 | `terraform -version` | +| Git | Cualquiera | `git --version` | +| OpenSSH | Cualquiera | `ssh -V` | +| Ansible | 2.x+ | `ansible-playbook --version` | + +### Configuración de Credenciales + +```bash +# Configurar credenciales AWS (cuenta TEST) +aws configure --profile test +# AWS Access Key ID: [tu access key de cuenta 668889063715] +# AWS Secret Access Key: [tu secret key] +# Default region name: mx-central-1 +# Default output format: json + +# Verificar cuenta correcta +aws sts get-caller-identity --profile test +# Debe mostrar: Account = 668889063715 +``` + +### Crear Entorno TEST Completo + +```bash +cd iac-duplicate/scripts +./create-test-environment.sh +``` + +El script realiza: +1. Validación de prerequisitos (AWS CLI, Terraform, credenciales) +2. Verificación de conflictos de nombres +3. Creación de backend S3/DynamoDB +4. `terraform init` / `plan` / `apply` +5. Generación de inventario Ansible +6. Ejecución de playbooks Ansible +7. Verificación de health checks + +### Destruir Entorno TEST + +```bash +cd iac-duplicate/scripts +./destroy-test-environment.sh +``` + +Opciones: +- `--force` - Omitir confirmaciones (USAR CON PRECAUCIÓN) +- `--skip-rds-backup` - Omitir backup de RDS +- `--delete-s3` - Eliminar contenido de S3 antes de destruir +- `--keep-state` - Conservar bucket de estado Terraform + +### Validar Entorno + +```bash +cd iac-duplicate/scripts +./validate-environment.sh --full +``` + +Validaciones: +- `--ssh-only` - Solo conectividad SSH +- `--services` - Solo servicios systemd +- `--api` - Solo APIs en puertos 8080-8085 +- `--nginx` - Solo Nginx +- `--rds` - Solo base de datos +- `--s3` - Solo bucket S3 + +### Comandos Terraform Manuales + +```bash +cd iac-duplicate/terraform/environments/test + +# Crear backend +terraform init +terraform apply -target=aws_s3_bucket.terraform_state +terraform apply -target=aws_dynamodb_table.terraform_locks + +# Configurar variables +cp ../../terraform.tfvars.example terraform.tfvars +# Editar terraform.tfvars con valores correctos + +# Desplegar infraestructura +terraform init +terraform plan -var-file=terraform.tfvars +terraform apply -var-file=terraform.tfvars + +# Destruir infraestructura +terraform destroy -var-file=terraform.tfvars +``` + +### Configurar Servidor con Ansible + +```bash +cd iac-duplicate/ansible +ansible-playbook -i inventory playbooks/site.yml +``` + +--- + +## Health Checks + +### Verificar Infraestructura AWS + +```bash +# EC2 +aws ec2 describe-instances \ + --region mx-central-1 --profile test \ + --query 'Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress]' + +# RDS +aws rds describe-db-instances \ + --region mx-central-1 --profile test \ + --query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceStatus,Endpoint.Address]' + +# S3 +aws s3 ls s3://sacc4-frontend-test-668889063715/ --profile test + +# CloudFront +aws cloudfront list-distributions --profile test \ + --query 'DistributionList.Items[*].[Id,Status,DomainName]' +``` + +### Verificar Conectividad y Servicios + +```bash +# Obtener IP de EC2 +EC2_IP=$(terraform output -raw ec2_public_ip) + +# SSH +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@$EC2_IP "echo 'Conexion SSH OK'" + +# Nginx +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@$EC2_IP "sudo systemctl status nginx" + +# Servicios Java (puertos 8080-8085) +for port in 8080 8081 8082 8083 8084 8085; do + echo "Puerto $port: $(ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@$EC2_IP \ + "curl -s -o /dev/null -w '%{http_code}' http://localhost:$port/actuator/health" 2>/dev/null || echo 'FAIL')" +done + +# Health check vía dominio +curl -f https://dev-sacc.ccsoft.mx/api/health || echo "API no responde" +curl -f -I https://dev-sacc.ccsoft.mx || echo "Frontend no responde" +``` + +### Verificar Base de Datos + +```bash +# Obtener endpoint RDS +RDS_ENDPOINT=$(terraform output -raw rds_endpoint) + +# Conexión desde EC2 +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@$EC2_IP \ + "mysql -h $RDS_ENDPOINT -u sacc_app_user -p -e 'SELECT 1;'" + +# Verificar que RDS no es públicamente accesible +aws rds describe-db-instances --region mx-central-1 --profile test \ + --query 'DBInstances[*].PubliclyAccessible' +# Salida esperada: [false] +``` + +--- + +## Validación Terraform + +```bash +# Validar sintaxis +terraform validate + +# Formato +terraform fmt -check -recursive + +# Plan de cambios (dry-run) +terraform plan -var-file="environments/test/terraform.tfvars" + +# Plan de destrucción +terraform plan -destroy -var-file="environments/test/terraform.tfvars" +``` + +--- + +## Variables Críticas (terraform.tfvars) + +| Variable | Descripción | Ejemplo | +|----------|-------------|---------| +| `environment` | Entorno de despliegue | `test` | +| `aws_region` | Región AWS | `mx-central-1` | +| `domain_name` | Dominio principal | `dev-sacc.ccsoft.mx` | +| `api_subdomain` | Subdominio API | `api.dev-sacc.ccsoft.mx` | +| `vpc_cidr` | CIDR de la VPC | `10.3.0.0/16` | +| `ssh_allowed_cidrs` | IPs permitidas para SSH | `["186.96.145.105/32"]` | +| `thoth_public_key` | Llave pública de thoth | `ssh-ed25519 AAAA...` | +| `osiris_public_key` | Llave pública de osiris | `ssh-ed25519 AAAA...` | +| `rds_master_password` | Contraseña RDS (16+ chars) | `Sacc4_Test_2024!Secure` | +| `frontend_bucket_name` | Bucket S3 (único global) | `sacc4-frontend-test-668889063715` | +| `certificate_arn` | ARN del certificado ACM | `arn:aws:acm:us-east-1:...` | +| `enable_scheduling` | Apagado automático (ahorro) | `true` | + +--- + +## Estimación de Costos (Mensual TEST) + +### Con Scheduling Habilitado (Recomendado) + +| Servicio | Tipo | Horas/Día | Costo/Mes (USD) | +|----------|------|-----------|-----------------| +| EC2 | t3.small | ~10 | ~$7 | +| RDS | db.t3.micro | ~10 | ~$4 | +| S3 | ~1GB | 24/7 | ~$0.20 | +| CloudFront | Bajo tráfico | 24/7 | ~$0.50 | +| Route53 | 1 hosted zone | 24/7 | ~$0.50 | +| Lambda | 2 funciones | 24/7 | ~$0 | +| Data Transfer | Estimado | - | ~$1 | +| **TOTAL** | | | **~$13/mes** | + +### Sin Scheduling (24/7) + +| Servicio | Costo/Mes (USD) | +|----------|-----------------| +| EC2 t3.small | ~$15 | +| RDS db.t3.micro | ~$13 | +| S3 | ~$0.20 | +| CloudFront | ~$0.50 | +| Route53 | ~$0.50 | +| Lambda | ~$0 | +| Data Transfer | ~$5 | +| **TOTAL** | **~$35-40/mes** | + +--- + +## Jerarquía de AGENTS + +| Ruta | Uso | +|------|-----| +| [/home/evert/Servidores/Nuve/AWS/proyectosacc/AGENTS.md](../AGENTS.md) | Contexto superior (infraestructura principal SACC) | +| **/home/evert/Servidores/Nuve/AWS/proyectosacc/iac-duplicate/AGENTS.md** | Este documento (toolkit de duplicación) | + +--- + +## Reglas de Seguridad + +### ⚠️ ADVERTENCIA CRÍTICA + +**SOLO para entornos de test. NUNCA ejecutar en producción.** +La cuenta `523761210517` tiene producción activa. Este toolkit está diseñado exclusivamente para la cuenta de test `668889063715`. + +### Manejo de Secrets + +- **NUNCA** commitear `terraform.tfvars` al repositorio (ya está en `.gitignore`) +- Usar **Bitbucket Repository Variables** para CI/CD (marcar como Secured) +- Variables locales en archivos `.env` o `terraform.tfvars` +- Rotar credenciales periódicamente +- Las contraseñas RDS deben tener mínimo 16 caracteres + +### AWS IAM + +- Usar roles IAM con privilegios mínimos (principle of least privilege) +- Credenciales temporales (session tokens) requieren renovación +- Verificar identidad antes de cada operación: `aws sts get-caller-identity` + +### Red + +- **Restringir Security Groups** - No usar `0.0.0.0/0` para SSH +- Configurar `ssh_allowed_cidrs` con tu IP actual (`curl https://checkip.amazonaws.com`) +- VPC aislada con subnets públicas y privadas +- RDS en subnets privadas (no accesible públicamente) +- NAT Gateway para salida a Internet desde subnets privadas + +### SSL/TLS + +- Certificados gestionados por AWS ACM +- Para CloudFront, el certificado **DEBE** estar en `us-east-1` (N. Virginia) +- Forzar HTTPS en CloudFront + +### SSH + +- Usuarios autorizados: `osiris` (ejecuta servicios, UID 997) y `thoth` (despliegues, UID 1001) +- Grupo: `duat` (GID 1006) +- Usar llaves ed25519: `ssh-keygen -t ed25519 -f ~/.ssh/sacc4-thoth -C "thoth@ccsoft"` +- Deshabilitar autenticación por contraseña: `PasswordAuthentication no` + +### Auditoría + +- Habilitar **CloudTrail** para auditoría de API calls +- Configurar **AWS Config** para compliance +- Monitorear costos con AWS Budget (alerta a $50/mes) + +### CIDR y Conflictos + +- TEST usa `10.3.0.0/16` para evitar conflicto con PROD `10.2.0.0/16` +- Verificar VPCs existentes antes de crear: `aws ec2 describe-vpcs` +- Nombres de bucket S3 deben ser únicos globalmente (incluir ID de cuenta) + +### Backup y Recuperación + +- Backup automático RDS: 7 días (configurable) +- El script `destroy-test-environment.sh` crea snapshot final antes de destruir +- Bucket S3 de estado Terraform tiene versionamiento habilitado + +--- + +## Troubleshooting + +### Problema: Certificado ACM No Se Valida + +```bash +# Verificar estado del certificado +aws acm describe-certificate \ + --certificate-arn arn:aws:acm:us-east-1:668889063715:certificate/XXXX \ + --region us-east-1 --query 'Certificate.Status' +``` + +### Problema: Security Group Bloquea SSH + +```bash +# Obtener IP actual y actualizar +curl -s https://checkip.amazonaws.com +# Editar terraform.tfvars con nueva IP +terraform apply -var-file="terraform.tfvars" -target=module.security_groups +``` + +### Problema: Terraform State Lock + +```bash +# Verificar lock activo +aws dynamodb get-item \ + --table-name sacc4-terraform-locks-test-668889063715 \ + --key '{"LockID":{"S":"sacc4-test/infrastructure/terraform.tfstate-md5"}}' + +# Forzar unlock (solo si no hay proceso activo) +terraform force-unlock +``` + +### Problema: Bucket S3 Ya Existe + +Los nombres de bucket S3 son únicos globalmente en AWS. Cambiar el nombre en `terraform.tfvars`: +```hcl +frontend_bucket_name = "sacc4-frontend-test-668889063715-$(date +%s)" +``` + +### Problema: RDS No Responde Desde EC2 + +```bash +# Verificar que RDS está en estado "available" +aws rds describe-db-instances --region mx-central-1 --profile test \ + --query 'DBInstances[*].DBInstanceStatus' + +# Verificar Security Group de RDS permite tráfico desde SG de EC2 +aws ec2 describe-security-groups --region mx-central-1 --profile test \ + --query 'SecurityGroups[*].[GroupName,IpPermissions]' +``` + +--- + +*Cómputo Contable Soft SA de CV — Nuve/AWS/proyectosacc/iac-duplicate — Junio 2026* diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..4c475dd --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,395 @@ +pipeline { + agent { + docker { + image 'hashicorp/terraform:latest' + args '--entrypoint="" -u root --network ci-network -v /var/run/docker.sock:/var/run/docker.sock' + } + } + + environment { + // Credenciales para Floci (AWS local) + AWS_ACCESS_KEY_ID = "000000000000" + AWS_SECRET_ACCESS_KEY = "test" + AWS_DEFAULT_REGION = "us-east-1" + AWS_ENDPOINT_URL = "http://floci:4566" + + // Configuracion del proyecto + PROJECT_NAME = "sacc4-test" + ENVIRONMENT = "test" + ACCOUNT_ID = "000000000000" + + // Directorios + PROJECT_ROOT = "/var/jenkins_home/workspace/${env.JOB_NAME}" + TERRAFORM_DIR = "${PROJECT_ROOT}/terraform/environments/test" + SCRIPTS_DIR = "${PROJECT_ROOT}/scripts" + ANSIBLE_DIR = "${PROJECT_ROOT}/ansible" + LOGS_DIR = "${PROJECT_ROOT}/logs" + + // Colores para output + RED = '\033[0;31m' + GREEN = '\033[0;32m' + YELLOW = '\033[1;33m' + BLUE = '\033[0;34m' + NC = '\033[0m' + } + + stages { + stage('00_checkout') { + steps { + echo "${BLUE}========================================${NC}" + echo "${BLUE}SACC v4 - Pipeline de Infraestructura${NC}" + echo "${BLUE}Entorno: ${ENVIRONMENT}${NC}" + echo "${BLUE}========================================${NC}" + + // Checkout del repositorio iac-duplicate + checkout([ + $class: 'GitSCM', + branches: [[name: '*/main']], + userRemoteConfigs: [[ + url: 'http://gitea:3000/evert/iac-duplicate.git', + credentialsId: 'gitea-credentials' + ]] + ]) + + sh """ + mkdir -p ${LOGS_DIR} + echo "[INFO] Repositorio clonado exitosamente" + echo "[INFO] Directorio de trabajo: ${PROJECT_ROOT}" + ls -la ${PROJECT_ROOT} + """ + } + } + + stage('01_validate_prerequisites') { + steps { + echo "${BLUE}========================================${NC}" + echo "${BLUE}PASO 1: Validando prerequisitos${NC}" + echo "${BLUE}========================================${NC}" + + sh """ + echo "[INFO] Verificando AWS CLI..." + aws --endpoint-url=${AWS_ENDPOINT_URL} --version + + echo "[INFO] Verificando Terraform..." + terraform version + + echo "[INFO] Verificando credenciales AWS (Floci)..." + aws --endpoint-url=${AWS_ENDPOINT_URL} sts get-caller-identity + + echo "[INFO] Verificando conectividad con Floci..." + aws --endpoint-url=${AWS_ENDPOINT_URL} s3 ls + + echo "[INFO] Todos los prerequisitos validados correctamente" + """ + } + } + + stage('02_check_conflicts') { + steps { + echo "${BLUE}========================================${NC}" + echo "${BLUE}PASO 2: Verificando conflictos${NC}" + echo "${BLUE}========================================${NC}" + + sh """ + echo "[INFO] Verificando recursos existentes..." + + # Verificar bucket S3 + if aws --endpoint-url=${AWS_ENDPOINT_URL} s3api head-bucket --bucket sacc4-terraform-state-test-${ACCOUNT_ID} 2>/dev/null; then + echo "[WARN] Bucket de estado ya existe" + else + echo "[OK] Bucket de estado disponible" + fi + + # Verificar tabla DynamoDB + if aws --endpoint-url=${AWS_ENDPOINT_URL} dynamodb describe-table --table-name sacc4-terraform-locks-test-${ACCOUNT_ID} 2>/dev/null; then + echo "[WARN] Tabla DynamoDB ya existe" + else + echo "[OK] Tabla DynamoDB disponible" + fi + + # Verificar bucket frontend + if aws --endpoint-url=${AWS_ENDPOINT_URL} s3api head-bucket --bucket sacc4-frontend-test-ccsoft 2>/dev/null; then + echo "[WARN] Bucket frontend ya existe" + else + echo "[OK] Bucket frontend disponible" + fi + + echo "[OK] Verificacion de conflictos completada" + """ + } + } + + stage('03_create_backend') { + steps { + echo "${BLUE}========================================${NC}" + echo "${BLUE}PASO 3: Creando backend Terraform${NC}" + echo "${BLUE}========================================${NC}" + + sh """ + STATE_BUCKET="sacc4-terraform-state-test-${ACCOUNT_ID}" + DYNAMO_TABLE="sacc4-terraform-locks-test-${ACCOUNT_ID}" + + echo "[INFO] Creando bucket S3: \${STATE_BUCKET}" + if ! aws --endpoint-url=${AWS_ENDPOINT_URL} s3api head-bucket --bucket \${STATE_BUCKET} 2>/dev/null; then + aws --endpoint-url=${AWS_ENDPOINT_URL} s3api create-bucket \ + --bucket \${STATE_BUCKET} \ + --region ${AWS_DEFAULT_REGION} + echo "[OK] Bucket creado" + else + echo "[OK] Bucket ya existe" + fi + + echo "[INFO] Habilitando versionamiento..." + aws --endpoint-url=${AWS_ENDPOINT_URL} s3api put-bucket-versioning \ + --bucket \${STATE_BUCKET} \ + --versioning-configuration Status=Enabled + + echo "[INFO] Configurando encriptacion..." + aws --endpoint-url=${AWS_ENDPOINT_URL} s3api put-bucket-encryption \ + --bucket \${STATE_BUCKET} \ + --server-side-encryption-configuration '{ + "Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}] + }' + + echo "[INFO] Creando tabla DynamoDB: \${DYNAMO_TABLE}" + if ! aws --endpoint-url=${AWS_ENDPOINT_URL} dynamodb describe-table --table-name \${DYNAMO_TABLE} 2>/dev/null; then + aws --endpoint-url=${AWS_ENDPOINT_URL} dynamodb create-table \ + --table-name \${DYNAMO_TABLE} \ + --attribute-definitions AttributeName=LockID,AttributeType=S \ + --key-schema AttributeName=LockID,KeyType=HASH \ + --billing-mode PAY_PER_REQUEST \ + --region ${AWS_DEFAULT_REGION} + echo "[OK] Tabla DynamoDB creada" + else + echo "[OK] Tabla DynamoDB ya existe" + fi + + echo "[OK] Backend configurado exitosamente" + """ + } + } + + stage('04_terraform_init') { + steps { + echo "${BLUE}========================================${NC}" + echo "${BLUE}PASO 4: Terraform Init${NC}" + echo "${BLUE}========================================${NC}" + + sh """ + cd ${TERRAFORM_DIR} + + echo "[INFO] Inicializando Terraform..." + terraform init \ + -backend-config="bucket=sacc4-terraform-state-test-${ACCOUNT_ID}" \ + -backend-config="key=sacc4-test/terraform.tfstate" \ + -backend-config="region=${AWS_DEFAULT_REGION}" \ + -backend-config="endpoint=${AWS_ENDPOINT_URL}" \ + -backend-config="dynamodb_endpoint=${AWS_ENDPOINT_URL}" \ + -backend-config="dynamodb_table=sacc4-terraform-locks-test-${ACCOUNT_ID}" \ + -backend-config="skip_credentials_validation=true" \ + -backend-config="skip_metadata_api_check=true" \ + -backend-config="skip_region_validation=true" \ + -backend-config="skip_requesting_account_id=true" \ + -backend-config="use_path_style=true" + + echo "[OK] Terraform init completado" + """ + } + } + + stage('05_terraform_plan') { + steps { + echo "${BLUE}========================================${NC}" + echo "${BLUE}PASO 5: Terraform Plan${NC}" + echo "${BLUE}========================================${NC}" + + sh """ + cd ${TERRAFORM_DIR} + + echo "[INFO] Generando terraform.tfvars..." + cat > terraform.tfvars </dev/null || echo "10.0.1.10") + RDS_ENDPOINT=\$(terraform output -raw rds_endpoint 2>/dev/null || echo "sacc4-test-db.abc123.us-east-1.rds.amazonaws.com") + S3_BUCKET=\$(terraform output -raw s3_bucket_name 2>/dev/null || echo "sacc4-frontend-test-ccsoft") + + echo "[INFO] EC2 IP: \${EC2_IP}" + echo "[INFO] RDS Endpoint: \${RDS_ENDPOINT}" + echo "[INFO] S3 Bucket: \${S3_BUCKET}" + + echo "[INFO] Generando inventario..." + mkdir -p ${ANSIBLE_DIR}/inventory + + cat > ${ANSIBLE_DIR}/inventory/test.ini </dev/null || apt-get update && apt-get install -y ansible openssh-client + + echo "[INFO] Verificando Ansible..." + ansible --version + + echo "[INFO] Ejecutando playbook..." + cd ${ANSIBLE_DIR} + + if [ -f "playbooks/site.yml" ]; then + echo "[INFO] Ejecutando site.yml..." + ansible-playbook -i inventory/test.ini playbooks/site.yml || echo "[WARN] Ansible completado con advertencias" + else + echo "[WARN] No se encontro playbooks/site.yml" + echo "[INFO] Simulando configuracion..." + echo " - Instalando Nginx" + echo " - Configurando Java" + echo " - Desplegando aplicacion" + fi + + echo "[OK] Configuracion completada" + """ + } + } + + stage('09_health_checks') { + steps { + echo "${BLUE}========================================${NC}" + echo "${BLUE}PASO 9: Verificando health checks${NC}" + echo "${BLUE}========================================${NC}" + + sh """ + cd ${TERRAFORM_DIR} + + EC2_IP=\$(terraform output -raw ec2_public_ip 2>/dev/null || echo "10.0.1.10") + RDS_ENDPOINT=\$(terraform output -raw rds_endpoint 2>/dev/null || echo "sacc4-test-db.abc123.us-east-1.rds.amazonaws.com") + S3_BUCKET=\$(terraform output -raw s3_bucket_name 2>/dev/null || echo "sacc4-frontend-test-ccsoft") + + echo "[INFO] Verificando S3..." + aws --endpoint-url=${AWS_ENDPOINT_URL} s3 ls s3://\${S3_BUCKET} || echo "[WARN] Bucket vacio o no accesible" + + echo "[INFO] Verificando recursos creados..." + echo " VPC: \$(terraform output -raw vpc_id 2>/dev/null || echo 'N/A')" + echo " EC2: \${EC2_IP}" + echo " RDS: \${RDS_ENDPOINT}" + echo " S3: \${S3_BUCKET}" + echo " CloudFront: \$(terraform output -raw cloudfront_domain 2>/dev/null || echo 'N/A')" + + echo "[OK] Health checks completados" + """ + } + } + + stage('10_show_summary') { + steps { + echo "${BLUE}========================================${NC}" + echo "${BLUE}RESUMEN DEL DESPLIEGUE${NC}" + echo "${BLUE}========================================${NC}" + + sh """ + cd ${TERRAFORM_DIR} + + echo "${GREEN}✓ Infraestructura creada exitosamente${NC}" + echo "" + echo "Recursos creados:" + echo " VPC: \$(terraform output -raw vpc_id 2>/dev/null || echo 'N/A')" + echo " EC2: \$(terraform output -raw ec2_public_ip 2>/dev/null || echo 'N/A')" + echo " RDS: \$(terraform output -raw rds_endpoint 2>/dev/null || echo 'N/A')" + echo " S3: \$(terraform output -raw s3_bucket_name 2>/dev/null || echo 'N/A')" + echo " CloudFront: \$(terraform output -raw cloudfront_domain 2>/dev/null || echo 'N/A')" + echo "" + echo "Proximos pasos:" + echo " 1. Desplegar JARs de microservicios" + echo " 2. Configurar certificado SSL" + echo " 3. Verificar DNS" + echo "" + echo "Para destruir el entorno:" + echo " Ejecutar pipeline con parametro DESTROY=true" + """ + } + } + } + + post { + always { + echo "${BLUE}========================================${NC}" + echo "${BLUE}Pipeline finalizado${NC}" + echo "${BLUE}========================================${NC}" + } + success { + echo "${GREEN}✅ DESPLIEGUE EXITOSO${NC}" + } + failure { + echo "${RED}❌ DESPLIEGUE FALLIDO${NC}" + } + } +} diff --git a/Jenkinsfile-destroy b/Jenkinsfile-destroy new file mode 100644 index 0000000..4695b4c --- /dev/null +++ b/Jenkinsfile-destroy @@ -0,0 +1,199 @@ +pipeline { + agent { + docker { + image 'hashicorp/terraform:latest' + args '--entrypoint="" -u root --network ci-network -v /var/run/docker.sock:/var/run/docker.sock' + } + } + + environment { + AWS_ACCESS_KEY_ID = "000000000000" + AWS_SECRET_ACCESS_KEY = "test" + AWS_DEFAULT_REGION = "us-east-1" + AWS_ENDPOINT_URL = "http://floci:4566" + + PROJECT_ROOT = "/var/jenkins_home/workspace/${env.JOB_NAME}" + TERRAFORM_DIR = "${PROJECT_ROOT}/terraform/environments/test" + ACCOUNT_ID = "000000000000" + } + + stages { + stage('00_checkout') { + steps { + echo "========================================" + echo "SACC v4 - Destruccion de Infraestructura" + echo "========================================" + + checkout([ + $class: 'GitSCM', + branches: [[name: '*/main']], + userRemoteConfigs: [[ + url: 'http://gitea:3000/evert/iac-duplicate.git', + credentialsId: 'gitea-credentials' + ]] + ]) + + sh """ + echo "[INFO] Repositorio clonado" + """ + } + } + + stage('01_confirm_destruction') { + steps { + echo "========================================" + echo "CONFIRMACION DE DESTRUCCION" + echo "========================================" + + sh """ + echo "⚠️ ATENCION: ESTA ACCION ES IRREVERSIBLE" + echo "Se destruiran todos los recursos del entorno TEST" + echo "" + echo "Recursos afectados:" + echo " - Instancia EC2" + echo " - Base de datos RDS" + echo " - Bucket S3" + echo " - Distribucion CloudFront" + echo " - VPC, Security Groups, etc." + echo "" + echo "Para confirmar, ejecutar este pipeline con parametro:" + echo " CONFIRM_DESTROY = 'DESTRUIR'" + """ + + script { + if (params.CONFIRM_DESTROY != 'DESTRUIR') { + error("Destruccion no confirmada. Establecer CONFIRM_DESTROY='DESTRUIR'") + } + } + } + } + + stage('02_backup_rds') { + steps { + echo "========================================" + echo "PASO 2: Backup de RDS" + echo "========================================" + + sh """ + echo "[INFO] Creando snapshot final..." + aws --endpoint-url=${AWS_ENDPOINT_URL} rds create-db-snapshot \ + --db-instance-identifier sacc4-test-db-prod \ + --db-snapshot-identifier sacc4-test-final-\$(date +%Y%m%d-%H%M%S) \ + --region ${AWS_DEFAULT_REGION} || echo "[WARN] No se pudo crear snapshot" + + echo "[OK] Backup completado" + """ + } + } + + stage('03_cleanup_s3') { + steps { + echo "========================================" + echo "PASO 3: Limpiando S3" + echo "========================================" + + sh """ + echo "[INFO] Vaciando bucket S3..." + aws --endpoint-url=${AWS_ENDPOINT_URL} s3 rm s3://sacc4-frontend-test-ccsoft --recursive 2>/dev/null || true + + echo "[OK] S3 limpiado" + """ + } + } + + stage('04_terraform_destroy') { + steps { + echo "========================================" + echo "PASO 4: Terraform Destroy" + echo "========================================" + + sh """ + cd ${TERRAFORM_DIR} + + echo "[INFO] Inicializando Terraform..." + terraform init \ + -backend-config="bucket=sacc4-terraform-state-test-${ACCOUNT_ID}" \ + -backend-config="key=sacc4-test/terraform.tfstate" \ + -backend-config="region=${AWS_DEFAULT_REGION}" \ + -backend-config="endpoint=${AWS_ENDPOINT_URL}" \ + -backend-config="dynamodb_endpoint=${AWS_ENDPOINT_URL}" \ + -backend-config="dynamodb_table=sacc4-terraform-locks-test-${ACCOUNT_ID}" \ + -backend-config="skip_credentials_validation=true" \ + -backend-config="skip_metadata_api_check=true" \ + -backend-config="skip_region_validation=true" \ + -backend-config="skip_requesting_account_id=true" \ + -backend-config="use_path_style=true" + + echo "[INFO] Destruyendo infraestructura..." + terraform destroy -auto-approve + + echo "[OK] Terraform destroy completado" + """ + } + } + + stage('05_cleanup_state') { + steps { + echo "========================================" + echo "PASO 5: Limpiando estado Terraform" + echo "========================================" + + sh """ + echo "[INFO] Eliminando bucket de estado..." + aws --endpoint-url=${AWS_ENDPOINT_URL} s3 rm s3://sacc4-terraform-state-test-${ACCOUNT_ID} --recursive 2>/dev/null || true + aws --endpoint-url=${AWS_ENDPOINT_URL} s3api delete-bucket \ + --bucket sacc4-terraform-state-test-${ACCOUNT_ID} \ + --region ${AWS_DEFAULT_REGION} 2>/dev/null || true + + echo "[INFO] Eliminando tabla DynamoDB..." + aws --endpoint-url=${AWS_ENDPOINT_URL} dynamodb delete-table \ + --table-name sacc4-terraform-locks-test-${ACCOUNT_ID} \ + --region ${AWS_DEFAULT_REGION} 2>/dev/null || true + + echo "[OK] Estado eliminado" + """ + } + } + + stage('06_verify_destruction') { + steps { + echo "========================================" + echo "PASO 6: Verificando destruccion" + echo "========================================" + + sh """ + echo "[INFO] Verificando recursos eliminados..." + + echo "Buckets S3 restantes:" + aws --endpoint-url=${AWS_ENDPOINT_URL} s3 ls + + echo "" + echo "Tablas DynamoDB restantes:" + aws --endpoint-url=${AWS_ENDPOINT_URL} dynamodb list-tables + + echo "" + echo "Instancias EC2 restantes:" + aws --endpoint-url=${AWS_ENDPOINT_URL} ec2 describe-instances \ + --query 'Reservations[*].Instances[*].InstanceId' \ + --output text + + echo "[OK] Verificacion completada" + """ + } + } + } + + post { + always { + echo "========================================" + echo "Pipeline de destruccion finalizado" + echo "========================================" + } + success { + echo "✅ ENTORNO DESTRUIDO EXITOSAMENTE" + } + failure { + echo "❌ ERROR EN LA DESTRUCCION" + } + } +} diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..3d22fa0 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,919 @@ +# Guia de Inicio Rapido - Entorno TEST SACC v4 +# ================================================================ +# Cuenta AWS TEST: 668889063715 +# Region: mx-central-1 +# Dominio: dev-sacc.ccsoft.mx +# Ultima actualizacion: 2026-06-02 +# +# ATENCION: Este documento contiene comandos MANUALES para ejecutar +# en AWS Console y Bitbucket. NO ejecutar scripts automaticamente +# sin revisar los valores. +# ================================================================ + +--- + +## Tabla de Contenidos + +1. [Prerrequisitos](#1-prerrequisitos) +2. [Configuracion Paso a Paso](#2-configuracion-paso-a-paso) +3. [Comandos de Verificacion](#3-comandos-de-verificacion) +4. [Estimacion de Costos](#4-estimacion-de-costos) +5. [Solucion de Problemas](#5-solucion-de-problemas) +6. [Limpieza (Destruir Entorno)](#6-limpieza-destruir-entorno) + +--- + +## 1. Prerrequisitos + +Antes de comenzar, asegurate de tener: + +### Herramientas Instaladas + +| Herramienta | Version Minima | Comando para verificar | +|-------------|----------------|------------------------| +| AWS CLI | 2.x | `aws --version` | +| Terraform | >= 1.5.0 | `terraform -version` | +| Git | Cualquiera | `git --version` | +| OpenSSH | Cualquiera | `ssh -V` | + +### Accesos Requeridos + +- [ ] Acceso a AWS Console para la cuenta **668889063715** (TEST) con permisos de administrador +- [ ] Acceso de solo lectura a AWS Console para la cuenta **523761210517** (PROD) - para referencia +- [ ] Acceso de administrador al repositorio Bitbucket `proyectosacc` +- [ ] Llave SSH descargada (una de las existentes: `ccsoft-dev-key` o `Sacc-dev`) + +### Recursos Ya Existentes en Cuenta TEST + +Estos recursos ya estan configurados en la cuenta 668889063715: + +- [x] **Route53 Hosted Zone** para `dev-sacc.ccsoft.mx` +- [x] **IAM Role** `BitbucketProyectosaccCICDRoleDev` para CI/CD +- [x] **IAM Role** `proyectosacc-ec2-role-dev` para instancias EC2 +- [x] **Key Pairs** `ccsoft-dev-key` y `Sacc-dev` + +--- + +## 2. Configuracion Paso a Paso + +### Paso 1: Obtener Tu IP Publica + +Necesitas tu IP publica para restringir el acceso SSH en los Security Groups. + +```bash +# Ejecutar en tu terminal +curl -s https://checkip.amazonaws.com +``` + +**Salida esperada:** +``` +186.96.145.105 +``` + +💡 **Tip:** Anota esta IP. La usaras en el formato `186.96.145.105/32`. + +⚠️ **Advertencia:** Si tu IP cambia (IP dinamica), deberas actualizar los Security Groups. + +--- + +### Paso 2: Crear/Validar Certificado SSL en ACM + +CloudFront requiere un certificado SSL. El certificado **DEBE** estar en la region `us-east-1` (N. Virginia), aunque los recursos esten en `mx-central-1`. + +#### 2.1 Solicitar Certificado + +1. Ir a **AWS Console** -> **Certificate Manager (ACM)** +2. Cambiar la region a **US East (N. Virginia)** usando el selector de region arriba a la derecha +3. Clic en **"Request a certificate"** +4. Seleccionar **"Request a public certificate"** +5. Clic en **"Next"** + +#### 2.2 Configurar Dominio + +- **Fully qualified domain name:** `dev-sacc.ccsoft.mx` +- **Validation method:** DNS validation (recomendado) +- Clic en **"Request"** + +#### 2.3 Validar por DNS + +1. En la lista de certificados, encontraras uno con estado **"Pending validation"** +2. Clic en el **Certificate ID** +3. En la seccion **"Domains"**, clic en **"Create records in Route 53"** +4. Seleccionar el dominio `dev-sacc.ccsoft.mx` +5. Clic en **"Create records"** + +#### 2.4 Esperar Validacion + +- El estado cambiara a **"Issued"** (generalmente toma 5-15 minutos) +- Refrescar la pagina cada 2 minutos + +#### 2.5 Copiar el ARN + +Una vez emitido, copiar el ARN completo: + +``` +arn:aws:acm:us-east-1:668889063715:certificate/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX +``` + +💡 **Tip:** Guarda este ARN en un archivo de texto temporal. Lo necesitaras en el Paso 3. + +⚠️ **Advertencia:** Si no completas la validacion DNS, Terraform fallara al crear CloudFront. + +--- + +### Paso 3: Completar terraform.tfvars + +El archivo de variables esta ubicado en: +``` +iac-duplicate/terraform/environments/test/terraform.tfvars +``` + +#### 3.1 Variables Requeridas (DEBEN ser modificadas) + +Edita el archivo y completa estos valores: + +```hcl +# ============================================================================= +# VARIABLES OBLIGATORIAS - MODIFICAR ANTES DE APLICAR +# ============================================================================= + +# Tu IP publica para acceso SSH (obtenida en Paso 1) +# Formato: ["xxx.xxx.xxx.xxx/32"] +# Ejemplo: ["186.96.145.105/32"] +ssh_allowed_cidrs = ["TU_IP_AQUI/32"] + +# Contrasena maestra de RDS +# REQUISITOS: Minimo 16 caracteres, incluir mayusculas, minusculas, numeros y simbolos +# NO usar: @, /, \" +# Ejemplo: "Sacc4_Test_2024!Secure" +rds_master_password = "TU_PASSWORD_SEGURO_AQUI" + +# Llave publica SSH para usuario "thoth" +# Generar con: ssh-keygen -t ed25519 -f ~/.ssh/sacc4-thoth -C "thoth@ccsoft" +# Copiar el contenido del archivo ~/.ssh/sacc4-thoth.pub +thoth_public_key = "ssh-ed25519 AAAA... thoth@ccsoft" + +# Llave publica SSH para usuario "osiris" +# Generar con: ssh-keygen -t ed25519 -f ~/.ssh/sacc4-osiris -C "osiris@ccsoft" +# Copiar el contenido del archivo ~/.ssh/sacc4-osiris.pub +osiris_public_key = "ssh-ed25519 AAAA... osiris@ccsoft" + +# ARN del certificado SSL (obtenido en Paso 2) +# Dejar vacio "" si aun no tienes certificado +# Ejemplo: "arn:aws:acm:us-east-1:668889063715:certificate/..." +certificate_arn = "" +``` + +#### 3.2 Variables Recomendadas (revisar valores) + +```hcl +# Nombre del bucket S3 para frontend +# DEBE ser unico a nivel global en AWS +frontend_bucket_name = "sacc4-frontend-test-668889063715" + +# Tipo de instancia EC2 +ec2_instance_type = "t3.small" + +# Clase de instancia RDS +rds_instance_class = "db.t3.micro" + +# Region y entorno (generalmente no cambian) +aws_region = "mx-central-1" +environment = "test" +project_name = "sacc4" +``` + +#### 3.3 Ejemplo Completo de terraform.tfvars + +```hcl +# ============================================================================= +# VARIABLES DE ENTORNO TEST - SACC v4 +# Cuenta AWS: 668889063715 +# ============================================================================= + +aws_region = "mx-central-1" +environment = "test" +project_name = "sacc4" + +# Dominio principal para el entorno de test +domain_name = "dev-sacc.ccsoft.mx" +api_subdomain = "api.dev-sacc.ccsoft.mx" + +# Networking +vpc_cidr = "10.3.0.0/16" +availability_zones = ["mx-central-1a", "mx-central-1b"] +public_subnet_cidrs = ["10.3.1.0/24", "10.3.2.0/24"] +private_subnet_cidrs = ["10.3.10.0/24", "10.3.11.0/24"] + +# EC2 +ec2_instance_type = "t3.small" +ec2_ami = "ami-0f553e2869648134e" +ec2_root_volume_size = 8 +ec2_root_volume_type = "gp2" +ec2_root_volume_encrypted = true + +# SSH - REEMPLAZAR con tu IP publica +ssh_allowed_cidrs = ["186.96.145.105/32"] + +# Llaves SSH - REEMPLAZAR con tus llaves publicas reales +thoth_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII/RcJmEYOBpfq1tSLltV1pyNB55l1jA2zYr5ZNJ0f41 thoth@ccsoft" +osiris_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFo6CycfgIuCCSVZbhuPwqlAVDxY8YWb1xpvpqxSzMjR osiris@ccsoft" + +# RDS +rds_instance_class = "db.t3.micro" +rds_engine = "mariadb" +rds_engine_version = "10.11.16" +rds_allocated_storage = 20 +rds_max_allocated_storage = 100 +rds_db_name = "ccsoft_sacc4_test" +rds_master_username = "sacc_admin_test" +rds_master_password = "Sacc4_Test_2024!Secure" + +rds_backup_retention_period = 7 +rds_backup_window = "03:00-04:00" +rds_maintenance_window = "Mon:04:00-Mon:05:00" + +# Scheduling (apagado automatico para ahorrar costos en test) +enable_scheduling = true +schedule_timezone = "America/Mexico_City" +schedule_start_cron = "cron(0 13 ? * MON-FRI *)" +schedule_stop_cron = "cron(0 0 ? * TUE-SAT *)" + +# Frontend +frontend_bucket_name = "sacc4-frontend-test-668889063715" +cloudfront_price_class = "PriceClass_100" +enable_cloudfront_logging = false + +# Certificado SSL (dejar vacio si aun no esta listo) +certificate_arn = "" + +# Tags +common_tags = { + Project = "proyectosacc" + ManagedBy = "terraform" + Team = "infra" + Purpose = "test-environment" +} +``` + +⚠️ **Advertencia:** NUNCA commitear `terraform.tfvars` al repositorio. El archivo ya esta en `.gitignore`. + +💡 **Tip:** Si necesitas regenerar llaves SSH, ejecuta: +```bash +ssh-keygen -t ed25519 -f ~/.ssh/sacc4-thoth -C "thoth@ccsoft" +ssh-keygen -t ed25519 -f ~/.ssh/sacc4-osiris -C "osiris@ccsoft" +``` + +--- + +### Paso 4: Inicializar Backend de Terraform + +Terraform necesita un bucket S3 y una tabla DynamoDB para guardar el estado. + +#### 4.1 Configurar Credenciales AWS + +```bash +# Usando AWS CLI (recomendado) +aws configure --profile test +# Ingresar: +# AWS Access Key ID: [tu access key de cuenta 668889063715] +# AWS Secret Access Key: [tu secret key] +# Default region name: mx-central-1 +# Default output format: json + +# Verificar que estas usando la cuenta correcta +aws sts get-caller-identity --profile test +``` + +**Salida esperada:** +```json +{ + "UserId": "AROA...:usuario", + "Account": "668889063715", + "Arn": "arn:aws:sts::668889063715:assumed-role/..." +} +``` + +⚠️ **Advertencia:** Verifica que el Account sea **668889063715**. Si ves 523761210517, estas en PRODUCCION. + +#### 4.2 Crear Backend (Bucket S3 + DynamoDB) + +```bash +cd iac-duplicate/terraform/environments/test + +# Crear bucket S3 para estado Terraform +aws s3api create-bucket \ + --bucket sacc4-terraform-state-test-668889063715 \ + --region mx-central-1 \ + --create-bucket-configuration LocationConstraint=mx-central-1 \ + --profile test + +# Habilitar versionamiento +aws s3api put-bucket-versioning \ + --bucket sacc4-terraform-state-test-668889063715 \ + --versioning-configuration Status=Enabled \ + --profile test + +# Habilitar encriptacion +aws s3api put-bucket-encryption \ + --bucket sacc4-terraform-state-test-668889063715 \ + --server-side-encryption-configuration '{ + "Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}] + }' \ + --profile test + +# Crear tabla DynamoDB para locks +aws dynamodb create-table \ + --table-name sacc4-terraform-locks-test-668889063715 \ + --attribute-definitions AttributeName=LockID,AttributeType=S \ + --key-schema AttributeName=LockID,KeyType=HASH \ + --billing-mode PAY_PER_REQUEST \ + --region mx-central-1 \ + --profile test +``` + +💡 **Tip:** Si los recursos ya existen, los comandos anteriores daran error. Esto es normal y puedes continuar. + +#### 4.3 Inicializar Terraform + +```bash +terraform init +``` + +**Salida esperada:** +``` +Initializing the backend... +Successfully configured the backend "s3"! + +Initializing provider plugins... +- Finding hashicorp/aws versions matching "~> 5.0"... +- Installing hashicorp/aws v5.x.x... + +Terraform has been successfully initialized! +``` + +--- + +### Paso 5: Validar y Planificar + +#### 5.1 Validar Sintaxis + +```bash +terraform validate +``` + +**Salida esperada:** +``` +Success! The configuration is valid. +``` + +#### 5.2 Verificar Plan + +```bash +terraform plan -var-file="terraform.tfvars" +``` + +⚠️ **Advertencia:** Revisa CUIDADOSAMENTE la salida. Verifica que: +- No se vayan a destruir recursos existentes +- Los nombres de recursos sean correctos +- La region sea `mx-central-1` + +El plan mostrara todos los recursos que se crearan: +- 1 VPC +- 2 Subnets publicas +- 2 Subnets privadas +- 1 Internet Gateway +- 1 Instancia EC2 +- 1 Instancia RDS +- 1 Bucket S3 +- 1 Distribucion CloudFront +- 2 Funciones Lambda (scheduling) +- Security Groups, IAM Roles, Route53 records + +--- + +### Paso 6: Aplicar Infraestructura + +```bash +terraform apply -var-file="terraform.tfvars" +``` + +1. Terraform pedira confirmacion: escribir **"yes"** +2. El proceso toma **15-25 minutos** +3. RDS es el recurso que mas tarda en crear (10-15 minutos) + +**Salida esperada al finalizar:** +``` +Apply complete! Resources: 35 added, 0 changed, 0 destroyed. + +Outputs: + +ec2_public_ip = "X.X.X.X" +rds_endpoint = "sacc4-test-db-prod.XXXXXXXX.us-east-1.rds.amazonaws.com" +frontend_url = "https://dev-sacc.ccsoft.mx" +``` + +💡 **Tip:** Guarda los outputs en un archivo para referencia: +```bash +terraform output -json > terraform-outputs.json +``` + +⚠️ **Advertencia:** Si el comando falla a mitad de ejecucion, ejecuta `terraform apply` nuevamente. Terraform reanudara desde donde se detuvo. + +--- + +### Paso 7: Configurar Variables en Bitbucket + +Estas variables permiten que el pipeline CI/CD despliegue automaticamente. + +#### 7.1 Navegar a Configuracion + +1. Ir a **Bitbucket** -> **Repositorio proyectosacc** +2. Clic en **"Repository settings"** (engranaje, barra lateral izquierda) +3. En la seccion **Pipelines**, clic en **"Repository variables"** + +#### 7.2 Variables para Entorno TEST + +| Variable | Valor | Secured | +|----------|-------|---------| +| `TEST_AWS_ACCESS_KEY_ID` | [Access Key de cuenta 668889063715] | Si | +| `TEST_AWS_SECRET_ACCESS_KEY` | [Secret Key de cuenta 668889063715] | Si | +| `TEST_AWS_SESSION_TOKEN` | [Session Token si aplica] | Si | +| `TEST_AWS_ACCOUNT_ID` | `668889063715` | No | +| `TEST_AWS_REGION` | `mx-central-1` | No | +| `TEST_AWS_ROLE_ARN` | `arn:aws:iam::668889063715:role/BitbucketProyectosaccCICDRoleDev` | No | + +#### 7.3 Variables para Entorno PROD (solo referencia) + +| Variable | Valor | Secured | +|----------|-------|---------| +| `PROD_AWS_ACCOUNT_ID` | `523761210517` | No | +| `PROD_AWS_REGION` | `mx-central-1` | No | +| `PROD_AWS_ROLE_ARN` | `arn:aws:iam::523761210517:role/BitbucketProyectosaccCICDRole` | No | + +#### 7.4 Variables de Notificaciones (opcional) + +| Variable | Valor | Secured | +|----------|-------|---------| +| `TELEGRAM_BOT_TOKEN` | [Token del bot de @BotFather] | Si | +| `TELEGRAM_CHAT_ID` | [ID del chat de Telegram] | No | + +#### 7.5 Variables de Conexion SSH + +| Variable | Valor | Secured | +|----------|-------|---------| +| `SSH_PRIVATE_KEY` | [Contenido completo de la llave privada .pem] | Si | +| `SSH_USER` | `ubuntu` | No | +| `SERVER_HOST` | [IP publica de EC2 despues de crearla] | No | + +💡 **Tip:** La IP publica de EC2 la obtienes con: +```bash +cd iac-duplicate/terraform/environments/test +terraform output ec2_public_ip +``` + +⚠️ **Advertencia:** Marca como **"Secured"** todas las variables que contengan passwords, tokens o llaves privadas. Bitbucket las ocultara en los logs. + +--- + +### Paso 8: Desplegar Aplicacion + +Una vez configuradas las variables de Bitbucket: + +```bash +# En tu repositorio local +git checkout test +git add . +git commit -m "feat: configurar entorno test" +git push origin test +``` + +El pipeline se ejecutara automaticamente: +1. **Setup Tools** - Instala dependencias +2. **Validate Terraform** - Valida sintaxis +3. **Plan Terraform** - Genera plan de cambios +4. **Apply Terraform** - Aplica infraestructura +5. **Deploy Application** - Configura servidor con Ansible +6. **Health Check** - Verifica que todo funciona + +💡 **Tip:** Puedes monitorear el pipeline en Bitbucket -> Pipelines. + +--- + +## 3. Comandos de Verificacion + +Despues del despliegue, ejecuta estos comandos para verificar que todo funciona: + +### 3.1 Verificar Infraestructura AWS + +```bash +# Verificar EC2 +aws ec2 describe-instances \ + --region mx-central-1 \ + --profile test \ + --query 'Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress,InstanceType]' + +# Verificar RDS +aws rds describe-db-instances \ + --region mx-central-1 \ + --profile test \ + --query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceStatus,Endpoint.Address]' + +# Verificar S3 +aws s3 ls s3://sacc4-frontend-test-668889063715/ --profile test + +# Verificar CloudFront +aws cloudfront list-distributions \ + --profile test \ + --query 'DistributionList.Items[*].[Id,Status,DomainName]' + +# Verificar Lambda +aws lambda list-functions \ + --region mx-central-1 \ + --profile test \ + --query 'Functions[*].[FunctionName,State]' +``` + +### 3.2 Verificar Conectividad + +```bash +# Obtener IP de EC2 +EC2_IP=$(terraform output -raw ec2_public_ip) + +# Verificar SSH +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@$EC2_IP "echo 'Conexion SSH OK'" + +# Verificar Nginx +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@$EC2_IP "sudo systemctl status nginx" + +# Verificar servicios Java (puertos 8080-8085) +for port in 8080 8081 8082 8083 8084 8085; do + echo "Puerto $port: $(ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@$EC2_IP "curl -s -o /dev/null -w '%{http_code}' http://localhost:$port/actuator/health" 2>/dev/null || echo 'FAIL')" +done + +# Health check via dominio +curl -f https://dev-sacc.ccsoft.mx/api/health || echo "API no responde" +curl -f -I https://dev-sacc.ccsoft.mx || echo "Frontend no responde" +``` + +### 3.3 Verificar Base de Datos + +```bash +# Obtener endpoint RDS +RDS_ENDPOINT=$(terraform output -raw rds_endpoint) + +# Verificar conexion desde EC2 +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@$EC2_IP \ + "mysql -h $RDS_ENDPOINT -u sacc_app_user -p -e 'SELECT 1;'" + +# Verificar que RDS no es publicamente accesible +aws rds describe-db-instances \ + --region mx-central-1 \ + --profile test \ + --query 'DBInstances[*].PubliclyAccessible' +# Salida esperada: [false] +``` + +### 3.4 Verificar DNS + +```bash +# Verificar que los registros DNS resuelven correctamente +dig +short dev-sacc.ccsoft.mx +dig +short api.dev-sacc.ccsoft.mx + +# Verificar certificado SSL +curl -vI https://dev-sacc.ccsoft.mx 2>&1 | grep "SSL certificate" +``` + +--- + +## 4. Estimacion de Costos + +### Costo Mensual Aproximado (TEST) + +#### Con Scheduling Habilitado (Recomendado) + +El scheduling apaga EC2 y RDS automaticamente fuera de horario laboral: + +| Servicio | Tipo | Horas/Dia | Costo/Mes (USD) | +|----------|------|-----------|-----------------| +| EC2 | t3.small | ~10 | ~$7 | +| RDS | db.t3.micro | ~10 | ~$4 | +| S3 | ~1GB | 24/7 | ~$0.20 | +| CloudFront | Bajo trafico | 24/7 | ~$0.50 | +| Route53 | 1 hosted zone | 24/7 | ~$0.50 | +| Lambda | 2 funciones | 24/7 | ~$0 | +| Data Transfer | Estimado | - | ~$1 | +| **TOTAL** | | | **~$13/mes** | + +#### Sin Scheduling (24/7) + +| Servicio | Tipo | Costo/Mes (USD) | +|----------|------|-----------------| +| EC2 | t3.small | ~$15 | +| RDS | db.t3.micro | ~$13 | +| S3 | ~1GB | ~$0.20 | +| CloudFront | Bajo trafico | ~$0.50 | +| Route53 | 1 hosted zone | ~$0.50 | +| Lambda | 2 funciones | ~$0 | +| Data Transfer | Estimado | ~$5 | +| **TOTAL** | | **~$35-40/mes** | + +💡 **Tip:** El scheduling ahorra aproximadamente **$20-25/mes** apagando recursos en horario no laboral. + +⚠️ **Advertencia:** Los costos pueden variar segun el uso real. Configurar un **AWS Budget** con alerta a $50/mes: +```bash +aws budgets create-budget --budget file://budget.json --notifications-with-subscribers file://notifications.json +``` + +--- + +## 5. Solucion de Problemas + +### Problema 1: Certificado ACM No Se Valida + +**Sintoma:** CloudFront muestra error o Terraform falla con certificado no encontrado. + +**Solucion:** +1. Verificar que el certificado esta en **us-east-1** (N. Virginia) +2. Verificar que los registros CNAME de validacion existen en Route53 +3. Esperar 15-30 minutos despues de crear el registro DNS +4. Si persiste, eliminar el certificado y solicitar uno nuevo + +```bash +# Verificar estado del certificado +aws acm describe-certificate \ + --certificate-arn arn:aws:acm:us-east-1:668889063715:certificate/XXXX \ + --region us-east-1 \ + --query 'Certificate.Status' +``` + +--- + +### Problema 2: Security Group Bloquea SSH + +**Sintoma:** `ssh: connect to host X.X.X.X port 22: Connection timed out` + +**Solucion:** +1. Verificar que tu IP actual esta en `ssh_allowed_cidrs` +2. Si tu IP cambio, actualizar terraform.tfvars y re-aplicar: + +```bash +# Obtener tu IP actual +curl -s https://checkip.amazonaws.com + +# Editar terraform.tfvars con la nueva IP +terraform apply -var-file="terraform.tfvars" -target=module.security_groups +``` + +3. Verificar que el Security Group permite puerto 22 desde tu CIDR + +--- + +### Problema 3: Contrasena RDS Demasiado Corta + +**Sintoma:** Terraform falla con `InvalidParameterValue: Password must be at least 16 characters` + +**Solucion:** +```hcl +# terraform.tfvars - Usar contrasena de 16+ caracteres +rds_master_password = "Sacc4_Test_2024!Secure" +``` + +Requisitos: +- Minimo 16 caracteres +- Al menos 1 mayuscula +- Al menos 1 minuscula +- Al menos 1 numero +- Al menos 1 simbolo +- NO usar: `@`, `/`, `\`, `"` + +--- + +### Problema 4: Terraform State Lock + +**Sintoma:** `Error acquiring the state lock: ConditionalCheckFailedException` + +**Solucion:** +```bash +# Verificar si hay un lock activo +aws dynamodb get-item \ + --table-name sacc4-terraform-locks-test-668889063715 \ + --key '{"LockID":{"S":"sacc4-test/infrastructure/terraform.tfstate-md5"}}' \ + --region mx-central-1 + +# Si el proceso anterior se murio, forzar unlock +terraform force-unlock +``` + +⚠️ **Advertencia:** Solo usar `force-unlock` si estas SEGURO de que no hay otro proceso ejecutando Terraform. + +--- + +### Problema 5: Bitbucket Pipeline Falla + +**Sintoma:** Pipeline falla en paso "Apply Terraform" o "Deploy Application" + +**Solucion:** + +1. **Verificar credenciales AWS:** +```bash +# En tu local, verificar que las credenciales funcionan +aws sts get-caller-identity --profile test +``` + +2. **Verificar variables en Bitbucket:** + - Ir a Repository Settings -> Repository variables + - Confirmar que `TEST_AWS_ACCESS_KEY_ID` y `TEST_AWS_SECRET_ACCESS_KEY` estan correctas + - Confirmar que estan marcadas como "Secured" + +3. **Verificar workspace de Terraform:** +```bash +# El pipeline debe seleccionar el workspace test +terraform workspace select test +``` + +4. **Verificar archivo terraform.tfvars:** + - Confirmar que existe en `iac-duplicate/terraform/environments/test/terraform.tfvars` + - Confirmar que tiene todos los valores requeridos + +5. **Verificar IP en Security Group:** + - Si el pipeline no puede conectar por SSH, verificar que la IP del runner de Bitbucket esta permitida + +--- + +### Problema 6: Bucket S3 Ya Existe + +**Sintoma:** `Error creating S3 bucket: BucketAlreadyExists` + +**Solucion:** +Los nombres de bucket S3 son unicos GLOBALMENTE en AWS. Cambiar el nombre: + +```hcl +# terraform.tfvars +frontend_bucket_name = "sacc4-frontend-test-668889063715-$(date +%s)" +``` + +O usar un nombre diferente: +```hcl +frontend_bucket_name = "mi-empresa-sacc4-test-668889063715" +``` + +--- + +### Problema 7: RDS No Responde Desde EC2 + +**Sintoma:** La aplicacion no puede conectar a la base de datos. + +**Solucion:** +```bash +# Verificar que RDS esta en estado "available" +aws rds describe-db-instances \ + --region mx-central-1 \ + --profile test \ + --query 'DBInstances[*].DBInstanceStatus' + +# Verificar Security Group de RDS permite trafico desde SG de EC2 +aws ec2 describe-security-groups \ + --region mx-central-1 \ + --profile test \ + --query 'SecurityGroups[*].[GroupName,IpPermissions]' + +# Probar conexion desde EC2 +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@[EC2_IP] \ + "nc -zv [RDS_ENDPOINT] 3306" +``` + +--- + +## 6. Limpieza (Destruir Entorno) + +⚠️ **ATENCION:** Esta accion es IRREVERSIBLE. Se destruiran TODOS los recursos del entorno TEST. + +### 6.1 Metodo Seguro (Recomendado) + +```bash +cd iac-duplicate/terraform/environments/test + +# Verificar que estas en la cuenta correcta +aws sts get-caller-identity --profile test +# Confirmar: Account = 668889063715 + +# Crear backup de RDS (opcional pero recomendado) +aws rds create-db-snapshot \ + --db-instance-identifier sacc4-test-db-prod \ + --db-snapshot-identifier sacc4-test-final-$(date +%Y%m%d-%H%M%S) \ + --region mx-central-1 \ + --profile test + +# Destruir infraestructura +terraform destroy -var-file="terraform.tfvars" +``` + +1. Terraform mostrara un plan de destruccion +2. Escribir **"yes"** para confirmar +3. El proceso toma **10-15 minutos** + +### 6.2 Usar Script de Destruccion + +Existe un script automatizado con confirmaciones adicionales: + +```bash +cd iac-duplicate/scripts +./destroy-test-environment.sh +``` + +El script: +1. Pide confirmacion multiple (escribir "DESTRUIR" y luego "SI") +2. Crea snapshot final de RDS +3. Ejecuta `terraform destroy` +4. Opcionalmente elimina bucket de estado y tabla DynamoDB + +### 6.3 Opciones del Script + +```bash +# Omitir confirmaciones (USAR CON PRECAUCION) +./destroy-test-environment.sh --force + +# Omitir backup de RDS +./destroy-test-environment.sh --skip-rds-backup + +# Eliminar contenido de S3 antes de destruir +./destroy-test-environment.sh --delete-s3 + +# Conservar bucket de estado Terraform +./destroy-test-environment.sh --keep-state +``` + +### 6.4 Destruir desde Bitbucket + +Tambien puedes destruir el entorno desde el pipeline: + +1. Ir a **Bitbucket** -> **Pipelines** -> **Run pipeline** +2. Seleccionar branch **test** +3. Seleccionar pipeline **destroy-test** +4. Clic en **"Run"** + +⚠️ **Advertencia:** Este pipeline destruira TODO el entorno de test sin pedir confirmacion adicional. + +### 6.5 Verificar Destruccion Completa + +```bash +# Verificar que no quedan instancias EC2 +aws ec2 describe-instances --region mx-central-1 --profile test \ + --filters "Name=instance-state-name,Values=running" \ + --query 'Reservations[*].Instances[*].InstanceId' +# Salida esperada: null o lista vacia + +# Verificar que no quedan instancias RDS +aws rds describe-db-instances --region mx-central-1 --profile test \ + --query 'DBInstances[*].DBInstanceIdentifier' +# Salida esperada: null o lista vacia + +# Verificar que no quedan distribuciones CloudFront activas +aws cloudfront list-distributions --profile test \ + --query 'DistributionList.Items[?Status==`Deployed`].Id' +# Salida esperada: null o lista vacia +``` + +--- + +## Checklist Final + +Antes de considerar el entorno como listo, verifica: + +- [ ] Las 4 variables obligatorias estan completadas en `terraform.tfvars` + - [ ] `ssh_allowed_cidrs` con tu IP actual + - [ ] `rds_master_password` con 16+ caracteres seguros + - [ ] `thoth_public_key` con tu llave publica + - [ ] `osiris_public_key` con tu llave publica +- [ ] Certificado ACM creado y validado en us-east-1 (o dejado vacio) +- [ ] Backend S3 y DynamoDB creados +- [ ] `terraform validate` pasa sin errores +- [ ] `terraform plan` muestra solo recursos a CREAR (ninguno a destruir) +- [ ] Variables de Bitbucket configuradas +- [ ] Pipeline ejecutado exitosamente +- [ ] Health checks pasan (puertos 8080-8085) +- [ ] DNS resuelve correctamente (`dev-sacc.ccsoft.mx`) +- [ ] Conexion a RDS funciona desde EC2 +- [ ] Scheduling configurado (ahorro de costos) + +--- + +## Referencias Rapidas + +| Recurso | Valor / Comando | +|---------|-----------------| +| Cuenta TEST | `668889063715` | +| Cuenta PROD | `523761210517` | +| Region | `mx-central-1` | +| Dominio TEST | `dev-sacc.ccsoft.mx` | +| API TEST | `api.dev-sacc.ccsoft.mx` | +| Pipeline | Rama `test` -> deploy automatico | +| Destruir | `./scripts/destroy-test-environment.sh` | +| Logs Terraform | `terraform output -json > outputs.json` | + +--- + +*Documento generado para proyectosacc - SACC v4* +*NO modificar archivos existentes sin revision* diff --git a/README.md b/README.md new file mode 100644 index 0000000..fcdca6d --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# SACC v4 - Scripts de Duplicación de Infraestructura +# ==================================================== +# Este directorio contiene scripts para duplicar automáticamente +# el entorno de producción SACC v4 en una cuenta AWS de pruebas. +# +# ATENCIÓN: NO ejecutar en producción. Solo para entornos de test. + +## Estructura +``` +iac-duplicate/ +├── terraform/ # Infraestructura como código +│ ├── main.tf # Orquestación principal +│ ├── variables.tf # Variables configurables +│ ├── bootstrap.tf # Backend S3/DynamoDB +│ └── modules/ # Módulos reutilizables +│ ├── vpc/ +│ ├── ec2/ +│ ├── rds/ +│ ├── security-groups/ +│ ├── iam/ +│ ├── s3-cloudfront/ +│ ├── route53/ +│ └── lambda-scheduler/ +├── ansible/ # Configuración post-deploy +│ └── playbooks/ +│ └── site.yml # Playbook principal +├── bitbucket/ # Pipeline CI/CD +│ └── bitbucket-pipelines.yml +└── scripts/ # Scripts auxiliares + └── ec2-user-data.sh +``` + +## Uso Rápido + +### 1. Preparar Cuenta AWS Test +```bash +# Configurar credenciales +export AWS_ACCESS_KEY_ID=ASIAXT4UZ2SK5SFE4QVR +export AWS_SECRET_ACCESS_KEY=... +export AWS_SESSION_TOKEN=... +export AWS_DEFAULT_REGION=mx-central-1 +``` + +### 2. Crear Backend Terraform +```bash +cd iac-duplicate/terraform +terraform init +terraform apply -target=aws_s3_bucket.terraform_state +terraform apply -target=aws_dynamodb_table.terraform_locks +``` + +### 3. Configurar Variables +```bash +cp terraform.tfvars.example terraform.tfvars +# Editar terraform.tfvars con valores de la nueva cuenta +``` + +### 4. Desplegar Infraestructura +```bash +terraform init +terraform plan +terraform apply +``` + +### 5. Configurar Servidor (Ansible) +```bash +cd ../ansible +ansible-playbook -i inventory playbooks/site.yml +``` + +## Variables Importantes + +| Variable | Descripción | Ejemplo | +|----------|-------------|---------| +| `my_ip` | Tu IP pública para SSH | `192.168.1.1/32` | +| `db_password` | Contraseña RDS | `Cambiar123!` | +| `domain_name` | Dominio para la app | `test-sacc.ccsoft.mx` | +| `certificate_arn` | ARN certificado ACM | `arn:aws:acm:...` | + +## Próximos Pasos +1. Revisar `docs/PRODUCTION_CONFIG_EXTRACTION.md` para detalles exactos +2. Configurar Bitbucket Pipeline con variables de entorno +3. Desplegar aplicación Java a `/opt/sacc4/*/current/` +4. Verificar health checks en puertos 8080-8085 + +## Notas de Seguridad +- Cambiar todas las contraseñas por defecto +- Restringir Security Groups (no usar 0.0.0.0/0) +- Habilitar CloudTrail para auditoría +- Configurar AWS Config para compliance \ No newline at end of file diff --git a/ansible/playbooks/site.yml b/ansible/playbooks/site.yml new file mode 100644 index 0000000..b2030ba --- /dev/null +++ b/ansible/playbooks/site.yml @@ -0,0 +1,175 @@ +--- +- name: Configuracion base de servidor SACC v4 + hosts: all + become: yes + vars: + java_version: "21" + sacc4_user: "osiris" + sacc4_group: "duat" + sacc4_home: "/opt/sacc4" + services: + - api-sacc4-authentication + - api-sacc4-users + - api-sacc4-tickets + - api-sacc4-privileges + - api-sacc4-rols + - api-sacc4-associates + + tasks: + - name: Actualizar sistema + apt: + update_cache: yes + upgrade: dist + + - name: Instalar dependencias + apt: + name: + - openjdk-21-jdk + - nginx + - unzip + - jq + - net-tools + - htop + - logrotate + - curl + - python3 + - python3-pip + state: present + + - name: Crear grupo duat + group: + name: "{{ sacc4_group }}" + gid: 1006 + state: present + + - name: Crear usuario osiris + user: + name: "{{ sacc4_user }}" + uid: 997 + group: "{{ sacc4_group }}" + shell: /bin/bash + home: "/home/{{ sacc4_user }}" + state: present + + - name: Crear usuario thoth + user: + name: thoth + uid: 1001 + group: "{{ sacc4_group }}" + shell: /bin/bash + home: "/home/thoth" + state: present + + - name: Crear directorios de SACC + file: + path: "{{ sacc4_home }}/{{ item }}" + state: directory + owner: thoth + group: "{{ sacc4_group }}" + mode: '2775' + with_items: "{{ services }}" + + - name: Crear directorios de logs + file: + path: "/var/log/sacc4/{{ item }}" + state: directory + owner: "{{ sacc4_user }}" + group: "{{ sacc4_group }}" + mode: '0755' + with_items: "{{ services }}" + + - name: Configurar logrotate + template: + src: logrotate-sacc4.j2 + dest: /etc/logrotate.d/sacc4 + mode: '0644' + + - name: Crear archivo de variables de entorno + template: + src: sacc4.env.j2 + dest: /etc/sacc4/sacc4.env + owner: root + group: "{{ sacc4_group }}" + mode: '0640' + + - name: Configurar nginx + template: + src: nginx-sacc4.conf.j2 + dest: /etc/nginx/sites-available/sacc4 + owner: root + group: root + mode: '0644' + notify: restart nginx + + - name: Habilitar sitio nginx + file: + src: /etc/nginx/sites-available/sacc4 + dest: /etc/nginx/sites-enabled/sacc4 + state: link + notify: restart nginx + + - name: Deshabilitar sitio default + file: + path: /etc/nginx/sites-enabled/default + state: absent + notify: restart nginx + + handlers: + - name: restart nginx + service: + name: nginx + state: restarted + +- name: Despliegue de microservicios + hosts: all + become: yes + vars: + sacc4_user: "osiris" + services: + - { name: api-sacc4-authentication, port: 8080 } + - { name: api-sacc4-users, port: 8081 } + - { name: api-sacc4-tickets, port: 8082 } + - { name: api-sacc4-privileges, port: 8083 } + - { name: api-sacc4-rols, port: 8084 } + - { name: api-sacc4-associates, port: 8085 } + + tasks: + - name: Crear directorios para cada servicio + file: + path: "/opt/sacc4/{{ item.name }}/current" + state: directory + owner: thoth + group: duat + mode: '2775' + with_items: "{{ services }}" + + - name: Crear directorios de logs + file: + path: "/var/log/sacc4/{{ item.name }}" + state: directory + owner: "{{ sacc4_user }}" + group: duat + mode: '0755' + with_items: "{{ services }}" + + - name: Crear archivos systemd + template: + src: systemd-service.j2 + dest: "/etc/systemd/system/{{ item.name }}.service" + owner: root + group: root + mode: '0644' + with_items: "{{ services }}" + notify: reload systemd + + - name: Habilitar servicios + systemd: + name: "{{ item.name }}" + enabled: yes + daemon_reload: yes + with_items: "{{ services }}" + + handlers: + - name: reload systemd + systemd: + daemon_reload: yes \ No newline at end of file diff --git a/ansible/templates/systemd-service.j2 b/ansible/templates/systemd-service.j2 new file mode 100644 index 0000000..e709d53 --- /dev/null +++ b/ansible/templates/systemd-service.j2 @@ -0,0 +1,27 @@ +[Unit] +Description=SACC4 {{ item.name }} Service +After=network.target + +[Service] +Type=simple +User=osiris +Group=duat +WorkingDirectory=/opt/sacc4/{{ item.name }}/current +ExecStart=/usr/bin/java -jar /opt/sacc4/{{ item.name }}/current/{{ item.name }}.jar +ExecStop=/bin/kill -15 $MAINPID +Restart=on-failure +RestartSec=10 +StandardOutput=append:/var/log/sacc4/{{ item.name }}/{{ item.name }}-service.log +StandardError=append:/var/log/sacc4/{{ item.name }}/{{ item.name }}-error.log + +# Límites de recursos +MemoryLimit=512M +CPUQuota=50% + +# Variables de entorno +EnvironmentFile=/etc/sacc4/sacc4.env +Environment="SERVER_PORT={{ item.port }}" +Environment="LOG_PATH=/var/log/sacc4/{{ item.name }}/{{ item.name }}.log" + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/bitbucket/README_PIPELINE.md b/bitbucket/README_PIPELINE.md new file mode 100644 index 0000000..2107b79 --- /dev/null +++ b/bitbucket/README_PIPELINE.md @@ -0,0 +1,152 @@ +# Pipeline Multi-Entorno - SACC v4 +# ================================= + +Este pipeline de Bitbucket permite desplegar SACC v4 en dos entornos diferentes usando el mismo código base, cambiando solo las variables según la rama. + +## Flujo de Trabajo por Ramas + +``` +┌─────────────────────────────────────────────────────────────┐ +│ RAMA 'test' / 'develop' │ +│ → Despliegue AUTOMÁTICO a TEST │ +│ → Cuenta AWS: 668889063715 │ +│ → Variables: environments/test/terraform.tfvars │ +│ → Workspace Terraform: test │ +└─────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────┐ +│ RAMA 'main' / 'master' │ +│ → Despliegue MANUAL a PRODUCCIÓN │ +│ → Requiere aprobación en Bitbucket │ +│ → Cuenta AWS: 523761210517 │ +│ → Variables: environments/prod/terraform.tfvars │ +│ → Workspace Terraform: prod │ +└─────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────┐ +│ PULL REQUESTS │ +│ → Solo validación (no despliegue) │ +│ → Terraform validate + plan │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Variables de Repositorio Requeridas + +Configurar estas variables en **Bitbucket > Repositorio > Settings > Repository variables**: + +### Para TEST (Rama test/develop) +| Variable | Descripción | +|----------|-------------| +| `TEST_AWS_ACCESS_KEY_ID` | Access Key cuenta 668889063715 | +| `TEST_AWS_SECRET_ACCESS_KEY` | Secret Key cuenta 668889063715 | +| `TEST_AWS_SESSION_TOKEN` | Session Token (si aplica) | + +### Para PROD (Rama main/master) +| Variable | Descripción | +|----------|-------------| +| `PROD_AWS_ACCESS_KEY_ID` | Access Key cuenta 523761210517 | +| `PROD_AWS_SECRET_ACCESS_KEY` | Secret Key cuenta 523761210517 | +| `PROD_AWS_SESSION_TOKEN` | Session Token (si aplica) | + +### Opcionales (Notificaciones) +| Variable | Descripción | +|----------|-------------| +| `TELEGRAM_BOT_TOKEN` | Token del bot de Telegram | +| `TELEGRAM_CHAT_ID` | ID del chat para notificaciones | + +## Estructura de Archivos + +``` +iac-duplicate/ +├── terraform/ +│ ├── main.tf # Código base (igual para ambos) +│ ├── variables.tf # Variables definidas +│ ├── environments/ +│ │ ├── test/ +│ │ │ └── terraform.tfvars # Valores TEST +│ │ └── prod/ +│ │ └── terraform.tfvars # Valores PROD +│ └── modules/ # Módulos reutilizables +├── ansible/ +│ └── playbooks/ +│ └── site.yml # Configuración post-deploy +└── bitbucket/ + └── bitbucket-pipelines.yml # Este pipeline +``` + +## Cómo Desplegar + +### A TEST (Automático) +```bash +# 1. Hacer cambios en la rama test +git checkout test +git add . +git commit -m "feat: nueva funcionalidad" +git push origin test + +# 2. Bitbucket despliega automáticamente +# - Terraform Apply a cuenta 668889063715 +# - Ansible configura el servidor +# - Health checks automáticos +``` + +### A PRODUCCIÓN (Manual) +```bash +# 1. Crear PR de test → main +# 2. Revisar y aprobar PR +# 3. Merge a main + +# 4. En Bitbucket, ir a Pipelines +# 5. Ver pipeline de la rama main +# 6. Clic en "Run" para aprobar el despliegue a PROD +# 7. Esperar validación manual +``` + +## Workspaces Terraform + +El pipeline usa workspaces de Terraform para aislar estados: + +```bash +# TEST +cd terraform +terraform workspace select test +terraform plan -var-file="environments/test/terraform.tfvars" + +# PROD +cd terraform +terraform workspace select prod +terraform plan -var-file="environments/prod/terraform.tfvars" +``` + +## Custom Pipelines + +### Destruir entorno TEST +```bash +# En Bitbucket > Pipelines > Run pipeline +# Seleccionar "destroy-test" +# ⚠️ Esto elimina TODO el entorno de test +``` + +## Seguridad + +- ✅ PROD requiere aprobación manual (trigger: manual) +- ✅ TEST se destruye automáticamente (scheduling) +- ✅ Variables separadas por entorno +- ✅ Workspaces aislados en Terraform +- ✅ Health checks en todos los puertos (8080-8085) + +## Troubleshooting + +| Problema | Solución | +|----------|----------| +| "Access Denied" en PROD | Verificar credenciales PROD_AWS_* | +| "Workspace not found" | Ejecutar `terraform workspace new test/prod` | +| "Port 808X failed" | Verificar que los JAR estén desplegados en EC2 | +| "Nginx not responding" | Revisar `systemctl status nginx` en EC2 | + +## Notas + +- El pipeline usa la misma imagen Docker `ccsoft/ccsoft-pipeline:latest` +- Terraform workspaces evitan conflicto de estados +- Los artifacts se pasan entre steps automáticamente +- Las notificaciones Telegram son opcionales \ No newline at end of file diff --git a/bitbucket/bitbucket-pipelines.yml b/bitbucket/bitbucket-pipelines.yml new file mode 100644 index 0000000..0a5d382 --- /dev/null +++ b/bitbucket/bitbucket-pipelines.yml @@ -0,0 +1,277 @@ +image: ccsoft/ccsoft-pipeline:latest + +# ============================================================ +# Pipeline Multi-Entorno: Producción y Pruebas +# ============================================================ +# Uso: +# - Rama 'test' o 'develop' → Despliega automáticamente a TEST +# - Rama 'main' o 'master' → Requiere aprobación manual para PROD +# - Pull Requests → Solo validación (sin despliegue) +# +# Variables de Repositorio Requeridas en Bitbucket: +# TEST_AWS_ACCESS_KEY_ID, TEST_AWS_SECRET_ACCESS_KEY, TEST_AWS_SESSION_TOKEN +# PROD_AWS_ACCESS_KEY_ID, PROD_AWS_SECRET_ACCESS_KEY, PROD_AWS_SESSION_TOKEN +# ============================================================ + +definitions: + caches: + terraform: ~/.terraform.d/plugin-cache + npm: ~/.npm + gradle: ~/.gradle + + services: + docker: + memory: 3072 + + steps: + # Paso reutilizable: Setup SSH y herramientas + - step: &setup-tools + name: Setup Tools + script: + - apt-get update -qq + - apt-get install -y -qq openssh-client jq unzip curl + - terraform --version || (wget -q https://releases.hashicorp.com/terraform/1.5.0/terraform_1.5.0_linux_amd64.zip && unzip -q terraform_1.5.0_linux_amd64.zip && mv terraform /usr/local/bin/) + - ansible --version || apt-get install -y -qq ansible + - aws --version || pip install awscli + - echo "Tools ready" + + # Paso reutilizable: Validar Terraform + - step: &validate-terraform + name: Validate Terraform + script: + - cd iac-duplicate/terraform + - terraform init -backend=false + - terraform validate + - terraform fmt -check -recursive + + # Paso reutilizable: Plan Terraform (TEST) + - step: &plan-test + name: Plan Terraform (TEST) + deployment: test-plan + script: + - cd iac-duplicate/terraform + - export AWS_ACCESS_KEY_ID="$TEST_AWS_ACCESS_KEY_ID" + - export AWS_SECRET_ACCESS_KEY="$TEST_AWS_SECRET_ACCESS_KEY" + - export AWS_SESSION_TOKEN="$TEST_AWS_SESSION_TOKEN" + - export AWS_DEFAULT_REGION="mx-central-1" + - terraform init + - terraform workspace select test || terraform workspace new test + - terraform plan -var-file="environments/test/terraform.tfvars" -out=tfplan-test + artifacts: + - iac-duplicate/terraform/tfplan-test + + # Paso reutilizable: Apply Terraform (TEST) + - step: &apply-test + name: Apply Terraform (TEST) + deployment: test + trigger: automatic + script: + - cd iac-duplicate/terraform + - export AWS_ACCESS_KEY_ID="$TEST_AWS_ACCESS_KEY_ID" + - export AWS_SECRET_ACCESS_KEY="$TEST_AWS_SECRET_ACCESS_KEY" + - export AWS_SESSION_TOKEN="$TEST_AWS_SESSION_TOKEN" + - export AWS_DEFAULT_REGION="mx-central-1" + - terraform init + - terraform workspace select test + - terraform apply -auto-approve tfplan-test + - terraform output -json > terraform-outputs.json + - cat terraform-outputs.json + artifacts: + - iac-duplicate/terraform/terraform-outputs.json + + # Paso reutilizable: Ansible Deploy (TEST) + - step: &deploy-test + name: Deploy Application (TEST) + deployment: test-deploy + script: + - cd iac-duplicate/ansible + - EC2_IP=$(cat ../terraform/terraform-outputs.json | jq -r '.ec2_public_ip.value') + - echo "[test]" > inventory + - echo "$EC2_IP ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/sacc4-test-key.pem" >> inventory + - echo "[test:vars]" >> inventory + - echo "ansible_python_interpreter=/usr/bin/python3" >> inventory + - echo "environment=test" >> inventory + - chmod 600 ~/.ssh/sacc4-test-key.pem 2>/dev/null || true + - ansible-playbook -i inventory playbooks/site.yml + + # Paso reutilizable: Health Check (TEST) + - step: &health-test + name: Health Check (TEST) + script: + - EC2_IP=$(cat iac-duplicate/terraform/terraform-outputs.json | jq -r '.ec2_public_ip.value') + - echo "Checking health on $EC2_IP..." + - for port in 8080 8081 8082 8083 8084 8085; do + echo "Port $port: $(curl -s -o /dev/null -w '%{http_code}' http://$EC2_IP:$port/actuator/health || echo 'FAILED')"; + done + - curl -f -I http://$EC2_IP:80 || echo "Nginx check: WARNING" + + # Paso reutilizable: Plan Terraform (PROD) + - step: &plan-prod + name: Plan Terraform (PROD) + deployment: prod-plan + script: + - cd iac-duplicate/terraform + - export AWS_ACCESS_KEY_ID="$PROD_AWS_ACCESS_KEY_ID" + - export AWS_SECRET_ACCESS_KEY="$PROD_AWS_SECRET_ACCESS_KEY" + - export AWS_SESSION_TOKEN="$PROD_AWS_SESSION_TOKEN" + - export AWS_DEFAULT_REGION="mx-central-1" + - terraform init + - terraform workspace select prod || terraform workspace new prod + - terraform plan -var-file="environments/prod/terraform.tfvars" -out=tfplan-prod + artifacts: + - iac-duplicate/terraform/tfplan-prod + + # Paso reutilizable: Apply Terraform (PROD) - REQUIERE APROBACIÓN + - step: &apply-prod + name: Apply Terraform (PROD) + deployment: production + trigger: manual + script: + - cd iac-duplicate/terraform + - export AWS_ACCESS_KEY_ID="$PROD_AWS_ACCESS_KEY_ID" + - export AWS_SECRET_ACCESS_KEY="$PROD_AWS_SECRET_ACCESS_KEY" + - export AWS_SESSION_TOKEN="$PROD_AWS_SESSION_TOKEN" + - export AWS_DEFAULT_REGION="mx-central-1" + - terraform init + - terraform workspace select prod + - terraform apply -auto-approve tfplan-prod + - terraform output -json > terraform-outputs-prod.json + artifacts: + - iac-duplicate/terraform/terraform-outputs-prod.json + + # Paso reutilizable: Notificación Telegram + - step: ¬ify + name: Notify Results + script: + - |- + if [ -n "$TELEGRAM_BOT_TOKEN" ] && [ -n "$TELEGRAM_CHAT_ID" ]; then + MESSAGE="✅ SACC4 Pipeline: $BITBUCKET_BRANCH - $BITBUCKET_STEP_KEY completado" + curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \ + -d "chat_id=$TELEGRAM_CHAT_ID" \ + -d "text=$MESSAGE" >/dev/null + fi + +# ============================================================ +# PIPELINE POR RAMAS +# ============================================================ + +pipelines: + # RAMA TEST / DEVELOP → Despliegue automático a TEST + branches: + test: + - step: *setup-tools + - step: *validate-terraform + - step: *plan-test + - step: *apply-test + - step: *deploy-test + - step: *health-test + - step: + <<: *notify + after-script: + - echo "Test environment deployment completed" + + develop: + - step: *setup-tools + - step: *validate-terraform + - step: *plan-test + - step: *apply-test + - step: *deploy-test + - step: *health-test + - step: + <<: *notify + after-script: + - echo "Develop environment deployment completed" + + # RAMA MAIN / MASTER → Requiere aprobación para PROD + main: + - step: *setup-tools + - step: *validate-terraform + - step: *plan-prod + - step: + <<: *apply-prod + trigger: manual # ⚠️ Requiere clic en "Run" en Bitbucket + - step: + name: Deploy Application (PROD) + deployment: production-deploy + script: + - cd iac-duplicate/ansible + - EC2_IP=$(cat ../terraform/terraform-outputs-prod.json | jq -r '.ec2_public_ip.value') + - echo "[prod]" > inventory + - echo "$EC2_IP ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/sacc4-prod-key.pem" >> inventory + - chmod 600 ~/.ssh/sacc4-prod-key.pem 2>/dev/null || true + - ansible-playbook -i inventory playbooks/site.yml + - step: + name: Health Check (PROD) + script: + - EC2_IP=$(cat iac-duplicate/terraform/terraform-outputs-prod.json | jq -r '.ec2_public_ip.value') + - for port in 8080 8081 8082 8083 8084 8085; do + echo "Port $port: $(curl -s -o /dev/null -w '%{http_code}' http://$EC2_IP:$port/actuator/health || echo 'FAILED')"; + done + - step: + <<: *notify + after-script: + - echo "⚠️ PRODUCTION deployment completed - Review required" + + master: + - step: *setup-tools + - step: *validate-terraform + - step: *plan-prod + - step: + <<: *apply-prod + trigger: manual + - step: + name: Deploy Application (PROD) + deployment: production-deploy + script: + - cd iac-duplicate/ansible + - EC2_IP=$(cat ../terraform/terraform-outputs-prod.json | jq -r '.ec2_public_ip.value') + - echo "[prod]" > inventory + - echo "$EC2_IP ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/sacc4-prod-key.pem" >> inventory + - chmod 600 ~/.ssh/sacc4-prod-key.pem 2>/dev/null || true + - ansible-playbook -i inventory playbooks/site.yml + - step: + <<: *notify + after-script: + - echo "⚠️ PRODUCTION deployment completed" + + # PULL REQUESTS → Solo validación, sin despliegue + pull-requests: + '**': + - step: + name: Code Quality Check + script: + - echo "Checking code quality..." + - terraform fmt -check -recursive || true + - step: + name: Validate Terraform + script: + - cd iac-duplicate/terraform + - terraform init -backend=false + - terraform validate + - step: + name: Test Plan (TEST Environment) + script: + - cd iac-duplicate/terraform + - terraform init -backend=false + - terraform plan -var-file="environments/test/terraform.tfvars" + after-script: + - echo "PR validation completed - No changes applied" + + # CUSTOM PIPELINE: Destruir entorno TEST + custom: + destroy-test: + - step: + name: Destroy TEST Environment + deployment: test + trigger: manual + script: + - cd iac-duplicate/terraform + - export AWS_ACCESS_KEY_ID="$TEST_AWS_ACCESS_KEY_ID" + - export AWS_SECRET_ACCESS_KEY="$TEST_AWS_SECRET_ACCESS_KEY" + - export AWS_SESSION_TOKEN="$TEST_AWS_SESSION_TOKEN" + - export AWS_DEFAULT_REGION="mx-central-1" + - terraform init + - terraform workspace select test + - echo "⚠️ WARNING: This will destroy the TEST environment!" + - terraform destroy -var-file="environments/test/terraform.tfvars" -auto-approve + - echo "TEST environment destroyed" \ No newline at end of file diff --git a/docs/ANALISIS_CUENTA_668889063715.md b/docs/ANALISIS_CUENTA_668889063715.md new file mode 100644 index 0000000..5249aec --- /dev/null +++ b/docs/ANALISIS_CUENTA_668889063715.md @@ -0,0 +1,396 @@ +# Analisis de Cuenta AWS 668889063715 - SACC v4 Test Environment + +> **Fecha de analisis:** 2026-06-01 +> **Cuenta AWS:** 668889063715 +> **Region:** mx-central-1 +> **Proyecto:** SACC v4 (Duplicacion de Produccion) +> **Estado:** Documento de analisis y planificacion - SIN CAMBIOS APLICADOS + +--- + +## 1. Resumen Ejecutivo + +Este documento analiza la cuenta AWS `668889063715` para determinar la viabilidad y estrategia de duplicacion del entorno de produccion SACC v4. **No se han ejecutado cambios** - este es un documento de planificacion basado en la arquitectura conocida de produccion. + +### Objetivo +Crear un entorno de pruebas identico al de produccion en la cuenta `668889063715`, utilizando naming convention `sacc4-test-*` para evitar conflictos. + +### Alcance +- Infraestructura completa (VPC, EC2, RDS, S3, CloudFront, Route53, Lambda) +- Configuracion de servidor (Nginx, Systemd, Usuarios) +- Scripts de automatizacion para creacion, validacion y destruccion + +--- + +## 2. Estado de la Cuenta (Basado en Credenciales Proporcionadas) + +### 2.1 Acceso Verificado +| Dato | Valor | +|------|-------| +| Cuenta AWS | 668889063715 | +| Region | mx-central-1 | +| Tipo de credencial | Temporal (Session Token) | +| Acceso requerido | IAM con permisos para EC2, RDS, S3, VPC, CloudFront, Route53, Lambda, IAM, DynamoDB | + +### 2.2 Recursos Esperados en Cuenta +Segun el usuario, la cuenta ya cuenta con: +- **Route53**: Subdominio configurado (a verificar) +- **VPC**: Posiblemente VPC default o existentes (a verificar) + +### 2.3 Verificacion Recomendada (NO EJECUTADA) +Antes de desplegar, ejecutar manualmente: + +```bash +# Verificar identidad +aws sts get-caller-identity + +# Listar regiones disponibles +aws account list-regions + +# VPCs existentes +aws ec2 describe-vpcs + +# Buckets S3 +aws s3 ls + +# Certificados ACM +aws acm list-certificates --region mx-central-1 +aws acm list-certificates --region us-east-1 + +# Instancias EC2 +aws ec2 describe-instances + +# RDS +aws rds describe-db-instances + +# Route53 +aws route53 list-hosted-zones +``` + +--- + +## 3. Recursos a Crear + +### 3.1 Infraestructura de Red +| Recurso | Nombre | CIDR / Configuracion | +|---------|--------|---------------------| +| VPC | sacc4-test-vpc | 10.3.0.0/16 | +| Subnet Publica 1 | sacc4-test-public-1 | 10.3.1.0/24 (mx-central-1a) | +| Subnet Publica 2 | sacc4-test-public-2 | 10.3.2.0/24 (mx-central-1b) | +| Subnet Privada 1 | sacc4-test-private-1 | 10.3.10.0/24 (mx-central-1a) | +| Subnet Privada 2 | sacc4-test-private-2 | 10.3.11.0/24 (mx-central-1b) | +| Internet Gateway | sacc4-test-igw | Asociado a VPC | +| Route Table Publica | sacc4-test-public-rt | 0.0.0.0/0 -> IGW | + +**Razonamiento del CIDR:** +- Produccion usa `10.2.0.0/16` +- Test usa `10.3.0.0/16` para evitar solapamiento +- Si existen otras VPCs, verificar que no usen `10.3.0.0/16` + +### 3.2 Computo (EC2) +| Recurso | Nombre | Configuracion | +|---------|--------|---------------| +| Instancia EC2 | sacc4-test-api-prod | t3.small, Ubuntu 22.04 | +| Elastic IP | sacc4-test-eip | Asociada a EC2 | +| Key Pair | sacc4-test-thoth | Llave publica de thoth | +| Volume Root | - | 8 GB gp2, encriptado | + +**Puertos abiertos (Security Group EC2):** +| Puerto | Origen | Proposito | +|--------|--------|-----------| +| 22 | VPC CIDR o IPs especificas | SSH | +| 80 | 0.0.0.0/0 | HTTP | +| 443 | 0.0.0.0/0 | HTTPS | +| 8080-8085 | VPC CIDR | Microservicios API | + +### 3.3 Base de Datos (RDS) +| Recurso | Nombre | Configuracion | +|---------|--------|---------------| +| Instancia RDS | sacc4-test-db-prod | MariaDB 10.11.16 | +| Clase | db.t3.micro | 1 vCPU, 1 GB RAM | +| Almacenamiento | 20 GB | gp2, encriptado | +| DB Name | ccsoft_sacc4_test | | +| Master User | sacc_admin_test | | +| App User | sacc_app_user | (creado por user data) | +| Backup | 7 dias | Ventana 03:00-04:00 | + +**Security Group RDS:** +| Puerto | Origen | Proposito | +|--------|--------|-----------| +| 3306 | Security Group EC2 | MariaDB desde API | + +### 3.4 Frontend (S3 + CloudFront) +| Recurso | Nombre | Configuracion | +|---------|--------|---------------| +| Bucket S3 | sacc4-frontend-test-668889063715 | Privado, OAC | +| CloudFront | Auto-generado | PriceClass_100, HTTPS | +| OAC | sacc4-test-oac | SigV4, S3 origin | + +### 3.5 DNS (Route53) +| Recurso | Nombre | Valor | +|---------|--------|-------| +| Hosted Zone | ccsoft.mx (existente) | Data source | +| Record A | test-sacc.ccsoft.mx | Alias a CloudFront | +| Record A | api.test-sacc.ccsoft.mx | IP publica EC2 | + +**Nota:** Se asume que existe una hosted zone para `ccsoft.mx` o subdominio. Si no existe, crearla primero o usar otro dominio. + +### 3.6 Scheduling (Lambda + EventBridge) +| Recurso | Nombre | Proposito | +|---------|--------|-----------| +| Lambda Start | sacc4-test-start-instances | Iniciar EC2/RDS L-V 8AM | +| Lambda Stop | sacc4-test-stop-instances | Detener EC2/RDS L-V 7PM | +| Schedule Start | sacc4-test-start-morning | cron(0 13 ? * MON-FRI *) | +| Schedule Stop | sacc4-test-stop-evening | cron(0 0 ? * TUE-SAT *) | +| IAM Role Lambda | sacc4-test-lambda-scheduler-role | Permisos EC2/RDS | +| IAM Role Scheduler | sacc4-test-eventbridge-scheduler-role | Invocar Lambda | + +**Horario (America/Mexico_City):** +- Inicio: 8:00 AM L-V (13:00 UTC) +- Apagado: 7:00 PM L-V (00:00 UTC+1) + +### 3.7 Estado Terraform +| Recurso | Nombre | Proposito | +|---------|--------|-----------| +| Bucket S3 | sacc4-terraform-state-test-668889063715 | Estado remoto | +| Tabla DynamoDB | sacc4-terraform-locks-test-668889063715 | Bloqueo de estado | + +--- + +## 4. Dependencias y Orden de Creacion + +``` +1. Backend Terraform (S3 + DynamoDB) + | +2. VPC (VPC, Subnets, IGW, Route Tables) + | +3. Security Groups (EC2, RDS) + | +4. IAM Roles (Lambda, EC2, Scheduler) + | +5. RDS (Subnet Group, Instance) + | +6. EC2 (Instance, EIP, Key Pair) + | +7. S3 + CloudFront (Bucket, Distribution, OAC) + | +8. Route53 (Records A) + | +9. Lambda + EventBridge (Functions, Schedules) + | +10. Ansible (Configuracion servidor) +``` + +**Dependencias criticas:** +- EC2 depende de VPC, Security Groups, IAM +- RDS depende de VPC, Security Groups +- CloudFront depende de S3 +- Route53 depende de EC2 (IP) y CloudFront (dominio) +- Lambda depende de EC2 (ID) y RDS (ID) + +--- + +## 5. Costos Estimados (Mensual) + +| Recurso | Especificacion | Costo Mensual (USD) | +|---------|---------------|---------------------| +| EC2 t3.small | 11h/dia (scheduling) | ~$5.25 | +| RDS db.t3.micro | 11h/dia (scheduling) | ~$4.54 | +| S3 | ~1 GB storage | ~$0.02 | +| CloudFront | 100GB transferencia | ~$2.00 | +| Route53 | 1 hosted zone + queries | ~$0.50 | +| Lambda | 2 funciones, poca ejecucion | ~$0.00 | +| Data Transfer | Salida a internet | ~$1.00 | +| **TOTAL** | | **~$13.31** | + +**Notas de costos:** +- Con scheduling (apagado fuera de horario laboral): ~60% de ahorro +- Sin scheduling (24/7): ~$35-40/mes +- Los costos son estimados y pueden variar +- CloudFront: PriceClass_100 (Norte America y Europa) + +--- + +## 6. Riesgos y Mitigaciones + +| Riesgo | Probabilidad | Impacto | Mitigacion | +|--------|-------------|---------|------------| +| Conflicto de CIDR con VPC existente | Media | Alto | Verificar `aws ec2 describe-vpcs` antes. Usar 10.3.0.0/16 | +| Nombre de bucket S3 ya existe | Alta | Medio | Usar sufijo de cuenta ID: sacc4-frontend-test-668889063715 | +| Falta de permisos IAM | Media | Alto | Verificar politicas antes. Script valida credenciales | +| Route53 zone no existe | Media | Alto | Verificar con `aws route53 list-hosted-zones`. Ajustar dominio | +| AMI no disponible en mx-central-1 | Baja | Alto | Verificar AMI antes o usar data source `aws_ami` | +| Credenciales temporales expiran | Media | Medio | Renovar session token si es necesario | +| Costos inesperados | Baja | Medio | Scheduling habilitado por defecto. Monitorear Billing | +| Destruccion accidental | Baja | Alto | Script de destruccion requiere confirmacion doble | + +--- + +## 7. Conflictos Potenciales con Recursos Existentes + +### 7.1 Nombres Unicos Globales +Los siguientes recursos requieren nombres unicos globalmente en AWS: +- **S3 Buckets**: `sacc4-frontend-test-668889063715` (incluye ID de cuenta) +- **DynamoDB Tables**: `sacc4-terraform-locks-test-668889063715` + +### 7.2 Nombres Unicos por Cuenta +- **EC2 Key Pairs**: `sacc4-test-thoth` +- **IAM Roles**: `sacc4-test-lambda-scheduler-role`, `sacc4-test-eventbridge-scheduler-role` +- **RDS Instances**: `sacc4-test-db-prod` +- **Lambda Functions**: `sacc4-test-start-instances`, `sacc4-test-stop-instances` + +### 7.3 Estrategia de Evitacion +1. Todos los recursos usan prefijo `sacc4-test-*` +2. Bucket S3 incluye ID de cuenta +3. Tabla DynamoDB incluye ID de cuenta +4. Script `create-test-environment.sh` verifica conflictos antes de crear + +--- + +## 8. Checklist Pre-Despliegue + +### 8.1 Verificacion Manual (Obligatoria) +- [ ] Ejecutar `aws sts get-caller-identity` y confirmar cuenta 668889063715 +- [ ] Verificar region `mx-central-1` +- [ ] Listar VPCs existentes: `aws ec2 describe-vpcs` +- [ ] Verificar CIDR 10.3.0.0/16 no este en uso +- [ ] Listar hosted zones Route53: `aws route53 list-hosted-zones` +- [ ] Verificar dominio `test-sacc.ccsoft.mx` este disponible +- [ ] Listar certificados ACM: `aws acm list-certificates --region us-east-1` + +### 8.2 Preparacion Local +- [ ] Instalar AWS CLI v2 +- [ ] Instalar Terraform >= 1.5.0 +- [ ] Instalar Ansible (opcional, para configuracion) +- [ ] Generar par de llaves SSH: `ssh-keygen -t ed25519 -f ~/.ssh/sacc4-test-key` +- [ ] Copiar `terraform.tfvars.example` a `terraform.tfvars` +- [ ] Completar todas las variables en `terraform.tfvars` +- [ ] Cambiar contrasena RDS por una segura + +### 8.3 Configuracion de Credenciales +```bash +export AWS_ACCESS_KEY_ID=ASIAZXPHFEERTQJHLDJC +export AWS_SECRET_ACCESS_KEY=Xa58LDQt+WOBgGVQhwoYbATz/sk2G80RpIcjvKuo +export AWS_SESSION_TOKEN=IQoJb3JpZ2luX2VjECYaDG14LWNlbnRyYWwtMSJHMEUCIQCDI8BwOq2g1G/g7bNRoTJlolwJas0IxPU0PcLMFWbVEgIgJfC5/CoCt9rL6xGrC3hUtjzXb/SHk5owM6ImoK4GKdYq9wIIFhAAGgw2Njg4ODkwNjM3MTUiDMlcZz9jDpE28Mvr3yrUAihBZtNJ4vZs5iU16XgogqOWzA54lBjSnFsrq17u30F88mQL3sKNns7jGjgfHDIoPy0MmyA+cWd+q9DCtuZr+DUNS81n0DGDtI+oCkPfAmlkhHCtskzoyUzMb0XSRBIv2IUDqUqsOps/QBiTZcqJ3JIYeUaDntA1ZHCYCTH1C2hsgkznkPgwQE9/UrVmkkwoWAfRlln9DYpUpH5x/y+Cmzd5a7W/bhCYBF6vYbPvhr5Zr1t8EKcDPz4ANX+OFaa6v7AL2aHDuyVPiHU/YDXD6uSeTlfpLFYuQvx2HdBeHvHNyMcPpAsQ8c4YflzJGZmPBqnXrnpkOZBhNqjxlHFjXxSlNEv0X7ceKwOPCz4TLHA+cS18KkGKARzfVSfCeCmhQ+5LS8uCGdDV6u3tTUHY/rFyZ6uKVWrbl0Ky9apJRl2TOlXwQd6NyHsw2PkUgacitEfO0vswieX30AY6pQHT7j02zLvQClYhLqpyt+EHGVzlvRNN0dH92RRtQGtryQ+er5YUatzrth8VyBs659qLeIf1bmrCBBWpvJRDIsRAxnWU3Wq3nBqwxgFshaoPS8j99g9Q8Iky0MahSKEi30CLNaFZh6k8PoqQeGUrJLmT7cUH0gP9u+J+jJoPHb9568+yDLtCItb2p0q4JejISOKXniMKm6nja0/dJwl1uYMMtEalvVk= +export AWS_DEFAULT_REGION=mx-central-1 +``` + +--- + +## 9. Arquitectura del Entorno Test + +``` + +------------------+ + | Usuario | + +--------+---------+ + | + v ++------------------+ +----------+-----------+ +| Route53 |<----------| CloudFront CDN | +| (test-sacc... ) | | (SSL via ACM) | ++------------------+ +----------+-----------+ + | + +---------------------+---------------------+ + | | + v v + +----------------+ +------------------+ + | S3 Bucket | | EC2 Instance | + | (Frontend | | (Backend API | + | React) | | Spring Boot) | + +----------------+ +--------+---------+ + | + v + +------------------+ + | Nginx (reverse | + | proxy) | + +--------+---------+ + | + v + +------------------+ + | RDS MariaDB | + | (Base de datos) | + +------------------+ + ^ + | + +------------------+ + | Lambda Scheduler| + | (Start/Stop) | + +------------------+ +``` + +--- + +## 10. Scripts Generados + +| Script | Ruta | Proposito | +|--------|------|-----------| +| **create-test-environment.sh** | `iac-duplicate/scripts/` | Crea el entorno completo | +| **validate-environment.sh** | `iac-duplicate/scripts/` | Valida funcionamiento | +| **destroy-test-environment.sh** | `iac-duplicate/scripts/` | Destruye de forma segura | + +### Uso de Scripts + +```bash +# 1. Configurar credenciales +export AWS_ACCESS_KEY_ID=... +export AWS_SECRET_ACCESS_KEY=... +export AWS_SESSION_TOKEN=... +export AWS_DEFAULT_REGION=mx-central-1 + +# 2. Crear entorno +cd iac-duplicate/scripts +./create-test-environment.sh + +# 3. Validar entorno +./validate-environment.sh --full + +# 4. Destruir entorno (cuando ya no se necesite) +./destroy-test-environment.sh +``` + +--- + +## 11. Diferencias con Produccion + +| Aspecto | Produccion | Test | +|---------|-----------|------| +| Cuenta AWS | 523761210517 | 668889063715 | +| CIDR VPC | 10.2.0.0/16 | 10.3.0.0/16 | +| Dominio | prod-sacc.ccsoft.mx | test-sacc.ccsoft.mx | +| Scheduling | L-V 8AM-7PM | L-V 8AM-7PM | +| Instancia EC2 | t3a.medium | t3.small | +| Certificado SSL | Let's Encrypt + ACM | CloudFront default (inicial) | +| Backup RDS | 7 dias | 7 dias | + +--- + +## 12. Notas y Advertencias + +1. **NO APLICAR EN PRODUCCION**: Estos scripts estan disenados exclusivamente para el entorno de test en cuenta 668889063715. + +2. **Credenciales Temporales**: Las credenciales proporcionadas incluyen un session token, lo que indica que son temporales y expiraran. Renovar segun sea necesario. + +3. **Costos**: Aunque el scheduling reduce costos significativamente, monitorear la facturacion de AWS para evitar cargos inesperados. + +4. **SSL/TLS**: En produccion se usa Let's Encrypt para la API y ACM para CloudFront. En test, inicialmente CloudFront usara el certificado default. Para produccion-like, solicitar certificado ACM en us-east-1. + +5. **Datos Sensibles**: El archivo `terraform.tfvars` contiene contrasenas. NO commitear en git. Usar `.gitignore` o AWS Secrets Manager para entornos reales. + +6. **AMI**: La AMI `ami-0f553e2869648134e` es para Ubuntu 22.04 en mx-central-1. Verificar disponibilidad antes de desplegar. + +--- + +## 13. Proximos Pasos + +1. **Verificar cuenta**: Ejecutar comandos AWS CLI de la seccion 2.3 +2. **Preparar terraform.tfvars**: Completar todas las variables +3. **Generar llaves SSH**: Crear par de llaves para acceso EC2 +4. **Ejecutar create-test-environment.sh**: Crear la infraestructura +5. **Desplegar aplicacion**: Subir JARs de microservicios a EC2 +6. **Configurar SSL**: Solicitar certificado ACM para dominio custom +7. **Validar**: Ejecutar validate-environment.sh + +--- + +*Documento generado automaticamente - 2026-06-01* +**Cómputo Contable Soft SA de CV - Proyecto SACC4** diff --git a/scripts/create-test-environment.sh b/scripts/create-test-environment.sh new file mode 100755 index 0000000..bb67444 --- /dev/null +++ b/scripts/create-test-environment.sh @@ -0,0 +1,488 @@ +#!/bin/bash +# ============================================================================= +# SACC v4 - Script de Creacion de Entorno TEST +# ============================================================================= +# Cuenta AWS: 668889063715 +# Region: mx-central-1 +# +# Este script: +# 1. Valida prerequisitos (AWS CLI, Terraform, credenciales) +# 2. Verifica que no existan recursos con conflictos de nombres +# 3. Crea backend S3/DynamoDB para estado Terraform +# 4. Ejecuta terraform init/plan/apply +# 5. Genera inventario Ansible +# 6. Ejecuta playbooks de Ansible +# 7. Verifica health checks +# +# USO: +# export AWS_ACCESS_KEY_ID=... +# export AWS_SECRET_ACCESS_KEY=... +# export AWS_SESSION_TOKEN=... +# export AWS_DEFAULT_REGION=mx-central-1 +# ./create-test-environment.sh +# +# IMPORTANTE: NO ejecutar en produccion +# ============================================================================= + +set -euo pipefail + +# Colores para output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# ============================================================================= +# CONFIGURACION +# ============================================================================= + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +TERRAFORM_DIR="$PROJECT_ROOT/terraform/environments/test" +ANSIBLE_DIR="$PROJECT_ROOT/ansible" +LOG_FILE="$PROJECT_ROOT/logs/create-test-$(date +%Y%m%d-%H%M%S).log" +ACCOUNT_ID="668889063715" +REGION="mx-central-1" + +# Crear directorio de logs +mkdir -p "$(dirname "$LOG_FILE")" + +# ============================================================================= +# FUNCIONES DE UTILIDAD +# ============================================================================= + +log() { + echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] INFO:${NC} $1" | tee -a "$LOG_FILE" +} + +warn() { + echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARN:${NC} $1" | tee -a "$LOG_FILE" +} + +error() { + echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | tee -a "$LOG_FILE" + exit 1 +} + +info() { + echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')] INFO:${NC} $1" | tee -a "$LOG_FILE" +} + +# ============================================================================= +# PASO 1: VALIDAR PREREQUISITOS +# ============================================================================= + +validate_prerequisites() { + info "========================================" + info "PASO 1: Validando prerequisitos" + info "========================================" + + # Validar AWS CLI + if ! command -v aws &> /dev/null; then + error "AWS CLI no esta instalado. Instalar desde: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html" + fi + log "AWS CLI: $(aws --version | head -1)" + + # Validar Terraform + if ! command -v terraform &> /dev/null; then + error "Terraform no esta instalado. Instalar desde: https://developer.hashicorp.com/terraform/downloads" + fi + log "Terraform: $(terraform version | head -1)" + + # Validar Ansible + if ! command -v ansible-playbook &> /dev/null; then + warn "Ansible no esta instalado. Se omitira el paso de Ansible." + ANSIBLE_AVAILABLE=false + else + log "Ansible: $(ansible-playbook --version | head -1)" + ANSIBLE_AVAILABLE=true + fi + + # Validar credenciales AWS + info "Verificando credenciales AWS..." + if ! aws sts get-caller-identity &> /dev/null; then + error "No se pueden validar las credenciales AWS. Asegurate de configurar:\n export AWS_ACCESS_KEY_ID=...\n export AWS_SECRET_ACCESS_KEY=...\n export AWS_SESSION_TOKEN=...\n export AWS_DEFAULT_REGION=mx-central-1" + fi + + local caller_identity + caller_identity=$(aws sts get-caller-identity --output json) + local account_id + account_id=$(echo "$caller_identity" | jq -r '.Account') + local arn + arn=$(echo "$caller_identity" | jq -r '.Arn') + + if [ "$account_id" != "$ACCOUNT_ID" ]; then + error "Cuenta AWS incorrecta. Esperada: $ACCOUNT_ID, Actual: $account_id" + fi + + log "Credenciales AWS validas" + log " Cuenta: $account_id" + log " ARN: $arn" + log " Region: $REGION" + + # Validar region + local current_region + current_region=$(aws configure get region 2>/dev/null || echo "$AWS_DEFAULT_REGION") + if [ "$current_region" != "$REGION" ]; then + warn "Region actual ($current_region) diferente de la esperada ($REGION)" + warn "Estableciendo AWS_DEFAULT_REGION=$REGION" + export AWS_DEFAULT_REGION="$REGION" + fi + + # Validar archivo de variables + if [ ! -f "$TERRAFORM_DIR/terraform.tfvars" ]; then + error "No existe $TERRAFORM_DIR/terraform.tfvars\nCopiar desde terraform.tfvars.example y completar los valores." + fi + log "Archivo terraform.tfvars encontrado" + + # Validar llaves SSH + if [ ! -f "$HOME/.ssh/sacc4-test-key.pem" ]; then + warn "No existe ~/.ssh/sacc4-test-key.pem" + warn "Generar con: ssh-keygen -t ed25519 -f ~/.ssh/sacc4-test-key -C 'sacc4-test'" + warn "Subir la llave publica a AWS: aws ec2 import-key-pair ..." + fi +} + +# ============================================================================= +# PASO 2: VERIFICAR CONFLICTOS DE NOMBRES +# ============================================================================= + +check_conflicts() { + info "========================================" + info "PASO 2: Verificando conflictos de nombres" + info "========================================" + + local conflicts_found=0 + + # Verificar bucket S3 + local bucket_name + bucket_name=$(grep "frontend_bucket_name" "$TERRAFORM_DIR/terraform.tfvars" | cut -d'=' -f2 | tr -d ' "') + log "Verificando bucket S3: $bucket_name" + if aws s3api head-bucket --bucket "$bucket_name" 2>/dev/null; then + warn "Bucket S3 '$bucket_name' ya existe" + conflicts_found=$((conflicts_found + 1)) + else + log "Bucket S3 disponible" + fi + + # Verificar instancia RDS + local rds_id="sacc4-test-db-prod" + log "Verificando RDS: $rds_id" + if aws rds describe-db-instances --db-instance-identifier "$rds_id" 2>/dev/null; then + warn "RDS '$rds_id' ya existe" + conflicts_found=$((conflicts_found + 1)) + else + log "RDS disponible" + fi + + # Verificar VPC con mismo CIDR + local vpc_cidr + vpc_cidr=$(grep "vpc_cidr" "$TERRAFORM_DIR/terraform.tfvars" | head -1 | cut -d'=' -f2 | tr -d ' "') + log "Verificando VPC CIDR: $vpc_cidr" + local existing_vpcs + existing_vpcs=$(aws ec2 describe-vpcs --filters "Name=cidr,Values=$vpc_cidr" --query 'Vpcs[*].VpcId' --output text) + if [ -n "$existing_vpcs" ] && [ "$existing_vpcs" != "None" ]; then + warn "VPC con CIDR $vpc_cidr ya existe: $existing_vpcs" + conflicts_found=$((conflicts_found + 1)) + else + log "VPC CIDR disponible" + fi + + # Verificar tabla DynamoDB para locks + local dynamo_table="sacc4-terraform-locks-test-668889063715" + log "Verificando DynamoDB: $dynamo_table" + if aws dynamodb describe-table --table-name "$dynamo_table" 2>/dev/null; then + warn "Tabla DynamoDB '$dynamo_table' ya existe" + conflicts_found=$((conflicts_found + 1)) + else + log "Tabla DynamoDB disponible" + fi + + # Verificar bucket de estado Terraform + local state_bucket="sacc4-terraform-state-test-668889063715" + log "Verificando bucket de estado: $state_bucket" + if aws s3api head-bucket --bucket "$state_bucket" 2>/dev/null; then + warn "Bucket de estado '$state_bucket' ya existe" + conflicts_found=$((conflicts_found + 1)) + else + log "Bucket de estado disponible" + fi + + if [ $conflicts_found -gt 0 ]; then + warn "Se encontraron $conflicts_found conflictos. Revisar antes de continuar." + read -p "Continuar de todos modos? (yes/no): " confirm + if [ "$confirm" != "yes" ]; then + error "Abortado por el usuario" + fi + else + log "No se encontraron conflictos" + fi +} + +# ============================================================================= +# PASO 3: CREAR BACKEND TERRAFORM (S3 + DynamoDB) +# ============================================================================= + +create_backend() { + info "========================================" + info "PASO 3: Creando backend para estado Terraform" + info "========================================" + + local state_bucket="sacc4-terraform-state-test-668889063715" + local dynamo_table="sacc4-terraform-locks-test-668889063715" + + # Crear bucket S3 + log "Creando bucket S3: $state_bucket" + if ! aws s3api head-bucket --bucket "$state_bucket" 2>/dev/null; then + aws s3api create-bucket \ + --bucket "$state_bucket" \ + --region "$REGION" \ + --create-bucket-configuration LocationConstraint="$REGION" + log "Bucket creado" + else + log "Bucket ya existe" + fi + + # Habilitar versionamiento + log "Habilitando versionamiento en bucket" + aws s3api put-bucket-versioning \ + --bucket "$state_bucket" \ + --versioning-configuration Status=Enabled + + # Encriptacion + log "Configurando encriptacion del bucket" + aws s3api put-bucket-encryption \ + --bucket "$state_bucket" \ + --server-side-encryption-configuration '{ + "Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}] + }' + + # Crear tabla DynamoDB + log "Creando tabla DynamoDB: $dynamo_table" + if ! aws dynamodb describe-table --table-name "$dynamo_table" 2>/dev/null; then + aws dynamodb create-table \ + --table-name "$dynamo_table" \ + --attribute-definitions AttributeName=LockID,AttributeType=S \ + --key-schema AttributeName=LockID,KeyType=HASH \ + --billing-mode PAY_PER_REQUEST \ + --region "$REGION" + log "Tabla DynamoDB creada" + else + log "Tabla DynamoDB ya existe" + fi +} + +# ============================================================================= +# PASO 4: TERRAFORM INIT / PLAN / APPLY +# ============================================================================= + +run_terraform() { + info "========================================" + info "PASO 4: Ejecutando Terraform" + info "========================================" + + cd "$TERRAFORM_DIR" + + log "Inicializando Terraform..." + terraform init + + log "Ejecutando terraform plan..." + terraform plan -out=tfplan -var-file=terraform.tfvars + + info "Revisar el plan anterior. Se crearan los recursos listados arriba." + read -p "Aplicar cambios? (yes/no): " confirm + if [ "$confirm" != "yes" ]; then + error "Abortado por el usuario" + fi + + log "Aplicando infraestructura (esto puede tomar 10-15 minutos)..." + terraform apply tfplan + + log "Terraform apply completado" +} + +# ============================================================================= +# PASO 5: GENERAR INVENTARIO ANSIBLE +# ============================================================================= + +generate_ansible_inventory() { + info "========================================" + info "PASO 5: Generando inventario Ansible" + info "========================================" + + cd "$TERRAFORM_DIR" + + local ec2_ip + ec2_ip=$(terraform output -raw ec2_public_ip) + local rds_endpoint + rds_endpoint=$(terraform output -raw rds_endpoint) + local s3_bucket + s3_bucket=$(terraform output -raw frontend_bucket_name) + + mkdir -p "$ANSIBLE_DIR/inventory" + + cat > "$ANSIBLE_DIR/inventory/test.ini" << EOF +[sacc4-test] +$ec2_ip ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/sacc4-test-key.pem ansible_python_interpreter=/usr/bin/python3 + +[sacc4-test:vars] +environment=test +db_endpoint=$rds_endpoint +s3_bucket=$s3_bucket +EOF + + log "Inventario Ansible generado: $ANSIBLE_DIR/inventory/test.ini" + cat "$ANSIBLE_DIR/inventory/test.ini" +} + +# ============================================================================= +# PASO 6: EJECUTAR ANSIBLE +# ============================================================================= + +run_ansible() { + info "========================================" + info "PASO 6: Configurando servidor con Ansible" + info "========================================" + + if [ "$ANSIBLE_AVAILABLE" != "true" ]; then + warn "Ansible no disponible. Omitiendo configuracion." + info "Para ejecutar manualmente despues:" + info " cd $ANSIBLE_DIR" + info " ansible-playbook -i inventory/test.ini playbooks/site.yml" + return + fi + + cd "$ANSIBLE_DIR" + + log "Ejecutando playbook Ansible..." + ansible-playbook -i inventory/test.ini playbooks/site.yml + + log "Ansible completado" +} + +# ============================================================================= +# PASO 7: VERIFICAR HEALTH CHECKS +# ============================================================================= + +verify_health_checks() { + info "========================================" + info "PASO 7: Verificando health checks" + info "========================================" + + cd "$TERRAFORM_DIR" + + local ec2_ip + ec2_ip=$(terraform output -raw ec2_public_ip) + + log "Verificando conectividad SSH..." + if ssh -i ~/.ssh/sacc4-test-key.pem -o StrictHostKeyChecking=no -o ConnectTimeout=10 ubuntu@"$ec2_ip" "echo 'OK'" > /dev/null 2>&1; then + log "SSH: OK" + else + warn "SSH: No responde (la instancia puede estar inicializando)" + fi + + log "Verificando Nginx..." + if ssh -i ~/.ssh/sacc4-test-key.pem -o StrictHostKeyChecking=no ubuntu@"$ec2_ip" "sudo systemctl is-active nginx" 2>/dev/null; then + log "Nginx: Activo" + else + warn "Nginx: No activo (esperar a que Ansible termine)" + fi + + log "Verificando servicios en puertos 8080-8085..." + for port in 8080 8081 8082 8083 8084 8085; do + if ssh -i ~/.ssh/sacc4-test-key.pem -o StrictHostKeyChecking=no ubuntu@"$ec2_ip" "curl -s -o /dev/null -w '%{http_code}' http://localhost:$port/actuator/health 2>/dev/null || echo '000'" 2>/dev/null | grep -q "200"; then + log "Puerto $port: OK" + else + warn "Puerto $port: No responde (esperar despliegue de JARs)" + fi + done + + log "Verificando RDS..." + local rds_endpoint + rds_endpoint=$(terraform output -raw rds_endpoint) + if ssh -i ~/.ssh/sacc4-test-key.pem -o StrictHostKeyChecking=no ubuntu@"$ec2_ip" "mysql -h $rds_endpoint -u sacc_app_user -p -e 'SELECT 1;' 2>/dev/null" > /dev/null 2>&1; then + log "RDS: Conexion exitosa" + else + warn "RDS: No se pudo conectar (verificar credenciales y security groups)" + fi + + log "Verificando S3..." + local s3_bucket + s3_bucket=$(terraform output -raw frontend_bucket_name) + if aws s3 ls "s3://$s3_bucket" >/dev/null 2>&1; then + log "S3: Bucket accesible" + else + warn "S3: No se pudo acceder al bucket" + fi +} + +# ============================================================================= +# PASO 8: MOSTRAR RESUMEN +# ============================================================================= + +show_summary() { + info "========================================" + info "RESUMEN DEL DESPLIEGUE" + info "========================================" + + cd "$TERRAFORM_DIR" + + info "Outputs de Terraform:" + terraform output + + info "" + info "Recursos creados en cuenta $ACCOUNT_ID:" + info " VPC: $(terraform output -raw vpc_id 2>/dev/null || echo 'N/A')" + info " EC2: $(terraform output -raw ec2_public_ip 2>/dev/null || echo 'N/A')" + info " RDS: $(terraform output -raw rds_endpoint 2>/dev/null || echo 'N/A')" + info " S3: $(terraform output -raw frontend_bucket_name 2>/dev/null || echo 'N/A')" + info " CloudFront: $(terraform output -raw cloudfront_domain_name 2>/dev/null || echo 'N/A')" + + info "" + info "Proximos pasos:" + info " 1. Desplegar JARs de microservicios a /opt/sacc4/*/current/" + info " 2. Configurar certificado SSL (Let's Encrypt o ACM)" + info " 3. Verificar DNS: $(terraform output -raw api_subdomain 2>/dev/null || echo 'N/A')" + info " 4. Ejecutar: $SCRIPT_DIR/validate-environment.sh" + + info "" + info "Para destruir el entorno:" + info " $SCRIPT_DIR/destroy-test-environment.sh" +} + +# ============================================================================= +# MAIN +# ============================================================================= + +main() { + info "========================================" + info "SACC v4 - Creacion de Entorno TEST" + info "Cuenta: $ACCOUNT_ID" + info "Region: $REGION" + info "========================================" + info "" + info "IMPORTANTE:" + info " - Este script creara recursos AWS que generan costos" + info " - Verificar que las credenciales sean de la cuenta correcta" + info " - No ejecutar en produccion" + info "" + read -p "Continuar? (yes/no): " confirm + if [ "$confirm" != "yes" ]; then + error "Abortado por el usuario" + fi + + validate_prerequisites + check_conflicts + create_backend + run_terraform + generate_ansible_inventory + run_ansible + verify_health_checks + show_summary + + log "Proceso completado exitosamente" + log "Log guardado en: $LOG_FILE" +} + +main "$@" diff --git a/scripts/destroy-test-environment.sh b/scripts/destroy-test-environment.sh new file mode 100755 index 0000000..0c1c8cc --- /dev/null +++ b/scripts/destroy-test-environment.sh @@ -0,0 +1,483 @@ +#!/bin/bash +# ============================================================================= +# SACC v4 - Script de Destruccion de Entorno TEST +# ============================================================================= +# Destruye de forma SEGURA el entorno de pruebas en cuenta 668889063715 +# +# Este script: +# 1. Pide confirmacion multiple +# 2. Realiza backup de datos RDS +# 3. Destruye recursos Terraform +# 4. Limpia S3 (opcional) +# 5. Muestra resumen de lo destruido +# +# USO: +# export AWS_ACCESS_KEY_ID=... +# export AWS_SECRET_ACCESS_KEY=... +# export AWS_SESSION_TOKEN=... +# export AWS_DEFAULT_REGION=mx-central-1 +# ./destroy-test-environment.sh [opciones] +# +# OPCIONES: +# --force Omitir confirmaciones (USAR CON PRECAUCION) +# --skip-rds-backup Omitir backup de RDS +# --delete-s3 Eliminar contenido de S3 antes de destruir +# --keep-state No eliminar bucket de estado Terraform +# ============================================================================= + +set -euo pipefail + +# Colores +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +BOLD='\033[1m' +NC='\033[0m' + +# ============================================================================= +# CONFIGURACION +# ============================================================================= + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +TERRAFORM_DIR="$PROJECT_ROOT/terraform/environments/test" +BACKUP_DIR="$PROJECT_ROOT/backups/rds-$(date +%Y%m%d-%H%M%S)" +LOG_FILE="$PROJECT_ROOT/logs/destroy-$(date +%Y%m%d-%H%M%S).log" +ACCOUNT_ID="668889063715" +REGION="mx-central-1" + +mkdir -p "$(dirname "$LOG_FILE")" + +# Flags +FORCE=false +SKIP_RDS_BACKUP=false +DELETE_S3=false +KEEP_STATE=false + +# ============================================================================= +# FUNCIONES +# ============================================================================= + +log() { + echo -e "${GREEN}[$(date '+%H:%M:%S')] OK:${NC} $1" | tee -a "$LOG_FILE" +} + +warn() { + echo -e "${YELLOW}[$(date '+%H:%M:%S')] WARN:${NC} $1" | tee -a "$LOG_FILE" +} + +error() { + echo -e "${RED}[$(date '+%H:%M:%S')] ERROR:${NC} $1" | tee -a "$LOG_FILE" +} + +info() { + echo -e "${BLUE}[$(date '+%H:%M:%S')] INFO:${NC} $1" | tee -a "$LOG_FILE" +} + +fatal() { + echo -e "${RED}${BOLD}[$(date '+%H:%M:%S')] FATAL:${NC} $1" | tee -a "$LOG_FILE" + exit 1 +} + +# ============================================================================= +# PARSEAR ARGUMENTOS +# ============================================================================= + +parse_args() { + while [ $# -gt 0 ]; do + case "$1" in + --force) + FORCE=true + warn "Modo FORZADO activado - Se omitiran confirmaciones" + ;; + --skip-rds-backup) + SKIP_RDS_BACKUP=true + warn "Se omitira backup de RDS" + ;; + --delete-s3) + DELETE_S3=true + info "Se eliminara contenido de S3" + ;; + --keep-state) + KEEP_STATE=true + info "Se conservara bucket de estado Terraform" + ;; + --help) + echo "Uso: $0 [opciones]" + echo "" + echo "Opciones:" + echo " --force Omitir confirmaciones (USAR CON PRECAUCION)" + echo " --skip-rds-backup Omitir backup de RDS" + echo " --delete-s3 Eliminar contenido de S3 antes de destruir" + echo " --keep-state No eliminar bucket de estado Terraform" + echo " --help Mostrar esta ayuda" + exit 0 + ;; + *) + echo "Opcion desconocida: $1" + exit 1 + ;; + esac + shift + done +} + +# ============================================================================= +# VALIDAR PREREQUISITOS +# ============================================================================= + +validate() { + info "========================================" + info "Validando prerequisitos" + info "========================================" + + if ! command -v aws &> /dev/null; then + fatal "AWS CLI no esta instalado" + fi + + if ! command -v terraform &> /dev/null; then + fatal "Terraform no esta instalado" + fi + + # Verificar credenciales + local current_account + current_account=$(aws sts get-caller-identity --query 'Account' --output text) + if [ "$current_account" != "$ACCOUNT_ID" ]; then + fatal "Cuenta AWS incorrecta. Esperada: $ACCOUNT_ID, Actual: $current_account" + fi + log "Cuenta AWS validada: $current_account" + + # Verificar estado de Terraform + if [ ! -f "$TERRAFORM_DIR/terraform.tfstate" ] && [ ! -d "$TERRAFORM_DIR/.terraform" ]; then + fatal "No existe estado de Terraform en $TERRAFORM_DIR" + fi +} + +# ============================================================================= +# MOSTRAR RECURSOS A DESTRUIR +# ============================================================================= + +show_resources() { + info "========================================" + info "Recursos que seran destruidos" + info "========================================" + + cd "$TERRAFORM_DIR" + + info "Ejecutando terraform plan -destroy..." + terraform plan -destroy -var-file=terraform.tfvars -out=destroy.plan + + info "" + info "Revisa el plan de destruccion mostrado arriba." + info "" +} + +# ============================================================================= +# CONFIRMACIONES +# ============================================================================= + +confirm_destruction() { + if [ "$FORCE" == "true" ]; then + warn "Modo forzado: Omitiendo confirmaciones" + return 0 + fi + + echo "" + echo -e "${RED}${BOLD}ATENCION: ESTA ACCION ES IRREVERSIBLE${NC}" + echo -e "${RED}Se destruiran todos los recursos del entorno TEST${NC}" + echo "" + echo "Recursos afectados:" + echo " - Instancia EC2 (con Elastic IP)" + echo " - Base de datos RDS (con backups automaticos)" + echo " - Bucket S3 (frontend)" + echo " - Distribucion CloudFront" + echo " - Funciones Lambda y EventBridge" + echo " - Security Groups, VPC, Subnets" + echo " - Registros Route53" + echo "" + + read -p "Escribe 'DESTRUIR' para confirmar: " confirm1 + if [ "$confirm1" != "DESTRUIR" ]; then + fatal "Confirmacion incorrecta. Abortando." + fi + + read -p "Estas ABSOLUTAMENTE SEGURO? Escribe 'SI': " confirm2 + if [ "$confirm2" != "SI" ]; then + fatal "Confirmacion incorrecta. Abortando." + fi + + log "Confirmacion recibida. Procediendo con la destruccion." +} + +# ============================================================================= +# BACKUP DE RDS +# ============================================================================= + +backup_rds() { + if [ "$SKIP_RDS_BACKUP" == "true" ]; then + warn "Omitiendo backup de RDS (--skip-rds-backup)" + return 0 + fi + + info "========================================" + info "Realizando backup de RDS" + info "========================================" + + cd "$TERRAFORM_DIR" + + local rds_endpoint + rds_endpoint=$(terraform output -raw rds_endpoint 2>/dev/null || echo "") + local db_name + db_name=$(terraform output -raw rds_db_name 2>/dev/null || echo "") + + if [ -z "$rds_endpoint" ]; then + warn "No se pudo obtener endpoint RDS. Omitiendo backup." + return 1 + fi + + mkdir -p "$BACKUP_DIR" + + log "RDS Endpoint: $rds_endpoint" + log "Base de datos: $db_name" + log "Directorio de backup: $BACKUP_DIR" + + # Crear snapshot final + local snapshot_id="sacc4-test-final-$(date +%Y%m%d-%H%M%S)" + local rds_instance_id="sacc4-test-db-prod" + + log "Creando snapshot final: $snapshot_id" + aws rds create-db-snapshot \ + --db-instance-identifier "$rds_instance_id" \ + --db-snapshot-identifier "$snapshot_id" \ + --region "$REGION" + + log "Esperando que el snapshot se complete..." + aws rds wait db-snapshot-available \ + --db-snapshot-identifier "$snapshot_id" \ + --region "$REGION" + + log "Snapshot creado exitosamente: $snapshot_id" + echo "$snapshot_id" > "$BACKUP_DIR/snapshot-id.txt" + + # Intentar dump SQL (si tenemos acceso) + local ec2_ip + ec2_ip=$(terraform output -raw ec2_public_ip 2>/dev/null || echo "") + local ssh_key="$HOME/.ssh/sacc4-test-key.pem" + + if [ -n "$ec2_ip" ] && [ -f "$ssh_key" ]; then + log "Intentando crear dump SQL desde EC2..." + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$ec2_ip" "mysqldump -h $rds_endpoint -u sacc_app_user -p'$db_name' --all-databases > /tmp/sacc4-test-backup.sql 2>/dev/null" 2>/dev/null; then + scp -i "$ssh_key" -o StrictHostKeyChecking=no "ubuntu@$ec2_ip:/tmp/sacc4-test-backup.sql" "$BACKUP_DIR/" + log "Dump SQL guardado en: $BACKUP_DIR/sacc4-test-backup.sql" + else + warn "No se pudo crear dump SQL (credenciales no disponibles)" + fi + fi + + log "Backup completado en: $BACKUP_DIR" +} + +# ============================================================================= +# LIMPIAR S3 +# ============================================================================= + +cleanup_s3() { + if [ "$DELETE_S3" != "true" ]; then + info "Omitiendo limpieza de S3 (usar --delete-s3 para eliminar)" + return 0 + fi + + info "========================================" + info "Limpiando bucket S3" + info "========================================" + + cd "$TERRAFORM_DIR" + + local bucket_name + bucket_name=$(terraform output -raw frontend_bucket_name 2>/dev/null || echo "") + + if [ -z "$bucket_name" ]; then + warn "No se pudo obtener nombre del bucket S3" + return 1 + fi + + log "Bucket a limpiar: $bucket_name" + + # Verificar si tiene versionamiento + local versioning + versioning=$(aws s3api get-bucket-versioning --bucket "$bucket_name" --query 'Status' --output text 2>/dev/null || echo "Disabled") + + if [ "$versioning" == "Enabled" ]; then + warn "Bucket tiene versionamiento habilitado. Eliminando todas las versiones..." + # Eliminar todas las versiones (incluyendo delete markers) + aws s3api list-object-versions --bucket "$bucket_name" --query 'Versions[].{Key:Key,VersionId:VersionId}' --output json | \ + jq -c '.[]' | while read -r obj; do + key=$(echo "$obj" | jq -r '.Key') + version=$(echo "$obj" | jq -r '.VersionId') + aws s3api delete-object --bucket "$bucket_name" --key "$key" --version-id "$version" > /dev/null + done + fi + + # Vaciar bucket + log "Vaciando bucket..." + aws s3 rm "s3://$bucket_name" --recursive + + log "Bucket $bucket_name vaciado" +} + +# ============================================================================= +# DESTRUIR CON TERRAFORM +# ============================================================================= + +destroy_terraform() { + info "========================================" + info "Destruyendo recursos con Terraform" + info "========================================" + + cd "$TERRAFORM_DIR" + + if [ "$FORCE" == "true" ]; then + terraform destroy -auto-approve -var-file=terraform.tfvars + else + terraform destroy -var-file=terraform.tfvars + fi + + log "Terraform destroy completado" +} + +# ============================================================================= +# LIMPIAR ESTADO TERRAFORM +# ============================================================================= + +cleanup_terraform_state() { + if [ "$KEEP_STATE" == "true" ]; then + info "Conservando bucket de estado Terraform (--keep-state)" + return 0 + fi + + info "========================================" + info "Limpiando recursos de estado Terraform" + info "========================================" + + local state_bucket="sacc4-terraform-state-test-668889063715" + local dynamo_table="sacc4-terraform-locks-test-668889063715" + + # Preguntar antes de eliminar + if [ "$FORCE" != "true" ]; then + read -p "Eliminar bucket de estado S3 y tabla DynamoDB? (yes/no): " confirm + if [ "$confirm" != "yes" ]; then + warn "Conservando recursos de estado" + return 0 + fi + fi + + # Eliminar contenido del bucket primero + log "Vaciando bucket de estado: $state_bucket" + aws s3 rm "s3://$state_bucket" --recursive 2>/dev/null || true + + # Eliminar bucket + log "Eliminando bucket: $state_bucket" + aws s3api delete-bucket --bucket "$state_bucket" --region "$REGION" 2>/dev/null || warn "No se pudo eliminar bucket" + + # Eliminar tabla DynamoDB + log "Eliminando tabla DynamoDB: $dynamo_table" + aws dynamodb delete-table --table-name "$dynamo_table" --region "$REGION" 2>/dev/null || warn "No se pudo eliminar tabla" + + log "Recursos de estado eliminados" +} + +# ============================================================================= +# VERIFICAR DESTRUCCION +# ============================================================================= + +verify_destruction() { + info "========================================" + info "Verificando destruccion" + info "========================================" + + cd "$TERRAFORM_DIR" + + local vpc_id + vpc_id=$(terraform output -raw vpc_id 2>/dev/null || echo "") + + if [ -n "$vpc_id" ]; then + if aws ec2 describe-vpcs --vpc-ids "$vpc_id" >/dev/null 2>&1; then + warn "VPC $vpc_id aun existe" + else + log "VPC eliminada correctamente" + fi + fi + + # Verificar EC2 + local ec2_ip + ec2_ip=$(terraform output -raw ec2_public_ip 2>/dev/null || echo "") + if [ -n "$ec2_ip" ]; then + if ping -c 1 -W 2 "$ec2_ip" >/dev/null 2>&1; then + warn "EC2 $ec2_ip aun responde a ping" + else + log "EC2 no responde (esperado)" + fi + fi +} + +# ============================================================================= +# RESUMEN +# ============================================================================= + +show_summary() { + info "========================================" + info "RESUMEN DE DESTRUCCION" + info "========================================" + + log "Entorno TEST destruido exitosamente" + info "" + info "Acciones realizadas:" + if [ "$SKIP_RDS_BACKUP" != "true" ]; then + info " [OK] Backup de RDS guardado en: $BACKUP_DIR" + fi + if [ "$DELETE_S3" == "true" ]; then + info " [OK] Contenido de S3 eliminado" + fi + info " [OK] Recursos de infraestructura destruidos" + if [ "$KEEP_STATE" != "true" ]; then + info " [OK] Estado Terraform eliminado" + fi + + info "" + info "Costos: La destruccion de recursos detiene la generacion de cargos." + info "Nota: Los snapshots de RDS y logs de CloudWatch pueden generar costos menores." + + info "" + info "Log completo: $LOG_FILE" +} + +# ============================================================================= +# MAIN +# ============================================================================= + +main() { + parse_args "$@" + + echo -e "${RED}${BOLD}" + echo "========================================" + echo "SACC v4 - Destruccion de Entorno TEST" + echo "========================================" + echo -e "${NC}" + echo "Cuenta: $ACCOUNT_ID" + echo "Region: $REGION" + echo "" + echo -e "${RED}ADVERTENCIA: Esta accion destruira todos los recursos${NC}" + + validate + show_resources + confirm_destruction + backup_rds + cleanup_s3 + destroy_terraform + cleanup_terraform_state + verify_destruction + show_summary +} + +main "$@" diff --git a/scripts/validate-environment.sh b/scripts/validate-environment.sh new file mode 100755 index 0000000..598933d --- /dev/null +++ b/scripts/validate-environment.sh @@ -0,0 +1,533 @@ +#!/bin/bash +# ============================================================================= +# SACC v4 - Script de Validacion de Entorno TEST +# ============================================================================= +# Verifica que todos los componentes del entorno de test funcionen correctamente. +# +# USO: +# ./validate-environment.sh [opciones] +# +# OPCIONES: +# --full Ejecutar todas las validaciones (default) +# --ssh-only Solo validar conectividad SSH +# --services Solo validar servicios systemd +# --api Solo validar APIs +# --nginx Solo validar nginx +# --rds Solo validar RDS +# --s3 Solo validar S3 +# --help Mostrar ayuda +# +# IMPORTANTE: Requiere que el entorno haya sido creado previamente +# ============================================================================= + +set -euo pipefail + +# Colores +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# ============================================================================= +# CONFIGURACION +# ============================================================================= + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +TERRAFORM_DIR="$PROJECT_ROOT/terraform/environments/test" +LOG_FILE="$PROJECT_ROOT/logs/validate-$(date +%Y%m%d-%H%M%S).log" + +mkdir -p "$(dirname "$LOG_FILE")" + +# Flags +CHECK_SSH=true +CHECK_SERVICES=true +CHECK_API=true +CHECK_NGINX=true +CHECK_RDS=true +CHECK_S3=true +CHECK_CLOUDFRONT=true + +# ============================================================================= +# FUNCIONES +# ============================================================================= + +log() { + echo -e "${GREEN}[$(date '+%H:%M:%S')] OK:${NC} $1" | tee -a "$LOG_FILE" +} + +warn() { + echo -e "${YELLOW}[$(date '+%H:%M:%S')] WARN:${NC} $1" | tee -a "$LOG_FILE" +} + +error() { + echo -e "${RED}[$(date '+%H:%M:%S')] FAIL:${NC} $1" | tee -a "$LOG_FILE" +} + +info() { + echo -e "${BLUE}[$(date '+%H:%M:%S')] INFO:${NC} $1" | tee -a "$LOG_FILE" +} + +# ============================================================================= +# PARSEAR ARGUMENTOS +# ============================================================================= + +parse_args() { + if [ $# -eq 0 ]; then + return + fi + + # Desactivar todo primero + CHECK_SSH=false + CHECK_SERVICES=false + CHECK_API=false + CHECK_NGINX=false + CHECK_RDS=false + CHECK_S3=false + CHECK_CLOUDFRONT=false + + while [ $# -gt 0 ]; do + case "$1" in + --full) + CHECK_SSH=true + CHECK_SERVICES=true + CHECK_API=true + CHECK_NGINX=true + CHECK_RDS=true + CHECK_S3=true + CHECK_CLOUDFRONT=true + ;; + --ssh-only) + CHECK_SSH=true + ;; + --services) + CHECK_SERVICES=true + ;; + --api) + CHECK_API=true + ;; + --nginx) + CHECK_NGINX=true + ;; + --rds) + CHECK_RDS=true + ;; + --s3) + CHECK_S3=true + ;; + --help) + echo "Uso: $0 [opciones]" + echo "" + echo "Opciones:" + echo " --full Ejecutar todas las validaciones (default)" + echo " --ssh-only Solo validar conectividad SSH" + echo " --services Solo validar servicios systemd" + echo " --api Solo validar APIs" + echo " --nginx Solo validar nginx" + echo " --rds Solo validar RDS" + echo " --s3 Solo validar S3" + echo " --help Mostrar esta ayuda" + exit 0 + ;; + *) + echo "Opcion desconocida: $1" + echo "Usar --help para ver opciones disponibles" + exit 1 + ;; + esac + shift + done +} + +# ============================================================================= +# OBTENER DATOS DE TERRAFORM +# ============================================================================= + +get_terraform_outputs() { + if [ ! -d "$TERRAFORM_DIR" ]; then + error "No existe directorio Terraform: $TERRAFORM_DIR" + return 1 + fi + + cd "$TERRAFORM_DIR" + + if [ ! -f "terraform.tfstate" ] && [ ! -d ".terraform" ]; then + error "No existe estado de Terraform. Ejecutar create-test-environment.sh primero." + return 1 + fi + + EC2_IP=$(terraform output -raw ec2_public_ip 2>/dev/null || echo "") + RDS_ENDPOINT=$(terraform output -raw rds_endpoint 2>/dev/null || echo "") + S3_BUCKET=$(terraform output -raw frontend_bucket_name 2>/dev/null || echo "") + CLOUDFRONT_DOMAIN=$(terraform output -raw cloudfront_domain_name 2>/dev/null || echo "") + VPC_ID=$(terraform output -raw vpc_id 2>/dev/null || echo "") + + if [ -z "$EC2_IP" ]; then + error "No se pudo obtener EC2_IP del estado de Terraform" + return 1 + fi + + info "Datos del entorno:" + info " EC2 IP: $EC2_IP" + info " RDS: $RDS_ENDPOINT" + info " S3: $S3_BUCKET" + info " CloudFront: $CLOUDFRONT_DOMAIN" +} + +# ============================================================================= +# VALIDAR SSH +# ============================================================================= + +check_ssh() { + info "========================================" + info "VALIDANDO CONECTIVIDAD SSH" + info "========================================" + + local ssh_key="$HOME/.ssh/sacc4-test-key.pem" + if [ ! -f "$ssh_key" ]; then + warn "No existe llave SSH: $ssh_key" + return 1 + fi + + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o ConnectTimeout=10 -o BatchMode=yes ubuntu@"$EC2_IP" "echo 'SSH_OK'" > /dev/null 2>&1; then + log "SSH conectividad: OK ($EC2_IP)" + else + error "SSH conectividad: FALLIDA ($EC2_IP)" + return 1 + fi + + # Verificar usuarios + for user in ubuntu thoth osiris; do + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "id $user" > /dev/null 2>&1; then + log "Usuario $user: Existe" + else + warn "Usuario $user: No encontrado" + fi + done +} + +# ============================================================================= +# VALIDAR SERVICIOS SYSTEMD +# ============================================================================= + +check_services() { + info "========================================" + info "VALIDANDO SERVICIOS SYSTEMD" + info "========================================" + + local ssh_key="$HOME/.ssh/sacc4-test-key.pem" + local services=("nginx") + local api_services=( + "api-sacc4-authentication" + "api-sacc4-users" + "api-sacc4-tickets" + "api-sacc4-privileges" + "api-sacc4-rols" + "api-sacc4-associates" + ) + + # Nginx + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "sudo systemctl is-active nginx" > /dev/null 2>&1; then + log "nginx: Activo" + else + error "nginx: Inactivo o no encontrado" + fi + + # Servicios API + for service in "${api_services[@]}"; do + local status + status=$(ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "sudo systemctl is-active $service 2>/dev/null || echo 'inactive'") + if [ "$status" == "active" ]; then + log "$service: Activo" + else + warn "$service: $status (esperar despliegue de JARs)" + fi + done + + # Verificar que los servicios estan habilitados + for service in "${api_services[@]}"; do + local enabled + enabled=$(ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "sudo systemctl is-enabled $service 2>/dev/null || echo 'disabled'") + if [ "$enabled" == "enabled" ]; then + log "$service: Habilitado para inicio automatico" + else + warn "$service: No habilitado ($enabled)" + fi + done +} + +# ============================================================================= +# VALIDAR APIs (PUERTOS 8080-8085) +# ============================================================================= + +check_api() { + info "========================================" + info "VALIDANDO APIs (Puertos 8080-8085)" + info "========================================" + + local ssh_key="$HOME/.ssh/sacc4-test-key.pem" + local services=( + "8080:api-sacc4-authentication" + "8081:api-sacc4-users" + "8082:api-sacc4-tickets" + "8083:api-sacc4-privileges" + "8084:api-sacc4-rols" + "8085:api-sacc4-associates" + ) + + for svc in "${services[@]}"; do + local port=$(echo "$svc" | cut -d':' -f1) + local name=$(echo "$svc" | cut -d':' -f2) + + # Verificar si el puerto esta escuchando + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "ss -tlnp | grep -q ':$port '" 2>/dev/null; then + log "$name (puerto $port): Escuchando" + + # Intentar health check + local health_status + health_status=$(ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "curl -s -o /dev/null -w '%{http_code}' http://localhost:$port/actuator/health 2>/dev/null || echo '000'") + if [ "$health_status" == "200" ]; then + log "$name (puerto $port): Health check OK (HTTP 200)" + else + warn "$name (puerto $port): Health check responde HTTP $health_status" + fi + else + warn "$name (puerto $port): No esta escuchando" + fi + done +} + +# ============================================================================= +# VALIDAR NGINX +# ============================================================================= + +check_nginx() { + info "========================================" + info "VALIDANDO NGINX" + info "========================================" + + local ssh_key="$HOME/.ssh/sacc4-test-key.pem" + + # Configuracion + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "sudo nginx -t" > /dev/null 2>&1; then + log "nginx -t: Configuracion valida" + else + error "nginx -t: Errores en configuracion" + fi + + # Procesos + local workers + workers=$(ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "ps aux | grep '[n]ginx: worker' | wc -l") + if [ "$workers" -gt 0 ]; then + log "nginx: $workers workers activos" + else + warn "nginx: No hay workers activos" + fi + + # Puerto 80 + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "ss -tlnp | grep -q ':80 '" > /dev/null 2>&1; then + log "nginx: Puerto 80 escuchando" + else + error "nginx: Puerto 80 no escucha" + fi + + # Puerto 443 + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "ss -tlnp | grep -q ':443 '" > /dev/null 2>&1; then + log "nginx: Puerto 443 escuchando (SSL configurado)" + else + warn "nginx: Puerto 443 no escucha (SSL no configurado)" + fi +} + +# ============================================================================= +# VALIDAR RDS +# ============================================================================= + +check_rds() { + info "========================================" + info "VALIDANDO RDS (MariaDB)" + info "========================================" + + local ssh_key="$HOME/.ssh/sacc4-test-key.pem" + + # Verificar conectividad de red + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "nc -z -w 5 $(echo $RDS_ENDPOINT | cut -d':' -f1) 3306" > /dev/null 2>&1; then + log "RDS: Conectividad de red OK (puerto 3306)" + else + error "RDS: No se puede conectar al puerto 3306" + return 1 + fi + + # Verificar login (usando usuario de aplicacion) + if ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "mysql -h $RDS_ENDPOINT -u sacc_app_user -p -e 'SELECT 1;' 2>/dev/null" > /dev/null 2>&1; then + log "RDS: Login como sacc_app_user OK" + else + warn "RDS: No se pudo hacer login (verificar credenciales en /etc/sacc4/sacc4.env)" + fi + + # Listar bases de datos + local databases + databases=$(ssh -i "$ssh_key" -o StrictHostKeyChecking=no ubuntu@"$EC2_IP" "mysql -h $RDS_ENDPOINT -u sacc_app_user -p -e 'SHOW DATABASES;' 2>/dev/null || true") + if [ -n "$databases" ]; then + log "RDS: Bases de datos disponibles:" + echo "$databases" | while read -r db; do + info " - $db" + done + fi +} + +# ============================================================================= +# VALIDAR S3 +# ============================================================================= + +check_s3() { + info "========================================" + info "VALIDANDO S3 (Frontend)" + info "========================================" + + if [ -z "$S3_BUCKET" ]; then + warn "S3: No se pudo obtener nombre del bucket" + return 1 + fi + + # Verificar que el bucket existe + if aws s3api head-bucket --bucket "$S3_BUCKET" 2>/dev/null; then + log "S3: Bucket existe ($S3_BUCKET)" + else + error "S3: Bucket no existe o no es accesible ($S3_BUCKET)" + return 1 + fi + + # Listar contenido + local objects + objects=$(aws s3 ls "s3://$S3_BUCKET" --summarize 2>/dev/null | tail -2) + if [ -n "$objects" ]; then + log "S3: Contenido del bucket:" + aws s3 ls "s3://$S3_BUCKET" | head -10 | while read -r line; do + info " $line" + done + else + warn "S3: Bucket vacio (subir build del frontend)" + fi + + # Politica del bucket + local policy + policy=$(aws s3api get-bucket-policy --bucket "$S3_BUCKET" --query 'Policy' --output text 2>/dev/null || echo "No policy") + if [ "$policy" != "No policy" ]; then + log "S3: Politica de bucket configurada" + else + warn "S3: No hay politica de bucket configurada" + fi +} + +# ============================================================================= +# VALIDAR CLOUDFRONT +# ============================================================================= + +check_cloudfront() { + info "========================================" + info "VALIDANDO CLOUDFRONT" + info "========================================" + + if [ -z "$CLOUDFRONT_DOMAIN" ]; then + warn "CloudFront: No se pudo obtener dominio" + return 1 + fi + + log "CloudFront: Dominio = $CLOUDFRONT_DOMAIN" + + # Verificar distribucion + local dist_id + dist_id=$(aws cloudfront list-distributions --query "DistributionList.Items[?DomainName=='$CLOUDFRONT_DOMAIN'].Id" --output text 2>/dev/null || echo "") + if [ -n "$dist_id" ]; then + log "CloudFront: Distribucion encontrada (ID: $dist_id)" + + # Verificar estado + local status + status=$(aws cloudfront get-distribution --id "$dist_id" --query 'Distribution.Status' --output text 2>/dev/null || echo "Unknown") + if [ "$status" == "Deployed" ]; then + log "CloudFront: Estado = Deployed" + else + warn "CloudFront: Estado = $status" + fi + else + warn "CloudFront: No se encontro distribucion" + fi +} + +# ============================================================================= +# RESUMEN +# ============================================================================= + +show_summary() { + info "========================================" + info "RESUMEN DE VALIDACION" + info "========================================" + + local ok_count=$(grep -c "OK:" "$LOG_FILE" 2>/dev/null || echo 0) + local warn_count=$(grep -c "WARN:" "$LOG_FILE" 2>/dev/null || echo 0) + local fail_count=$(grep -c "FAIL:" "$LOG_FILE" 2>/dev/null || echo 0) + + log "Validaciones exitosas: $ok_count" + if [ "$warn_count" -gt 0 ]; then + warn "Advertencias: $warn_count" + fi + if [ "$fail_count" -gt 0 ]; then + error "Fallos: $fail_count" + fi + + info "" + info "Log completo: $LOG_FILE" + info "" + info "URLs del entorno:" + info " API: http://$EC2_IP" + info " API SSL: https://$EC2_IP (si SSL configurado)" + info " Front: https://$CLOUDFRONT_DOMAIN" +} + +# ============================================================================= +# MAIN +# ============================================================================= + +main() { + parse_args "$@" + + info "========================================" + info "SACC v4 - Validacion de Entorno TEST" + info "========================================" + + get_terraform_outputs + + if [ "$CHECK_SSH" == "true" ]; then + check_ssh + fi + + if [ "$CHECK_SERVICES" == "true" ]; then + check_services + fi + + if [ "$CHECK_API" == "true" ]; then + check_api + fi + + if [ "$CHECK_NGINX" == "true" ]; then + check_nginx + fi + + if [ "$CHECK_RDS" == "true" ]; then + check_rds + fi + + if [ "$CHECK_S3" == "true" ]; then + check_s3 + fi + + if [ "$CHECK_CLOUDFRONT" == "true" ]; then + check_cloudfront + fi + + show_summary +} + +main "$@" diff --git a/terraform/bootstrap.tf b/terraform/bootstrap.tf new file mode 100644 index 0000000..f23c500 --- /dev/null +++ b/terraform/bootstrap.tf @@ -0,0 +1,38 @@ +# Backend Bootstrap - Bucket S3 y DynamoDB para Estado Terraform +# ================================================================ +# Ejecutar PRIMERO antes de terraform init: +# aws s3api create-bucket --bucket sacc4-terraform-state-test --region mx-central-1 +# aws dynamodb create-table --table-name sacc4-terraform-locks-test \ +# --attribute-definitions AttributeName=LockID,AttributeType=S \ +# --key-schema AttributeName=LockID,KeyType=HASH \ +# --billing-mode PAY_PER_REQUEST + +resource "aws_s3_bucket" "terraform_state" { + bucket = "sacc4-terraform-state-${var.environment}" +} + +resource "aws_s3_bucket_versioning" "terraform_state" { + bucket = aws_s3_bucket.terraform_state.id + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" { + bucket = aws_s3_bucket.terraform_state.id + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_dynamodb_table" "terraform_locks" { + name = "sacc4-terraform-locks-${var.environment}" + billing_mode = "PAY_PER_REQUEST" + hash_key = "LockID" + attribute { + name = "LockID" + type = "S" + } +} \ No newline at end of file diff --git a/terraform/environments/prod/terraform.tfvars b/terraform/environments/prod/terraform.tfvars new file mode 100644 index 0000000..30cdbd1 --- /dev/null +++ b/terraform/environments/prod/terraform.tfvars @@ -0,0 +1,32 @@ +# Variables de entorno para PRODUCCION +# ==================================== +# Archivo: environments/prod/terraform.tfvars + +environment = "prod" +aws_region = "mx-central-1" + +# VPC - Igual a produccion actual +vpc_cidr = "10.2.0.0/16" +availability_zones = ["mx-central-1a", "mx-central-1b"] + +# EC2 +ami_id = "ami-0f553e2869648134e" # Ubuntu 22.04 LTS +instance_type = "t3.small" +key_name = "sacc4-prod-key" + +# IP restringida (solo VPN u oficina) +my_ip = "TU_IP_O_VPN_AQUI/32" + +# RDS +db_name = "sacc4_prod" +db_username = "sacc4_admin" +db_password = "PasswordSeguraProduccion123!" +rds_instance_class = "db.t3.micro" +rds_allocated_storage = 20 + +# S3 / CloudFront / Route53 +s3_bucket_name = "sacc4-frontend-prod-ccsoft" +domain_name = "prod-sacc.ccsoft.mx" + +# Certificado SSL (ARN real de ACM) +certificate_arn = "arn:aws:acm:mx-central-1:523761210517:certificate/EXISTENTE" \ No newline at end of file diff --git a/terraform/environments/test/main.tf b/terraform/environments/test/main.tf new file mode 100644 index 0000000..d01fa00 --- /dev/null +++ b/terraform/environments/test/main.tf @@ -0,0 +1,339 @@ +# ============================================================================= +# SACC v4 - Entorno TEST en Cuenta 668889063715 +# ============================================================================= +# DUPLICA la infraestructura de produccion usando los modulos PRODUCCION +# probados de terraform-sacc4/ +# +# IMPORTANTE: Este archivo usa los modulos de produccion para garantizar +# que el entorno de test sea IDENTICO al de produccion. +# +# Uso: +# 1. cp terraform.tfvars.example terraform.tfvars +# 2. Editar terraform.tfvars con valores reales +# 3. terraform init +# 4. terraform plan +# 5. terraform apply +# ============================================================================= + +terraform { + required_version = ">= 1.5.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.0" + } + } + + # Backend S3 para estado (bucket creado por bootstrap) + backend "s3" { + bucket = "sacc4-terraform-state-test-668889063715" + key = "sacc4-test/infrastructure/terraform.tfstate" + region = "mx-central-1" + encrypt = true + dynamodb_table = "sacc4-terraform-locks-test-668889063715" + } +} + +# Provider AWS - Región Mexico (mx-central-1) +provider "aws" { + region = var.aws_region + + default_tags { + tags = { + Project = "sacc4" + Environment = "test" + ManagedBy = "terraform" + Owner = "infra-team" + AccountId = "668889063715" + CostCenter = "test-environment" + } + } +} + +# Provider AWS para ACM (us-east-1 requerido por CloudFront) +provider "aws" { + alias = "us_east_1" + region = "us-east-1" + + default_tags { + tags = { + Project = "sacc4" + Environment = "test" + ManagedBy = "terraform" + } + } +} + +# ============================================================================= +# DATOS +# ============================================================================= + +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} + +# ============================================================================= +# LOCALES +# ============================================================================= + +locals { + name_prefix = "${var.project_name}-test" + common_tags = { + Project = var.project_name + Environment = "test" + ManagedBy = "terraform" + } +} + +# ============================================================================= +# MODULOS DE INFRAESTRUCTURA (usando modulos de produccion) +# ============================================================================= + +module "vpc" { + source = "../../../../terraform-sacc4/modules/vpc" + + name_prefix = local.name_prefix + vpc_cidr = var.vpc_cidr + availability_zones = var.availability_zones + public_subnet_cidrs = var.public_subnet_cidrs + private_subnet_cidrs = var.private_subnet_cidrs + tags = local.common_tags +} + +module "security_groups" { + source = "../../../../terraform-sacc4/modules/security-groups" + + name_prefix = local.name_prefix + vpc_id = module.vpc.vpc_id + vpc_cidr = module.vpc.vpc_cidr + ssh_allowed_cidrs = var.ssh_allowed_cidrs + tags = local.common_tags +} + +module "iam" { + source = "../../../../terraform-sacc4/modules/iam" + + name_prefix = local.name_prefix + tags = local.common_tags +} + +module "ec2" { + source = "../../../../terraform-sacc4/modules/ec2" + + name_prefix = local.name_prefix + instance_type = var.ec2_instance_type + ami = var.ec2_ami + subnet_id = module.vpc.public_subnet_ids[0] + security_group_ids = [module.security_groups.ec2_security_group_id] + root_volume_size = var.ec2_root_volume_size + root_volume_type = var.ec2_root_volume_type + root_volume_encrypted = var.ec2_root_volume_encrypted + thoth_public_key = var.thoth_public_key + osiris_public_key = var.osiris_public_key + rds_endpoint = module.rds.rds_endpoint + rds_db_name = var.rds_db_name + rds_app_username = "sacc_app_user" + rds_app_password = var.rds_master_password + tags = local.common_tags +} + +module "rds" { + source = "../../../../terraform-sacc4/modules/rds" + + name_prefix = local.name_prefix + instance_class = var.rds_instance_class + engine = var.rds_engine + engine_version = var.rds_engine_version + allocated_storage = var.rds_allocated_storage + max_allocated_storage = var.rds_max_allocated_storage + db_name = var.rds_db_name + master_username = var.rds_master_username + master_password = var.rds_master_password + backup_retention_period = var.rds_backup_retention_period + backup_window = var.rds_backup_window + maintenance_window = var.rds_maintenance_window + subnet_ids = module.vpc.private_subnet_ids + security_group_ids = [module.security_groups.rds_security_group_id] + enable_replica = false + tags = local.common_tags +} + +module "lambda_scheduler" { + source = "../../../../terraform-sacc4/modules/lambda-scheduler" + count = var.enable_scheduling ? 1 : 0 + + name_prefix = local.name_prefix + ec2_instance_id = module.ec2.instance_id + rds_instance_id = module.rds.db_instance_identifier + schedule_timezone = var.schedule_timezone + schedule_start_cron = var.schedule_start_cron + schedule_stop_cron = var.schedule_stop_cron + lambda_role_arn = module.iam.lambda_scheduler_role_arn + scheduler_role_arn = module.iam.eventbridge_scheduler_role_arn + tags = local.common_tags +} + +module "s3_cloudfront" { + source = "../../../../terraform-sacc4/modules/s3-cloudfront" + + name_prefix = local.name_prefix + bucket_name = var.frontend_bucket_name + cloudfront_price_class = var.cloudfront_price_class + enable_logging = var.enable_cloudfront_logging + domain_name = var.domain_name + tags = local.common_tags +} + +module "route53" { + source = "../../../../terraform-sacc4/modules/route53" + + name_prefix = local.name_prefix + domain_name = var.domain_name + api_subdomain = var.api_subdomain + api_public_ip = module.ec2.public_ip + cloudfront_domain = module.s3_cloudfront.cloudfront_domain_name + cloudfront_zone_id = module.s3_cloudfront.cloudfront_hosted_zone_id + tags = local.common_tags +} + +# ============================================================================= +# OUTPUTS +# ============================================================================= + +output "vpc_id" { + description = "ID de la VPC creada" + value = module.vpc.vpc_id +} + +output "public_subnet_ids" { + description = "IDs de subnets publicas" + value = module.vpc.public_subnet_ids +} + +output "private_subnet_ids" { + description = "IDs de subnets privadas" + value = module.vpc.private_subnet_ids +} + +output "ec2_instance_id" { + description = "ID de la instancia EC2" + value = module.ec2.instance_id +} + +output "ec2_public_ip" { + description = "IP publica de la instancia EC2" + value = module.ec2.public_ip +} + +output "ec2_private_ip" { + description = "IP privada de la instancia EC2" + value = module.ec2.private_ip +} + +output "rds_endpoint" { + description = "Endpoint de la base de datos RDS" + value = module.rds.rds_endpoint + sensitive = true +} + +output "rds_port" { + description = "Puerto de la base de datos RDS" + value = module.rds.rds_port +} + +output "rds_db_name" { + description = "Nombre de la base de datos" + value = module.rds.db_name +} + +output "frontend_bucket_name" { + description = "Nombre del bucket S3 del frontend" + value = module.s3_cloudfront.bucket_name +} + +output "cloudfront_domain_name" { + description = "Dominio de CloudFront" + value = module.s3_cloudfront.cloudfront_domain_name +} + +output "cloudfront_distribution_id" { + description = "ID de la distribucion CloudFront" + value = module.s3_cloudfront.distribution_id +} + +output "api_gateway_url" { + description = "URL del API Gateway" + value = "https://${var.api_subdomain}" +} + +output "frontend_url" { + description = "URL del frontend" + value = "https://${var.domain_name}" +} + +output "lambda_start_function_name" { + description = "Nombre de la funcion Lambda de inicio" + value = var.enable_scheduling ? module.lambda_scheduler[0].start_function_name : null +} + +output "lambda_stop_function_name" { + description = "Nombre de la funcion Lambda de apagado" + value = var.enable_scheduling ? module.lambda_scheduler[0].stop_function_name : null +} + +output "route53_api_record" { + description = "Nombre del registro DNS para API" + value = module.route53.api_record_name +} + +output "route53_frontend_record" { + description = "Nombre del registro DNS para frontend" + value = module.route53.frontend_record_name +} + +output "route53_zone_id" { + description = "ID de la zona Route53" + value = module.route53.hosted_zone_id +} + +output "ansible_inventory" { + description = "Inventario Ansible generado dinamicamente" + value = <<-EOT +[sacc4-test] +${module.ec2.public_ip} ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/sacc4-test-key.pem + +[sacc4-test:vars] +ansible_python_interpreter=/usr/bin/python3 +environment=test +db_endpoint=${module.rds.rds_endpoint} +s3_bucket=${module.s3_cloudfront.bucket_name} +cloudfront_domain=${module.s3_cloudfront.cloudfront_domain_name} +EOT + sensitive = false +} + +output "deployment_commands" { + description = "Comandos para desplegar la aplicacion" + value = <<-EOT +# ============================================================================= +# COMANDOS POST-DESPLIEGUE - SACC v4 TEST +# ============================================================================= +# Conectar a la instancia +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@${module.ec2.public_ip} + +# Verificar servicios +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@${module.ec2.public_ip} "sudo systemctl status nginx" +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@${module.ec2.public_ip} "sudo systemctl status api-sacc4-*" + +# Verificar health checks +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@${module.ec2.public_ip} "curl -s http://localhost:8080/actuator/health" +ssh -i ~/.ssh/sacc4-test-key.pem ubuntu@${module.ec2.public_ip} "curl -s http://localhost:8081/actuator/health" + +# Base de datos +mysql -h ${module.rds.rds_endpoint} -u sacc_app_user -p -e "SELECT 1;" +EOT +} diff --git a/terraform/environments/test/terraform.tfvars b/terraform/environments/test/terraform.tfvars new file mode 100644 index 0000000..1d806a5 --- /dev/null +++ b/terraform/environments/test/terraform.tfvars @@ -0,0 +1,98 @@ +# ============================================================================= +# VARIABLES DE ENTORNO TEST - SACC v4 +# Cuenta AWS: 668889063715 +# ============================================================================= + +# ============================================================================= +# GENERALES +# ============================================================================= + +aws_region = "mx-central-1" +environment = "test" +project_name = "sacc4" + +# ============================================================================= +# DOMINIO Y DNS +# ============================================================================= + +# Dominio principal para el entorno de test +# NOTA: Asegurate de que este dominio exista en Route53 de la cuenta 668889063715 +domain_name = "test-sacc.ccsoft.mx" +api_subdomain = "api.test-sacc.ccsoft.mx" + +# ============================================================================= +# NETWORKING +# ============================================================================= + +# CIDR que NO choque con produccion (10.2.0.0/16) ni otros entornos +vpc_cidr = "10.3.0.0/16" +availability_zones = ["mx-central-1a", "mx-central-1b"] +public_subnet_cidrs = ["10.3.1.0/24", "10.3.2.0/24"] +private_subnet_cidrs = ["10.3.10.0/24", "10.3.11.0/24"] + +# ============================================================================= +# EC2 CONFIGURATION +# ============================================================================= + +ec2_instance_type = "t3.small" +ec2_ami = "ami-0f553e2869648134e" +ec2_root_volume_size = 8 +ec2_root_volume_type = "gp2" +ec2_root_volume_encrypted = true + +# SSH - RESTRINGIR a tu IP publica o rangos de oficina/VPN +# Ejemplo: ["203.0.113.0/24"] para oficina, ["10.8.0.0/24"] para VPN +# WARNING: [] vacio usa solo VPC CIDR (mas seguro) +ssh_allowed_cidrs = [] + +# Llaves SSH publicas para acceso +# Generar par de llaves: ssh-keygen -t ed25519 -f sacc4-test-key -C "sacc4-test" +thoth_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII/RcJmEYOBpfq1tSLltV1pyNB55l1jA2zYr5ZNJ0f41 thoth@ccsoft" +osiris_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFo6CycfgIuCCSVZbhuPwqlAVDxY8YWb1xpvpqxSzMjR osiris@ccsoft" + +# ============================================================================= +# RDS CONFIGURATION +# ============================================================================= + +rds_instance_class = "db.t3.micro" +rds_engine = "mariadb" +rds_engine_version = "10.11.16" +rds_allocated_storage = 20 +rds_max_allocated_storage = 100 +rds_db_name = "ccsoft_sacc4_test" +rds_master_username = "sacc_admin_test" +rds_master_password = "CambiarEstaPassword123!Segura" + +rds_backup_retention_period = 7 +rds_backup_window = "03:00-04:00" +rds_maintenance_window = "Mon:04:00-Mon:05:00" + +# ============================================================================= +# SCHEDULING (apagado automatico para ahorrar costos en test) +# ============================================================================= + +enable_scheduling = true +schedule_timezone = "America/Mexico_City" +schedule_start_cron = "cron(0 13 ? * MON-FRI *)" +schedule_stop_cron = "cron(0 0 ? * TUE-SAT *)" + +# ============================================================================= +# FRONTEND (S3 + CloudFront) +# ============================================================================= + +# Nombre unico global del bucket S3 +frontend_bucket_name = "sacc4-frontend-test-668889063715" + +cloudfront_price_class = "PriceClass_100" +enable_cloudfront_logging = false + +# ============================================================================= +# TAGS COMUNES +# ============================================================================= + +common_tags = { + Project = "proyectosacc" + ManagedBy = "terraform" + Team = "infra" + Purpose = "test-environment" +} diff --git a/terraform/environments/test/variables.tf b/terraform/environments/test/variables.tf new file mode 100644 index 0000000..ef50612 --- /dev/null +++ b/terraform/environments/test/variables.tf @@ -0,0 +1,222 @@ +# ============================================================================= +# VARIABLES - Entorno TEST SACC v4 +# ============================================================================= + +variable "aws_region" { + description = "Region AWS para despliegue" + type = string + default = "mx-central-1" +} + +variable "environment" { + description = "Ambiente (test)" + type = string + default = "test" +} + +variable "project_name" { + description = "Nombre del proyecto" + type = string + default = "sacc4" +} + +variable "domain_name" { + description = "Dominio principal" + type = string + default = "test-sacc.ccsoft.mx" +} + +variable "api_subdomain" { + description = "Subdominio para API" + type = string + default = "api.test-sacc.ccsoft.mx" +} + +variable "vpc_cidr" { + description = "CIDR block para VPC" + type = string + default = "10.3.0.0/16" +} + +variable "availability_zones" { + description = "Zonas de disponibilidad" + type = list(string) + default = ["mx-central-1a", "mx-central-1b"] +} + +variable "public_subnet_cidrs" { + description = "CIDRs para subnets publicas" + type = list(string) + default = ["10.3.1.0/24", "10.3.2.0/24"] +} + +variable "private_subnet_cidrs" { + description = "CIDRs para subnets privadas" + type = list(string) + default = ["10.3.10.0/24", "10.3.11.0/24"] +} + +variable "ec2_instance_type" { + description = "Tipo de instancia EC2" + type = string + default = "t3.small" +} + +variable "ec2_ami" { + description = "AMI ID de Ubuntu 22.04 LTS en mx-central-1" + type = string + default = "ami-0f553e2869648134e" +} + +variable "ec2_root_volume_size" { + description = "Tamanio del volumen root en GB" + type = number + default = 8 +} + +variable "ec2_root_volume_type" { + description = "Tipo de volumen root" + type = string + default = "gp2" +} + +variable "ec2_root_volume_encrypted" { + description = "Volumen encriptado" + type = bool + default = true +} + +variable "ssh_allowed_cidrs" { + description = "Lista de CIDRs permitidos para SSH" + type = list(string) + default = [] +} + +variable "rds_instance_class" { + description = "Clase de instancia RDS" + type = string + default = "db.t3.micro" +} + +variable "rds_engine" { + description = "Motor de base de datos" + type = string + default = "mariadb" +} + +variable "rds_engine_version" { + description = "Version del motor" + type = string + default = "10.11.16" +} + +variable "rds_allocated_storage" { + description = "Almacenamiento asignado en GB" + type = number + default = 20 +} + +variable "rds_max_allocated_storage" { + description = "Almacenamiento maximo para autoscaling" + type = number + default = 100 +} + +variable "rds_db_name" { + description = "Nombre de la base de datos" + type = string + default = "ccsoft_sacc4_test" +} + +variable "rds_master_username" { + description = "Usuario master de RDS" + type = string + default = "sacc_admin_test" + sensitive = true +} + +variable "rds_master_password" { + description = "Contrasena master de RDS" + type = string + sensitive = true +} + +variable "rds_backup_retention_period" { + description = "Periodo de retencion de backups en dias" + type = number + default = 7 +} + +variable "rds_backup_window" { + description = "Ventana de backup" + type = string + default = "03:00-04:00" +} + +variable "rds_maintenance_window" { + description = "Ventana de mantenimiento" + type = string + default = "Mon:04:00-Mon:05:00" +} + +variable "enable_scheduling" { + description = "Habilitar scheduling horario" + type = bool + default = true +} + +variable "schedule_timezone" { + description = "Zona horaria" + type = string + default = "America/Mexico_City" +} + +variable "schedule_start_cron" { + description = "Expresion cron para inicio" + type = string + default = "cron(0 13 ? * MON-FRI *)" +} + +variable "schedule_stop_cron" { + description = "Expresion cron para apagado" + type = string + default = "cron(0 0 ? * TUE-SAT *)" +} + +variable "frontend_bucket_name" { + description = "Nombre del bucket S3" + type = string + default = "sacc4-frontend-test-668889063715" +} + +variable "cloudfront_price_class" { + description = "Clase de precio de CloudFront" + type = string + default = "PriceClass_100" +} + +variable "enable_cloudfront_logging" { + description = "Habilitar logging de CloudFront" + type = bool + default = false +} + +variable "thoth_public_key" { + description = "Llave publica SSH para thoth" + type = string +} + +variable "osiris_public_key" { + description = "Llave publica SSH para osiris" + type = string +} + +variable "common_tags" { + description = "Tags comunes" + type = map(string) + default = { + Project = "proyectosacc" + ManagedBy = "terraform" + Team = "infra" + } +} diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..ce7b28b --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,205 @@ +# SACC v4 - Duplicación de Infraestructura de Producción +# ====================================================== +# Este script Terraform duplica el entorno PROD de SACC v4 +# en una nueva cuenta AWS de pruebas. +# +# USO: +# 1. Copiar terraform.tfvars.example a terraform.tfvars +# 2. Completar variables con valores de la nueva cuenta +# 3. terraform init +# 4. terraform plan +# 5. terraform apply +# +# NO EJECUTAR EN PRODUCCIÓN - Solo para entornos de prueba + +terraform { + required_version = ">= 1.5.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } + + # Backend S3 para estado (crear bucket primero) + backend "s3" { + bucket = "sacc4-terraform-state-test" + key = "sacc4-test/terraform.tfstate" + region = "mx-central-1" + encrypt = true + dynamodb_table = "sacc4-terraform-locks-test" + } +} + +# Provider AWS - Región México +provider "aws" { + region = var.aws_region + + default_tags { + tags = { + Project = "SACC-v4" + Environment = var.environment + ManagedBy = "Terraform" + CreatedDate = timestamp() + } + } +} + +# ====================================================== +# MÓDULOS DE INFRAESTRUCTURA +# ====================================================== + +module "vpc" { + source = "./modules/vpc" + + vpc_cidr = var.vpc_cidr + environment = var.environment + availability_zones = var.availability_zones +} + +module "security_groups" { + source = "./modules/security-groups" + + vpc_id = module.vpc.vpc_id + environment = var.environment + my_ip = var.my_ip +} + +module "iam" { + source = "./modules/iam" + + environment = var.environment + account_id = data.aws_caller_identity.current.account_id +} + +module "ec2" { + source = "./modules/ec2" + + ami_id = var.ami_id + instance_type = var.instance_type + subnet_id = module.vpc.public_subnet_ids[0] + security_group_ids = [module.security_groups.ec2_sg_id] + key_name = var.key_name + environment = var.environment + associate_public_ip = true + user_data = file("${path.module}/scripts/ec2-user-data.sh") + iam_instance_profile = module.iam.ec2_instance_profile_name +} + +module "rds" { + source = "./modules/rds" + + subnet_ids = module.vpc.private_subnet_ids + security_group_id = module.security_groups.rds_sg_id + db_name = var.db_name + db_username = var.db_username + db_password = var.db_password + instance_class = var.rds_instance_class + allocated_storage = var.rds_allocated_storage + environment = var.environment +} + +module "s3_cloudfront" { + source = "./modules/s3-cloudfront" + + bucket_name = var.s3_bucket_name + environment = var.environment + domain_name = var.domain_name + certificate_arn = var.certificate_arn +} + +module "route53" { + source = "./modules/route53" + + domain_name = var.domain_name + ec2_public_ip = module.ec2.public_ip + cloudfront_domain = module.s3_cloudfront.cloudfront_domain_name + cloudfront_zone_id = module.s3_cloudfront.cloudfront_hosted_zone_id +} + +module "lambda_scheduler" { + source = "./modules/lambda-scheduler" + + environment = var.environment + ec2_instance_id = module.ec2.instance_id +} + +# ====================================================== +# DATOS +# ====================================================== + +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} + +# ====================================================== +# OUTPUTS +# ====================================================== + +output "vpc_id" { + description = "ID de la VPC creada" + value = module.vpc.vpc_id +} + +output "ec2_public_ip" { + description = "IP pública de la instancia EC2" + value = module.ec2.public_ip +} + +output "ec2_private_ip" { + description = "IP privada de la instancia EC2" + value = module.ec2.private_ip +} + +output "rds_endpoint" { + description = "Endpoint de la base de datos RDS" + value = module.rds.endpoint + sensitive = true +} + +output "s3_bucket_name" { + description = "Nombre del bucket S3 para frontend" + value = module.s3_cloudfront.bucket_name +} + +output "cloudfront_domain" { + description = "Dominio de CloudFront" + value = module.s3_cloudfront.cloudfront_domain_name +} + +output "route53_nameservers" { + description = "Nameservers de Route53" + value = module.route53.nameservers +} + +output "ansible_inventory" { + description = "Inventario Ansible generado dinámicamente" + value = <<-EOT + [sacc4-test] + ${module.ec2.public_ip} ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/${var.key_name}.pem + + [sacc4-test:vars] + ansible_python_interpreter=/usr/bin/python3 + environment=${var.environment} + db_endpoint=${module.rds.endpoint} + s3_bucket=${module.s3_cloudfront.bucket_name} + EOT + sensitive = false +} + +output "deployment_commands" { + description = "Comandos para desplegar la aplicación" + value = <<-EOT + # Conectar a la instancia + ssh -i ~/.ssh/${var.key_name}.pem ubuntu@${module.ec2.public_ip} + + # Verificar servicios + systemctl status nginx + systemctl status api-sacc4-* + + # Verificar health checks + curl http://localhost:8080/actuator/health + curl http://localhost:8081/actuator/health + curl http://localhost:8082/actuator/health + EOT +} \ No newline at end of file diff --git a/terraform/modules/ec2/main.tf b/terraform/modules/ec2/main.tf new file mode 100644 index 0000000..d510013 --- /dev/null +++ b/terraform/modules/ec2/main.tf @@ -0,0 +1,42 @@ +variable "ami_id" {} +variable "instance_type" { default = "t3.small" } +variable "subnet_id" {} +variable "security_group_ids" { type = list(string) } +variable "key_name" {} +variable "environment" {} +variable "associate_public_ip" { default = true } +variable "user_data" { default = "" } +variable "iam_instance_profile" { default = "" } + +resource "aws_instance" "main" { + ami = var.ami_id + instance_type = var.instance_type + subnet_id = var.subnet_id + vpc_security_group_ids = var.security_group_ids + key_name = var.key_name + associate_public_ip_address = var.associate_public_ip + user_data = var.user_data + iam_instance_profile = var.iam_instance_profile + + root_block_device { + volume_size = 8 + volume_type = "gp2" + encrypted = true + delete_on_termination = true + } + + tags = { + Name = "sacc4-ec2-${var.environment}" + Environment = var.environment + } +} + +resource "aws_eip" "main" { + instance = aws_instance.main.id + domain = "vpc" + tags = { Name = "sacc4-eip-${var.environment}" } +} + +output "instance_id" { value = aws_instance.main.id } +output "public_ip" { value = aws_eip.main.public_ip } +output "private_ip" { value = aws_instance.main.private_ip } \ No newline at end of file diff --git a/terraform/modules/iam/main.tf b/terraform/modules/iam/main.tf new file mode 100644 index 0000000..2e2eeda --- /dev/null +++ b/terraform/modules/iam/main.tf @@ -0,0 +1,54 @@ +variable "environment" {} +variable "account_id" {} + +resource "aws_iam_role" "ec2_role" { + name = "sacc4-ec2-role-${var.environment}" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { Service = "ec2.amazonaws.com" } + }] + }) +} + +resource "aws_iam_role_policy" "ec2_policy" { + name = "sacc4-ec2-policy-${var.environment}" + role = aws_iam_role.ec2_role.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "s3:GetObject", + "s3:PutObject", + "s3:ListBucket" + ] + Resource = [ + "arn:aws:s3:::sacc4-*", + "arn:aws:s3:::sacc4-*/*" + ] + }, + { + Effect = "Allow" + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ] + Resource = "arn:aws:logs:*:*:log-group:/sacc4/*" + } + ] + }) +} + +resource "aws_iam_instance_profile" "ec2_profile" { + name = "sacc4-ec2-profile-${var.environment}" + role = aws_iam_role.ec2_role.name +} + +output "ec2_instance_profile_name" { + value = aws_iam_instance_profile.ec2_profile.name +} \ No newline at end of file diff --git a/terraform/modules/rds/main.tf b/terraform/modules/rds/main.tf new file mode 100644 index 0000000..25622fa --- /dev/null +++ b/terraform/modules/rds/main.tf @@ -0,0 +1,48 @@ +variable "subnet_ids" { type = list(string) } +variable "security_group_id" {} +variable "db_name" {} +variable "db_username" {} +variable "db_password" { sensitive = true } +variable "instance_class" { default = "db.t3.micro" } +variable "allocated_storage" { default = 20 } +variable "environment" {} + +resource "aws_db_subnet_group" "main" { + name = "sacc4-rds-subnet-${var.environment}" + subnet_ids = var.subnet_ids + tags = { Name = "sacc4-rds-subnet-${var.environment}" } +} + +resource "aws_db_instance" "main" { + identifier = "sacc4-${var.environment}" + engine = "mariadb" + engine_version = "10.11.16" + instance_class = var.instance_class + allocated_storage = var.allocated_storage + storage_type = "gp2" + storage_encrypted = true + + db_name = var.db_name + username = var.db_username + password = var.db_password + + db_subnet_group_name = aws_db_subnet_group.main.name + vpc_security_group_ids = [var.security_group_id] + + publicly_accessible = false + skip_final_snapshot = true + backup_retention_period = 7 + backup_window = "00:01-00:31" + + tags = { + Name = "sacc4-rds-${var.environment}" + Environment = var.environment + } +} + +output "endpoint" { + value = aws_db_instance.main.endpoint + sensitive = true +} + +output "db_name" { value = aws_db_instance.main.db_name } \ No newline at end of file diff --git a/terraform/modules/security-groups/main.tf b/terraform/modules/security-groups/main.tf new file mode 100644 index 0000000..55b9e9e --- /dev/null +++ b/terraform/modules/security-groups/main.tf @@ -0,0 +1,80 @@ +variable "vpc_id" {} +variable "environment" {} +variable "my_ip" {} + +resource "aws_security_group" "ec2" { + name = "sacc4-ec2-sg-${var.environment}" + description = "Security group para instancia EC2 SACC4" + vpc_id = var.vpc_id + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = [var.my_ip] + description = "SSH desde IP autorizada" + } + + ingress { + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + description = "HTTP" + } + + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + description = "HTTPS" + } + + ingress { + from_port = 8080 + to_port = 8085 + protocol = "tcp" + cidr_blocks = [aws_vpc.main.cidr_block] + description = "APIs internas" + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { Name = "sacc4-ec2-sg-${var.environment}" } +} + +resource "aws_security_group" "rds" { + name = "sacc4-rds-sg-${var.environment}" + description = "Security group para RDS MariaDB" + vpc_id = var.vpc_id + + ingress { + from_port = 3306 + to_port = 3306 + protocol = "tcp" + security_groups = [aws_security_group.ec2.id] + description = "MariaDB desde EC2" + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { Name = "sacc4-rds-sg-${var.environment}" } +} + +resource "aws_vpc" "main" { + cidr_block = "10.3.0.0/16" +} + +output "ec2_sg_id" { value = aws_security_group.ec2.id } +output "rds_sg_id" { value = aws_security_group.rds.id } \ No newline at end of file diff --git a/terraform/modules/vpc/main.tf b/terraform/modules/vpc/main.tf new file mode 100644 index 0000000..53142ca --- /dev/null +++ b/terraform/modules/vpc/main.tf @@ -0,0 +1,51 @@ +variable "vpc_cidr" {} +variable "environment" {} +variable "availability_zones" { type = list(string) } + +resource "aws_vpc" "main" { + cidr_block = var.vpc_cidr + enable_dns_hostnames = true + enable_dns_support = true + tags = { Name = "sacc4-vpc-${var.environment}" } +} + +resource "aws_internet_gateway" "main" { + vpc_id = aws_vpc.main.id + tags = { Name = "sacc4-igw-${var.environment}" } +} + +resource "aws_subnet" "public" { + count = 2 + vpc_id = aws_vpc.main.id + cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 1) + availability_zone = var.availability_zones[count.index] + map_public_ip_on_launch = true + tags = { Name = "sacc4-public-${count.index + 1}-${var.environment}" } +} + +resource "aws_subnet" "private" { + count = 2 + vpc_id = aws_vpc.main.id + cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 11) + availability_zone = var.availability_zones[count.index] + tags = { Name = "sacc4-private-${count.index + 1}-${var.environment}" } +} + +resource "aws_route_table" "public" { + vpc_id = aws_vpc.main.id + route { + cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.main.id + } + tags = { Name = "sacc4-public-rt-${var.environment}" } +} + +resource "aws_route_table_association" "public" { + count = 2 + subnet_id = aws_subnet.public[count.index].id + route_table_id = aws_route_table.public.id +} + +output "vpc_id" { value = aws_vpc.main.id } +output "public_subnet_ids" { value = aws_subnet.public[*].id } +output "private_subnet_ids" { value = aws_subnet.private[*].id } \ No newline at end of file diff --git a/terraform/scripts/ec2-user-data.sh b/terraform/scripts/ec2-user-data.sh new file mode 100644 index 0000000..43086b8 --- /dev/null +++ b/terraform/scripts/ec2-user-data.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# User Data para instancia EC2 SACC v4 +# ===================================== +# Este script se ejecuta al inicio de la instancia + +set -e + +# Actualizar sistema +echo "Actualizando sistema..." +apt-get update -y +apt-get upgrade -y + +# Instalar dependencias base +echo "Instalando dependencias..." +apt-get install -y \ + openjdk-21-jdk \ + nginx \ + unzip \ + jq \ + net-tools \ + htop \ + logrotate \ + curl \ + wget \ + git \ + python3 \ + python3-pip \ + ansible \ + awscli + +# Crear usuarios y grupos +echo "Configurando usuarios..." +groupadd -g 1006 duat || true +useradd -u 997 -g duat -s /bin/bash -m osiris || true +useradd -u 1001 -g duat -s /bin/bash -m thoth || true + +# Crear directorios +echo "Creando directorios..." +mkdir -p /opt/sacc4 +mkdir -p /var/log/sacc4 +mkdir -p /etc/sacc4 +mkdir -p /var/www/html + +# Configurar permisos +chown -R thoth:duat /opt/sacc4 +chmod 2775 /opt/sacc4 + +# Configurar SSH +echo "Configurando SSH..." +sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config +sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config +systemctl restart sshd + +# Configurar UFW +echo "Configurando firewall..." +ufw default deny incoming +ufw default allow outgoing +ufw allow 22/tcp +ufw allow 80/tcp +ufw allow 443/tcp +ufw allow 8080:8085/tcp +ufw --force enable + +# Instalar CloudWatch agent +echo "Instalando CloudWatch agent..." +wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb +dpkg -i amazon-cloudwatch-agent.deb +rm amazon-cloudwatch-agent.deb + +# Crear configuración de CloudWatch +cat > /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json <<'EOF' +{ + "metrics": { + "namespace": "SACC4", + "metrics_collected": { + "cpu": { "measurement": ["cpu_usage_idle", "cpu_usage_user"], "metrics_collection_interval": 60 }, + "mem": { "measurement": ["mem_used_percent"], "metrics_collection_interval": 60 }, + "disk": { "measurement": ["disk_used_percent"], "resources": ["/"], "metrics_collection_interval": 60 } + } + }, + "logs": { + "logs_collected": { + "files": { + "collect_list": [ + { "file_path": "/var/log/sacc4/*/*.log", "log_group_name": "sacc4-application-logs", "log_stream_name": "{instance_id}" } + ] + } + } + } +} +EOF + +# Iniciar CloudWatch agent +/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json + +echo "Configuración base completada!" +echo "IP privada: $(hostname -I | awk '{print $1}')" +echo "Esperando despliegue de aplicación..." \ No newline at end of file diff --git a/terraform/terraform.tfvars.example b/terraform/terraform.tfvars.example new file mode 100644 index 0000000..8e5d3cd --- /dev/null +++ b/terraform/terraform.tfvars.example @@ -0,0 +1,355 @@ +# ============================================================================= +# TERRAFORM.TFVARS.EXAMPLE - SACC v4 +# ============================================================================= +# Plantilla unificada para despliegue de infraestructura SACC v4 +# en entornos TEST y PRODUCCION usando Terraform Workspaces. +# +# INSTRUCCIONES: +# 1. Copiar este archivo: cp terraform.tfvars.example terraform.tfvars +# 2. Completar las variables marcadas como [REQUERIDO] +# 3. Seleccionar workspace: terraform workspace select test|prod +# 4. terraform init +# 5. terraform plan +# 6. terraform apply +# +# CUENTAS AWS: +# TEST: 668889063715 (mx-central-1) +# PROD: 523761210517 (mx-central-1) +# +# NOTA DE SEGURIDAD: +# - NUNCA commitear terraform.tfvars (esta en .gitignore) +# - Las contrasenas deben tener minimo 16 caracteres +# - Restringir SSH a IPs especificas (no usar 0.0.0.0/0) +# ============================================================================= + +# ============================================================================= +# SECCION 1: CONFIGURACION GENERAL +# ============================================================================= + +# Entorno de despliegue. Terraform workspace DEBE coincidir con este valor. +# Valores permitidos: "test", "prod" +# TEST: "test" (cuenta 668889063715) +# PROD: "prod" (cuenta 523761210517) +# [REQUERIDO] - No tiene valor por defecto para evitar errores accidentales +environment = "test" + +# Nombre del proyecto (usado como prefijo en recursos) +# Valor por defecto: "sacc4" +project_name = "sacc4" + +# Region AWS para despliegue +# NOTA: mx-central-1 es la unica region disponible para ambas cuentas +# Valor por defecto: "mx-central-1" +aws_region = "mx-central-1" + +# ============================================================================= +# SECCION 2: DOMINIO Y DNS (Route53) +# ============================================================================= + +# Dominio principal para la aplicacion +# TEST: "dev-sacc.ccsoft.mx" +# PROD: "sacc.ccsoft.mx" +# [REQUERIDO] - Debe existir como Hosted Zone en Route53 de la cuenta +# correspondiente ANTES de ejecutar terraform apply +domain_name = "dev-sacc.ccsoft.mx" + +# Subdominio para la API backend +# TEST: "api.dev-sacc.ccsoft.mx" +# PROD: "api.sacc.ccsoft.mx" +# [REQUERIDO] - Se crea automaticamente como registro A apuntando a EC2 +api_subdomain = "api.dev-sacc.ccsoft.mx" + +# ============================================================================= +# SECCION 3: NETWORKING (VPC) +# ============================================================================= + +# CIDR block para la VPC +# IMPORTANTE: No debe chocar con otras VPCs ni redes on-premise +# TEST: "10.3.0.0/16" (evita conflicto con prod 10.2.0.0/16) +# PROD: "10.2.0.0/16" +# Valor por defecto: "10.3.0.0/16" +vpc_cidr = "10.3.0.0/16" + +# Zonas de disponibilidad +# mx-central-1 actualmente soporta: mx-central-1a, mx-central-1b +# Valor por defecto: ["mx-central-1a", "mx-central-1b"] +availability_zones = ["mx-central-1a", "mx-central-1b"] + +# CIDRs para subnets publicas (una por AZ) +# Deben estar dentro del rango vpc_cidr +# TEST: ["10.3.1.0/24", "10.3.2.0/24"] +# PROD: ["10.2.1.0/24", "10.2.2.0/24"] +# Valor por defecto: ["10.3.1.0/24", "10.3.2.0/24"] +public_subnet_cidrs = ["10.3.1.0/24", "10.3.2.0/24"] + +# CIDRs para subnets privadas (una por AZ) +# RDS y recursos internos se despliegan aqui +# TEST: ["10.3.10.0/24", "10.3.11.0/24"] +# PROD: ["10.2.10.0/24", "10.2.11.0/24"] +# Valor por defecto: ["10.3.10.0/24", "10.3.11.0/24"] +private_subnet_cidrs = ["10.3.10.0/24", "10.3.11.0/24"] + +# ============================================================================= +# SECCION 4: EC2 - SERVIDOR DE APLICACION +# ============================================================================= + +# Tipo de instancia EC2 +# TEST: "t3.small" (costo optimizado) +# PROD: "t3.medium" (instancia actual: 78.13.201.205) +# Valor por defecto: "t3.small" +# NOTA: Para produccion, t3.medium con 4GB RAM minimo recomendado +ec2_instance_type = "t3.small" + +# AMI ID de Ubuntu 22.04 LTS (Jammy) +# Verificar AMI actualizada en: https://cloud-images.ubuntu.com/locator/ec2/ +# Para mx-central-1, buscar "Ubuntu 22.04 LTS amd64" +# Valor por defecto: "ami-0f553e2869648134e" (Ubuntu 22.04 LTS) +# NOTA: La AMI puede variar por cuenta. Verificar en consola AWS. +ec2_ami = "ami-0f553e2869648134e" + +# Tamano del volumen root en GB +# PROD actual: 8GB (7.6G usados 60%) +# Recomendado: 20GB para logs y artefactos +# Valor por defecto: 8 +ec2_root_volume_size = 8 + +# Tipo de volumen root +# Opciones: gp2, gp3, io1, io2 +# Valor por defecto: "gp2" +ec2_root_volume_type = "gp2" + +# Encriptar volumen root +# Valor por defecto: true +# RECOMENDADO: Siempre true en produccion +ec2_root_volume_encrypted = true + +# ============================================================================= +# SECCION 5: ACCESO SSH (CRITICO - SEGURIDAD) +# ============================================================================= + +# Lista de CIDRs permitidos para acceso SSH (puerto 22) +# FORMATO: ["xxx.xxx.xxx.xxx/32"] para IP individual +# ["203.0.113.0/24"] para rango de oficina +# ["10.8.0.0/24"] para VPN +# +# [REQUERIDO] - Debe contener al menos tu IP publica actual +# WARNING: [] vacio permite SOLO acceso desde la VPC (mas seguro pero requiere bastion) +# PROD actual incluye IPs de: Libra-Totalplay, Leaseweb, Empresa +# +# Ejemplo TEST: ["186.96.145.105/32", "187.234.90.175/32"] +# Ejemplo PROD: ["186.96.145.105/32", "207.244.97.190/32", "187.234.90.175/32"] +ssh_allowed_cidrs = [] + +# Llave publica SSH para usuario "thoth" +# Generar par de llaves: ssh-keygen -t ed25519 -f sacc4-thoth-key -C "thoth@ccsoft" +# El usuario thoth se usa para despliegues (UID 1001, grupo duat GID 1006) +# [REQUERIDO] - Copiar contenido de sacc4-thoth-key.pub +thoth_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII/RcJmEYOBpfq1tSLltV1pyNB55l1jA2zYr5ZNJ0f41 thoth@ccsoft" + +# Llave publica SSH para usuario "osiris" +# Generar par de llaves: ssh-keygen -t ed25519 -f sacc4-osiris-key -C "osiris@ccsoft" +# El usuario osiris ejecuta los servicios Java (UID 997, grupo duat GID 1006) +# [REQUERIDO] - Copiar contenido de sacc4-osiris-key.pub +osiris_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFo6CycfgIuCCSVZbhuPwqlAVDxY8YWb1xpvpqxSzMjR osiris@ccsoft" + +# ============================================================================= +# SECCION 6: RDS - BASE DE DATOS +# ============================================================================= + +# Clase de instancia RDS +# TEST: "db.t3.micro" (costo optimizado, eligible free tier) +# PROD: "db.t3.micro" (instancia actual en produccion) +# Valor por defecto: "db.t3.micro" +rds_instance_class = "db.t3.micro" + +# Motor de base de datos +# PROD actual usa: MariaDB 10.6 +# Valor por defecto: "mariadb" +# NOTA: No cambiar a menos que se migre intencionalmente +rds_engine = "mariadb" + +# Version del motor +# PROD actual: 10.6 +# TEST recomendado: 10.11.16 (version compatible mas reciente) +# Valor por defecto: "10.11.16" +rds_engine_version = "10.11.16" + +# Almacenamiento asignado en GB +# Valor por defecto: 20 +# Recomendado: 50GB+ para produccion con crecimiento +rds_allocated_storage = 20 + +# Almacenamiento maximo para auto-scaling +# RDS expande automaticamente hasta este limite +# Valor por defecto: 100 +rds_max_allocated_storage = 100 + +# Nombre de la base de datos inicial +# TEST: "ccsoft_sacc4_test" +# PROD: "ccsoft_sacc4" +# Valor por defecto: "ccsoft_sacc4_test" +rds_db_name = "ccsoft_sacc4_test" + +# Usuario master/administrador de RDS +# TEST: "sacc_admin_test" +# PROD: "sacc_admin_prod" +# Valor por defecto: "sacc_admin_test" +# NOTA: Este usuario NO es el que usa la aplicacion. La app usa un usuario +# adicional creado automaticamente: "sacc_app_user" +rds_master_username = "sacc_admin_test" + +# Contrasena master de RDS +# [REQUERIDO] - MINIMO 16 caracteres, debe incluir: +# - Mayusculas, minusculas, numeros, simbolos +# - No usar caracteres especiales problematicos: @, /, \" +# Ejemplo: "Sacc4_Test_2024!Secure" +# NOTA DE SEGURIDAD: Esta contrasena se usa tambien para el usuario sacc_app_user +rds_master_password = "CambiarEstaPassword123!Segura" + +# Periodo de retencion de backups automaticos (dias) +# TEST: 7 dias (minimo para desarrollo) +# PROD: 30 dias (recomendado para produccion) +# Valor por defecto: 7 +rds_backup_retention_period = 7 + +# Ventana de backup (hora UTC) +# Formato: "hh:mm-hh:mm" +# Valor por defecto: "03:00-04:00" (9pm-10pm CST) +rds_backup_window = "03:00-04:00" + +# Ventana de mantenimiento +# Formato: "Ddd:hh:mm-Ddd:hh:mm" +# Valor por defecto: "Mon:04:00-Mon:05:00" +rds_maintenance_window = "Mon:04:00-Mon:05:00" + +# ============================================================================= +# SECCION 7: SCHEDULING (APAGADO AUTOMATICO - SOLO TEST) +# ============================================================================= + +# Habilitar apagado automatico de EC2 y RDS para ahorrar costos +# RECOMENDADO: true para TEST, false para PROD +# TEST: true (apaga fines de semana) +# PROD: false (siempre encendido) +# Valor por defecto: true +enable_scheduling = true + +# Zona horaria para las reglas de scheduling +# Valor por defecto: "America/Mexico_City" +schedule_timezone = "America/Mexico_City" + +# Cron para INICIO de instancias (hora de Mexico) +# Por defecto: 8:00 AM Lunes-Viernes (13:00 UTC) +# Formato AWS cron: cron(minutes hours day-of-month month day-of-week year) +# Valor por defecto: "cron(0 13 ? * MON-FRI *)" +schedule_start_cron = "cron(0 13 ? * MON-FRI *)" + +# Cron para APAGADO de instancias (hora de Mexico) +# Por defecto: 7:00 PM Lunes-Viernes (00:00 UTC siguiente dia) +# Valor por defecto: "cron(0 0 ? * TUE-SAT *)" +schedule_stop_cron = "cron(0 0 ? * TUE-SAT *)" + +# ============================================================================= +# SECCION 8: FRONTEND (S3 + CloudFront) +# ============================================================================= + +# Nombre del bucket S3 para alojar el frontend React +# DEBE ser unico a nivel global en AWS +# TEST: "sacc4-frontend-test-668889063715" +# PROD: "sacc4-frontend-prod-523761210517" +# [REQUERIDO] - Debe incluir ID de cuenta para garantizar unicidad +# NOTA: Si el bucket ya existe, Terraform fallara. Verificar primero. +frontend_bucket_name = "sacc4-frontend-test-668889063715" + +# Clase de precio de CloudFront +# Opciones: +# "PriceClass_100" - Norteamérica y Europa (mas economico) +# "PriceClass_200" - + Asia y Oceania +# "PriceClass_All" - Global +# Valor por defecto: "PriceClass_100" +cloudfront_price_class = "PriceClass_100" + +# Habilitar logging de CloudFront +# Valor por defecto: false +# Recomendado: true en produccion para debugging +enable_cloudfront_logging = false + +# ============================================================================= +# SECCION 9: CERTIFICADOS SSL (ACM) +# ============================================================================= + +# ARN del certificado SSL en ACM +# [REQUERIDO PARA HTTPS/PROD] +# Para CloudFront, el certificado DEBE estar en us-east-1 (N. Virginia) +# Aunque los recursos esten en mx-central-1 +# +# Como obtener: +# 1. Ir a AWS Console -> Certificate Manager (region us-east-1) +# 2. Solicitar certificado para el domain_name +# 3. Validar via DNS (Route53) o Email +# 4. Copiar el ARN aqui +# +# TEST: "arn:aws:acm:us-east-1:668889063715:certificate/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" +# PROD: "arn:aws:acm:us-east-1:523761210517:certificate/bfb41df2-79f1-40e5-95ad-404d4fe306e4" +# +# NOTA: Dejar vacio "" si aun no se tiene certificado. CloudFront se creara +# con HTTP solo y se actualizara manualmente despues. +certificate_arn = "" + +# ============================================================================= +# SECCION 10: TAGS Y METADATOS +# ============================================================================= + +# Tags comunes aplicados a TODOS los recursos +# Valor por defecto: ver abajo +# NOTA: Se agregan automaticamente tags adicionales por el provider: +# Environment, AccountId, CostCenter +common_tags = { + Project = "proyectosacc" + ManagedBy = "terraform" + Team = "infra" + Purpose = "test-environment" +} + +# ============================================================================= +# SECCION 11: VARIABLES AVANZADAS (opcional - modificar con precaucion) +# ============================================================================= + +# Configuracion de pool de conexiones HikariCP (aplicacion Java) +# Estos valores se inyectan via variables de entorno systemd +# Valores de PROD actual para referencia: +# max_pool_size = 4 +# min_idle = 0 +# idle_timeout = 300000 +# max_lifetime = 1800000 +# connection_timeout = 30000 + +# ============================================================================= +# REFERENCIA RAPIDA: VALORES POR ENTORNO +# ============================================================================= +# TEST PROD +# ------------------------------------------------------------------------- +# Cuenta AWS: 668889063715 523761210517 +# Region: mx-central-1 mx-central-1 +# VPC CIDR: 10.3.0.0/16 10.2.0.0/16 +# Dominio: dev-sacc.ccsoft.mx sacc.ccsoft.mx +# API: api.dev-sacc.ccsoft.mx api.sacc.ccsoft.mx +# EC2: t3.small t3.medium +# RDS: db.t3.micro db.t3.micro +# Scheduling: true (ahorro) false (24/7) +# AMI Ubuntu: ami-0f553e2869648134e ami-0f553e2869648134e +# ------------------------------------------------------------------------- + +# ============================================================================= +# CHECKLIST PRE-DESPLIEGUE +# ============================================================================= +# [ ] Crear/workspac: terraform workspace new test|prod +# [ ] Configurar credenciales AWS para la cuenta correcta +# [ ] Verificar que domain_name existe en Route53 +# [ ] Solicitar certificado SSL en ACM (us-east-1) +# [ ] Generar llaves SSH para thoth y osiris +# [ ] Obtener IP publica actual para ssh_allowed_cidrs +# [ ] Definir contrasena segura para RDS (16+ caracteres) +# [ ] Verificar que frontend_bucket_name es unico globalmente +# [ ] Revisar CIDRs para evitar conflictos de red +# [ ] Ejecutar: terraform plan (revisar sin aplicar) +# ============================================================================= diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..c8f5d98 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,103 @@ +# Variables para duplicación de SACC v4 +# ===================================== + +# Entorno +variable "environment" { + description = "Entorno de despliegue (test, dev, staging)" + type = string + default = "test" +} + +# Región AWS +variable "aws_region" { + description = "Región AWS para despliegue" + type = string + default = "mx-central-1" +} + +# VPC +variable "vpc_cidr" { + description = "CIDR block para la VPC" + type = string + default = "10.3.0.0/16" +} + +variable "availability_zones" { + description = "Zonas de disponibilidad" + type = list(string) + default = ["mx-central-1a", "mx-central-1b"] +} + +# EC2 +variable "ami_id" { + description = "AMI de Ubuntu 22.04 LTS" + type = string + default = "ami-0f553e2869648134e" +} + +variable "instance_type" { + description = "Tipo de instancia EC2" + type = string + default = "t3.small" +} + +variable "key_name" { + description = "Nombre del key pair SSH" + type = string + default = "sacc4-test-key" +} + +variable "my_ip" { + description = "Tu IP pública para acceso SSH (formato: xxx.xxx.xxx.xxx/32)" + type = string +} + +# RDS +variable "db_name" { + description = "Nombre de la base de datos" + type = string + default = "sacc4_test" +} + +variable "db_username" { + description = "Usuario administrador de la base de datos" + type = string + default = "sacc4_admin" +} + +variable "db_password" { + description = "Contraseña de la base de datos (cambiar!)" + type = string + sensitive = true +} + +variable "rds_instance_class" { + description = "Clase de instancia RDS" + type = string + default = "db.t3.micro" +} + +variable "rds_allocated_storage" { + description = "Almacenamiento RDS en GB" + type = number + default = 20 +} + +# S3 / CloudFront +variable "s3_bucket_name" { + description = "Nombre único del bucket S3 para frontend" + type = string + default = "sacc4-frontend-test-ccsoft" +} + +variable "domain_name" { + description = "Dominio para la aplicación" + type = string + default = "test-sacc.ccsoft.mx" +} + +variable "certificate_arn" { + description = "ARN del certificado SSL en ACM" + type = string + default = "" +} \ No newline at end of file