Saltar al contenido
aprendeaws.dev

Módulo 10 · Operación y automatización/Lección 65

Infraestructura como código a escala

StackSets para varias cuentas y regiones, Hooks y políticas como código para impedir lo indebido antes de desplegarlo.

⏱ 12 min

Al terminar podrás

  • →Desplegar en muchas cuentas y regiones con StackSets
  • →Validar antes de desplegar con CloudFormation Hooks y Guard
  • →Corregir desvíos con políticas como código

Con una cuenta, un stack de CloudFormation basta. Con cuarenta cuentas en tres regiones, el problema cambia: necesitas el mismo rol de auditoría, el mismo trail y las mismas alarmas en las 120 combinaciones, y necesitas que nadie despliegue un bucket público o una base de datos sin cifrar, aunque tenga permisos para hacerlo.

Las bases de infraestructura como código siguen igual. Lo nuevo es cómo repartir plantillas a muchas cuentas y cómo poner controles antes, durante y después de cada despliegue.

StackSets: una plantilla, muchas cuentas y regiones

Un StackSet es un contenedor de stacks creados desde la misma plantilla en varias cuentas y regiones. Cada stack concreto (cuenta + región) es una instancia de stack. Cambias la plantilla una vez y el cambio llega a todas las instancias. Hay dos modelos de permisos:

CriterioSelf-managedService-managed
RolesTú creas el rol de administración y un rol de ejecución en cada cuenta destinoStackSets crea los roles por ti
DestinosCualquier cuenta donde puedas crear esos roles, incluso fuera de tu organizaciónCuentas y unidades organizativas (OU) de AWS Organizations
Cuentas nuevasLas agregas túDespliegue automático al entrar a la OU; opcionalmente borra o conserva el stack si la cuenta sale
Quién lo administraLa cuenta donde creas el StackSetLa cuenta de administración o una cuenta de administrador delegado

Los destinos de despliegue se definen por OU, por lista de cuentas o con un filtro que combina ambos (por ejemplo, «toda la OU Workloads menos esta cuenta»). Al crear o actualizar eliges cómo avanza la operación:

  • Máximo de cuentas concurrentes: cuántas cuentas a la vez, en número o porcentaje.
  • Tolerancia a fallos: cuántos stacks pueden fallar por región antes de detener la operación.
  • Concurrencia de regiones: secuencial (por defecto, en el orden que indiques) o en paralelo.
  • Modo de concurrencia: estricto, donde la concurrencia baja si aparecen fallos, o flexible, donde se mantiene mientras no se supere la tolerancia.

Validar antes de desplegar: Hooks y Guard

Un CloudFormation Hook es código que corre justo antes de que CloudFormation cree, actualice o borre algo. Si encuentra una configuración que incumple tus reglas, hace una de dos cosas según su modo: FAIL detiene la operación; WARN deja seguir con una advertencia. Lo normal es activarlo primero en WARN, ver qué rompería y luego pasarlo a FAIL. Puede evaluar cuatro objetivos:

ObjetivoQué revisa
RESOURCECada recurso antes de crearlo, cambiarlo o borrarloCon sus propiedades ya resueltas
STACKLa plantilla completa de la operación de stack
CHANGE_SETEl conjunto de cambios cuando se creaPuedes frenarlo antes de ejecutarlo
CLOUD_CONTROLRecursos creados con la API de Cloud ControlPor ejemplo, desde herramientas que usan esa API

La lógica del Hook se escribe de cuatro formas: activando controles proactivos de AWS Control Tower (ya escritos), con reglas de Guard, con una función Lambda o como Hook propio con la CloudFormation CLI.

AWS CloudFormation Guard es un lenguaje de políticas como código, abierto, para validar datos estructurados. Esta regla exige versionado y bloqueo de acceso público en cada bucket:

# reglas/s3.guard
let buckets = Resources.*[ Type == 'AWS::S3::Bucket' ]

rule s3_versionado when %buckets !empty {
  %buckets.Properties.VersioningConfiguration.Status == 'Enabled'
  <<
    Violación: el bucket debe tener versionado.
    Arreglo: agrega VersioningConfiguration con Status: Enabled.
  >>
}

rule s3_sin_acceso_publico when %buckets !empty {
  %buckets.Properties.PublicAccessBlockConfiguration exists
  %buckets.Properties.PublicAccessBlockConfiguration.BlockPublicAcls == true
  %buckets.Properties.PublicAccessBlockConfiguration.RestrictPublicBuckets == true
}

La misma regla corre en el pipeline, contra la plantilla, antes de que exista un stack:

cfn-guard validate --data plantilla.yaml --rules reglas/s3.guard

Si usas CDK, los Aspects recorren todos los constructos del árbol antes de sintetizar y pueden agregar errores o advertencias. El proyecto abierto cdk-nag usa Aspects para aplicar paquetes de reglas de seguridad.

Detectar y corregir lo que ya existe

Lo preventivo no cubre todo: recursos creados antes de la regla, cambios manuales, servicios que no pasan por CloudFormation. Ahí entran los controles detectivos de AWS Config:

  • Reglas de Config: evalúan la configuración real y marcan cada recurso como COMPLIANT o NON_COMPLIANT. Algunas reglas administradas también tienen modo proactivo, pero ese modo solo informa: no bloquea ni corrige.
  • Paquetes de conformidad (conformance packs): un conjunto de reglas y acciones de remediación que despliegas como una unidad, en una cuenta o en toda la organización.
  • Remediación: cada regla puede asociarse a un documento de Systems Manager Automation que corrige el recurso, de forma manual o automática.
  • Detección de drift: compara stacks e instancias de StackSets con la realidad y te dice qué se cambió a mano.
  1. 1

    En el pull request

    El pipeline corre cfn-guard o cdk-nag. El error aparece en minutos, antes de desplegar.
  2. 2

    Al desplegar

    Un Hook en FAIL, activado en todas las cuentas, rechaza lo que se salte el pipeline pero pase por CloudFormation.
  3. 3

    Siempre

    Las SCP de Organizations niegan acciones prohibidas, vengan de donde vengan.
  4. 4

    Después

    Config detecta lo que no cumple y Systems Manager Automation lo corrige. El drift se lleva de vuelta a la plantilla.

Secretos en la plantilla

Una contraseña escrita en la plantilla queda en Git, en el historial del pipeline y en la consola de CloudFormation. Con referencias dinámicas, la plantilla solo nombra dónde vive el valor y CloudFormation lo busca al desplegar:

  • {{resolve:ssm:nombre}} para parámetros normales de Parameter Store.
  • {{resolve:ssm-secure:nombre}} para parámetros SecureString, solo en las propiedades de recursos que lo admiten.
  • {{resolve:secretsmanager:secreto:SecretString:clave}} para secretos de Secrets Manager.
Resources:
  Reportes:
    Type: AWS::Lambda::Function
    Properties:
      # ...
      Environment:
        Variables:
          # Parámetro normal de Parameter Store: se resuelve al desplegar
          NIVEL_LOG: '{{resolve:ssm:/reportes/prod/nivel-log}}'
  Bodega:
    Type: AWS::RDS::DBInstance
    Properties:
      # ...
      MasterUsername: '{{resolve:secretsmanager:prod/bodega:SecretString:usuario}}'
      MasterUserPassword: '{{resolve:secretsmanager:prod/bodega:SecretString:clave}}'

Mejor aún, deja que el servicio maneje el secreto. En RDS y Aurora, ManageMasterUserPassword: true crea la contraseña en Secrets Manager y la rota sin que la plantilla la mencione.

Quiz

Pon a prueba lo que aprendiste

0 de 5 correctas · 5 sin responder

  1. 1.Una empresa crea cuentas nuevas cada semana con AWS Organizations. Cada cuenta debe tener un rol de auditoría en cuanto entra a la OU Workloads, sin pasos manuales. ¿Qué haces?

  2. 2.Seguridad quiere que ningún stack de CloudFormation pueda crear un bucket S3 sin cifrado, y quiere ver primero cuántos equipos romperían la regla. ¿Qué propones?

  3. 3.Un StackSet actualiza 200 cuentas en 4 regiones. Quieres que la operación pare si fallan más de 2 stacks en una región. ¿Qué configuras?

  4. 4.Activaste controles proactivos de Control Tower. Un administrador crea desde la consola una tabla de DynamoDB que incumple uno de ellos. ¿Qué pasa?

  5. 5.Una plantilla necesita la contraseña de una base de datos guardada en Secrets Manager. ¿Cuál es la mejor forma de pasarla?