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
This commit is contained in:
Jenkins CI
2026-06-03 04:39:01 +00:00
commit 71be2abd2e
27 changed files with 6424 additions and 0 deletions
+525
View File
@@ -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 <LOCK_ID>
```
### 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*
Vendored
+395
View File
@@ -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 <<EOF
environment = "test"
aws_region = "us-east-1"
vpc_cidr = "10.3.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b"]
ami_id = "ami-test-sacc4"
instance_type = "t3.small"
key_name = "sacc4-test-key"
my_ip = "0.0.0.0/0"
db_name = "sacc4_test"
db_username = "sacc4_admin"
db_password = "TestPassword123!"
rds_instance_class = "db.t3.micro"
rds_allocated_storage = 20
s3_bucket_name = "sacc4-frontend-test-ccsoft"
domain_name = "test-sacc.ccsoft.mx"
certificate_arn = ""
EOF
echo "[INFO] Ejecutando terraform plan..."
terraform plan -out=tfplan -var-file=terraform.tfvars
echo "[OK] Terraform plan completado"
echo "[INFO] Revisa el plan anterior"
"""
}
}
stage('06_terraform_apply') {
steps {
echo "${BLUE}========================================${NC}"
echo "${BLUE}PASO 6: Terraform Apply${NC}"
echo "${BLUE}========================================${NC}"
sh """
cd ${TERRAFORM_DIR}
echo "[INFO] Aplicando infraestructura..."
terraform apply -auto-approve tfplan
echo "[OK] Terraform apply completado"
"""
}
}
stage('07_generate_inventory') {
steps {
echo "${BLUE}========================================${NC}"
echo "${BLUE}PASO 7: Generando inventario Ansible${NC}"
echo "${BLUE}========================================${NC}"
sh """
cd ${TERRAFORM_DIR}
echo "[INFO] Obteniendo outputs de Terraform..."
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] 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 <<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
echo "[OK] Inventario generado:"
cat ${ANSIBLE_DIR}/inventory/test.ini
"""
}
}
stage('08_run_ansible') {
steps {
echo "${BLUE}========================================${NC}"
echo "${BLUE}PASO 8: Configurando servidor (Ansible)${NC}"
echo "${BLUE}========================================${NC}"
sh """
echo "[INFO] Instalando Ansible..."
apk add --no-cache ansible openssh-client 2>/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}"
}
}
}
+199
View File
@@ -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"
}
}
}
+919
View File
@@ -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 <LOCK_ID>
```
⚠️ **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*
+90
View File
@@ -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
+175
View File
@@ -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
+27
View File
@@ -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
+152
View File
@@ -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
+277
View File
@@ -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: &notify
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"
+396
View File
@@ -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**
+488
View File
@@ -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 "$@"
+483
View File
@@ -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 "$@"
+533
View File
@@ -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 "$@"
+38
View File
@@ -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"
}
}
@@ -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"
+339
View File
@@ -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
}
@@ -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"
}
+222
View File
@@ -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"
}
}
+205
View File
@@ -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
}
+42
View File
@@ -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 }
+54
View File
@@ -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
}
+48
View File
@@ -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 }
+80
View File
@@ -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 }
+51
View File
@@ -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 }
+98
View File
@@ -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..."
+355
View File
@@ -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)
# =============================================================================
+103
View File
@@ -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 = ""
}