docker images mit clair auf bekannte CVEs prüfen

Datum

Clair is an open source project for the static analysis of vulnerabilities in appc and docker containers.

Quelle: Clair 2.0.1 Documentation

Github-Page: coreos/clair
quay.io: coreos / clair

clair ist in der Lage docker Images zu scannen und zu prüfen ob CVEs für das betreffende Image zutreffen. Dabei werden auch die „Zwischenimages“ geprüft.

Aufbau
Ich habe versucht zu verstehen, wie clair genau arbeitet, leider ist die offizielle Dokumentation dazu sehr dürftig. Grundsätzlich besteht clair aus 3 Komponenten:
  • Postgres-DB —> dient zum speichern der (meta)daten
  • clair-server —> stellt REST-API zur Verfügung; kommuniziert mit der Postgres-DB; aktualisiert die CVE-(meta)daten
  • clair-client —> wird zum prüfen der Images aufgerufen; kommuniziert mit dem clair-server

Die Komponenten müssen nicht zwangsläufig auf dem gleichen System laufen, ich habe das nur aus Gründen der Einfachheit so eingerichtet.
Des weiteren kann man das prüfen per clair auch in eine CI-Pipeline einbauen und somit gleich nach der Erstellung eines neuen images dieses auf Schwachstellen hin überprüfen.

Erstellen der clair-client Binärdatei

Um den clair-client zu kompilieren benötigt man einen go-Interpreter und das Go dependency management tool ‚dep‘.

Wenn diese beiden Voraussetzungen erfüllt sind, lauten die durchzuführenden Schritte wie folgt:
Erstellen des clair-server und Postgres-DB

Ich verwende sowohl für den clair-server als auch für die Postgres-DB jeweils einen docker container und diese lasse ich mir per docker-compose erstellen. Dazu verwende ich die folgende docker-compose.yml:

version: '2'
services:
  postgres:
    container_name: clair_postgres
    image: docker.io/postgres
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: password
    networks:
      - clair_net

  clair:
    container_name: clair_clair
    image: quay.io/coreos/clair:latest
    restart: unless-stopped
    depends_on:
      - postgres
    networks:
      - clair_net
    ports:
      - "4660-4661:6060-6061"
    links:
      - postgres
    volumes:
      - /storage/data/clair/tmp:/tmp
      - /storage/data/clair/config:/config
    command: [-config, /config/config.yaml]

networks:
  clair_net:
    external:
      name: clair_net

Hierbei wird als erstes das Postgres-docker-Image geladen und als Passwort für die DB wird password gesetzt und der Postgres-container ist Voraussetzung für den clair-server-container.
Beim clair-server-container werden die Ports angepasst (kann man bei Bedarf auch weglassen) und es wird zum einen ein /tmp und das entsprechende config Verzeichnis gemountet.

die clair-server config

hier mal die config.yaml welche beim clair-server container verwendet wird, welche entsprechend abgelegt werden muss und in den clair-server container eingebunden wird:

# The values specified here are the default values that Clair uses if no configuration file is specified or if the keys are not defined.
clair:
  database:
    # Database driver
    type: pgsql
    options:
      # PostgreSQL Connection string
      # https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
      # postgresql://postgres:password@postgres:5432?sslmode=disable
      source: host=postgres port=5432 user=postgres password=password sslmode=disable statement_timeout=60000

      # Number of elements kept in the cache
      # Values unlikely to change (e.g. namespaces) are cached in order to save prevent needless roundtrips to the database.
      cachesize: 16384

      # 32-bit URL-safe base64 key used to encrypt pagination tokens
      # If one is not provided, it will be generated.
      # Multiple clair instances in the same cluster need the same value.
      paginationkey:

  api:
    # v3 grpc/RESTful API server address
    addr: "0.0.0.0:6060"

    # Health server address
    # This is an unencrypted endpoint useful for load balancers to check to healthiness of the clair server.
    healthaddr: "0.0.0.0:6061"

    # Deadline before an API request will respond with a 503
    timeout: 900s

    # Optional PKI configuration
    # If you want to easily generate client certificates and CAs, try the following projects:
    # https://github.com/coreos/etcd-ca
    # https://github.com/cloudflare/cfssl
    servername:
    cafile:
    keyfile:
    certfile:

  updater:
    # Frequency the database will be updated with vulnerabilities from the default data sources
    # The value 0 disables the updater entirely.
    interval: 2h
    enabledupdaters:
      - rhel
      - alpine

  notifier:
    # Number of attempts before the notification is marked as failed to be sent
    attempts: 3

    # Duration before a failed notification is retried
    renotifyinterval: 2h

    http:
      # Optional endpoint that will receive notifications via POST requests
      endpoint:

      # Optional PKI configuration
      # If you want to easily generate client certificates and CAs, try the following projects:
      # https://github.com/cloudflare/cfssl
      # https://github.com/coreos/etcd-ca
      servername:
      cafile:
      keyfile:
      certfile:

      # Optional HTTP Proxy: must be a valid URL (including the scheme).
      proxy:

Auch hierbei sollte man sich die config.yaml entsprechend anpassen. Zu beachten ist hierbei auch der Punkt enabledupdaters, hierbei werden die Images angegeben für die die (meta)daten regelmäßig aktualisiert werden.

clair-server starten

Nach einem docker-compose up -d sollten die container entsprechend gebaut und gestartet werden.
Wenn alles geklappt hat, sollte der clair-server direkt nach dem starten damit beginnen seine (meta)daten zu aktualisieren:

clair zum prüfen von docker images verwenden

Grundsätzliche hat clair folgende Optionen:

Usage: clair-scanner [OPTIONS] IMAGE

Scan local Docker images for vulnerabilities with Clair

Arguments:
  IMAGE=""     Name of the Docker image to scan

Options:
  -w, --whitelist=""                    Path to the whitelist file
  -t, --threshold="Unknown"             CVE severity threshold. Valid values; 'Defcon1', 'Critical', 'High', 'Medium', 'Low', 'Negligible', 'Unknown'
  -c, --clair="http://127.0.0.1:6060"   Clair URL
  --ip="localhost"                      IP address where clair-scanner is running on
  -l, --log=""                          Log to a file
  --all, --reportAll=true               Display all vulnerabilities, even if they are approved
  -r, --report=""                       Report output file, as JSON
  --exit-when-no-features=false         

Der Aufruf zum prüfen eines docker Images, welches auf dem gleichen System wie der clair-client, clair-server und die Postgres-DB läuft, lautet wie folgt:

clair-scanner -c http://<IP vom clair-server>:<eingestellter Port der API> --ip <IP vom clair-server> <das zu prüfende Image>

Beispiel:

Whitelist

Wenn man die angezeigten CVEs geprüft hat und meint das diesen den Betrieb nicht negativ beeinflussen, kann man diese auch in eine Whitelist eintragen.
Damit wird diese Schwachstelle bei einem erneuten Scan nicht noch einmal ausgegeben.

Hierfür legt man sich einen whitelist mit dem Namen clair-whitelist.yml an und trägt dort entsprechend die Ausnahmen ein:

generalwhitelist:
    RHSA-2019:0679: libssh2

Damit die whitelist beim prüfen durch clair auch beachtet wird, wird diese beim Aufruf per -w Parameter angegeben.

Beispiel: clair-scanner -c http://<IP vom clair-server>:<eingestellter Port der API> -w clair-whitelist.yml --ip <IP vom clair-server> <das zu prüfende Image>

Autor
Kategorien container, docker

PRTG Map