TP : Construire une mini-CNAPP locale avec Trivy, Syft, Grype et Kubescape
Prérequis
Environnement technique
- Docker installé et fonctionnel.
- Accès à un terminal Bash ou Zsh.
- Accès aux registres Docker Hub et GHCR.
- jq installé pour lire, filtrer et consolider les rapports JSON.
- Kubescape installé localement.
- Accès Internet pour télécharger les images, les bases de vulnérabilités et les frameworks Kubescape.
- Environnement recommandé sur Windows : WSL2 + Ubuntu + Docker Desktop.
Installer jq
Sur Debian / Ubuntu :
sudo apt updatesudo apt install -y jqSur macOS avec Homebrew :
brew install jqInstaller Kubescape
Sur macOS avec Homebrew :
brew install kubescapeSur Linux :
curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bashVérifier l’installation :
kubescape versionCompatibilité Windows
Ce TP est conçu pour être exécuté dans un terminal Bash.
Sur Windows, l’environnement recommandé est :
Windows + WSL2 + Ubuntu + Docker Desktop + jq + KubescapeDepuis Ubuntu WSL2, vérifier que Docker est accessible :
docker --versiondocker run --rm hello-worldL’exécution directe en PowerShell n’est pas recommandée, car plusieurs commandes utilisent une syntaxe Bash :
- heredocs
<<'EOF' - variable
$PWD - blocs
{ echo ... } - pipes et redirections
- chemins Linux pour les volumes Docker
Outils utilisés
Les outils utilisés via Docker sont :
aquasec/trivy:0.71.0ghcr.io/anchore/syft:v1.45.1ghcr.io/anchore/grype:v0.114.0Kubescape est utilisé localement avec la commande :
kubescapeImage utilisée
python:3.4-alpineCette image est volontairement obsolète. Python 3.4 est en fin de vie et ne doit pas être utilisé en production.
Objectifs
À la fin de ce TP, l’apprenant doit être capable de :
- Comprendre la logique d’une mini-CNAPP locale.
- Scanner une image de conteneur avec Trivy.
- Générer un SBOM avec Syft.
- Scanner une image avec Grype.
- Scanner un SBOM avec Grype.
- Scanner des manifests Kubernetes avec Trivy.
- Scanner des manifests Kubernetes avec Kubescape.
- Produire des rapports JSON exploitables.
- Consolider plusieurs résultats dans un rapport unique.
- Comprendre la complémentarité entre scan image, SBOM, vulnérabilités, configuration Kubernetes et posture sécurité.
- Interpréter un code de retour dans un contexte CI/CD.
Commandes
1. Créer l’arborescence du TP
mkdir -p mini-cnapp-localecd mini-cnapp-locale
mkdir -p k8smkdir -p reportsmkdir -p .trivy-cache2. Télécharger l’image vulnérable
docker pull python:3.4-alpine3. Télécharger les images des outils
docker pull aquasec/trivy:0.71.0docker pull ghcr.io/anchore/syft:v1.45.1docker pull ghcr.io/anchore/grype:v0.114.04. Vérifier les versions des outils Docker
docker run --rm aquasec/trivy:0.71.0 --versiondocker run --rm ghcr.io/anchore/syft:v1.45.1 versiondocker run --rm ghcr.io/anchore/grype:v0.114.0 version5. Vérifier la version de Kubescape
kubescape version6. Créer un manifeste Kubernetes volontairement vulnérable
cat > k8s/pod-vulnerable.yaml <<'EOF'apiVersion: v1kind: Podmetadata: name: vulnerable-pod labels: app: vulnerable-appspec: hostPID: true containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 securityContext: privileged: true runAsUser: 0EOF7. Scanner l’image locale avec Trivy
docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$PWD/.trivy-cache:/root/.cache/" \ -v "$PWD:/workdir" \ aquasec/trivy:0.71.0 \ image --format json --output /workdir/reports/trivy-image.json python:3.4-alpineecho "Code de retour Trivy image : $?"8. Lire la synthèse des vulnérabilités Trivy
jq '[.Results[]?.Vulnerabilities[]? | .Severity] | sort | group_by(.) | map({severity: .[0], count: length})' reports/trivy-image.json9. Afficher les principales vulnérabilités Trivy
jq -r '.Results[]?.Vulnerabilities[]? | [.VulnerabilityID, .Severity, .PkgName, .InstalledVersion, (.FixedVersion // "non renseigné")] | @tsv' reports/trivy-image.json | head -2010. Générer un SBOM Syft au format Syft JSON
docker run --rm \ -v "$PWD:/workdir" \ ghcr.io/anchore/syft:v1.45.1 \ registry:python:3.4-alpine \ -o syft-json=/workdir/reports/syft-sbom.jsonecho "Code de retour Syft JSON : $?"11. Générer un SBOM Syft au format CycloneDX JSON
docker run --rm \ -v "$PWD:/workdir" \ ghcr.io/anchore/syft:v1.45.1 \ registry:python:3.4-alpine \ -o cyclonedx-json=/workdir/reports/syft-cyclonedx.jsonecho "Code de retour Syft CycloneDX : $?"12. Vérifier les SBOM générés
ls -lh reports/syft-sbom.json reports/syft-cyclonedx.json13. Lire une synthèse du SBOM Syft
jq '{schema: .schema.version, artifacts: (.artifacts | length)}' reports/syft-sbom.json14. Lire une synthèse du SBOM CycloneDX
jq '{bomFormat, specVersion, components: (.components | length)}' reports/syft-cyclonedx.json15. Scanner l’image avec Grype depuis le registre
docker run --rm \ -v "$PWD:/workdir" \ ghcr.io/anchore/grype:v0.114.0 \ registry:python:3.4-alpine \ -o json=/workdir/reports/grype-image.jsonecho "Code de retour Grype image : $?"16. Lire la synthèse des vulnérabilités Grype sur l’image
jq '[.matches[]?.vulnerability.severity] | sort | group_by(.) | map({severity: .[0], count: length})' reports/grype-image.json17. Afficher les principales vulnérabilités Grype sur l’image
jq -r '.matches[]? | [.vulnerability.id, .vulnerability.severity, .artifact.name, .artifact.version, (.vulnerability.fix.versions[0] // "non renseigné")] | @tsv' reports/grype-image.json | head -2018. Scanner le SBOM Syft avec Grype
docker run --rm \ -v "$PWD:/workdir" \ ghcr.io/anchore/grype:v0.114.0 \ sbom:/workdir/reports/syft-sbom.json \ -o json=/workdir/reports/grype-sbom.jsonecho "Code de retour Grype SBOM : $?"19. Lire la synthèse des vulnérabilités Grype sur le SBOM
jq '[.matches[]?.vulnerability.severity] | sort | group_by(.) | map({severity: .[0], count: length})' reports/grype-sbom.json20. Afficher les principales vulnérabilités Grype sur le SBOM
jq -r '.matches[]? | [.vulnerability.id, .vulnerability.severity, .artifact.name, .artifact.version, (.vulnerability.fix.versions[0] // "non renseigné")] | @tsv' reports/grype-sbom.json | head -2021. Scanner les manifests Kubernetes avec Trivy
docker run --rm \ -v "$PWD/.trivy-cache:/root/.cache/" \ -v "$PWD:/workdir" \ aquasec/trivy:0.71.0 \ config --format json --output /workdir/reports/trivy-config-k8s.json /workdir/k8secho "Code de retour Trivy config Kubernetes : $?"22. Lire la synthèse des mauvaises configurations Trivy
jq '[.Results[]?.Misconfigurations[]? | .Severity] | sort | group_by(.) | map({severity: .[0], count: length})' reports/trivy-config-k8s.json23. Afficher les principales mauvaises configurations Trivy
jq -r '.Results[]?.Misconfigurations[]? | [.ID, .Severity, .Title, (.CauseMetadata.Resource? // "non renseigné")] | @tsv' reports/trivy-config-k8s.json | head -2024. Scanner les manifests Kubernetes locaux avec Kubescape
kubescape scan ./k8s/ \ --format json \ --format-version v2 \ --output reports/kubescape-k8s.jsonecho "Code de retour Kubescape : $?"25. Vérifier que le rapport Kubescape a bien été généré
ls -lh reports/kubescape-k8s.json26. Lire les clés principales du rapport Kubescape
jq 'keys' reports/kubescape-k8s.json27. Afficher une synthèse des statuts Kubescape
jq -r '.results[]?.controls[]?.status.status? // empty' reports/kubescape-k8s.json | sort | uniq -c28. Vérifier l’ensemble des rapports générés
ls -lh reports29. Construire un rapport de synthèse mini-CNAPP
{ echo "# Rapport mini-CNAPP locale" echo echo "## Cartographie des contrôles" echo echo "| Domaine | Outil | Rapport |" echo "|---|---|---|" echo "| Vulnérabilités image | Trivy | reports/trivy-image.json |" echo "| SBOM Syft JSON | Syft | reports/syft-sbom.json |" echo "| SBOM CycloneDX | Syft | reports/syft-cyclonedx.json |" echo "| Vulnérabilités image | Grype | reports/grype-image.json |" echo "| Vulnérabilités depuis SBOM | Grype | reports/grype-sbom.json |" echo "| Misconfigurations Kubernetes | Trivy | reports/trivy-config-k8s.json |" echo "| Posture Kubernetes | Kubescape | reports/kubescape-k8s.json |" echo echo "## Synthèse Trivy image" echo echo '```json' jq '[.Results[]?.Vulnerabilities[]? | .Severity] | sort | group_by(.) | map({severity: .[0], count: length})' reports/trivy-image.json echo '```' echo echo "## Synthèse Syft SBOM" echo echo '```json' jq '{schema: .schema.version, artifacts: (.artifacts | length)}' reports/syft-sbom.json echo '```' echo echo "## Synthèse Grype image" echo echo '```json' jq '[.matches[]?.vulnerability.severity] | sort | group_by(.) | map({severity: .[0], count: length})' reports/grype-image.json echo '```' echo echo "## Synthèse Grype SBOM" echo echo '```json' jq '[.matches[]?.vulnerability.severity] | sort | group_by(.) | map({severity: .[0], count: length})' reports/grype-sbom.json echo '```' echo echo "## Synthèse Trivy configuration Kubernetes" echo echo '```json' jq '[.Results[]?.Misconfigurations[]? | .Severity] | sort | group_by(.) | map({severity: .[0], count: length})' reports/trivy-config-k8s.json echo '```' echo echo "## Synthèse Kubescape" echo echo '```text' jq -r '.results[]?.controls[]?.status.status? // empty' reports/kubescape-k8s.json | sort | uniq -c echo '```'} > reports/mini-cnapp-summary.md30. Afficher le rapport de synthèse
cat reports/mini-cnapp-summary.md31. Rendre le scan Grype bloquant à partir du SBOM
docker run --rm \ -v "$PWD:/workdir" \ ghcr.io/anchore/grype:v0.114.0 \ sbom:/workdir/reports/syft-sbom.json \ --fail-on highecho "Code de retour Grype bloquant : $?"32. Rendre le scan Trivy bloquant sur les vulnérabilités HIGH et CRITICAL
docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$PWD/.trivy-cache:/root/.cache/" \ aquasec/trivy:0.71.0 \ image --severity HIGH,CRITICAL --exit-code 1 python:3.4-alpineecho "Code de retour Trivy bloquant : $?"Résultat attendu
| Fichier produit | Description |
|---|---|
reports/trivy-image.json | Rapport Trivy de vulnérabilités sur l’image |
reports/syft-sbom.json | SBOM généré par Syft au format JSON |
reports/syft-cyclonedx.json | SBOM généré par Syft au format CycloneDX |
reports/grype-image.json | Rapport Grype de vulnérabilités sur l’image |
reports/grype-sbom.json | Rapport Grype de vulnérabilités sur le SBOM Syft |
reports/trivy-config-k8s.json | Rapport Trivy de misconfigurations sur les manifests Kubernetes |
reports/kubescape-k8s.json | Rapport Kubescape de conformité sur les manifests Kubernetes |
reports/mini-cnapp-summary.md | Rapport de synthèse centralisant les résultats de tous les outils |
| Contrôle | Résultat attendu |
|---|---|
| Rapport de synthèse | mini-cnapp-summary.md centralise les résultats principaux de chaque outil |
| Approche CNAPP | Plusieurs contrôles regroupés localement simulent une approche CNAPP simplifiée |
Gate Grype --fail-on high | Code de retour différent de 0 si vulnérabilités high ou critical détectées |
Gate Trivy --exit-code 1 | Code de retour différent de 0 si vulnérabilités HIGH ou CRITICAL détectées |