Saltar al contenido

Seguridad de infraestructura como código: tfsec, Checkov y OIDC a la nube

    Seguridad de infraestructura como código:

    tfsec, Checkov y OIDC a la nube

    DevSecOps  |  unfantasmaenelsistema.com

    Cuando la infraestructura se define en ficheros de Terraform, CloudFormation o Bicep, cada error de configuración deja de ser un clic desafortunado en una consola y se convierte en una línea de código que se revisa, se versiona y se repite en cada despliegue. Eso es una buena noticia: un bucket público, un grupo de seguridad abierto al mundo o una base de datos sin cifrado se pueden detectar antes de existir, en el mismo sitio donde se detectan los bugs del resto del código.

    Este artículo recorre cómo se asegura una canalización de infraestructura como código (IaC): el escaneo estático del código y del plan, las políticas como código que bloquean lo que no debe desplegarse, el fichero de estado de Terraform tratado como el secreto que es, la detección de deriva, y el salto de las claves estáticas del pipeline a la federación OIDC con la nube. Enlaza con nuestros artículos de gestión de secretos, cadena de suministro de software y los tres de IAM en la nube.

    Qué aprenderas en este articulo

    Por qué conviene revisar el plan antes del apply y qué añade cada tipo de comprobación · Qué hacen tfsec/Trivy, Checkov y KICS, y en qué se diferencian de las políticas como código · Cómo tratar el estado de Terraform: cifrado, bloqueo y acceso mínimo · Qué es la deriva (drift) y cómo detectarla antes de que rompa un despliegue · Cómo sustituir las claves de acceso del pipeline por OIDC federado con AWS, Azure o GCP

    1. Revisar antes de aplicar: las cuatro capas

    Una canalización de IaC madura no confía en una sola comprobación. Cada capa atrapa una clase distinta de problema y todas se ejecutan antes de tocar la nube.

    CapaQué compruebaHerramientas típicas
    Lint y formatoSintaxis, estilo, variables sin usar, versiones de proveedor sin fijarterraform fmt/validate, tflint
    Escaneo estático de seguridad (SAST de IaC)Malas configuraciones conocidas en el código: cifrado, exposición pública, loggingtfsec/Trivy, Checkov, KICS
    Política como códigoReglas propias de la organización: etiquetas obligatorias, regiones permitidas, tipos de instanciaOPA/Conftest, Sentinel, Checkov custom
    Análisis del planEl efecto real del cambio (`terraform plan -out`), no solo el texto: qué se crea, cambia o destruyeCheckov/tfsec sobre el plan JSON, políticas sobre el plan

    La diferencia entre escanear el código y escanear el plan importa. El código puede tener un valor que viene de una variable o de un módulo remoto y que el escáner no resuelve; el plan ya tiene todos los valores concretos. Escanear el plan detecta, por ejemplo, que un módulo aparentemente inocuo va a abrir el puerto 22 a `0.0.0.0/0` porque así se le pasó el parámetro.

    2. Escáneres estáticos: tfsec, Checkov y KICS

    • tfsec (ahora integrado en Trivy): rápido, centrado en Terraform, con cientos de comprobaciones y buenos mensajes que enlazan a la explicación. `trivy config .` cubre además Dockerfile, Kubernetes y CloudFormation
    • Checkov (Prisma Cloud / Bridgecrew): multi-formato (Terraform, CloudFormation, Bicep, Kubernetes, Helm, Serverless), con una base de políticas muy amplia y soporte para reglas propias en Python o YAML. Sabe leer un plan de Terraform en JSON
    • KICS (Checkmarx): open source, cobertura parecida, útil como segunda opinión porque no siempre coinciden los hallazgos

    En la práctica se suele ejecutar uno como principal (Checkov o Trivy) y aceptar que ninguno encuentra el 100%. Lo importante es integrarlo en tres puntos: el editor del desarrollador (un pre-commit hook), la pull request (un check que comenta los hallazgos) y la propia canalización de despliegue (un paso que falla el build).

    # Checkov sobre el directorio de codigo
    checkov -d . --compact --quiet
     
    # Checkov sobre el plan ya calculado (valores resueltos)
    terraform plan -out tfplan.binary
    terraform show -json tfplan.binary > tfplan.json
    checkov -f tfplan.json
     
    # Trivy: configuracion incorrecta en todo el repo (IaC, Docker, k8s)
    trivy config --severity HIGH,CRITICAL .

    Gestionar las excepciones sin vaciar el escáner

    Toda regla que se silencia debe llevar motivo y responsable: un comentario `#checkov:skip=CKV_…: motivo` o una entrada en el fichero de configuración, nunca un `–skip-check` global · Revisa la lista de excepciones cada cierto tiempo: las que eran temporales rara vez lo son · Un escáner con la mitad de las reglas desactivadas da una falsa sensación de cobertura peor que no tenerlo

    3. Políticas como código: de la recomendación a la barrera

    Los escáneres traen reglas genéricas. Las políticas como código son las reglas de tu organización, escritas en un lenguaje que la canalización evalúa: «toda cuenta de almacenamiento lleva la etiqueta `centro-de-coste`», «nada se despliega fuera de `eu-west-1` y `eu-central-1`», «ninguna base de datos sin backups».

    • OPA / Rego con Conftest: el estándar abierto. Se evalúan políticas Rego contra el plan de Terraform en JSON o contra manifiestos de Kubernetes. Portable entre herramientas
    • HashiCorp Sentinel: integrado en Terraform Cloud/Enterprise, con niveles de obligación (advisory, soft-mandatory, hard-mandatory)
    • Reglas propias de Checkov: si ya usas Checkov, añadir políticas de organización en YAML es el camino de menos fricción

    El patrón recomendado: los escáneres y las políticas corren en la pull request como checks obligatorios, y además se replican como control preventivo en la nube (SCP en AWS Organizations, Azure Policy, Organization Policy en GCP), para el caso de que alguien despliegue sin pasar por la canalización.

    4. El estado de Terraform es un secreto

    El fichero `terraform.tfstate` contiene el mapa completo de la infraestructura y, muy a menudo, valores sensibles en claro: contraseñas de bases de datos generadas por Terraform, claves privadas, tokens. Tratarlo como un fichero de configuración cualquiera es uno de los errores más comunes y más graves.

    • Nunca en el repositorio de código. Nunca en local para un proyecto compartido
    • Backend remoto con cifrado en reposo y bloqueo de estado (state locking) para evitar escrituras concurrentes: S3 + DynamoDB, Azure Storage con lease, GCS, o Terraform Cloud
    • Acceso al bucket o contenedor del estado restringido al rol de la canalización y al equipo de plataforma; nada de acceso de lectura general
    • Versionado activado en el almacén, para poder recuperar un estado corrupto
    • Si el estado ya se expuso, hay que rotar todos los secretos que contiene, no solo mover el fichero

    Marca los outputs sensibles

    Un `output` sin `sensitive = true` se imprime en los logs de la canalización y queda en el historial de ejecuciones · Aun con `sensitive = true`, el valor sigue estando en claro dentro del fichero de estado: la marca solo evita mostrarlo, no lo cifra · Para secretos que la aplicación necesita en ejecución, que Terraform los escriba en un gestor de secretos (Vault, Secrets Manager, Key Vault) y no en un output

    5. Deriva: cuando la nube deja de parecerse al código

    La deriva (drift) es la diferencia entre lo que dice el código y lo que hay realmente desplegado. Aparece cuando alguien toca un recurso a mano en la consola «para salir del paso», cuando un proceso automático modifica algo, o cuando un despliegue falla a medias.

    • Detección periódica: un `terraform plan` programado (por ejemplo cada noche) que alerta si el plan no está vacío. Herramientas dedicadas: driftctl, o la detección de deriva de Terraform Cloud y de AWS CloudFormation
    • Política clara sobre qué hacer con la deriva: reconciliar el código con la realidad, o revertir el cambio manual. Dejarla acumular hace que cada `apply` futuro dé miedo
    • Reducir la causa raíz: quitar o limitar el acceso de escritura a la consola en los entornos gestionados por IaC, de modo que el único camino para cambiar algo sea la canalización

    6. Credenciales del pipeline: de las claves estáticas a OIDC

    Durante años, la canalización que despliega infraestructura guardaba una clave de acceso de larga vida con permisos amplios como variable secreta del sistema de CI. Es un objetivo goloso: no caduca, y quien comprometa el runner de CI o un workflow malicioso en una pull request se la lleva.

    La alternativa moderna es la federación de identidad OIDC. El sistema de CI (GitHub Actions, GitLab, Buildkite) emite un token OIDC firmado que describe el workflow, el repositorio y la rama. La nube confía en ese emisor y, si el token cumple las condiciones que has fijado, entrega credenciales temporales. No hay ninguna clave almacenada.

    NubeMecanismoCondición que conviene fijar
    AWSIAM OIDC identity provider + rol con `sts:AssumeRoleWithWebIdentity``sub` limitado a `repo:org/repo:ref:refs/heads/main` y `aud` correcto
    AzureWorkload identity federation sobre un app registration / managed identity`subject` y `issuer` del repositorio y entorno concretos
    GCPWorkload Identity Federation + service account con acceso vía `principalSet`Atributo `repository` y `ref` en la condición del pool

    El detalle que convierte OIDC en un agujero

    Si la condición de confianza (`sub`, `subject`) se deja demasiado abierta — por ejemplo cualquier rama o cualquier repositorio de la organización — un workflow desde una rama de prueba o desde un fork puede asumir el rol de despliegue · Fija el repositorio, la rama protegida y, si el CI lo soporta, el `environment` de despliegue · Separa roles por entorno: el workflow de `dev` nunca debería poder asumir el rol de `prod`

    7. Módulos de terceros y su cadena de suministro

    Un `module «x» { source = «…» }` que apunta a un registro público o a un repositorio de GitHub trae código que se ejecutará con los permisos de tu canalización. Es la misma clase de riesgo que una dependencia de npm o de PyPI, y se trata igual.

    • Fija la versión de cada módulo y de cada proveedor (`version = «~> 5.0″`), y usa el fichero de bloqueo `.terraform.lock.hcl` con hashes
    • Prefiere módulos de fuentes conocidas y con mantenimiento; revisa el código de los módulos poco populares antes de adoptarlos
    • Considera un registro de módulos interno (un espejo curado) para los proyectos críticos, en lugar de tirar directamente del registro público
    • Escanea también los módulos: Checkov y Trivy siguen los `source` locales; para los remotos, revísalos al fijarlos

    Solo sobre infraestructura propia y con autorización

    Todo lo descrito aquí se aplica a cuentas y organizaciones de nube propias o sobre las que tienes autorización escrita del titular · Ejecutar escáneres, extraer estado de Terraform o enumerar la configuración de infraestructura de terceros sin permiso es un acceso ilícito a un sistema informático (en España, Código Penal art. 197 bis, art. 197 ter y art. 264 y siguientes) · Si detectas una mala configuración en infraestructura de otra organización, sigue un proceso de divulgación responsable a través de su canal de seguridad o del INCIBE-CERT

    Referencias

    aquasecurity.github.io/tfsec y trivy.dev — Escáner de IaC (tfsec integrado en Trivy) · checkov.io — Checkov, políticas incluidas y guía de reglas propias · openpolicyagent.org y conftest.dev — OPA/Rego y Conftest para política como código · developer.hashicorp.com/terraform/language/state — Estado remoto, bloqueo y datos sensibles · docs.github.com/actions/deployment/security-hardening-your-deployments — OIDC desde GitHub Actions a AWS, Azure y GCP

    Conclusión

    La infraestructura como código convierte los errores de configuración en algo revisable, y asegurarla consiste en aprovechar ese hecho: escanear el código y el plan, escribir las reglas de la organización como código que la canalización evalúa, y replicar esas mismas barreras como control preventivo en la nube por si alguien se salta el proceso.

    Los dos puntos que más disgustos evitan son poco vistosos: tratar el fichero de estado como el secreto que es — cifrado, bloqueado, con acceso mínimo — y quitar del pipeline la clave estática de larga vida a favor de OIDC federado, con una condición de confianza estrecha. Ambos se implementan en una tarde y cierran las dos vías por las que un compromiso del CI se convierte en un compromiso de toda la nube.

    unfantasmaenelsistema.com | Seguridad, sistemas y todo lo que no debería funcionar (pero funciona)

    Resumen de privacidad

    Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.