
layerleak – der Docker Hub Secret Scanner
Siehe CONTRIBUTING.md für Richtlinien zur Mitarbeit.
Die veröffentlichte Seite wird aus web/ im main-Branch von .github/workflows/pages.yml erstellt. Die Quellen der Dokumentation und die simulierte Browser-Demo befinden sich in diesem Verzeichnis.
Voraussetzungen:
Installation mit Go:
go install github.com/brumbelow/layerleak@latest
layerleak --help
Das kanonische Installationsziel ist das Modul-Root. Um eine bestimmte Version festzulegen:
go install github.com/brumbelow/[email protected]
Ersetzen Sie v1.0.0 durch das gewünschte veröffentlichte v1.x.y-Tag.
Stellen Sie sicher, dass Ihr GOBIN- oder GOPATH/bin-Verzeichnis in PATH enthalten ist.
Der Modulpfad ist github.com/brumbelow/layerleak, daher löst go install @latest das höchste veröffentlichte v1.x.y-Tag auf. Eine v2.x.y-Modulveröffentlichung würde erfordern, dass der Modulpfad zu github.com/brumbelow/layerleak/v2 geändert wird. Modul-installierte Binärdateien melden die aufgelöste Modulversion über layerleak --version; lokale Checkout-Builds melden die Version, die Go für den Checkout einbettet, und fallen auf dev zurück, wenn keine Modulversion verfügbar ist.
Build aus dem Quellcode:
git clone https://github.com/brumbelow/layerleak.git
cd layerleak
go build -o layerleak .
./layerleak --help
Die API mit einem Container-Image ausführen:
docker pull ghcr.io/brumbelow/layerleak:latest
docker run --rm \
-p 8080:8080 \
-e LAYERLEAK_DATABASE_URL='postgres://<user>:<password>@<host>:5432/layerleak?sslmode=disable' \
ghcr.io/brumbelow/layerleak:latest
Das Container-Image führt standardmäßig die API aus und setzt LAYERLEAK_API_ADDR=0.0.0.0:8080.
Optionale Umgebungskonfiguration:
cp .env.example .env
Ergebnis- und Datenbankkonfiguration:
export LAYERLEAK_LOG_LEVEL=info
export LAYERLEAK_FINDINGS_DIR=findings
export LAYERLEAK_API_ADDR=127.0.0.1:8080
export LAYERLEAK_PERSIST_RAW_SECRETS=0
export LAYERLEAK_TAG_PAGE_SIZE=100
export LAYERLEAK_HTTP_TIMEOUT=30s
export LAYERLEAK_MAX_FILE_BYTES=1048576
export LAYERLEAK_MAX_LAYER_BYTES=536870912
export LAYERLEAK_MAX_LAYER_ENTRIES=50000
export LAYERLEAK_MAX_MANIFEST_BYTES=0
export LAYERLEAK_MAX_CONFIG_BYTES=0
export LAYERLEAK_MAX_TAG_RESPONSE_BYTES=8388608
export LAYERLEAK_MAX_REPOSITORY_TAGS=0
export LAYERLEAK_MAX_REPOSITORY_TARGETS=0
export LAYERLEAK_REGISTRY_REQUEST_ATTEMPTS=2
# Optionale Registry-Überschreibungen; normalerweise nicht gesetzt.
export LAYERLEAK_REGISTRY_BASE_URL=
export LAYERLEAK_REGISTRY_AUTH_URL=
export LAYERLEAK_DATABASE_URL=postgres://postgres:postgres@localhost:5432/layerleak?sslmode=disable
Dieselben Variablen und ihre Standardwerte befinden sich in .env.example, das die Quelle der Wahrheit für Standardwerte ist.
Wenn eines der MAX_*-Limits auf einen positiven Wert gesetzt ist, führt dessen Überschreitung zu einem Scann-Fehler mit einer klaren Fehlermeldung, anstatt die Arbeit stillschweigend abzuschneiden.
Ergebnisverhalten:
findings und bestimmen den Nicht-Null-Scan-Exit-Status.total_findings.disposition, disposition_reason und line_number, um Triage und Überprüfung von Fehlalarmen zu erleichtern.1, da der Scan unvollständig ist.Layerleak enthält versionierte SQL-Migrationen unter migrations/.
Migrationen sind bewusst manuell. Der Scanner erstellt oder aktualisiert das Schema nicht automatisch.
Layerleak erfordert PostgreSQL-Server >= 16.13 für DB-gestützte API- und Scanner-Persistenz.
Wenden Sie die Migrationen mit psql in der richtigen Reihenfolge an:
psql "$LAYERLEAK_DATABASE_URL" -f migrations/0001_initial.up.sql
psql "$LAYERLEAK_DATABASE_URL" -f migrations/0002_finding_occurrence_metadata.up.sql
psql "$LAYERLEAK_DATABASE_URL" -f migrations/0003_scan_runs.up.sql
Oder wenden Sie Migrationen mit dem Container-Hilfsbefehl an:
docker run --rm \
-e LAYERLEAK_DATABASE_URL="$LAYERLEAK_DATABASE_URL" \
ghcr.io/brumbelow/layerleak:latest \
layerleak-migrate-up
layerleak-migrate-up kann sicher erneut ausgeführt werden, wenn Migrationen bereits angewendet sind.
Wenn ein teilweiser Migrationszustand erkannt wird, wird mit einem Nicht-Null-Exit beendet und um manuelles Eingreifen gebeten.
Der Helfer erzwingt auch die Serverversion >= 16.13 und überprüft, ob das gebündelte postgresql-client-16
das Ubuntu PGDG 24.04-Paket verwendet (.pgdg24.04+) in Version >= 16.13-1.pgdg24.04+1.
Rückgängigmachen der Migrationen in umgekehrter Reihenfolge:
psql "$LAYERLEAK_DATABASE_URL" -f migrations/0003_scan_runs.down.sql
psql "$LAYERLEAK_DATABASE_URL" -f migrations/0002_finding_occurrence_metadata.down.sql
psql "$LAYERLEAK_DATABASE_URL" -f migrations/0001_initial.down.sql
Betriebliche Standardeinstellungen:
first_seen_at und last_seen_at bei und speichert zusätzlich eine append-only Scan-Historie in scan_runs.(manifest_digest, fingerprint) dedupliziert, und wiederholte identische Kontextausschnitte werden vor der Persistenz zusammengefasst.Hinweis zur Secrets-Sicherheit:
LAYERLEAK_PERSIST_RAW_SECRETS=1 gesetzt ist, speichert Postgres auch rohe Fundwerte und rohe Ausschnitte.scan_runs.result_json-Momentaufnahme bleibt geschwärzt.CLI-Hilfe anzeigen:
layerleak --help
layerleak scan --help

Führen Sie einen Scan gegen ein öffentliches OCI-Image auf einer beliebigen unterstützten Registry aus:
./layerleak scan ubuntu
./layerleak scan library/nginx:latest --format json
./layerleak scan alpine:latest --platform linux/amd64
./layerleak scan mongo
./layerleak scan ghcr.io/homebrew/core/hello:latest
./layerleak scan quay.io/prometheus/busybox:latest
./layerleak scan gcr.io/distroless/static:nonroot
./layerleak scan public.ecr.aws/docker/library/alpine:3.20
./layerleak scan mcr.microsoft.com/hello-world:latest

Jeder Scan schreibt eine JSON-Ergebnisdatei in das Ausgabeverzeichnis für Funde.
Wenn LAYERLEAK_FINDINGS_DIR nicht gesetzt ist, ist das Standardausgabeverzeichnis findings/ unter dem nächstgelegenen übergeordneten Verzeichnis, das go.mod enthält (normalerweise das Repository-Root), mit einem Fallback auf das aktuelle Arbeitsverzeichnis, wenn kein Repository-Root gefunden wird.
Diese gespeicherten Ergebnisdateien enthalten Funddatensätze mit redacted_value, geschwärztem context_snippet, genauer Quellposition, Dispositionsmetadaten und Zeilennummer für jeden Fund.
Wenn LAYERLEAK_PERSIST_RAW_SECRETS=1 gesetzt ist, enthalten die gespeicherten Ergebnisdateien auch rohe value und raw_context_snippet.
Wenn die Postgres-Persistenz aktiviert ist, bleiben rohe findings.value und finding_occurrences.raw_snippet leer, es sei denn, LAYERLEAK_PERSIST_RAW_SECRETS=1 ist gesetzt.
Bei Multi-Architektur-Images überspringt layerleak Attestations- und Provenance-Manifeste wie application/vnd.in-toto+json, anstatt sie als fehlgeschlagene Plattform-Scans zu zählen.
Repositoryweite Scans:
mongo zählt jedes öffentliche Tag in diesem Repository auf, löst jedes Tag in einen Digest auf, gruppiert doppelte Digests und scannt die verschiedenen Ziele.mongo:latest oder mongo@sha256:....Befehlsyntax:
layerleak [command]
layerleak scan <image-ref> [flags]
Gültigkeitsflags für Repository-Scans (jedes überschreibt die entsprechende Umgebungsvariable für einen einzelnen Befehl):
Layerleak enthält auch eine minimale JSON-API unter cmd/api.
Die API ist Postgres-gestützt und erfordert LAYERLEAK_DATABASE_URL; sie bedient nicht aus den Ergebnisdateien auf der Festplatte.
Starten Sie sie mit:
go run ./cmd/api
Oder führen Sie den API-Container aus:
docker run --rm \
-p 8080:8080 \
-e LAYERLEAK_DATABASE_URL='postgres://<user>:<password>@<host>:5432/layerleak?sslmode=disable' \
ghcr.io/brumbelow/layerleak:latest
Aktuelle Endpunkte:
GET /healthPOST /api/v1/scansGET /api/v1/scans/{id}GET /api/v1/repositoriesGET /api/v1/repositories/{repository}/scansGET /api/v1/repositories/{repository}/findingsGET /api/v1/findings/{id}GET /health gibt {"status":"ok"} zurück und benötigt keinen konfigurierten Store oder Scanner.
Er eignet sich für Kubernetes-Readiness-Probes und Docker-Compose-healthcheck-Ziele.
POST /api/v1/scans bleibt synchron. Er akzeptiert einen JSON-Body mit reference und optionalem platform und gibt scan_run_id zurück, wenn die Postgres-Persistenz aktiviert ist.
API-Scan-Antworten verwenden dasselbe geschwärzte Ergebnisschema wie die CLI-JSON-Ausgabe.
GET /api/v1/scans/{id} gibt die persistierten Lauf-Metadaten sowie die gespeicherte geschwärzte Ergebnismomentaufnahme zurück.
Repository- und Finding-Endpunkte bleiben ebenfalls geschwärzt: Sie geben redacted_value und geschwärztes context_snippet zurück, niemals rohe Secret-Werte oder rohe Ausschnitte aus Postgres.
GET /api/v1/repositories/{repository}/scans und GET /api/v1/repositories/{repository}/findings akzeptieren einen optionalen registry-Abfrageparameter (z.B. ?registry=ghcr.io). Wenn er weggelassen wird, standardmäßig docker.io aus Gründen der Abwärtskompatibilität. Verwenden Sie dies, um Scans von Repositories auf GHCR, Quay, GCR, MCR, Amazon ECR Public oder einem selbst gehosteten Registry abzurufen.
List-Endpunkte (/repositories, /repositories/{repository}/scans, /repositories/{repository}/findings) akzeptieren ?limit= und ?offset= für Paginierung. limit standardmäßig 50 und ist auf 200 begrenzt. /repositories/{repository}/findings akzeptiert auch ?disposition=actionable|suppressed|all; wenn weggelassen, enthält die Antwort nur umsetzbare Funde.
Die API enthält keine Authentifizierung. Für Organisationsbereitstellungen halten Sie sie in einem privaten Netzwerk und stellen Sie ihr ein eigenes Authn/Authz-Gateway oder Reverse-Proxy-Richtlinie voran.
Dieses Repository enthält einen Compose-Stack in docker-compose.yml mit den Diensten db, migrate und api.
Der db-Dienst-Baseline ist auf postgres:16.13-alpine festgelegt.
Wenn Sie ein anderes Postgres-Image verwenden, halten Sie die Serverversion auf 16.13 oder neuer.
Setzen Sie Bereitstellungsvariablen (in der Shell exportieren oder in einer .env-Datei neben docker-compose.yml ablegen):
export LAYERLEAK_IMAGE=ghcr.io/brumbelow/layerleak:latest
export LAYERLEAK_DB_NAME=layerleak
export LAYERLEAK_DB_USER=layerleak
export LAYERLEAK_DB_PASSWORD=replace-me
export LAYERLEAK_API_PORT=8080
Überprüfen Sie die gerenderte Compose-Konfiguration vor der Bereitstellung:
docker compose config
Führen Sie Migrationen einmalig aus, bevor Sie die API starten:
docker compose --profile manual run --rm migrate
Starten Sie den API-Dienst:
docker compose up -d api
In Dockge oder Komodo importieren Sie dieselbe Compose-Datei und führen Sie den migrate-Dienst einmalig aus, bevor Sie den langlebigen api-Dienst aktivieren.
Veröffentlicht unter der MIT-Lizenz – siehe LICENSE.
Wenn dieses Repo Ihnen Zeit gespart oder geholfen hat, können Sie zukünftige Updates hier unterstützen:
Danke :) Es hilft wirklich, das Projekt am Laufen zu halten.
| Variable | Standard | Zweck |
|---|
LAYERLEAK_LOG_LEVEL | info | Log-Level: debug, info, warn oder error. |
LAYERLEAK_FINDINGS_DIR | nicht gesetzt | Wohin JSON-Ergebnisdateien geschrieben werden. Wenn nicht gesetzt, standardmäßig findings/ unter dem nächstgelegenen übergeordneten Verzeichnis mit go.mod, ansonsten das aktuelle Arbeitsverzeichnis. |
LAYERLEAK_API_ADDR | 127.0.0.1:8080 | Bind-Adresse für den API-Server. Das Container-Image überschreibt dies auf 0.0.0.0:8080. |
LAYERLEAK_PERSIST_RAW_SECRETS | 0 | Auf 1 setzen, um rohe Secret-Werte und rohe Kontextausschnitte auf die Festplatte und nach Postgres zu schreiben. Ergebnisse bleiben standardmäßig geschwärzt. |
LAYERLEAK_HTTP_TIMEOUT | 30s | Timeout pro Anfrage für jeden Registry-Aufruf (Manifeste, Blobs, Tag-Seiten, Authentifizierungstoken). Akzeptiert jede Go-Dauer (30s, 2m, 1h). |
LAYERLEAK_MAX_FILE_BYTES | 1048576 (1 MiB) | Maximale dekomprimierte Bytes, die pro Datei innerhalb eines Layers gepuffert werden. Größere Dateien werden als zu groß übersprungen. Muss größer als Null sein. |
LAYERLEAK_MAX_LAYER_BYTES | 536870912 (512 MiB) | Maximale dekomprimierte Layer-Stream-Bytes pro Layer. 0 deaktiviert das Limit. |
LAYERLEAK_MAX_LAYER_ENTRIES | 50000 | Maximale Tar-Einträge pro Layer. 0 deaktiviert das Limit. |
LAYERLEAK_MAX_MANIFEST_BYTES | 0 | Maximale Manifest-Body-Bytes. 0 deaktiviert das Limit. |
LAYERLEAK_MAX_CONFIG_BYTES | 0 | Maximale Image-Konfigurations-Body-Bytes. 0 deaktiviert das Limit. |
LAYERLEAK_MAX_TAG_RESPONSE_BYTES | 8388608 (8 MiB) | Maximale Bytes pro Registry-Tag-Listen-Antwortseite. 0 deaktiviert das Limit. |
LAYERLEAK_TAG_PAGE_SIZE | 100 | Größe der Registry-Tag-Listenseite für repositoryweite Scans. |
LAYERLEAK_MAX_REPOSITORY_TAGS | 0 | Maximale Tags, die pro Repository-Scan aufgezählt werden. 0 deaktiviert das Limit. |
LAYERLEAK_MAX_REPOSITORY_TARGETS | 0 | Maximale verschiedene Ziele, die pro Repository-Scan aufgelöst werden. 0 deaktiviert das Limit. |
LAYERLEAK_REGISTRY_REQUEST_ATTEMPTS | 2 | Anzahl der Versuche (einschließlich des ersten) für jede Registry-Anfrage. |
LAYERLEAK_REGISTRY_BASE_URL | nicht gesetzt | Optionale Überschreibung. Normalerweise leitet layerleak dies von jeder Image-Referenz ab; nur setzen, um Scans über einen Proxy oder alternativen Endpunkt zu erzwingen. |
LAYERLEAK_REGISTRY_AUTH_URL | nicht gesetzt | Optionale Überschreibung. Normalerweise aus der WWW-Authenticate-Challenge des Registrys ermittelt. |
LAYERLEAK_DATABASE_URL | nicht gesetzt | Wenn gesetzt, schreibt layerleak Scans nach Postgres und schlägt der Befehl fehl, wenn die Persistenz nicht erfolgreich ist. |
| Flag | Zweck |
|---|
--tag-page-size | Größe der Registry-Tag-Listenseite für Repository-Scans. Muss größer als Null sein. Überschreibt LAYERLEAK_TAG_PAGE_SIZE. |
--max-repository-tags | Maximale Tags, die pro Repository-Scan aufgezählt werden. 0 deaktiviert das Limit. Überschreibt LAYERLEAK_MAX_REPOSITORY_TAGS. |
--max-repository-targets | Maximale verschiedene Ziele, die pro Repository-Scan aufgelöst werden. 0 deaktiviert das Limit. Überschreibt LAYERLEAK_MAX_REPOSITORY_TARGETS. |