← Retour aux tutoriels

Kubernetes — scan d'images avec Trivy et admission de vulnérabilités

Analyse de vulnérabilités des images conteneur avec Trivy : scan en CI, scan des charges en cluster avec trivy-operator et blocage des images critiques à l'admission.

Analyse des vulnérabilités des images conteneur avec Trivy, en intégration continue et au sein du cluster.

Contexte

Les images conteneur embarquent des bibliothèques système et applicatives dont les CVE s’accumulent entre deux reconstructions. Sans scan systématique, des images vulnérables atteignent la production. Trivy analyse les couches d’image, le système de fichiers et les manifestes ; couplé à un contrôleur d’admission, il bloque le déploiement d’images au-delà d’un seuil de sévérité.

Détection

Scan d’une image avec seuil de sévérité et code de sortie exploitable en CI :

trivy image --severity HIGH,CRITICAL --exit-code 1 --ignore-unfixed registry.exemple.fr/web:1.4.2
trivy image --format json --output rapport.json registry.exemple.fr/web:1.4.2
jq -r '.Results[].Vulnerabilities[]? | "\(.Severity) \(.VulnerabilityID) \(.PkgName)"' rapport.json | sort | uniq -c

Scan des charges déjà déployées dans le cluster via trivy-operator (rapports VulnerabilityReport) :

kubectl get vulnerabilityreports -A -o wide
kubectl get vulnerabilityreports -A -o json | jq -r '.items[] | "\(.metadata.namespace)/\(.report.artifact.repository) CRIT=\(.report.summary.criticalCount)"' | grep -v 'CRIT=0'

Détection de secrets et de mauvaises configurations dans les manifestes :

trivy fs --scanners secret,misconfig ./deploy/

Durcissement

Intégration du scan bloquant dans le pipeline de build (échec si CVE corrigeable de sévérité élevée) :

scan-image:
  stage: test
  script:
    - trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 "$IMAGE:$TAG"
    - trivy config --severity HIGH,CRITICAL --exit-code 1 ./deploy/

Déploiement de trivy-operator pour le scan continu en cluster :

helm install trivy-operator aquasecurity/trivy-operator \
  --namespace trivy-system --create-namespace \
  --set trivy.severity=HIGH\,CRITICAL \
  --set operator.scannerReportTTL=24h

Application d’un fichier .trivyignore versionné pour les CVE acceptées avec justification documentée, plutôt que la désactivation globale du scan :

# CVE-XXXX-YYYY : composant non exposé, exception validée jusqu'au prochain rebuild
CVE-XXXX-YYYY

Politique d’admission bloquant les images non scannées ou critiques, via les rapports trivy-operator interrogés par une policy (Kyverno) :

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: block-critical-cve
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-clean-scan
      match:
        any:
          - resources:
              kinds: [Pod]
      context:
        - name: report
          apiCall:
            urlPath: "/apis/aquasecurity.github.io/v1alpha1/namespaces/{{request.namespace}}/vulnerabilityreports"
      validate:
        message: "Image avec CVE critiques non autorisee"
        deny:
          conditions:
            any:
              - key: "{{ report.items[].report.summary.criticalCount || `0` }}"
                operator: GreaterThan
                value: 0

Vérification

Confirmation que le scan bloque une image volontairement vulnérable et passe sur une image saine :

trivy image --severity CRITICAL --exit-code 1 --ignore-unfixed registry.exemple.fr/web:1.4.2; echo "code=$?"

Vérification de l’absence de rapports critiques en cluster :

kubectl get vulnerabilityreports -A -o json | jq '[.items[].report.summary.criticalCount] | add'

Un code de sortie non nul sur l’image vulnérable et une somme de criticalCount à 0 en cluster confirment la chaîne de contrôle.

Vous avez un projet sur ces sujets ?

Nous contacter →