OpenTofu (Infraestructura como Código)
GenericSuite trae una implementación de [OpenTofu] (compatible con Terraform) de cada implementación de AWS que anteriormente se realizaba con plantillas de CloudFormation y llamadas de AWS CLI en crudo. Proporciona a los equipos de DevOps, seguridad e infraestructura una única cadena de herramientas de Infraestructura como Código (IaC), con estado remoto, detección de deriva y planes revisables.
La ruta de OpenTofu convive junto a los scripts existentes — las plantillas de CloudFormation y los scripts de despliegue CLI no se eliminan ni se modifican. Puede adoptar la pila OpenTofu pila por pila, y ejecutar ambos enfoques en la misma cuenta de AWS.
- Pila de Frontend:
genericsuite-fe-scripts/scripts/aws_tf/ - Pila de Backend:
genericsuite-be-scripts/scripts/aws_tf/
Por qué OpenTofu
- Una cadena de herramientas para todos los equipos. El mismo flujo de trabajo de
plan/applycubre hosting del frontend, cómputo del backend, bases de datos, secretos y DNS. - Cambios revisables.
tofu planmuestra exactamente qué cambiará antes de que se aplique algo — ya no hay flujos de recuperación de “eliminar la pila y reintentar”. - Estado remoto y bloqueado. El estado se almacena en S3 con bloqueo nativo, de modo que todo el equipo comparte una única fuente de verdad.
- Fortalecimiento de la seguridad. La conversión aprovechó la oportunidad para corregir problemas antiguos (véase Mejoras de seguridad).
Coexistencia con CloudFormation
Los nombres de recursos coinciden con las convenciones actuales ({app}-{stage}-secrets, {app}_{stage}_{table}, {lambda}-{stage}, genericsuite-key, etc.), por lo que los recursos de OpenTofu son reconocibles junto a los heredados. Las pilas de CloudFormation existentes quedan intactas.
Para pilas cuyos nombres de recurso son globalmente únicos o únicos por cuenta (el ALB de la pila EC2 + ALB, Auto Scaling Group, target group y launch template; el alias de KMS alias/genericsuite-key), OpenTofu y una pila de CloudFormation aún viva con el mismo nombre no pueden poseer el recurso al mismo tiempo. Elimina primero la pila de CloudFormation, o importa el recurso existente al estado de OpenTofu (ver Notas de migración). Las pilas que crean recursos netos nuevos (secretos, tablas de DynamoDB, repositorios ECR, el bucket S3 del chatbot) coexisten sin conflicto.
Requisitos previos
- OpenTofu ≥ 1.10 — requerido para el bloqueo de estado nativo de S3.
bash brew install opentofu # macOS tofu version # confirmar >= 1.10 - AWS CLI configurado con credenciales para la cuenta objetivo (
aws sts get-caller-identity). jq(utilizado por el constructor de variables de secretos).- Una aplicación consumidora con un archivo
.envpor etapa (el mismo.envque leen los scripts heredados). Ejecute el wrapper desde el directorio raíz de la aplicación.
Gestión del estado
Cada aplicación tiene su propio bucket de estado:
- Bucket:
{app_name_lowercase}-tf-state-{aws_account_id} - Key:
{stage}/{stack}.tfstate(p. ej.dev/frontend.tfstate,prod/dynamodb.tfstate) - Versionado, cifrado SSE, todo acceso público bloqueado y bloqueo mediante bloqueo nativo de S3 (
use_lockfile— no es necesario una tabla de bloqueo de DynamoDB).
El bucket se crea automáticamente la primera vez que ejecuta el wrapper (llama a bootstrap-tf-state.sh antes de tofu init). Nunca edita la configuración del backend a mano — el wrapper la inyecta mediante tofu init -backend-config=....
Despliegues de backend
Todas las pilas de backend se gestionan con un único wrapper:
bash node_modules/genericsuite-be-scripts/scripts/aws_tf/run-tf-deployment.sh ACTION STAGE STACK
- ACCIÓN:
init|validate|plan|apply|destroy|output - ETAPA:
dev|qa|staging|demo|prod - PILE: una de
kms,secrets,s3,dynamodb,ecr,domain,ec2,lambda
Establezca CICD_MODE=1 para ejecuciones no interactivas (agrega -auto-approve en apply/destroy).
Pilas
| Pila | Reemplaza | Crea |
|---|---|---|
kms |
cf-template-kms-key.yml |
Clave KMS + alias/genericsuite-key + roles IAM key-admin/use/attach/ASG |
secrets |
aws_secrets_manager.sh + cf-template-secrets.yml |
{app}-{stage}-secrets (KMS-encriptado) y {app}-{stage}-envs |
s3 |
create_s3_bucket.sh / create_chatbot_s3_bucket.sh |
Bucket de adjuntos del chatbot S3 (privado) + política |
dynamodb |
run-dynamodb-deploy.sh |
Tablas DynamoDB desde la configuración JSON (PAY_PER_REQUEST, PITR) |
ecr |
run-fastapi-ecr-creation.sh / clean_ecr_images.sh |
Repositorios ECR de Lambda + EC2 con escaneo on-push y retención |
domain |
cf-template-ec2-domain.yml |
Certificado ACM con validación DNS nativa + registros de Route53 |
ec2 |
cf-template-ec2-elb.yml |
VPC, subredes, IAM, grupos de seguridad, plantilla de lanzamiento, ASG, ALB, escuchador HTTPS, alias de Route53 |
lambda |
template-sam.yml (SAM) |
Lambda (contenedor o zip) + API Gateway REST API + dominio personalizado opcional |
Variables .env requeridas
Comunes (todas las pilas de backend): APP_NAME, AWS_REGION, CLOUD_PROVIDER=aws, y opcionalmente AWS_ACCOUNT_ID (detección automática vía STS si no se establece) y KMS_KEY_ALIAS (predeterminado a genericsuite-key).
Por pila, adicionalmente:
- secrets — el secreto central/AI/app y variables de entorno (las mismas listas que
aws_secrets_manager.sh), ademásAPP_DOMAIN_NAME. Los valores de secreto viajan solo como variables de entorno sensiblesTF_VAR_*— nunca se escriben en archivos.tfvarsen disco. - s3 —
AWS_S3_CHATBOT_ATTACHMENTS_BUCKET_{STAGE}. - dynamodb —
GIT_SUBMODULE_LOCAL_PATH(el directorio de configuración JSON; sus archivosfrontend/, fusionados conbackend/, definen las tablas). - ecr / ec2 / lambda —
AWS_LAMBDA_FUNCTION_NAME(el nombre base del recurso), yECR_DOCKER_IMAGE_TAGpara la imagen a desplegar. La pilaec2lee adicionalmente las salidas de la piladomain(ARN del certificado, zona hospedada) vía estado remoto; la pilalambdausa la URL por defectoexecute-apia menos que des un dominio personalizado y certificado explícitamente.
Orden recomendado de aplicación
BE=node_modules/genericsuite-be-scripts/scripts/aws_tf/run-tf-deployment.sh
CICD_MODE=1 bash $BE apply qa kms # una vez por cuenta (omitir si existe alias/genericsuite-key)
CICD_MODE=1 bash $BE apply qa secrets
CICD_MODE=1 bash $BE apply qa s3
CICD_MODE=1 bash $BE apply qa dynamodb
CICD_MODE=1 bash $BE apply qa ecr
CICD_MODE=1 bash $BE apply qa domain # ruta EC2/ALB
CICD_MODE=1 bash $BE apply qa ec2 # o: aplicar qa lambda
secrets lee la clave KMS existente por alias, así que si alias/genericsuite-key ya existe en la cuenta puedes ejecutar kms en modo plan solamente y mantener la clave existente. La construcción de imágenes Docker y el push a ECR permanecen en los scripts bash existentes (eso es empaquetado de la aplicación, no infraestructura); dirígelos al output del repositorio de la pila ecr.
Recuperación de salidas
bash $BE output qa lambda # endpoint_url, function_arn, custom_domain_url
bash $BE output qa ec2 # load_balancer_dns_name, app_url
Despliegues de Frontend
El frontend tiene su propio wrapper más un pipeline de despliegue completo:
# Infraestructura solamente (S3 + CloudFront):
bash node_modules/genericsuite-fe-scripts/scripts/aws_tf/run-tf-deployment.sh apply STAGE frontend
# Pipeline completo (infra + build + upload + invalidación de caché):
bash node_modules/genericsuite-fe-scripts/scripts/aws_tf/aws_tf_deploy_to_s3.sh STAGE [VARIABLE_TYPE]
aws_tf_deploy_to_s3.sh es la contraparte de OpenTofu del legado aws_deploy_to_s3.sh (que permanece en su lugar). Aplica la pila frontend, lee el bucket y la distribución de sus salidas, compila la aplicación con el empaquetador configurado (vite, webpack, o react-app-rewired), ejecuta aws s3 sync e invalida la caché de CloudFront.
Variables .env requeridas: AWS_S3_BUCKET_NAME_{TYPE} (se sustituye un token [STAGE]), APP_{TYPE}_URL, AWS_REGION, y opcionalmente AWS_SSL_CERTIFICATE_ARN[_{TYPE}] (TYPE por defecto es FE). Si no se proporciona un ARN de certificado y la URL de la aplicación está establecida, la pila busca el certificado en us-east-1 por dominio.
Qué cambió respecto al script frontend heredado
- Control de Acceso de Origen (OAC) en lugar de la obsoleta Identidad de Acceso de Origen (OAI); el bucket S3 es totalmente privado (todas las banderas de bloqueo de acceso público activadas), servido solo a través de CloudFront.
ViewerProtocolPolicyahora es redirect-to-https, y la versión mínima de TLS es TLSv1.2_2021.- Ruteo de SPA — las respuestas 403/404 de S3 se mapean a
/index.html(200). - Ya no hay permisos ACL públicos para buckets;
aws s3 syncse ejecuta sin banderas ACL.
Mejoras de seguridad
La conversión endureció varias áreas en relación con los originales de CloudFormation/CLI:
- CloudFront usa OAC con un bucket privado (sin OAI, sin ACLs públicas); TLS mínimo elevado a TLSv1.2_2021; HTTP redirige a HTTPS.
- Los secretos se pasan como variables sensibles de OpenTofu y se almacenan en Secrets Manager — nunca como parámetros de pila de CloudFormation (que son visibles en la consola y CloudTrail).
- Las políticas de IAM están restringidas — por ejemplo,
secretsmanager:GetSecretValuese limita a los dos ARNs de secretos de la aplicación en lugar de*. - Validación DNS nativa de ACM reemplaza a los dos recursos personalizados respaldados por Lambda y al registro A de marcador de posición en la antigua plantilla de dominio de EC2.
- La AMI de EC2 se resuelve a partir del parámetro público SSM de Amazon Linux 2 en lugar de un ID de AMI codificado duro y propenso a la deprecación; ambas subredes de ALB están asociadas a la tabla de enrutamiento; la entrada SSH se abre solo cuando se proporciona un CIDR explícitamente.
Notas de migración
- Ejecuta ambas rutas lado a lado. Debido a que los nombres de recursos coinciden, puedes validar las pilas de OpenTofu con
plancontra un entorno activo antes de la migración total. - Importación de recursos existentes. Para recursos únicos por cuenta que quieras que OpenTofu gestione sin recrearlos, impórtalos al estado, por ejemplo:
bash cd node_modules/genericsuite-be-scripts/scripts/aws_tf/stacks/secrets tofu import module.secrets.aws_secretsmanager_secret.encrypted \ arn:aws:secretsmanager:us-east-1:ACCOUNT:secret:myapp-qa-secrets - Alias de KMS. Si
alias/genericsuite-keyya existe (por una implementación previa de CloudFormation), conservalo: ejecuta la pilakmssolo conplan, y las pilassecrets/ec2/lambdaharán referencia a la clave existente por alias. - Corte EC2/ALB. Elimina la pila legada de CloudFormation EC2 (o importa su ALB/ASG/grupo objetivo/plantilla de lanzamiento) antes de aplicar la pila
ec2, ya que esos nombres son únicos por cuenta.
Aún no cubierto
Estas implementaciones no forman parte aún de la ruta OpenTofu y permanecen en sus herramientas existentes:
- RDS (PostgreSQL / MySQL) —
genericsuite-be-scripts/scripts/sql_db/run_sql_db_deploy.sh. - Despliegues Chalice-nativos —
genericsuite-be-scripts/scripts/aws/run_aws.sh. - Pruebas LocalStack para las pilas OpenTofu (el modo LocalStack del procesador de CloudFormation no ha cambiado).