
Modelador de amenazas de IaC con los frameworks STRIDE, MITRE ATT&CK y PASTA. Soporte para REST API, GraphQL y Docker para Terraform, CloudFormation y Kubernetes.
Modelador de amenazas estático para IaC que analiza manifiestos de Terraform, CloudFormation y Kubernetes y genera informes estructurados de modelos de amenazas utilizando los marcos STRIDE, MITRE ATT&CK o PASTA. Sin llamadas de red, sin credenciales en la nube, completamente offline. Se ejecuta como CLI, API REST o servicio contenerizado.
CLI:
pip install threatmap
threatmap scan ./ejemplos --output informe.md --fail-on HIGH
Docker:
docker run -v $(pwd):/workspace bogdynn/threatmap:2.1.0 threatmap scan /workspace --output /workspace/informe.md
Servidor API REST:
threatmap serve --host 0.0.0.0 --port 8000
# O mediante Docker:
docker run -p 8000:8000 bogdynn/threatmap:2.1.0
# Endpoints de la API: /health, /version, /rules, /analyze
API GraphQL:
docker run -p 8000:8000 bogdynn/threatmap:2.1.0
# Endpoint GraphQL: http://localhost:8000/graphql
# Consultas: health, version, rules
# Mutaciones: analyze(content, filename, framework)
| Formato | Proveedor | Extensión |
|---|---|---|
| Terraform HCL | AWS, Azure, GCP | .tf |
| CloudFormation | AWS | .yaml, .yml, .json |
| Manifiestos de Kubernetes | Kubernetes | .yaml, .yml |
Instalar desde PyPI:
pip install threatmap
O para desarrollo local:
git clone https://github.com/bogdanticu88/threatmap.git
cd threatmap
pip install -e .
Escanea un directorio e imprime un informe Markdown en stdout:
threatmap scan ./terraform/
Escanea múltiples rutas y escribe un informe JSON en un archivo:
threatmap scan ./terraform/ ./k8s/ ./cloudformation/ --format json --output informe.json
Genera un informe HTML interactivo o un informe SARIF para GitHub Security:
threatmap scan ./infra/ --format html --output informe.html
threatmap scan ./infra/ --format sarif --output informe.sarif
Puerta de CI: código de salida 1 si se encuentra alguna amenaza CRÍTICA o ALTA:
threatmap scan ./infra/ --fail-on HIGH --output informe-amenazas.md
Imprime solo una tabla resumen en terminal, sin escribir un informe completo:
threatmap scan ./infra/ --summary
Utiliza indicadores de severidad solo ASCII (sin emojis) para entornos que no soportan Unicode:
threatmap scan ./infra/ --ascii --output informe.md
Analiza usando diferentes marcos de modelado de amenazas:
# STRIDE (por defecto)
threatmap scan ./infra/ --framework stride
# MITRE ATT&CK (mapea a tácticas y técnicas)
threatmap scan ./infra/ --framework mitre --format json
# PASTA (modelado de amenazas centrado en activos)
threatmap scan ./infra/ --framework pasta --format json
STRIDE (73 reglas)
MITRE ATT&CK (11 reglas, 14 tácticas)
PASTA (12 reglas, centrado en activos)
Ejecutar threatmap scan ./ejemplos --output informe.md contra los ejemplos incluidos produce un informe Markdown completo. A continuación se muestra un extracto representativo.
| ID | Severidad | Categoría STRIDE | Recurso | Descripción |
|---|---|---|---|---|
| T-001 | 🔴 CRÍTICA | Divulgación de información | AuditBucket | El bucket S3 'AuditBucket' no tiene configurado un bloque de acceso público; el bucket puede ser accesible públicamente. |
| T-002 | 🔴 CRÍTICA | Suplantación | WebSecurityGroup | El grupo de seguridad 'WebSecurityGroup' expone SSH/RDP (puerto 22/3389) a 0.0.0.0/0. |
| T-003 | 🔴 CRÍTICA | Elevación de privilegios | app_contributor | La asignación de rol 'app_contributor' otorga el rol privilegiado 'Contributor'. |
| T-006 | 🟠 ALTA | Divulgación de información | AuditBucket | El bucket S3 'AuditBucket' no tiene cifrado del lado del servidor configurado. |
| T-008 | 🟠 ALTA | Elevación de privilegios | api | El contenedor 'api' en el Deployment 'api' puede ejecutarse como root (sin runAsNonRoot=true o runAsUser=0). |
| T-011 | 🟠 ALTA | Elevación de privilegios | web | La instancia EC2 'web' permite IMDSv1; el servicio de metadatos accesible sin tokens de sesión, permitiendo el robo de credenciales basado en SSRF. |
### T-002 — Suplantación (CRÍTICA)
Recurso: AWS::EC2::SecurityGroup.WebSecurityGroup
Propiedad: ingress.ssh_rdp_open
Hallazgo: El grupo de seguridad 'WebSecurityGroup' expone SSH/RDP (puerto 22/3389) a 0.0.0.0/0.
Mitigación: Eliminar el acceso público a SSH/RDP. Usar AWS Systems Manager Session Manager
o un bastion host con restricciones de IP.
El informe añade un diagrama flowchart LR en Mermaid. Los nodos se colorean según la severidad máxima (🔴 rojo = CRÍTICA, 🟠 naranja = ALTA). Pega el bloque en cualquier renderizador de Mermaid o véelo directamente en GitHub.
flowchart LR
Internet((Internet))
subgraph Red
aws_security_group_web_sg{web_sg}
NetworkPolicy_default_deny{default-deny}
azurerm_network_security_group_app_nsg{app_nsg}
end
subgraph Computación
aws_instance_web[web]
end
subgraph Kubernetes
Namespace_myapp[myapp]
Deployment_api[api]
Service_api_svc[api-svc]
Ingress_api_ingress[api-ingress]
end
subgraph Datos
aws_s3_bucket_app_data[(app_data)]
aws_db_instance_app_db[(app_db)]
azurerm_storage_account_app_storage[(app_storage)]
end
subgraph Seguridad
azurerm_key_vault_app_kv[app_kv]
end
subgraph Identidad
azurerm_role_assignment_app_contributor[/app_contributor/]
end
AWS__S3__Bucket_AppBucket -->|ref| AWS__S3__Bucket_AuditBucket
AWS__CloudTrail__Trail_AppTrail -->|ref| AWS__S3__Bucket_AuditBucket
Internet -->|HTTPS| Ingress_api_ingress
style aws_security_group_web_sg fill:#ff4444,color:#fff
style aws_s3_bucket_app_data fill:#ff4444,color:#fff
style aws_instance_web fill:#ff8800,color:#fff
style Deployment_api fill:#ff8800,color:#fff
style azurerm_key_vault_app_kv fill:#ffcc00,color:#000
style azurerm_network_security_group_app_nsg fill:#ff8800,color:#fff
style azurerm_role_assignment_app_contributor fill:#ff4444,color:#fffthreatmap ahora incluye Inteligencia de Grafos que rastrea las relaciones entre recursos. Identifica automáticamente amenazas "encadenadas" donde el compromiso de un recurso (por ejemplo, una EC2 expuesta a Internet) conduce directamente a otro (por ejemplo, un bucket S3 privado), marcando estas rutas como Elevación de privilegios.
Puedes definir requisitos internos de seguridad creando un archivo threatmap_rules.yaml en la raíz de tu proyecto.
rules:
- resource_type: "aws_s3_bucket"
property: "force_destroy"
expected: false
stride: "Tampering"
severity: "MEDIUM"
description: "Los buckets de producción no deberían tener force_destroy habilitado."
mitigation: "Establece force_destroy = false."
La mayoría de los hallazgos ahora incluyen un campo de remediación (visible en informes JSON, HTML y SARIF) que proporciona el fragmento de código exacto necesario para solucionar el problema de seguridad.
Analizador STRIDE — Reglas de amenazas específicas del proveedor:
threatmap/analyzers/
├── aws.py # 22 reglas — S3, IAM, EC2, RDS, EKS, CloudTrail, KMS, Lambda
├── azure.py # 19 reglas — Storage, Key Vault, NSG, RBAC, AKS, ACR, SQL
├── gcp.py # 15 reglas — GCS, Firewall, Compute, Cloud SQL, GKE, IAM, KMS
└── kubernetes.py # 17 reglas — workloads, RBAC, network, secrets
Analizador MITRE ATT&CK — 11 reglas mapeadas a tácticas MITRE:
Analizador PASTA — 12 reglas con enfoque centrado en activos:
APIs:
/health, /version, /rules, /analyze, /analyze/file/graphql con Query (health, version, rules) y Mutation (analyze)Cada regla es una función que recibe un objeto Resource (normalizado a partir del formato fuente analizado) y devuelve un Threat si se cumple la condición. Las reglas son condicionales simples en Python — sin DSL, sin motor de expresiones regulares, sin archivos de reglas externos.
La severidad refleja tanto la explotabilidad como el radio de explosión:
| Severidad | Significado |
|---|---|
| CRÍTICA | Explotable directamente sin condiciones adicionales (ej.: SSH abierto a 0.0.0.0/0, política IAM comodín, enlace cluster-admin a anónimo) |
| ALTA | Riesgo significativo que requiere un paso adicional (ej.: RDS sin cifrar con acceso público, IMDSv1 en una instancia EC2) |
| MEDIA | Faltan controles de defensa en profundidad: riesgo inmediato menor pero viola líneas base de seguridad (ej.: sin versionado, sin registro, sin límites de recursos) |
| BAJA | Brechas de buenas prácticas con explotabilidad limitada por sí mismas (ej.: Lambda sin VPC) |
publicly_accessible = true, Principal: "*").metadata_options en una instancia EC2 significa que IMDSv1 está activo, porque ese es el valor predeterminado de AWS).(stride_category, resource_name, trigger_property), por lo que el mismo problema lógico nunca se informa dos veces, incluso si aparece en múltiples formatos de archivo.# .github/workflows/threat-model.yml
name: Modelo de amenazas
on: [pull_request]
jobs:
threatmap:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configurar Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Instalar threatmap
run: pip install threatmap
- name: Ejecutar análisis de modelo de amenazas
run: |
threatmap scan ./infra/ \
--format markdown \
--output informe-amenazas.md \
--fail-on HIGH
- name: Subir informe de amenazas
if: always()
uses: actions/upload-artifact@v4
with:
name: informe-amenazas
path: informe-amenazas.md
La bandera --fail-on HIGH hace que el trabajo termine con código 1 si se encuentra alguna amenaza ALTA o CRÍTICA, bloqueando la fusión del PR. El artefacto subido proporciona a los revisores el informe completo sin salir de la solicitud de extracción.
| Proveedor | Reglas |
|---|---|
| AWS (Terraform + CloudFormation) | 22 |
| Azure (Terraform) | 19 |
| GCP (Terraform) | 15 |
| Kubernetes | 17 |
| Total | 73 |
Categorías cubiertas por proveedor:
| Proveedor | S | T | R | I | D | E |
|---|---|---|---|---|---|---|
| AWS | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Azure | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| GCP | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Kubernetes | ✓ | ✓ | — | ✓ | ✓ | ✓ |
(S=Suplantación, T=Manipulación, R=Repudio, I=Divulgación de información, D=Denegación de servicio, E=Elevación de privilegios)
Ejecutar pruebas:
pytest tests/ -v
Ejecutar con cobertura:
pytest tests/ --cov=threatmap --cov-report=term-missing
threatmap/analyzers/<proveedor>.py siguiendo el patrón existentetests/fixtures/ que active la nueva reglatests/test_analyzers.py