Aller au contenu

Scanner les vulnérabilités de conteneurs avec grype

Mise à jour :

logo

En tant que spécialiste DevOps, je suis constamment à la recherche d’outils innovants pour renforcer la sécurité des applications, en particulier dans l’environnement des conteneurs qui devient de plus en plus omniprésent. Parmi ces outils, Grype se distingue comme une solution robuste et efficace pour l’analyse de vulnérabilités des images de conteneurs.

Grype offre une approche simplifiée, mais, puissante pour identifier et gérer les vulnérabilités au sein des conteneurs. Avec l’augmentation des menaces de sécurité et la complexité croissante des architectures de microservices, l’utilisation d’un outil comme Grype n’est plus une option, mais une nécessité pour assurer la sécurité des déploiements conteneurisés.

Installation de Grype

Sur Linux

L’installation peut se faire avec asdf-vm :

Terminal window
asdf plugin add grype
asdf install grype latest
asdf global grype latest

Sur Macos

L’installation sur macOS se fait avec brew :

Terminal window
brew tap anchore/grype
brew install grype

Vérification de l’installation

Pour vérifier que l’installation s’est faite correctement, tapez la commande suivante :

Terminal window
grype --version
grype 0.73.5

Si tout est ok, vous devriez voir le numéro de version s’afficher.

Utilisation Grype

Grype peut scanner le contenu d’une image de conteneur ou d’un répertoire à la recherche de vulnérabilités.

Il prend en charge les gestionnaires de package et les langages de développement suivant :

  • Alpine (apk)
  • C (conan)
  • C++ (conan)
  • Dart (pubs)
  • Debian (dpkg)
  • Dotnet (deps.json)
  • Objective-C (cocoapods)
  • Go (go.mod, Go binaries)
  • Haskell (cabal, stack)
  • Java (jar, ear, war, par, sar)
  • JavaScript (npm, yarn)
  • Jenkins Plugins (jpi, hpi)
  • PHP (composer)
  • Python (wheel, egg, poetry, requirements.txt)
  • Red Hat (rpm)
  • Ruby (gem)
  • Rust (cargo.lock)
  • Swift (cocoapods)

Recherche de vulnérabilités avec grype

Maintenant, nous pouvons regarder ce que propose grype. Commençons par le lancer sur une image de container :

Terminal window
grype dkron/dkron
Vulnerability DB [updated]
Loaded image dkron/dkron:latest
Parsed image sha256:43f45ba9495628b1a66bfdf9bdfde7b85660a46e9975f9fbd9ea737dbf914822
Scanned for vulnerabilities [8 vulnerability matches]
├── by severity: 2 critical, 1 high, 5 medium, 0 low, 0 negligible
└── by status: 5 fixed, 3 not-fixed, 0 ignored
[0001] WARN some package(s) are missing CPEs. This may result in missing vulnerabilities. You may autogenerate these using: --add-cpes-if-none
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
busybox 1.34.1-r7 apk CVE-2022-48174 Critical
github.com/dgrijalva/jwt-go v3.2.0+incompatible go-module GHSA-w73w-5m7g-f7qc High
golang.org/x/crypto v0.16.0 0.17.0 go-module GHSA-45x7-px36-x8w8 Medium
k8s.io/client-go v0.18.2 0.18.14 go-module GHSA-8cfg-vx93-jvxw Medium
ssl_client 1.34.1-r7 apk CVE-2022-48174 Critical

On retrouve les mêmes que celles remontées par trivy. Donc plutôt rassurant. Comme pour trivy il est possible de l’exécuter sur un répertoire. Par exemple sur le même dossier que précédemment :

Terminal window
grype dir:./
Indexed file system .
Vulnerability DB [no update available]
Scanned for vulnerabilities [13 vulnerability matches]
├── by severity: 2 critical, 6 high, 5 medium, 0 low, 0 negligible
└── by status: 13 fixed, 0 not-fixed, 0 ignored
[0000] WARN no explicit name and version provided for directory source, deriving artifact ID from the given path (which is not ideal)
[0006] WARN some package(s) are missing CPEs. This may result in missing vulnerabilities. You may autogenerate these using: --add-cpes-if-none
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
@babel/traverse 7.22.20 7.23.2 npm GHSA-67hx-6x53-jw92 Critical
axios 0.25.0 1.6.0 npm GHSA-wf5p-g6vw-rhxx Medium
git 1.2.5 1.11.0 gem GHSA-69p6-wvmq-27gg Critical
git 1.2.5 1.13.0 gem GHSA-pphf-gfrm-v32r High
git 1.2.5 1.13.0 gem GHSA-pfpr-3463-c6jh High
got 9.6.0 11.8.5 npm GHSA-pfrx-2q88-qq97 Medium
json 1.7.4 1.7.7 gem GHSA-x457-cw4h-hq5f High
json 1.7.4 2.3.0 gem GHSA-jphg-qwrw-7w9g High
postcss 8.4.30 8.4.31 npm GHSA-7fh5-64p2-3v2j Medium
rake 0.9.2.2 12.3.3 gem GHSA-jppv-gw3r-w3q8 Medium
rdoc 3.12 6.1.2.1 gem GHSA-ggxm-pgc9-g7fp High
rdoc 3.12 3.12.1 gem GHSA-v2r9-c84j-v7xm Medium
trim 0.0.1 0.0.3 npm GHSA-w5p7-h5w8-2hfq High

Grype prend en argument les sources suivantes :

Terminal window
grype podman:yourrepo/yourimage:tag explicitly use the Podman daemon
grype docker:yourrepo/yourimage:tag explicitly use the Docker daemon
grype docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
grype oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Podman or otherwise)
grype oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
grype singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
grype dir:path/to/yourproject read directly from a path on disk (any directory)
grype sbom:path/to/syft.json read Syft JSON from path on disk
grype registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
grype purl:path/to/purl/file read a newline separated file of purls from a path on disk

Obtenir des informations sur les vulnérabilités

Grype possède une fonction explain qui permet d’approfondir la compréhension des vulnérabilités identifiées lors des scans.

Lorsque vous exécutez la commande explain, Grype fournit une sortie détaillée, qui comprend :

  • Origine de la Vulnérabilité : D’où vient la vulnérabilité et comment elle a été introduite dans l’image.
  • Chemin de Dépendance : Montre comment le paquet vulnérable est lié à d’autres composants de l’image.
  • Détails de la Vulnérabilité : Fournit des informations sur la nature de la vulnérabilité, sa sévérité et, si disponible, des liens vers des sources externes pour plus d’informations.
  • Recommandations de Correction : Des suggestions sur la manière de résoudre ou de mitiger la vulnérabilité.

Exemple : attention à bien mettre -o json en sortie de l’analyse

Terminal window
grype dkron/dkron -o json | grype explain --id GHSA-w73w-5m7g-f7qc
Vulnerability DB [no update available]
Loaded image dkron/dkron:latest
Parsed image sha256:43f45ba9495628b1a66bfdf9bdfde7b85660a46e9975f9fbd9ea737dbf914822
Scanned for vulnerabilities [8 vulnerability matches]
├── by severity: 2 critical, 1 high, 5 medium, 0 low, 0 negligible
└── by status: 5 fixed, 3 not-fixed, 0 ignored
[0001] WARN some package(s) are missing CPEs. This may result in missing vulnerabilities. You may autogenerate these using: --add-cpes-if-none
GHSA-w73w-5m7g-f7qc from github:language:go (High)
Authorization bypass in github.com/dgrijalva/jwt-go
Related vulnerabilities:
- nvd:cpe CVE-2020-26160 (High)
Matched packages:
- Package: github.com/dgrijalva/jwt-go, version: v3.2.0+incompatible
PURL: pkg:golang/github.com/dgrijalva/jwt-go@v3.2.0+incompatible
Match explanation(s):
- github:language:go:GHSA-w73w-5m7g-f7qc Direct match (package name, version, and ecosystem) against github.com/dgrijalva/jwt-go (version v3.2.0+incompatible).
Locations:
- /usr/local/bin/dkron
URLs:
- https://github.com/advisories/GHSA-w73w-5m7g-f7qc
- https://nvd.nist.gov/vuln/detail/CVE-2020-26160

Choix du format de sortie

Grype peut produire ces types de fichiers :

  • table: Un résumé en colonnes (par défaut).
  • cyclonedx: Un rapport XML conforme à la spécification CycloneDX 1.4 .
  • cyclonedx-json: Un rapport JSON conforme à la spécification CycloneDX 1.4 .
  • json: Utilisez-le pour obtenir autant d’informations que possible sur Grype !
  • template: Permet à l’utilisateur de spécifier le format de sortie.

Fixer le niveau pour produire une erreur

Vous pouvez faire en sorte que Grype se termine avec une erreur si des vulnérabilités sont signalées au niveau ou au-dessus du niveau de gravité spécifié. Cela s’avère pratique lorsque vous utilisez Grype dans un script ou un pipeline CI. Pour ce faire, utilisez l’option suivante :

Terminal window
grype ubuntu:latest --fail-on medium
Vulnerability DB [no update available]
Pulled image
Loaded image ubuntu:latest
Parsed image sha256:174c8c134b2a94b5bb0b37d9a2b6ba0663d82d23ebf62bd51f74a2fd457333da
Scan for vulnerabilities [13 vulnerability matches]
├── by severity: 0 critical, 0 high, 1 medium, 9 low, 3 negligible
└── by status: 0 fixed, 13 not-fixed, 0 ignored
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
bash 5.1-6ubuntu1 deb CVE-2022-3715 Low
coreutils 8.32-4.1ubuntu1 deb CVE-2016-2781 Low
gcc-12-base 12.3.0-1ubuntu1~22.04 deb CVE-2022-27943 Low
gpgv 2.2.27-3ubuntu2.1 deb CVE-2022-3219 Low
libc-bin 2.35-0ubuntu3.5 deb CVE-2016-20013 Negligible
libc6 2.35-0ubuntu3.5 deb CVE-2016-20013 Negligible
libgcc-s1 12.3.0-1ubuntu1~22.04 deb CVE-2022-27943 Low
liblzma5 5.2.5-2ubuntu1 deb CVE-2020-22916 Medium
libpcre3 2:8.39-13ubuntu0.22.04.1 deb CVE-2017-11164 Negligible
libstdc++6 12.3.0-1ubuntu1~22.04 deb CVE-2022-27943 Low
libzstd1 1.4.8+dfsg-3build1 deb CVE-2022-4899 Low
login 1:4.8.1-2ubuntu2.1 deb CVE-2023-29383 Low
passwd 1:4.8.1-2ubuntu2.1 deb CVE-2023-29383 Low
1 error occurred:
* discovered vulnerabilities at or above the severity threshold

Configuration de Grype

Pour configurer grype, on peut utiliser un fichier de configuration. Voici l’ensemble des paramètres que vous pouvez y mettre :

log:
# suppress all logging output (env: GRYPE_LOG_QUIET)
quiet: false
# increase verbosity (-v = info, -vv = debug) (env: GRYPE_LOG_VERBOSITY)
verbosity: 0
# explicitly set the logging level (available: [error warn info debug trace]) (env: GRYPE_LOG_LEVEL)
level: warn
# file path to write logs to (env: GRYPE_LOG_FILE)
file: ''
dev:
# capture resource profiling data (available: [cpu, mem]) (env: GRYPE_DEV_PROFILE)
profile: none
# report output formatter, formats=[json table cyclonedx cyclonedx-json sarif template], deprecated formats=[embedded-cyclonedx-vex-json embedded-cyclonedx-vex-xml] (env: GRYPE_OUTPUT)
output: []
# file to write the default report output to (default is STDOUT) (env: GRYPE_FILE)
file: ''
# distro to match against in the format: <distro>:<version> (env: GRYPE_DISTRO)
distro: ''
# generate CPEs for packages with no CPE data (env: GRYPE_ADD_CPES_IF_NONE)
add-cpes-if-none: false
# specify the path to a Go template file (requires 'template' output to be selected) (env: GRYPE_OUTPUT_TEMPLATE_FILE)
output-template-file: ''
# (env: GRYPE_CHECK_FOR_APP_UPDATE)
check-for-app-update: true
# ignore matches for vulnerabilities that are not fixed (env: GRYPE_ONLY_FIXED)
only-fixed: false
# ignore matches for vulnerabilities that are fixed (env: GRYPE_ONLY_NOTFIXED)
only-notfixed: false
# ignore matches for vulnerabilities with specified comma separated fix states, options=[fixed not-fixed unknown wont-fix] (env: GRYPE_IGNORE_WONTFIX)
ignore-wontfix: ''
# an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux') (env: GRYPE_PLATFORM)
platform: ''
search:
# selection of layers to analyze, options=[squashed all-layers] (env: GRYPE_SEARCH_SCOPE)
scope: 'squashed'
# (env: GRYPE_SEARCH_UNINDEXED_ARCHIVES)
unindexed-archives: false
# (env: GRYPE_SEARCH_INDEXED_ARCHIVES)
indexed-archives: true
ignore: []
# exclude paths from being scanned using a glob expression (env: GRYPE_EXCLUDE)
exclude: []
db:
# (env: GRYPE_DB_CACHE_DIR)
cache-dir: '/home/bob/.cache/grype/db'
# (env: GRYPE_DB_UPDATE_URL)
update-url: 'https://toolbox-data.anchore.io/grype/databases/listing.json'
# (env: GRYPE_DB_CA_CERT)
ca-cert: ''
# (env: GRYPE_DB_AUTO_UPDATE)
auto-update: true
# (env: GRYPE_DB_VALIDATE_BY_HASH_ON_START)
validate-by-hash-on-start: false
# (env: GRYPE_DB_VALIDATE_AGE)
validate-age: true
# (env: GRYPE_DB_MAX_ALLOWED_BUILT_AGE)
max-allowed-built-age: 120h0m0s
external-sources:
# (env: GRYPE_EXTERNAL_SOURCES_ENABLE)
enable: false
maven:
# (env: GRYPE_EXTERNAL_SOURCES_MAVEN_SEARCH_MAVEN_UPSTREAM)
search-maven-upstream: true
# (env: GRYPE_EXTERNAL_SOURCES_MAVEN_BASE_URL)
base-url: 'https://search.maven.org/solrsearch/select'
match:
java:
# (env: GRYPE_MATCH_JAVA_USING_CPES)
using-cpes: false
dotnet:
# (env: GRYPE_MATCH_DOTNET_USING_CPES)
using-cpes: false
golang:
# (env: GRYPE_MATCH_GOLANG_USING_CPES)
using-cpes: false
# (env: GRYPE_MATCH_GOLANG_ALWAYS_USE_CPE_FOR_STDLIB)
always-use-cpe-for-stdlib: true
javascript:
# (env: GRYPE_MATCH_JAVASCRIPT_USING_CPES)
using-cpes: false
python:
# (env: GRYPE_MATCH_PYTHON_USING_CPES)
using-cpes: false
ruby:
# (env: GRYPE_MATCH_RUBY_USING_CPES)
using-cpes: false
rust:
# (env: GRYPE_MATCH_RUST_USING_CPES)
using-cpes: false
stock:
# (env: GRYPE_MATCH_STOCK_USING_CPES)
using-cpes: true
# set the return code to 1 if a vulnerability is found with a severity >= the given severity, options=[negligible low medium high critical] (env: GRYPE_FAIL_ON_SEVERITY)
fail-on-severity: ''
registry:
# (env: GRYPE_REGISTRY_INSECURE_SKIP_TLS_VERIFY)
insecure-skip-tls-verify: false
# (env: GRYPE_REGISTRY_INSECURE_USE_HTTP)
insecure-use-http: false
auth: []
# (env: GRYPE_REGISTRY_CA_CERT)
ca-cert: ''
# show suppressed/ignored vulnerabilities in the output (only supported with table output format) (env: GRYPE_SHOW_SUPPRESSED)
show-suppressed: false
# orient results by CVE instead of the original vulnerability ID when possible (env: GRYPE_BY_CVE)
by-cve: false
# set the name of the target being analyzed (env: GRYPE_NAME)
name: ''
# (env: GRYPE_DEFAULT_IMAGE_PULL_SOURCE)
default-image-pull-source: ''
# a list of VEX documents to consider when producing scanning results (env: GRYPE_VEX_DOCUMENTS)
vex-documents: []
# (env: GRYPE_VEX_ADD)
vex-add: []
# delete downloaded databases after diff occurs (env: GRYPE_DELETE)
delete: false
# CVE IDs to explain (env: GRYPE_CVE_IDS)
cve-ids: []

Lors de son lancement Grype vérifie la présence d’un fichier de configuration correspond à ces chemins :

  • .grype.yaml
  • .grype/config.yaml
  • ${HOME}/.grype.yaml
  • ${HOME}/.config/grype/config.yaml
  • /etc/xdg/grype/config.yaml

Gestion de la DB

Il est utile de vérifier le statut de la base de données de Grype, surtout pour confirmer que les mises à jour ont été correctement appliquées. La commande suivante vous donne des informations sur la version actuelle de la base de données et la date de la dernière mise à jour :

Terminal window
grype db status
Location: /home/bob/.cache/grype/db/5
Built: 2024-01-03 01:26:16 +0000 UTC
Schema: 5
Checksum: sha256:29fb5bb2796844c92e21ed1753d9b2c4c11cf1a0a905c3e3de4e5b4aad3c71db
Status: valid

Grype vérifie régulièrement les mises à jour, mais vous pouvez exécuter manuellement cette commande pour vous assurer que vous utilisez les données les plus récentes.

Terminal window
grype db update
Vulnerability DB [no update available]
No vulnerability database update available

Intégration Outils CI/CD

L’intégration de Grype dans votre pipeline CI/CD (Continuous Integration/Continuous Deployment) est une étape importante pour automatiser la détection des vulnérabilités dans vos images de conteneurs. Cette intégration assure une évaluation continue et automatique des vulnérabilités, contribuant ainsi à une meilleure sécurité des applications.

Si vous utilisez déjà Trivy, vous pouvez l’intégrer en parralèle.

Conclusion

Grype se distingue par sa simplicité d’utilisation, sa capacité à s’intégrer facilement dans les pipelines CI/CD et sa mise à jour régulière de la base de données de vulnérabilités. Ces caractéristiques en font un outil indispensable pour les consultants DevOps qui souhaitent assurer une surveillance proactive des vulnérabilités.

En conclusion, je recommande fortement d’adopter Grype comme une composante clé de votre arsenal DevOps. Son utilisation régulière et son intégration dans vos processus de développement et de déploiement aideront à garantir que vos applications restent sécurisées et à jour face aux menaces de sécurité émergentes.

Plus d’infos