
layerleak - le scanner de secrets Docker Hub
Consultez CONTRIBUTING.md pour les directives de contribution.
Le site publié est construit à partir de web/ sur main par .github/workflows/pages.yml. La source de la documentation et la démo simulée du navigateur résident tous les deux dans ce répertoire.
Prérequis :
Installer avec Go :
go install github.com/brumbelow/layerleak@latest
layerleak --help
La cible d’installation canonique est la racine du module. Pour épingler une version explicitement :
go install github.com/brumbelow/[email protected]
Remplacez v1.0.0 par l’étiquette v1.x.y publiée souhaitée.
Assurez-vous que votre répertoire GOBIN ou GOPATH/bin est dans le PATH.
Le chemin du module est github.com/brumbelow/layerleak, donc go install @latest résout la plus haute étiquette v1.x.y publiée. Une version de module v2.x.y nécessiterait que le chemin du module devienne github.com/brumbelow/layerleak/v2. Les binaires installés via le module rapportent la version résolue via layerleak --version ; les constructions à partir d’un checkout local rapportent la version que Go intègre pour le checkout, en revenant à dev quand aucune version de module n’est disponible.
Construire à partir des sources :
git clone https://github.com/brumbelow/layerleak.git
cd layerleak
go build -o layerleak .
./layerleak --help
Exécuter l’API avec une image conteneur :
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
L’image conteneur exécute l’API par défaut et définit LAYERLEAK_API_ADDR=0.0.0.0:8080.
Configuration d’environnement optionnelle :
cp .env.example .env
Configuration des résultats et de la base de données :
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
# Remplacements de registre optionnels ; généralement laisser non défini.
export LAYERLEAK_REGISTRY_BASE_URL=
export LAYERLEAK_REGISTRY_AUTH_URL=
export LAYERLEAK_DATABASE_URL=postgres://postgres:postgres@localhost:5432/layerleak?sslmode=disable
Les mêmes variables et leurs valeurs par défaut se trouvent dans .env.example, qui est la source de vérité pour les valeurs par défaut.
Lorsque l’une des limites MAX_* est définie à une valeur positive, son dépassement fait échouer l’analyse avec une erreur claire au lieu de tronquer silencieusement le travail.
Comportement des résultats :
findings et déterminent le code de sortie non nul de l’analyse.total_findings.disposition, disposition_reason et line_number pour faciliter le triage et la revue des faux positifs.1 car l’analyse est incomplète.Layerleak fournit des migrations SQL versionnées sous migrations/.
Les migrations sont volontairement manuelles. Le scanner ne crée ni ne met à jour automatiquement le schéma.
Layerleak nécessite un serveur PostgreSQL >= 16.13 pour l’API et la persistance du scanner.
Appliquer les migrations avec psql dans l’ordre :
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
Ou appliquer les migrations en utilisant la commande d’aide du conteneur :
docker run --rm \
-e LAYERLEAK_DATABASE_URL="$LAYERLEAK_DATABASE_URL" \
ghcr.io/brumbelow/layerleak:latest \
layerleak-migrate-up
layerleak-migrate-up peut être exécuté de nouveau sans risque lorsque les migrations sont déjà appliquées.
S’il détecte un état de migration partielle, il se termine avec un code non nul et demande une intervention manuelle.
L’aide impose également la version du serveur >= 16.13 et vérifie que le postgresql-client-16 groupé utilise l’empaquetage Ubuntu PGDG 24.04 (.pgdg24.04+) à la version >= 16.13-1.pgdg24.04+1.
Annuler les migrations dans l’ordre inverse :
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
Valeurs par défaut opérationnelles :
first_seen_at et last_seen_at, et stocke également l’historique d’analyse append-only dans scan_runs.(manifest_digest, fingerprint), et les fragments de contexte identiques répétés sont réduits avant la persistance.Note sur la sécurité des secrets :
LAYERLEAK_PERSIST_RAW_SECRETS=1, Postgres stocke également les valeurs brutes des résultats et les fragments bruts.scan_runs.result_json reste masqué.Afficher l’aide en ligne de commande :
layerleak --help
layerleak scan --help

Lancer une analyse contre une image OCI publique sur tout registre supporté :
./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

Chaque analyse écrit un fichier JSON des résultats dans le répertoire de sortie des résultats.
Si LAYERLEAK_FINDINGS_DIR n’est pas défini, le répertoire de sortie par défaut est findings/ sous le plus proche répertoire parent contenant go.mod (généralement la racine du dépôt), avec un repli sur le répertoire de travail courant lorsqu’aucune racine de dépôt n’est trouvée.
Ces fichiers de résultats enregistrés contiennent des enregistrements de résultats avec redacted_value, context_snippet masqué, emplacement source exact, métadonnées de disposition et numéro de ligne pour chaque résultat.
Si LAYERLEAK_PERSIST_RAW_SECRETS=1, les fichiers de résultats enregistrés incluent également la value brute et raw_context_snippet.
Si la persistance Postgres est activée, findings.value brut et finding_occurrences.raw_snippet restent vides sauf si LAYERLEAK_PERSIST_RAW_SECRETS=1.
Pour les images multi-architectures, layerleak ignore les manifestes d’attestation et de provenance tels que application/vnd.in-toto+json au lieu de les compter comme des analyses de plateforme échouées.
Balayages de dépôt nus :
mongo énumère chaque étiquette publique dans ce dépôt, résout chaque étiquette en un digest, regroupe les digest en double et analyse les cibles distinctes.mongo:latest ou mongo@sha256:....Syntaxe des commandes :
layerleak [command]
layerleak scan <image-ref> [flags]
Drapeaux de portée pour les balayages de dépôt (chacun remplace la variable d’environnement correspondante pour une seule commande) :
Layerleak fournit également une API JSON minimale sous cmd/api.
L’API est basée sur Postgres et nécessite LAYERLEAK_DATABASE_URL ; elle ne sert pas à partir des fichiers de résultats sur le disque.
La lancer avec :
go run ./cmd/api
Ou exécuter le conteneur API :
docker run --rm \
-p 8080:8080 \
-e LAYERLEAK_DATABASE_URL='postgres://<user>:<password>@<host>:5432/layerleak?sslmode=disable' \
ghcr.io/brumbelow/layerleak:latest
Points de terminaison actuels :
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 retourne {"status":"ok"} et ne nécessite pas de magasin ou scanner configuré.
Il est adapté aux sondes de préparation Kubernetes et aux cibles healthcheck de Docker Compose.
POST /api/v1/scans reste synchrone. Il accepte un corps JSON avec reference et platform optionnel, et retourne scan_run_id lorsque la persistance Postgres est activée.
Les réponses d’analyse API réutilisent le même schéma de résultat masqué que la sortie JSON de la CLI.
GET /api/v1/scans/{id} retourne les métadonnées d’exécution persistées ainsi que l’instantané de résultat masqué stocké.
Les points de terminaison de dépôt et de résultats restent également masqués : ils retournent redacted_value et context_snippet masqué, jamais les valeurs brutes des secrets ni les fragments bruts de Postgres.
GET /api/v1/repositories/{repository}/scans et GET /api/v1/repositories/{repository}/findings acceptent un paramètre de requête registry optionnel (par exemple ?registry=ghcr.io). Lorsqu’il est omis, le registre par défaut est docker.io pour la rétrocompatibilité. Utilisez-le pour récupérer les analyses de dépôts sur GHCR, Quay, GCR, MCR, Amazon ECR Public, ou tout registre auto-hébergé.
Les points de terminaison de liste (/repositories, /repositories/{repository}/scans, /repositories/{repository}/findings) acceptent ?limit= et ?offset= pour la pagination. limit par défaut à 50 et est plafonné à 200. /repositories/{repository}/findings accepte également ?disposition=actionable|suppressed|all ; lorsqu’omis, la réponse n’inclut que les résultats exploitables.
L’API n’inclut pas d’authentification. Pour les déploiements en organisation, conservez-la sur un réseau privé et placez-la derrière votre propre passerelle d’authentification/autorisation ou politique de proxy inverse.
Ce dépôt fournit une pile Compose dans docker-compose.yml avec les services db, migrate et api.
La base de référence du service db est épinglée à postgres:16.13-alpine.
Si vous utilisez une image Postgres différente, conservez la version du serveur à 16.13 ou plus récente.
Définissez les variables de déploiement (exportez dans le shell ou placez dans un fichier .env à côté de docker-compose.yml) :
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
Validez la configuration Compose rendue avant le déploiement :
docker compose config
Exécutez les migrations une fois avant de démarrer l’API :
docker compose --profile manual run --rm migrate
Démarrez le service API :
docker compose up -d api
Dans Dockge ou Komodo, importez le même fichier Compose et exécutez le service migrate une fois avant d’activer le service api à longue durée.
Publié sous la licence MIT — voir LICENSE.
Si ce dépôt vous a fait gagner du temps ou vous a aidé, vous pouvez soutenir les futures mises à jour ici :
Merci :) cela aide réellement à maintenir le projet.
| Variable | Valeur par défaut | Objectif |
|---|
LAYERLEAK_LOG_LEVEL | info | Niveau de journalisation : debug, info, warn ou error. |
LAYERLEAK_FINDINGS_DIR | non défini | Où écrire les fichiers JSON des résultats. Si non défini, par défaut findings/ sous le plus proche parent contenant go.mod, avec repli sur le répertoire de travail courant. |
LAYERLEAK_API_ADDR | 127.0.0.1:8080 | Adresse d’écoute du serveur API. L’image conteneur remplace cela par 0.0.0.0:8080. |
LAYERLEAK_PERSIST_RAW_SECRETS | 0 | Mettre à 1 pour écrire les valeurs brutes des secrets et les fragments de contexte bruts sur le disque et dans Postgres. Les résultats restent masqués par défaut. |
LAYERLEAK_HTTP_TIMEOUT | 30s | Timeout par requête pour chaque appel au registre (manifestes, blobs, pages d’étiquettes, jetons d’authentification). Accepte toute durée Go (30s, 2m, 1h). |
LAYERLEAK_MAX_FILE_BYTES | 1048576 (1 Mio) | Nombre maximal d’octets décompressés mis en mémoire tampon par fichier dans une couche. Les fichiers plus grands sont ignorés comme étant trop volumineux. Doit être supérieur à zéro. |
LAYERLEAK_MAX_LAYER_BYTES | 536870912 (512 Mio) | Nombre maximal d’octets du flux de couche décompressé par couche. 0 désactive la limite. |
LAYERLEAK_MAX_LAYER_ENTRIES | 50000 | Nombre maximal d’entrées tar par couche. 0 désactive la limite. |
LAYERLEAK_MAX_MANIFEST_BYTES | 0 | Nombre maximal d’octets du corps du manifeste. 0 désactive la limite. |
LAYERLEAK_MAX_CONFIG_BYTES | 0 | Nombre maximal d’octets du corps de la configuration d’image. 0 désactive la limite. |
LAYERLEAK_MAX_TAG_RESPONSE_BYTES | 8388608 (8 Mio) | Nombre maximal d’octets par page de réponse de liste d’étiquettes du registre. 0 désactive la limite. |
LAYERLEAK_TAG_PAGE_SIZE | 100 | Taille de page de la liste d’étiquettes du registre pour les analyses à l’échelle du dépôt. |
LAYERLEAK_MAX_REPOSITORY_TAGS | 0 | Nombre maximal d’étiquettes énumérées par analyse de dépôt. 0 désactive la limite. |
LAYERLEAK_MAX_REPOSITORY_TARGETS | 0 | Nombre maximal de cibles distinctes résolues par analyse de dépôt. 0 désactive la limite. |
LAYERLEAK_REGISTRY_REQUEST_ATTEMPTS | 2 | Nombre de tentatives (y compris la première) pour chaque requête au registre. |
LAYERLEAK_REGISTRY_BASE_URL | non défini | Remplacement optionnel. Normalement layerleak dérive cette URL de chaque référence d’image ; définir seulement pour forcer les analyses via un proxy ou un point de terminaison alternatif. |
LAYERLEAK_REGISTRY_AUTH_URL | non défini | Remplacement optionnel. Normalement découverte à partir du défi WWW-Authenticate du registre. |
LAYERLEAK_DATABASE_URL | non défini | Si défini, layerleak écrit les analyses dans Postgres et échoue la commande si la persistance échoue. |
| Drapeau | Objectif |
|---|
--tag-page-size | Taille de page de la liste d’étiquettes du registre pour les balayages de dépôt. Doit être supérieur à zéro. Remplace LAYERLEAK_TAG_PAGE_SIZE. |
--max-repository-tags | Nombre maximal d’étiquettes énumérées par balayage de dépôt. 0 désactive la limite. Remplace LAYERLEAK_MAX_REPOSITORY_TAGS. |
--max-repository-targets | Nombre maximal de cibles distinctes résolues par balayage de dépôt. 0 désactive la limite. Remplace LAYERLEAK_MAX_REPOSITORY_TARGETS. |