
Modélisateur de menaces IaC avec les frameworks STRIDE, MITRE ATT&CK et PASTA. Support pour REST API, GraphQL et Docker pour Terraform, CloudFormation et Kubernetes.
Modélisateur de menaces IaC statique qui analyse les manifests Terraform, CloudFormation et Kubernetes et produit des rapports structurés de modélisation des menaces en utilisant les frameworks STRIDE, MITRE ATT&CK ou PASTA. Aucun appel réseau, aucune information d'identification cloud, entièrement hors ligne. Fonctionne en CLI, API REST ou service conteneurisé.
CLI :
pip install threatmap
threatmap scan ./examples --output report.md --fail-on HIGH
Docker :
docker run -v $(pwd):/workspace bogdynn/threatmap:2.1.0 threatmap scan /workspace --output /workspace/report.md
Serveur API REST :
threatmap serve --host 0.0.0.0 --port 8000
# Ou via Docker :
docker run -p 8000:8000 bogdynn/threatmap:2.1.0
# Points de terminaison API : /health, /version, /rules, /analyze
API GraphQL :
docker run -p 8000:8000 bogdynn/threatmap:2.1.0
# Point de terminaison GraphQL : http://localhost:8000/graphql
# Requêtes : health, version, rules
# Mutations : analyze(content, filename, framework)
| Format | Fournisseur | Extension |
|---|---|---|
| Terraform HCL | AWS, Azure, GCP | .tf |
| CloudFormation | AWS | .yaml, .yml, .json |
| Manifests Kubernetes | Kubernetes | .yaml, .yml |
Installer depuis PyPI :
pip install threatmap
Ou pour le développement local :
git clone https://github.com/bogdanticu88/threatmap.git
cd threatmap
pip install -e .
Analyser un répertoire et afficher un rapport Markdown sur la sortie standard :
threatmap scan ./terraform/
Analyser plusieurs chemins et écrire un rapport JSON dans un fichier :
threatmap scan ./terraform/ ./k8s/ ./cloudformation/ --format json --output report.json
Générer un rapport HTML interactif ou un rapport SARIF pour GitHub Security :
threatmap scan ./infra/ --format html --output report.html
threatmap scan ./infra/ --format sarif --output report.sarif
Porte CI — code de sortie 1 si une menace CRITIQUE ou HAUTE est trouvée :
threatmap scan ./infra/ --fail-on HIGH --output threat-report.md
Afficher uniquement un tableau récapitulatif dans le terminal, sans écrire de rapport complet :
threatmap scan ./infra/ --summary
Utiliser des indicateurs de sévérité ASCII uniquement (sans émojis) pour les environnements ne supportant pas Unicode :
threatmap scan ./infra/ --ascii --output report.md
Analyser en utilisant différents cadres de modélisation des menaces :
# STRIDE (par défaut)
threatmap scan ./infra/ --framework stride
# MITRE ATT&CK (mappe vers tactiques et techniques)
threatmap scan ./infra/ --framework mitre --format json
# PASTA (modélisation des menaces centrée sur les actifs)
threatmap scan ./infra/ --framework pasta --format json
STRIDE (73 règles)
MITRE ATT&CK (11 règles, 14 tactiques)
PASTA (12 règles, centré sur les actifs)
L'exécution de threatmap scan ./examples --output report.md sur les exemples fournis produit un rapport Markdown complet. Voici un extrait représentatif.
| ID | Sévérité | Catégorie STRIDE | Ressource | Description |
|---|---|---|---|---|
| T-001 | 🔴 CRITIQUE | Divulgation d'informations | AuditBucket | Le bucket S3 'AuditBucket' n'a pas de bloc d'accès public configuré — le bucket peut être accessible publiquement. |
| T-002 | 🔴 CRITIQUE | Usurpation | WebSecurityGroup | Le groupe de sécurité 'WebSecurityGroup' expose SSH/RDP (port 22/3389) à 0.0.0.0/0. |
| T-003 | 🔴 CRITIQUE | Élévation de privilèges | app_contributor | L'attribution de rôle 'app_contributor' accorde le rôle privilégié 'Contributeur'. |
| T-006 | 🟠 HAUTE | Divulgation d'informations | AuditBucket | Le bucket S3 'AuditBucket' n'a pas de chiffrement côté serveur configuré. |
| T-008 | 🟠 HAUTE | Élévation de privilèges | api | Le conteneur 'api' dans le déploiement 'api' peut s'exécuter en tant que root (pas de runAsNonRoot=true ou runAsUser=0). |
| T-011 | 🟠 HAUTE | Élévation de privilèges | web | L'instance EC2 'web' autorise IMDSv1 — le service de métadonnées accessible sans jetons de session, permettant le vol d'identifiants basé sur SSRF. |
### T-002 — Usurpation (CRITIQUE)
Ressource : AWS::EC2::SecurityGroup.WebSecurityGroup
Propriété : ingress.ssh_rdp_open
Constat : Le groupe de sécurité 'WebSecurityGroup' expose SSH/RDP (port 22/3389) à 0.0.0.0/0.
Atténuation : Supprimer l'accès SSH/RDP public. Utiliser AWS Systems Manager Session Manager
ou un bastion avec restrictions IP.
Le rapport ajoute un diagramme Mermaid flowchart LR. Les nœuds sont colorés selon la sévérité maximale (🔴 rouge = CRITIQUE, 🟠 orange = HAUTE). Copiez le bloc dans n'importe quel rendu Mermaid ou visualisez-le directement sur GitHub.
flowchart LR
Internet((Internet))
subgraph Mise en réseau
aws_security_group_web_sg{web_sg}
NetworkPolicy_default_deny{default-deny}
azurerm_network_security_group_app_nsg{app_nsg}
end
subgraph Calcul
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 Données
aws_s3_bucket_app_data[(app_data)]
aws_db_instance_app_db[(app_db)]
azurerm_storage_account_app_storage[(app_storage)]
end
subgraph Sécurité
azurerm_key_vault_app_kv[app_kv]
end
subgraph Identité
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 inclut désormais une Intelligence de graphe qui trace les relations entre les ressources. Il identifie automatiquement les menaces "en chaîne" où la compromission d'une ressource (ex. une EC2 exposée à Internet) mène directement à une autre (ex. un bucket S3 privé), les signalant comme des chemins d'attaque par Élévation de privilèges.
Vous pouvez définir des exigences de sécurité internes en créant un fichier threatmap_rules.yaml à la racine de votre projet.
rules:
- resource_type: "aws_s3_bucket"
property: "force_destroy"
expected: false
stride: "Falsification"
severity: "MOYENNE"
description: "Les buckets de production ne devraient pas avoir force_destroy activé."
mitigation: "Définir force_destroy = false."
La plupart des constats incluent désormais un champ remédiation (visible dans les rapports JSON, HTML et SARIF) qui fournit l'extrait de code exact nécessaire pour corriger le problème de sécurité.
Analyseur STRIDE — Règles de menace spécifiques au fournisseur :
threatmap/analyzers/
├── aws.py # 22 règles — S3, IAM, EC2, RDS, EKS, CloudTrail, KMS, Lambda
├── azure.py # 19 règles — Stockage, Key Vault, NSG, RBAC, AKS, ACR, SQL
├── gcp.py # 15 règles — GCS, Pare-feu, Compute, Cloud SQL, GKE, IAM, KMS
└── kubernetes.py # 17 règles — charges de travail, RBAC, réseau, secrets
Analyseur MITRE ATT&CK — 11 règles mappées aux tactiques MITRE :
Analyseur PASTA — 12 règles avec une focalisation centrée sur les actifs :
API :
/health, /version, /rules, /analyze, /analyze/file/graphql avec Query (health, version, rules) et Mutation (analyze)Chaque règle est une fonction qui reçoit un objet Resource (normalisé à partir du format source analysé) et renvoie une Threat si la condition est satisfaite. Les règles sont des conditionnelles Python simples — pas de DSL, pas de moteur regex, pas de fichiers de règles externes.
La sévérité reflète à la fois l'exploitabilité et le rayon de l'explosion :
| Sévérité | Signification |
|---|---|
| CRITIQUE | Exploitable directement sans pré-conditions supplémentaires (ex. SSH ouvert à 0.0.0.0/0, politique IAM wildcard, liaison cluster-admin à anonymous) |
| HAUTE | Risque significatif nécessitant une étape supplémentaire (ex. RDS non chiffré avec accès public, IMDSv1 sur une instance EC2) |
| MOYENNE | Contrôles de défense en profondeur manquants — risque immédiat plus faible mais viole les bases de sécurité (ex. pas de versioning, pas de journalisation, pas de limites de ressources) |
| BASSE | Écarts de bonnes pratiques avec une exploitabilité limitée isolément (ex. Lambda pas dans un VPC) |
publicly_accessible = true, Principal: "*").metadata_options sur une instance EC2 signifie qu'IMDSv1 est actif, car c'est le défaut d'AWS).(stride_category, resource_name, trigger_property) afin que le même problème logique ne soit jamais signalé deux fois, même s'il apparaît dans plusieurs formats de fichiers.# .github/workflows/threat-model.yml
name: Modèle de menace
on: [pull_request]
jobs:
threatmap:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configurer Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Installer threatmap
run: pip install threatmap
- name: Exécuter l'analyse du modèle de menace
run: |
threatmap scan ./infra/ \
--format markdown \
--output threat-report.md \
--fail-on HIGH
- name: Télécharger le rapport de menace
if: always()
uses: actions/upload-artifact@v4
with:
name: rapport-menace
path: threat-report.md
Le flag --fail-on HIGH fait que le job se termine avec le code 1 si une menace HAUTE ou CRITIQUE est trouvée, bloquant la fusion de la PR. L'artefact téléchargé donne aux relecteurs le rapport complet sans quitter la pull request.
| Fournisseur | Règles |
|---|---|
| AWS (Terraform + CloudFormation) | 22 |
| Azure (Terraform) | 19 |
| GCP (Terraform) | 15 |
| Kubernetes | 17 |
| Total | 73 |
Catégories couvertes par fournisseur :
| Fournisseur | S | T | R | I | D | E |
|---|---|---|---|---|---|---|
| AWS | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Azure | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| GCP | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Kubernetes | ✓ | ✓ | — | ✓ | ✓ | ✓ |
(S=Usurpation, T=Falsification, R=Répudiation, I=Divulgation d'informations, D=Déni de service, E=Élévation de privilèges)
Exécuter les tests :
pytest tests/ -v
Exécuter avec couverture :
pytest tests/ --cov=threatmap --cov-report=term-missing
threatmap/analyzers/<provider>.py en suivant le modèle existanttests/fixtures/ qui déclenche la nouvelle règletests/test_analyzers.py