Skip to main content

Container-Image-Formate im Detail

Artikel von
Headshot of Agata Krajewska

Agata Krajewska

18. November 2020

0 Min. Lesezeit

In den letzten Jahren sind Container nach der Veröffentlichung von Docker immer mehr zum Standard für die Bereitstellung von Software geworden.

Wir beobachten eine zunehmende Zahl containerbasierter Lösungen. Innovationen in diesem Bereich sind natürlich willkommen, zugleich müssen jedoch bestimmte Standards für Format und Laufzeit festgelegt werden.

Durch das rasante Wachstum des Docker-Projekts wurden Docker-Images für viele Zwecke zum Standard. Gleichzeitig besteht großes Interesse an einer einheitlichen, offenen Container-Spezifikation, die:

  • nicht an übergeordnete Konstrukte wie einen bestimmten Client oder Orchestrierungs-Stack gebunden ist,

  • nicht eng mit einem bestimmten kommerziellen Anbieter oder Projekt verbunden ist,

  • auf einer Vielzahl von Betriebssystemen, Hardware, CPU-Architekturen, Public Clouds usw. portierbar ist.

OCI (Open Container Initiative) ist ein Projekt der Linux Foundation zur Entwicklung offener Standards für die Virtualisierung auf Betriebssystemebene, insbesondere für Linux-Container.

Docker hat der OCI sowohl einen Entwurf für eine Spezifikation des Basisformats und der Laufzeit als auch den Code einer Referenzimplementierung dieser Spezifikation zur Verfügung gestellt.

Verschiedene Open-Source-Build-Tools unterstützen inzwischen das OCI-Image-Format, darunter:

  • BuildKit: eine optimierte Neuentwicklung der Docker-Build-Engine

  • Podman: eine alternative Implementierung des Docker-Kommandozeilen-Tools

  • Buildah: eine Kommandozeilen-Alternative zum Schreiben von Dockerfiles

Snyk unterstützt alle gängigen Container-Image-Formate. Dadurch können wir Integrationen mit einer Vielzahl von Tools aus dem gesamten Ökosystem anbieten. In diesem Blogbeitrag sehen wir uns einige davon an und zeigen, wie Snyk mit ihnen funktioniert.

Docker-Archiv

Sehen wir uns zunächst das Docker-Archivformat an. Es gehört zur veralteten v1 der Docker-Image-Spezifikation. Die vollständige Spezifikation finden Sie hier. Wenn Sie docker save ausführen, gibt der Docker-Client standardmäßig dieses Format aus, das aus Gründen der Abwärtskompatibilität mit anderen Tools verwendet wird. Container-Registries verwenden zum Speichern der Images ein neueres Format.

Wenn Sie Docker lokal ausführen und die Snyk CLI oder eine unserer Container-Integrationen verwenden, nutzen wir Ihre lokale Docker-Instanz, um das Image abzurufen, im Dateisystem zu speichern und die Analyse zu starten.

Sehen wir uns an, wie dieses Archiv aussieht und welche Inhalte für Snyk interessant sind.

In diesem Beitrag verwende ich das Image ubuntu:bionic. Speichern wir zunächst das Archiv in Ihrem lokalen Dateisystem:

docker save --output ubuntu-docker.tar ubuntu:bionic

Die Distribution bionic umfasst drei Image-Layer, die wir uns genauer ansehen.

Nachdem wir das tar-Archiv entpackt haben, können wir den Inhalt untersuchen:

[ubuntu-docker] ll                                                                                                               
total 24
drwxr-xr-x  5 agatakrajewska  staff   160B 25 Sep 23:33 46076a325f0de3f745254638b8b0f0de343685b34e7ca6ec5cd0b6b7930eb7fa
drwxr-xr-x  5 agatakrajewska  staff   160B 25 Sep 23:33 468327b5cd7ce539db695bd0ef05dae8a4ff77b02870a8e823ed74dedad4bd55
-rw-r--r--  1 agatakrajewska  staff   3.3K 25 Sep 23:33 56def654ec22f857f480cdcc640c474e2f84d4be2e549a9d16eaba3f397596e9.json
drwxr-xr-x  5 agatakrajewska  staff   160B 25 Sep 23:33 8bf067b107a6f7444876e33c6ed85652355f679ac98ebab97ab3ebad63f0dff3
-rw-r--r--  1 agatakrajewska  staff   356B  1 Jan  1970 manifest.json
-rw-r--r--  1 agatakrajewska  staff    89B  1 Jan  1970 repositories

Sehen wir uns manifest.json an:

[ubuntu-docker] cat manifest.json | jq                                                                                           
[
  {
    "Config": "56def654ec22f857f480cdcc640c474e2f84d4be2e549a9d16eaba3f397596e9.json",
    "RepoTags": [
      "ubuntu:bionic"
    ],
    "Layers": [
      "8bf067b107a6f7444876e33c6ed85652355f679ac98ebab97ab3ebad63f0dff3/layer.tar",
      "468327b5cd7ce539db695bd0ef05dae8a4ff77b02870a8e823ed74dedad4bd55/layer.tar",
      "46076a325f0de3f745254638b8b0f0de343685b34e7ca6ec5cd0b6b7930eb7fa/layer.tar"
    ]
  }
]

Die Datei verweist auf die Container-Konfiguration, in der wir nützliche Informationen wie Architektur, Konfiguration und Root-Dateisystem-Layer finden. Besonders interessant für Snyk ist die Eigenschaft Layers: Sie verweist auf die eigentlichen Image-Layer, also Verzeichnisse im Archiv. Wechseln wir in eines dieser Verzeichnisse, sehen wir, was es enthält:

[8bf067b107a6f7444876e33c6ed85652355f679ac98ebab97ab3ebad63f0dff3] ll                                                            
total 128160
-rw-r--r--  1 agatakrajewska  staff     3B 25 Sep 23:33 VERSION
-rw-r--r--  1 agatakrajewska  staff   401B 25 Sep 23:33 json
-rw-r--r--  1 agatakrajewska  staff    63M 25 Sep 23:33 layer.tar

Sehen wir uns den Inhalt genauer an und entpacken das layer.tar-Archiv:

[layer] ll                                                                                                                       
total 0
drwxr-xr-x  87 agatakrajewska  staff   2.7K 21 Sep 18:17 bin
drwxr-xr-x   2 agatakrajewska  staff    64B 24 Apr  2018 boot
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:17 dev
drwxr-xr-x  68 agatakrajewska  staff   2.1K 21 Sep 18:17 etc
drwxr-xr-x   2 agatakrajewska  staff    64B 24 Apr  2018 home
drwxr-xr-x   8 agatakrajewska  staff   256B 23 May  2017 lib
drwxr-xr-x   3 agatakrajewska  staff    96B 21 Sep 18:16 lib64
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:14 media
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:14 mnt
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:14 opt
drwxr-xr-x   2 agatakrajewska  staff    64B 24 Apr  2018 proc
drwx------   4 agatakrajewska  staff   128B 21 Sep 18:17 root
drwxr-xr-x   5 agatakrajewska  staff   160B 21 Sep 18:14 run
drwxr-xr-x  68 agatakrajewska  staff   2.1K 21 Sep 18:17 sbin
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:14 srv
drwxr-xr-x   2 agatakrajewska  staff    64B 24 Apr  2018 sys
drwxrwxrwt   2 agatakrajewska  staff    64B 21 Sep 18:17 tmp
drwxr-xr-x  10 agatakrajewska  staff   320B 21 Sep 18:14 usr
drwxr-xr-x  13 agatakrajewska  staff   416B 21 Sep 18:17 var

Wie Sie oben sehen, enthält das layer.tar-Archiv lediglich die Änderungen am Dateisystem des Image-Layers sowie – je nach Image-Inhalt – alle Abhängigkeiten und sonstigen Binärdateien. Nachdem wir den Inhalt extrahiert und analysiert haben,

können wir Ihnen die Liste der anfälligen Pfade anzeigen.

Testen wir nun das gespeicherte Docker-Archiv-Image mit snyk test. Ein lokales Archiv können wir testen, indem wir das Präfix docker-archive: angeben:

snyk container test docker-archive:ubuntu-docker.tar oder scannen Sie das Image aus Ihrem lokalen Docker-Repository:

snyk container test ubuntu:bionic

Beide Befehle liefern genau dieselbe Ausgabe:

Testing ubuntu:bionic...

✗ Low severity vulnerability found in tar
  Description: Loop with Unreachable Exit Condition ('Infinite Loop')
  Info: <https://snyk.io/vuln/SNYK-UBUNTU1804-TAR-312298>
  Introduced through: tar@1.29b-2ubuntu0.1, pam/libpam-runtime@1.1.8-3.6ubuntu2.18.04.2
  From: tar@1.29b-2ubuntu0.1
  From: pam/libpam-runtime@1.1.8-3.6ubuntu2.18.04.2 > debconf@1.5.66ubuntu1 > perl/perl-base@5.26.1-6ubuntu0.3 > dpkg@1.19.0.5ubuntu2.3 > tar@1.29b-2ubuntu0.1

✗ Low severity vulnerability found in tar
  Description: NULL Pointer Dereference
  Info: <https://snyk.io/vuln/SNYK-UBUNTU1804-TAR-559435>
  Introduced through: tar@1.29b-2ubuntu0.1, pam/libpam-runtime@1.1.8-3.6ubuntu2.18.04.2
  From: tar@1.29b-2ubuntu0.1
  From: pam/libpam-runtime@1.1.8-3.6ubuntu2.18.04.2 > debconf@1.5.66ubuntu1 > perl/perl-base@5.26.1-6ubuntu0.3 > dpkg@1.19.0.5ubuntu2.3 > tar@1.29b-2ubuntu0.1

# vuln list continues in here
...

Organization:      example-org
Package manager:   deb
Project name:      docker-image|ubuntu
Docker image:      ubuntu:bionic
Licenses:          enabled

Tested 90 dependencies for known issues, found 31 issues.

Pro tip: use `--file` option to get base image remediation advice.
Example: $ snyk test --docker ubuntu:bionic --file=path/to/Dockerfile

OCI-Image

In den letzten Monaten haben wir das Scannen von OCI-Archiven als Funktion in die Snyk CLI aufgenommen.

Sehen wir uns nun die Spezifikation und den Inhalt des Archivs an. Auch in diesem Abschnitt verwende ich ubuntu:bionic.

Wenn Sie selbst ein OCI-Archiv-Tarball untersuchen möchten, können Sie folgenden Befehl ausführen:

skopeo copy --override-os linux docker://ubuntu:bionic oci-archive:ubuntu.tar

Zum Speichern des Images verwende ich hier Skopeo. Das cli-Dienstprogramm erleichtert verschiedene Vorgänge mit Images erheblich.

Um ein ubuntu-Image im OCI-Format zu speichern, müssen wir lediglich das Präfix oci-archive: für die tar-Ausgabe angeben.

Beachten Sie, dass ich außerdem das Flag --override-os verwende: Ich arbeite mit macOS, und offizielle Docker Hub ubuntu images sind nur für Linux verfügbar. Auf Images mit mehreren Architekturen gehen wir weiter unten ebenfalls ein.

Sobald wir das tar-Archiv entpackt haben, können wir den Inhalt untersuchen:

[ubuntu] ll                                                                                                                      
total 16
drwxr-xr-x  3 agatakrajewska  staff    96B 28 Oct 11:18 blobs
-rw-r--r--  1 agatakrajewska  staff   186B 28 Oct 11:18 index.json
-rw-r--r--  1 agatakrajewska  staff    31B 28 Oct 11:18 oci-layout

Im Stammverzeichnis befindet sich eine interessante Datei namens index.json. Sehen wir uns ihren Inhalt an:

[ubuntu] cat index.json | jq                                                                                                     
{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:afa93a8ce255ca452ca8c88f4b5c821a466cf0a3e0148a31d0d97dfdb91d9aef",
      "size": 658
    }
  ]
}

Dies ist unser optionales Manifest der höheren Ebene. Es verweist auf bestimmte Image-Manifeste und enthält Informationen zu einer Gruppe von Images, die verschiedene Architekturen und Betriebssysteme umfassen können. Weitere Informationen finden Sie in der vollständigen Spezifikation.

Sehen wir uns nun das spezifische Image-Manifest an, auf das index.json im Verzeichnis blobs/sha256 verweist:

[sha256] cat afa93a8ce255ca452ca8c88f4b5c821a466cf0a3e0148a31d0d97dfdb91d9aef | jq                                               
{
  "schemaVersion": 2,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "digest": "sha256:33a51d09088285451e7a7525d4bd64fc15563264afe5a91ef84a8b3042018899",
    "size": 2426
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:171857c49d0f5e2ebf623e6cb36a8bcad585ed0c2aa99c87a055df034c1e5848",
      "size": 26701612
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:419640447d267f068d2f84a093cb13a56ce77e130877f5b8bdb4294f4a90a84f",
      "size": 852
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:61e52f862619ab016d3bcfbd78e5c7aaaa1989b4c295e6dbcacddd2d7b93e1f5",
      "size": 162
    }
  ]
}

Hier finden wir interessante Inhalte wie die Container-Konfiguration mit vielen nützlichen Informationen zur Image-Architektur, den Basis-Image-Layern, der Konfiguration usw. Außerdem erhalten wir Informationen zu den Image-Layern, die in unserem Image ubuntu:bionic vorhanden sind.

Wie unten zu sehen ist, entspricht der Inhalt des ersten Layers genau dem des Docker-Archivs oben.

[171857c49d0f5e2ebf623e6cb36a8bcad585ed0c2aa99c87a055df034c1e5848] ll                                                            
total 0
drwxr-xr-x  87 agatakrajewska  staff   2.7K 21 Sep 18:17 bin
drwxr-xr-x   2 agatakrajewska  staff    64B 24 Apr  2018 boot
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:17 dev
drwxr-xr-x  68 agatakrajewska  staff   2.1K 21 Sep 18:17 etc
drwxr-xr-x   2 agatakrajewska  staff    64B 24 Apr  2018 home
drwxr-xr-x   8 agatakrajewska  staff   256B 23 May  2017 lib
drwxr-xr-x   3 agatakrajewska  staff    96B 21 Sep 18:16 lib64
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:14 media
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:14 mnt
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:14 opt
drwxr-xr-x   2 agatakrajewska  staff    64B 24 Apr  2018 proc
drwx------   4 agatakrajewska  staff   128B 21 Sep 18:17 root
drwxr-xr-x   5 agatakrajewska  staff   160B 21 Sep 18:14 run
drwxr-xr-x  68 agatakrajewska  staff   2.1K 21 Sep 18:17 sbin
drwxr-xr-x   2 agatakrajewska  staff    64B 21 Sep 18:14 srv
drwxr-xr-x   2 agatakrajewska  staff    64B 24 Apr  2018 sys
drwxrwxrwt   2 agatakrajewska  staff    64B 21 Sep 18:17 tmp
drwxr-xr-x  10 agatakrajewska  staff   320B 21 Sep 18:14 usr
drwxr-xr-x  13 agatakrajewska  staff   416B 21 Sep 18:17 var

Sie können Ihr lokales OCI-Archiv mit folgendem Befehl scannen:

snyk container test oci-archive:ubuntu.tar

Verschiedene Plattformen und Architekturen

Bei der Untersuchung der Docker-Archiv- und OCI-Image-Manifeste ist uns aufgefallen, dass beide Informationen zur Architektur enthalten. Werfen wir noch einmal einen Blick auf den Inhalt des Container-Konfigurationsmanifests im Verzeichnis ubuntu-docker, in dem wir unser docker archive gespeichert haben:

[sha256] cat 56def654ec22f857f480cdcc640c474e2f84d4be2e549a9d16eaba3f397596e9.json | jq
{
  ...
  "architecture": "amd64",
  "os": "linux",
  ...
}

Neben anderen Angaben sehen wir Architektur und Betriebssystem. In meinem Fall sind das amd64 und linux. Was aber, wenn unser Image auf arm64 basiert oder wir mit der Plattform windows arbeiten?

Zum Glück unterstützt Snyk auch andere Plattformen. Dazu übergeben Sie der Snyk CLI das Flag -—platform.

Wir haben uns das Archivformat von docker save angesehen. Werfen wir nun einen Blick auf das Format, in dem Images in Docker Hub gespeichert werden: das v2-Schema, das unter der Oberfläche sehr interessant ist. Diese zweite Version des v2-Schemas wurde für zwei Hauptziele entwickelt. Laut der Docker-Dokumentation:

Erstens sollen Multi-Architektur-Images ermöglicht werden: Ein „Fat Manifest“ verweist dazu auf Image-Manifeste für plattformspezifische Versionen eines Images. Zweitens soll die Docker-Engine auf inhaltsadressierbare Images umgestellt werden. Dazu wird ein Image-Modell unterstützt, bei dem sich die Konfiguration eines Images hashen lässt, um eine ID für das Image zu erzeugen.

Mit unserem lokalen Docker können wir zunächst das „Fat Manifest“ des gewünschten Images untersuchen und prüfen, welche Plattformvarianten verfügbar sind. Wie oben erklärt, kann ein einzelnes Repository mehrere Images für unterschiedliche Architekturen enthalten.

docker manifest inspect ubuntu:bionic

Das Ergebnis ist ein Array mit Manifesten:

{
   ...
  "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 943,
         "digest": "sha256:45c6f8f1b2fe15adaa72305616d69a6cd641169bc8b16886756919e7c01fa48b",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 943,
         "digest": "sha256:e80b8affb2361dc632c1fa8fcbf6b6514f750eb6ef99b7e7f825a55f849bfd89",
         "platform": {
            "architecture": "arm",
            "os": "linux",
            "variant": "v7"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 943,
         "digest": "sha256:01a2038b20d165ab7df81934f9849bdfbc59bd6f6322c5d11e341504f66ec266",
         "platform": {
            "architecture": "arm64",
            "os": "linux",
            "variant": "v8"
         }
      },
...

Nachdem wir nun wissen, dass das Image ubuntu für verschiedene Plattformen verfügbar ist, sehen wir uns an, wie Sie ein ubuntu-Image für die Plattformarchitektur arm64 scannen.

Achten Sie darauf, dass experimentelle Funktionen in Docker auf Ihrem Host aktiviert sind. Dann können Sie folgenden Befehl ausführen:

snyk container test --platform=linux/arm64 ubuntu:bionic

Sehen wir uns die Ausgabe an:

Testing ubuntu:bionic...

✗ Low severity vulnerability found in tar
  Description: Loop with Unreachable Exit Condition ('Infinite Loop')
  Info: <https://snyk.io/vuln/SNYK-UBUNTU1804-TAR-312298>
  Introduced through: tar@1.29b-2ubuntu0.1, pam/libpam-runtime@1.1.8-3.6ubuntu2.18.04.2
  From: tar@1.29b-2ubuntu0.1
  From: pam/libpam-runtime@1.1.8-3.6ubuntu2.18.04.2 > debconf@1.5.66ubuntu1 > perl/perl-base@5.26.1-6ubuntu0.3 > dpkg@1.19.0.5ubuntu2.3 > tar@1.29b-2ubuntu0.1

✗ Low severity vulnerability found in tar
  Description: NULL Pointer Dereference
  Info: <https://snyk.io/vuln/SNYK-UBUNTU1804-TAR-559435>
  Introduced through: tar@1.29b-2ubuntu0.1, pam/libpam-runtime@1.1.8-3.6ubuntu2.18.04.2
  From: tar@1.29b-2ubuntu0.1
  From: pam/libpam-runtime@1.1.8-3.6ubuntu2.18.04.2 > debconf@1.5.66ubuntu1 > perl/perl-base@5.26.1-6ubuntu0.3 > dpkg@1.19.0.5ubuntu2.3 > tar@1.29b-2ubuntu0.1

# vuln list continues in here
...

Organization:      example-org
Package manager:   apk
Project name:      docker-image|ubuntu:bionic
Docker image:      alpine:3.12
Platform:          linux/arm64
Licenses:          enabled

Tested 90 dependencies for known issues, found 31 issues.

Pro tip: use `--file` option to get base image remediation advice.
Example: $ snyk test --docker ubuntu:bionic --file=path/to/Dockerfile

Wir sehen alle entdeckten anfälligen Pfade sowie Angaben zur „Platform“ in der Scan-Ausgabe.

In diesem Blogbeitrag haben wir die beiden wichtigsten Container-Image-Formate von Docker und OCI untersucht und gezeigt, wie Snyk mit beiden Formaten und sogar mit mehreren Architekturen funktioniert.

Zum Abschluss finden Sie hier weitere Informationen zu bewährten Sicherheitspraktiken für die Erstellung optimaler Docker-Images für Node.js- und Java-Anwendungen:

  1. 10 Best Practices für Docker-Sicherheit — beschreibt Sicherheitspraktiken, die Sie beim Erstellen und Abrufen von Docker-Basis-Images beachten sollten, und führt außerdem in Docker Content Trust ein.

  2. Entwickeln Sie mit Java? Diese Ressource ist für Sie interessant: Docker für Java-Entwickler: 5 Dinge, die Sie für Ihre Sicherheit wissen müssen

  3. 10 Best Practices für das Containerisieren von Node.js-Webanwendungen mit Docker – Wenn Sie mit Node.js entwickeln, wird Ihnen diese Schritt-für-Schritt-Anleitung gefallen. Sie zeigt, wie Sie sichere und leistungsfähige Docker-Basis-Images für Ihre Node.js-Anwendungen erstellen.

All diese Funktionen stehen Ihnen in Snyk kostenlos zur Verfügung — registrieren Sie sich für ein Konto.

Starten Sie mit Capture the Flag

Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.

Gepostet in:

Weiterlesen

Blog

Stadium-Sommer: Die Snyk Connect Fan Zone Tour

Die Fan Zone Tour von Snyk brachte KI-Security-Workshops, Networking und freundschaftlichen Wettbewerb in 8 Städte und 3 virtuelle Sessions. Die Teilnehmenden bauten ihre Kompetenzen aus, tauschten Ideen aus und entwickelten sich gemeinsam weiter.

Blog

Snyk VulnBench JS 1.0: Finden LLMs zweimal dieselben Fehler?

Snyk VulnBench JS 1.0: 300 wiederholte Scans zeigen, dass LLM-Sicherheitsergebnisse von Durchlauf zu Durchlauf variieren, während SAST und Modelle unterschiedliche Sicherheitslücken aufdecken.

blog feature toolkit
Blog

Bösartige Veröffentlichung des elementary-data-PyPI-Pakets stiehlt Cloud-Zugangsdaten von Data Engineers

Angreifer nutzten eine Sicherheitslücke durch Skriptinjektion in GitHub Actions aus, um eine bösartige Version der elementary-data-Python-CLI (v0.23.3) zu veröffentlichen. Diese enthielt eine Backdoor zum Diebstahl von Zugangsdaten, die auf dbt-Profile, Cloud-Anbieterschlüssel und SSH-Geheimnisse in Data-Engineering-Umgebungen abzielte.