Aller au contenu principal

Scanner les vulnérabilités de conteneurs avec grype

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 :

asdf plugin add grype
asdf install grype latest
asdf global grype latest

Sur Macos

L'installation sur macOS se fait avec brew :

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 :

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 :

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 :

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 :

    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

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 :

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 :

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.

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.

attention

Attention, si vous utilisez un système de cache dans vous outils de CI/CD, pensez à mettre à jour souvent la base de données, ainsi que la version de Grype.

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