Seguridad en AWS CloudFormation: mejores prácticas
Una guía práctica de seguridad en CloudFormation: manejo de secretos, mínimo privilegio de IAM, defaults inseguros, drift, stack policies y scanning en CI.
AWS CloudFormation convierte tu infraestructura en templates declarativos, y precisamente por eso la seguridad en CloudFormation merece el mismo rigor que aplicas al código de la aplicación. Un template es un plano de recursos reales —roles de IAM, buckets S3, security groups, bases de datos— y cualquier debilidad incorporada en ese plano se reproduce fielmente cada vez que el stack se despliega, en cada cuenta y región a la que lo distribuyes. La buena noticia es que la misma propiedad "as code" que permite que una configuración errónea se propague también te permite revisarla, probarla y bloquearla automáticamente. Este artículo es una inmersión práctica y específica de CloudFormation en las mejores prácticas de seguridad de AWS CloudFormation que evitan que tus templates se conviertan en una fuente repetible de riesgo. Forma parte de nuestro pilar más amplio de seguridad de Infrastructure as Code, así que si quieres el panorama estratégico entre herramientas, comienza por ahí y regresa por los detalles específicos de CloudFormation.
Un breve encuadre antes de los detalles. CloudFormation no es seguro por defecto en el sentido que la gente suele suponer: creará con gusto un recurso totalmente abierto si eso es lo que describe tu template. Su trabajo es hacer real el estado deseado, no juzgar si ese estado es seguro. Por lo tanto, la seguridad vive en dos lugares: en los templates que escribes y en el pipeline que convierte esos templates en stacks desplegados. Si aciertas en ambos, obtienes templates de CloudFormation seguros que se mantienen seguros a medida que evolucionan.
Mantén los secretos fuera de tus templates
El error más común y más dañino en CloudFormation es poner secretos directamente en un template. Una contraseña de base de datos, una clave de API o un token escrito como cadena literal queda ahora comiteado en el control de versiones, copiado en cada evento del stack y visible para cualquiera con acceso de lectura al template o al stack. Rotarlo después significa editar y volver a desplegar, y el valor antiguo permanece para siempre en el historial de git.
La solución es referenciar los secretos en lugar de incrustarlos. CloudFormation admite dynamic references que resuelven valores en el momento del despliegue desde AWS Secrets Manager o SSM Parameter Store, de modo que el secreto nunca aparece en el propio template:
Resources:
Database:
Type: AWS::RDS::DBInstance
Properties:
Engine: postgres
MasterUsername: admin
MasterUserPassword: '{{resolve:secretsmanager:prod/db:SecretString:password}}'
Para valores que se pasan en el momento del despliegue, declara el parámetro con NoEcho: true para que quede enmascarado en la consola, la CLI y las respuestas de la API:
Parameters:
DbPassword:
Type: String
NoEcho: true
Description: Injected at deploy time; never stored in the template.
NoEcho es una mejora genuina, pero trátalo como una capa, no como una garantía. Los secretos aún pueden filtrarse por varios canales laterales: un parámetro NoEcho aparece en texto plano si lo referencias en una sección Outputs, los valores pueden aparecer en eventos del stack y change sets, y todo lo que imprimas en la Lambda de un custom resource puede terminar en los logs de CloudWatch. Así que la regla es más amplia que "usa NoEcho": nunca coloques un secreto en un output, ten cuidado con lo que registran los custom resources y prefiere resolver los secretos en tiempo de ejecución desde un store gestionado antes que pasarlos a través del stack.
Aplica el mínimo privilegio de IAM
CloudFormation e IAM se cruzan de dos maneras, y ambas importan. Primero, los roles, policies y usuarios de IAM que tu template crea deben seguir el mínimo privilegio: otorga solo las acciones y recursos que una carga de trabajo realmente necesita, acota los ARN de los recursos en lugar de usar "Resource": "*" y resiste la comodidad de Action: "*" o de wildcards amplios a nivel de servicio como s3:*. Un rol que tu stack provisiona con permisos equivalentes a admin es un riesgo permanente durante toda la vida del stack.
Segundo, está la identidad que el propio CloudFormation usa. Por defecto, el servicio actúa con los permisos de quien lo invoca, pero puedes y en general deberías adjuntar una service role dedicada a un stack, para que sus acciones queden acotadas y sean auditables con independencia de quién ejecute el despliegue. Cuando un template crea o modifica recursos de IAM, CloudFormation exige que lo reconozcas explícitamente con CAPABILITY_IAM, o con CAPABILITY_NAMED_IAM cuando esos recursos tienen nombres personalizados. Ese reconocimiento existe precisamente porque los cambios de IAM son sensibles: trata su concesión como un punto de revisión deliberado, no como una casilla que marcas para hacer desaparecer un error. Un pull request que de repente necesita CAPABILITY_NAMED_IAM es una señal para observar de cerca qué permisos se están creando.
Detecta los defaults inseguros de los recursos
La mayor parte del riesgo real en CloudFormation no es exótica: son recursos comunes desplegados con configuraciones permisivas o sin cifrado. Algunos infractores recurrentes:
- Buckets S3 públicos y bucket policies — buckets dejados legibles para todo el mundo, o policies con un
Principaligual a"*", son una fuente perenne de exposición de datos. ConfiguraPublicAccessBlockConfigurationy mantén acotadas las bucket policies. - Security groups abiertos — una regla de ingress que permite
0.0.0.0/0en el puerto 22 o 3389 expone SSH o RDP a toda la internet. - Almacenamiento sin cifrado — buckets S3, volúmenes EBS e instancias RDS sin cifrado en reposo, o recursos que omiten el cifrado en tránsito.
- Bases de datos accesibles públicamente — una instancia RDS con
PubliclyAccessible: trueubicada en una subred pública.
Así se ve un security group sobreexpuesto en un template: exactamente el tipo de cosa que el análisis estático debería señalar antes siquiera de desplegar:
SshFromAnywhere:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Bad idea
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0 # exposes SSH to the whole internet
Estas son propiedades declarativas, lo que significa que una herramienta de análisis estático puede leer el template y decirte que el recurso está mal configurado antes de que se realice una sola llamada a la API. Ese es el hábito de mayor apalancamiento en la seguridad de CloudFormation: haz scan del template, no solo de la cuenta en ejecución.
Protege los stacks desplegados: policies, protección contra terminación y drift
La seguridad no termina en el despliegue. Una vez que un stack está activo, tres funciones de CloudFormation ayudan a mantenerlo confiable.
Las stack policies protegen los recursos críticos de actualizaciones o reemplazos accidentales durante una actualización de stack. Adjuntar una policy que deniegue actualizaciones a, por ejemplo, una base de datos de producción evita que un cambio descuidado en el template la reemplace y destruya datos.
La protección contra terminación impide que un stack se elimine —ya sea por accidente o por un atacante con permisos sobre el stack— hasta que la protección se desactive explícitamente. Actívala en cualquier stack cuya eliminación resultaría disruptiva.
El drift detection te avisa cuando los recursos reales se han desviado de lo que declara el template. El drift suele significar que alguien hizo un cambio directamente en la consola o la CLI, saltándose tu pipeline revisado. Eso es a la vez un riesgo operativo y de seguridad: un security group abierto a mano, o una configuración de cifrado deshabilitada en silencio, no aparecerá en tus templates. Ejecuta el drift detection con una cadencia regular e investiga todo lo que regrese con drift, porque tus templates solo son una fuente de verdad si la realidad de hecho coincide con ellos.
Confía en la cadena de suministro de tus templates
Los templates rara vez viven solos. Los nested stacks, los módulos de CloudFormation y los templates compartidos que se obtienen desde S3 o un registry traen código que no necesariamente escribiste. Cada uno de ellos es una dependencia de la cadena de suministro, y la misma cautela que aplicas a las bibliotecas de terceros aplica aquí:
- Obtén los nested stacks y módulos desde repositorios y buckets que controlas y en los que confías, no desde URL públicas arbitrarias.
- Fija versiones en lugar de siempre tomar la "latest", para que un cambio upstream no pueda alterar en silencio lo que despliegas.
- Revisa los templates compartidos antes de adoptarlos y vuelve a hacerles scan como parte de tu propio pipeline, en lugar de suponer que un autor upstream ya lo hizo.
Una configuración errónea heredada de un nested stack es tan real como una que escribiste tú mismo, así que trae los templates importados dentro de tu límite de scanning y revisión.
Coloca barreras de protección en el pipeline
Todo lo anterior solo se vuelve sostenible cuando se automatiza. La revisión manual detecta algunos problemas, pero la manera confiable de exigir templates de CloudFormation seguros es hacer que tu pipeline lo haga en cada cambio.
Comienza con linting y policy-as-code. cfn-lint valida la estructura del template, las propiedades de los recursos y las intrinsic functions, capturando clases enteras de errores antes del despliegue. AWS CloudFormation Guard te permite expresar reglas organizacionales como policy —"todo bucket S3 debe bloquear el acceso público", "ningún security group puede permitir 0.0.0.0/0 en el puerto 22"— y evaluar los templates frente a ellas automáticamente. Ejecutar esto en la integración continua significa que una violación de regla aparece como una verificación fallida en el pull request, donde es una edición rápida, en lugar de como un incidente semanas después.
Luego agrega el scanning de seguridad de los propios templates. Haz scan de cada template en busca de configuraciones erróneas —los defaults inseguros descritos arriba y más— y haz que el pipeline falle ante hallazgos de alta severidad, para que un bucket abierto o una policy de IAM demasiado amplia no puedan hacer merge en silencio. Bloquea los despliegues según estas verificaciones de la misma forma en que los bloqueas según las pruebas que pasan. El objetivo es simple: la seguridad viaja con el cambio, automáticamente, de modo que el camino seguro sea también el camino de menor resistencia para tus desarrolladores.
Cómo ayuda Rainforest
Hacer todo esto a mano en muchos templates, stacks y cuentas no escala. Rainforest lleva la seguridad de CloudFormation a tu flujo de desarrollo normal con scanning de infrastructure-as-code que lee tus templates y señala configuraciones erróneas —almacenamiento público, security groups abiertos, ausencia de cifrado, IAM con privilegios excesivos, secretos en hardcode— antes de que se envíen. Los hallazgos aparecen directamente en los pull requests y la CI, priorizados por severidad, para que tu equipo corrija los problemas en el origen en lugar de descubrirlos en una cuenta activa. Como la misma plataforma también cubre el código de tu aplicación y las dependencias, obtienes una vista consistente del riesgo en toda la stack, en lugar de coser herramientas desconectadas. Y como CloudFormation es apenas uno de varios formatos de IaC que usan los equipos, hacerle scan junto con tus otros templates mantiene uniformes tus estándares sin importar cómo se defina una determinada pieza de infraestructura.
Si quieres verla en acción con tus propios templates, conoce nuestra herramienta de seguridad de IaC, explora la plataforma de application security testing más amplia o agenda una demostración.
Preguntas frecuentes
¿CloudFormation es seguro por defecto?
No de la manera que la gente suele esperar. CloudFormation despliega de forma confiable todo lo que describe tu template, pero no juzga si esa descripción es segura: si tu template define un bucket S3 público o un security group abierto a la internet, creará exactamente eso. AWS protege el servicio CloudFormation en sí; la seguridad de lo que despliegas es tu responsabilidad. Por eso hacer scan de los templates y aplicar barreras de protección en el pipeline importa tanto.
¿Cómo manejo los secretos en CloudFormation?
Nunca los pongas en hardcode. Usa dynamic references ({{resolve:secretsmanager:...}} o {{resolve:ssm-secure:...}}) para que los valores se tomen de AWS Secrets Manager o SSM Parameter Store en el momento del despliegue y nunca queden almacenados en el template. Marca cualquier parámetro sensible con NoEcho: true para enmascararlo. Recuerda los caminos de filtración que NoEcho no cierra: mantén los secretos fuera de los outputs del stack, vigila lo que las Lambdas de custom resources escriben en los logs y ten presente que los valores pueden aparecer en los eventos del stack. Prefiere resolver los secretos en tiempo de ejecución antes que pasarlos a través del stack.
¿Cómo aplico el mínimo privilegio en CloudFormation?
Acota los recursos de IAM que crean tus templates —otorga acciones específicas sobre ARN de recursos específicos en lugar de wildcards "*"— y dale a CloudFormation una service role dedicada y bien acotada, en lugar de desplegar con permisos amplios de quien lo invoca. Trata CAPABILITY_IAM y CAPABILITY_NAMED_IAM como puntos de revisión deliberados, ya que señalan que un cambio crea o modifica permisos. Revisar y hacer scan de los cambios de IAM en cada pull request evita que el privilege creep se acumule.
¿Cómo hago scan de los templates de CloudFormation en busca de configuraciones erróneas?
Ejecuta análisis estático en los templates antes de que se desplieguen. Usa cfn-lint para la validación estructural y de propiedades, CloudFormation Guard para reglas de policy-as-code y un scanner de seguridad de IaC para detectar defaults inseguros como buckets públicos, security groups abiertos, almacenamiento sin cifrado e IAM demasiado amplio. Conéctalos a la CI y haz que el build falle ante hallazgos de alta severidad, para que los problemas se corrijan en el pull request en lugar de en una cuenta activa.
¿Qué es el drift detection?
El drift detection es una función de CloudFormation que compara la configuración real de los recursos de un stack con lo que declara el template. Cuando difieren —normalmente porque alguien cambió un recurso directamente en la consola o la CLI— el recurso se reporta como drifted. Eso importa para la seguridad porque los cambios fuera de banda, como un security group abierto a mano o el cifrado apagado, se saltan tu pipeline revisado y son invisibles en tus templates. Ejecutar el drift detection con regularidad mantiene tus templates como una verdadera fuente de verdad.

Escrito por
Bruno Baldo
CMO
Um pouco de marketing e um pouco de curiosidade e temos a receita pra criar um apaixonado por cyber!

Seguridad de Infrastructure as Code (IaC): la guía completa
Seguridad de IaC explicada: el modelo de amenazas, el scanning a lo largo del SDLC, policy as code, secrets y state y un flujo práctico de remediación.

Seguridad en Terraform: Mejores Prácticas para una Infraestructura Segura
Mejores prácticas de seguridad en Terraform para state, secretos, IAM, módulos y CI para que tu infraestructura como código llegue a producción de forma segura.

Seguridad en Kubernetes: la guía completa
Guía completa de seguridad en Kubernetes: el modelo de las 4C, superficie de ataque, RBAC, pods, network policies, secrets, cadena de suministro y shift-left.
