
layerleak el escáner de secretos de Docker Hub
Consulta CONTRIBUTING.md para las pautas de contribución.
El sitio publicado se construye desde web/ en main mediante .github/workflows/pages.yml. La fuente de la documentación y la demo simulada del navegador residen en ese directorio.
Requisitos previos:
Instalar con Go:
go install github.com/brumbelow/layerleak@latest
layerleak --help
El destino de instalación canónico es la raíz del módulo. Para fijar una versión explícitamente:
go install github.com/brumbelow/[email protected]
Reemplaza v1.0.0 con la etiqueta v1.x.y publicada que desees.
Asegúrate de que tu directorio GOBIN o GOPATH/bin esté en PATH.
La ruta del módulo es github.com/brumbelow/layerleak, por lo que go install @latest se resuelve a la etiqueta v1.x.y más alta publicada. Un lanzamiento del módulo v2.x.y requeriría cambiar la ruta del módulo a github.com/brumbelow/layerleak/v2. Los binarios instalados mediante módulos reportan la versión del módulo resuelta a través de layerleak --version; las compilaciones desde el clon local reportan la versión que Go incrusta para el clon, cayendo a dev cuando no hay una versión de módulo disponible.
Compilar desde el código fuente:
git clone https://github.com/brumbelow/layerleak.git
cd layerleak
go build -o layerleak .
./layerleak --help
Ejecutar la API con una imagen de contenedor:
docker pull ghcr.io/brumbelow/layerleak:latest
docker run --rm \
-p 8080:8080 \
-e LAYERLEAK_DATABASE_URL='postgres://<usuario>:<contraseña>@<host>:5432/layerleak?sslmode=disable' \
ghcr.io/brumbelow/layerleak:latest
La imagen del contenedor ejecuta la API por defecto y establece LAYERLEAK_API_ADDR=0.0.0.0:8080.
Configuración opcional de entorno:
cp .env.example .env
Configuración de resultados y base de datos:
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
# Anulaciones opcionales de registro; normalmente se dejan sin establecer.
export LAYERLEAK_REGISTRY_BASE_URL=
export LAYERLEAK_REGISTRY_AUTH_URL=
export LAYERLEAK_DATABASE_URL=postgres://postgres:postgres@localhost:5432/layerleak?sslmode=disable
Las mismas variables y sus valores predeterminados se encuentran en .env.example, que es la fuente de verdad para los valores predeterminados.
Cuando cualquiera de los límites MAX_* se establece a un valor positivo, excederlo hace que el escaneo falle con un error claro en lugar de truncar silenciosamente el trabajo.
Comportamiento de los resultados:
findings y determinan el estado de salida del escaneo distinto de cero.total_findings.disposition, disposition_reason y line_number para facilitar la revisión de falsos positivos.1 porque el escaneo está incompleto.Layerleak incluye migraciones SQL versionadas bajo migrations/.
Las migraciones son manuales a propósito. El escáner no crea ni actualiza automáticamente el esquema.
Layerleak requiere un servidor PostgreSQL >= 16.13 para la API basada en DB y la persistencia del escáner.
Aplica las migraciones con psql en orden:
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
O aplica las migraciones usando el comando auxiliar del contenedor:
docker run --rm \
-e LAYERLEAK_DATABASE_URL="$LAYERLEAK_DATABASE_URL" \
ghcr.io/brumbelow/layerleak:latest \
layerleak-migrate-up
layerleak-migrate-up es seguro de volver a ejecutar cuando las migraciones ya están aplicadas.
Si detecta un estado de migración parcial, sale con código distinto de cero y solicita intervención manual.
El auxiliar también impone la versión del servidor >= 16.13 y valida que el postgresql-client-16 incluido use el paquete Ubuntu PGDG 24.04 (.pgdg24.04+) en la versión >= 16.13-1.pgdg24.04+1.
Revertir las migraciones en orden inverso:
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
Valores predeterminados operativos:
first_seen_at y last_seen_at, y también almacena el historial de escaneos de solo añadido en scan_runs.(manifest_digest, fingerprint), y los fragmentos de contexto idénticos repetidos se colapsan antes de la persistencia.Nota de seguridad de secretos:
LAYERLEAK_PERSIST_RAW_SECRETS=1, Postgres también almacena valores de hallazgos sin procesar y fragmentos sin procesar.scan_runs.result_json permanece redactada.Mostrar la ayuda de CLI:
layerleak --help
layerleak scan --help

Ejecutar un escaneo contra una imagen OCI pública en cualquier registro compatible:
./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

Cada escaneo escribe un archivo JSON de hallazgos en el directorio de salida de hallazgos.
Si LAYERLEAK_FINDINGS_DIR no está establecido, el directorio de salida predeterminado es findings/ dentro del directorio padre más cercano que contenga go.mod (típicamente la raíz del repositorio), con un fallback al directorio de trabajo actual cuando no se encuentra la raíz del repositorio.
Esos archivos de hallazgos guardados contienen registros de hallazgos con redacted_value, context_snippet redactado, ubicación exacta de origen, metadatos de disposición y número de línea para cada hallazgo.
Si LAYERLEAK_PERSIST_RAW_SECRETS=1, los archivos de hallazgos guardados también incluyen value sin procesar y raw_context_snippet.
Si la persistencia en Postgres está habilitada, findings.value y finding_occurrences.raw_snippet sin procesar permanecen vacíos a menos que LAYERLEAK_PERSIST_RAW_SECRETS=1.
Para imágenes multi-arquitectura, layerleak omite los manifiestos de atestación y procedencia como application/vnd.in-toto+json en lugar de contarlos como escaneos de plataforma fallidos.
Barridos de repositorios desnudos:
mongo enumera cada etiqueta pública en ese repositorio, resuelve cada etiqueta a un digest, agrupa digests duplicados y escanea los objetivos distintos.mongo:latest o mongo@sha256:....Sintaxis de comando:
layerleak [command]
layerleak scan <image-ref> [flags]
Indicadores de alcance para barridos de repositorios (cada uno anula la variable de entorno correspondiente para un solo comando):
Layerleak también incluye una API JSON mínima bajo cmd/api.
La API está respaldada por Postgres y requiere LAYERLEAK_DATABASE_URL; no sirve desde los archivos de hallazgos en disco.
Iniciarla con:
go run ./cmd/api
O ejecutar el contenedor de la API:
docker run --rm \
-p 8080:8080 \
-e LAYERLEAK_DATABASE_URL='postgres://<usuario>:<contraseña>@<host>:5432/layerleak?sslmode=disable' \
ghcr.io/brumbelow/layerleak:latest
Puntos finales actuales:
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 devuelve {"status":"ok"} y no requiere un almacén o escáner configurado.
Es adecuado para sondas de preparación de Kubernetes y objetivos healthcheck de Docker Compose.
POST /api/v1/scans permanece sincrónico. Acepta un cuerpo JSON con reference y platform opcional, y devuelve scan_run_id siempre que la persistencia en Postgres esté habilitada.
Las respuestas de escaneo de API reutilizan el mismo esquema de resultados redactados que la salida JSON de CLI.
GET /api/v1/scans/{id} devuelve los metadatos de ejecución persistentes más la instantánea de resultados redactados almacenada.
Los puntos finales de repositorios y hallazgos también permanecen redactados: devuelven redacted_value y context_snippet redactado, nunca valores secretos sin procesar ni fragmentos sin procesar de Postgres.
GET /api/v1/repositories/{repository}/scans y GET /api/v1/repositories/{repository}/findings aceptan un parámetro de consulta registry opcional (por ejemplo ?registry=ghcr.io). Cuando se omite, el registro predeterminado es docker.io para compatibilidad hacia atrás. Úsalo para obtener escaneos de repositorios en GHCR, Quay, GCR, MCR, Amazon ECR Public o cualquier registro auto-alojado.
Los puntos finales de listado (/repositories, /repositories/{repository}/scans, /repositories/{repository}/findings) aceptan ?limit= y ?offset= para paginación. limit predeterminado a 50 y tiene un límite máximo de 200. /repositories/{repository}/findings también acepta ?disposition=actionable|suppressed|all; cuando se omite, la respuesta solo incluye hallazgos procesables.
La API no incluye autenticación. Para despliegues organizacionales, mantenla en una red privada y coloca delante tu propia puerta de enlace de autenticación/autorización o política de proxy inverso.
Este repositorio incluye una pila Compose en docker-compose.yml con servicios db, migrate y api.
El servicio db tiene una línea base fijada a postgres:16.13-alpine.
Si usas una imagen Postgres diferente, mantén la versión del servidor en 16.13 o más reciente.
Establecer las variables de despliegue (exportar en la shell o colocar en un archivo .env junto a 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
Validar la configuración de Compose renderizada antes del despliegue:
docker compose config
Ejecutar las migraciones una vez antes de iniciar la API:
docker compose --profile manual run --rm migrate
Iniciar el servicio API:
docker compose up -d api
En Dockge o Komodo, importa el mismo archivo Compose y ejecuta el servicio migrate una vez antes de habilitar el servicio api de larga duración.
Publicado bajo la Licencia MIT — consulta LICENSE.
Si este repo te ahorró tiempo o te ayudó, puedes apoyar las futuras actualizaciones aquí:
¡Gracias! :) realmente ayuda a mantener el proyecto.
| Variable | Valor predeterminado | Propósito |
|---|
LAYERLEAK_LOG_LEVEL | info | Nivel de registro: debug, info, warn o error. |
LAYERLEAK_FINDINGS_DIR | sin establecer | Dónde escribir los archivos JSON de hallazgos. Si no se establece, por defecto es findings/ dentro del padre más cercano que contenga go.mod, cayendo al directorio de trabajo actual. |
LAYERLEAK_API_ADDR | 127.0.0.1:8080 | Dirección de enlace para el servidor API. La imagen del contenedor lo anula a 0.0.0.0:8080. |
LAYERLEAK_PERSIST_RAW_SECRETS | 0 | Establecer a 1 para escribir valores secretos sin procesar y fragmentos de contexto sin procesar en disco y Postgres. Los hallazgos permanecen redactados por defecto. |
LAYERLEAK_HTTP_TIMEOUT | 30s | Tiempo de espera por solicitud para cada llamada al registro (manifiestos, blobs, páginas de etiquetas, tokens de autenticación). Acepta cualquier duración de Go (30s, 2m, 1h). |
LAYERLEAK_MAX_FILE_BYTES | 1048576 (1 MiB) | Máximo de bytes descomprimidos almacenados en búfer por archivo dentro de una capa. Los archivos más grandes de esto se omiten por ser demasiado grandes. Debe ser mayor que cero. |
LAYERLEAK_MAX_LAYER_BYTES | 536870912 (512 MiB) | Máximo de bytes de flujo de capa descomprimida por capa. 0 deshabilita el límite. |
LAYERLEAK_MAX_LAYER_ENTRIES | 50000 | Máximo de entradas tar por capa. 0 deshabilita el límite. |
LAYERLEAK_MAX_MANIFEST_BYTES | 0 | Máximo de bytes del cuerpo del manifiesto. 0 deshabilita el límite. |
LAYERLEAK_MAX_CONFIG_BYTES | 0 | Máximo de bytes del cuerpo de configuración de la imagen. 0 deshabilita el límite. |
LAYERLEAK_MAX_TAG_RESPONSE_BYTES | 8388608 (8 MiB) | Máximo de bytes por página de respuesta de lista de etiquetas del registro. 0 deshabilita el límite. |
LAYERLEAK_TAG_PAGE_SIZE | 100 | Tamaño de página de lista de etiquetas del registro para escaneos en todo el repositorio. |
LAYERLEAK_MAX_REPOSITORY_TAGS | 0 | Máximo de etiquetas enumeradas por escaneo de repositorio. 0 deshabilita el límite. |
LAYERLEAK_MAX_REPOSITORY_TARGETS | 0 | Máximo de objetivos distintos resueltos por escaneo de repositorio. 0 deshabilita el límite. |
LAYERLEAK_REGISTRY_REQUEST_ATTEMPTS | 2 | Número de intentos (incluyendo el primero) por cada solicitud al registro. |
LAYERLEAK_REGISTRY_BASE_URL | sin establecer | Anulación opcional. Normalmente layerleak deriva esto de cada referencia de imagen; establecer solo para forzar escaneos a través de un proxy o punto final alternativo. |
LAYERLEAK_REGISTRY_AUTH_URL | sin establecer | Anulación opcional. Normalmente se descubre a partir del desafío WWW-Authenticate del registro. |
LAYERLEAK_DATABASE_URL | sin establecer | Si se establece, layerleak escribe los escaneos en Postgres y falla el comando si la persistencia no tiene éxito. |
| Indicador | Propósito |
|---|
--tag-page-size | Tamaño de página de lista de etiquetas del registro para barridos de repositorios. Debe ser mayor que cero. Anula LAYERLEAK_TAG_PAGE_SIZE. |
--max-repository-tags | Máximo de etiquetas enumeradas por barrido de repositorio. 0 deshabilita el límite. Anula LAYERLEAK_MAX_REPOSITORY_TAGS. |
--max-repository-targets | Máximo de objetivos distintos resueltos por barrido de repositorio. 0 deshabilita el límite. Anula LAYERLEAK_MAX_REPOSITORY_TARGETS. |