查看 CONTRIBUTING.md 了解贡献指南。
已发布的站点由.github/workflows/pages.yml从main分支的web/目录构建。文档源码和模拟浏览器演示都在该目录下。
先决条件:
使用Go安装:
go install github.com/brumbelow/layerleak@latest
layerleak --help
规范安装目标为模块根目录。 要显式固定某个版本:
go install github.com/brumbelow/[email protected]
将v1.0.0替换为你想要发布的v1.x.y标签。
确保你的GOBIN或GOPATH/bin目录在PATH中。
模块路径是github.com/brumbelow/layerleak,因此go install @latest会解析到最高发布的v1.x.y标签。v2.x.y模块版本需要将模块路径改为github.com/brumbelow/layerleak/v2。模块安装的二进制文件通过layerleak --version报告解析的模块版本;本地检出构建报告Go嵌入的版本,如果没有模块版本可用则回退到dev。
从源码构建:
git clone https://github.com/brumbelow/layerleak.git
cd layerleak
go build -o layerleak .
./layerleak --help
使用容器镜像运行API:
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
容器镜像默认运行API,并设置LAYERLEAK_API_ADDR=0.0.0.0:8080。
可选的环境配置:
cp .env.example .env
结果和数据库配置:
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
# 可选仓库覆盖;通常保持未设置。
export LAYERLEAK_REGISTRY_BASE_URL=
export LAYERLEAK_REGISTRY_AUTH_URL=
export LAYERLEAK_DATABASE_URL=postgres://postgres:postgres@localhost:5432/layerleak?sslmode=disable
相同的变量及其默认值位于.env.example中,它是默认值的真实来源。
当任何MAX_*限制设置为正值时,超出限制会导致扫描失败并显示明确的错误,而不是静默截断工作。
结果行为:
findings中,并驱动非零的扫描退出状态。total_findings。disposition、disposition_reason和line_number,使分类和误报审查更容易。1退出,因为扫描不完整。Layerleak在migrations/目录下附带版本化的SQL迁移。
迁移是有意手动执行的。扫描器不会自动创建或升级模式。
Layerleak需要PostgreSQL服务器>= 16.13以支持基于数据库的API和扫描器持久化。
按顺序使用psql应用迁移:
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
或者使用容器辅助命令应用迁移:
docker run --rm \
-e LAYERLEAK_DATABASE_URL="$LAYERLEAK_DATABASE_URL" \
ghcr.io/brumbelow/layerleak:latest \
layerleak-migrate-up
layerleak-migrate-up在迁移已应用时重复运行是安全的。
如果检测到部分迁移状态,它会以非零状态退出并请求手动干预。
该辅助命令还会强制检查服务器版本>= 16.13,并验证捆绑的postgresql-client-16使用Ubuntu PGDG 24.04打包(.pgdg24.04+),版本>= 16.13-1.pgdg24.04+1。
按相反顺序回滚迁移:
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
操作默认值:
first_seen_at和last_seen_at,还以追加方式存储扫描历史记录在scan_runs中。(manifest_digest, fingerprint)规范去重,持久化前会折叠重复的相同上下文片段。关于秘密安全的说明:
LAYERLEAK_PERSIST_RAW_SECRETS=1,Postgres也会存储原始发现值和原始片段。scan_runs.result_json快照保持脱敏。显示CLI帮助:
layerleak --help
layerleak scan --help

对任何支持仓库上的公共OCI镜像运行扫描:
./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

每次扫描都会将JSON结果文件写入结果输出目录。
如果未设置LAYERLEAK_FINDINGS_DIR,默认输出目录是包含go.mod的最近父目录下的findings/(通常是仓库根目录),如果未找到仓库根目录,则回退到当前工作目录。
这些保存的结果文件包含发现记录,包括redacted_value、脱敏的context_snippet、精确的源位置、分类元数据以及每个发现的行号。
如果LAYERLEAK_PERSIST_RAW_SECRETS=1,保存的结果文件还包括原始value和raw_context_snippet。
如果启用了Postgres持久化,原始findings.value和finding_occurrences.raw_snippet保持为空,除非设置了LAYERLEAK_PERSIST_RAW_SECRETS=1。
对于多架构镜像,layerleak会跳过证明和来源清单(如application/vnd.in-toto+json),而不是将其计为失败的平台扫描。
裸仓库扫描:
mongo)会枚举该仓库中的每个公共标签,将每个标签解析为摘要,对重复摘要进行分组,然后扫描不同的目标。mongo:latest或mongo@sha256:...。命令语法:
layerleak [command]
layerleak scan <image-ref> [flags]
仓库扫描的范围标志(每个标志会覆盖相应的环境变量,仅对单个命令生效):
Layerleak还附带一个最小的JSON API,位于cmd/api下。
该API基于Postgres,需要LAYERLEAK_DATABASE_URL;它不提供磁盘上的结果文件服务。
启动它:
go run ./cmd/api
或者运行API容器:
docker run --rm \
-p 8080:8080 \
-e LAYERLEAK_DATABASE_URL='postgres://<user>:<password>@<host>:5432/layerleak?sslmode=disable' \
ghcr.io/brumbelow/layerleak:latest
当前端点:
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返回{"status":"ok"},不需要配置存储或扫描器。
它适用于Kubernetes就绪探针和Docker Compose的healthcheck目标。
POST /api/v1/scans保持同步。它接受一个包含reference和可选platform的JSON体,并在Postgres持久化启用时返回scan_run_id。
API扫描响应重用与CLI JSON输出相同的脱敏结果模式。
GET /api/v1/scans/{id}返回持久化的运行元数据以及存储的脱敏结果快照。
仓库和发现端点也保持脱敏:它们返回redacted_value和脱敏的context_snippet,绝不返回Postgres中的原始秘密值或原始片段。
GET /api/v1/repositories/{repository}/scans和GET /api/v1/repositories/{repository}/findings接受一个可选的registry查询参数(例如?registry=ghcr.io)。如果省略,则仓库默认使用docker.io以实现向后兼容。使用此参数获取GHCR、Quay、GCR、MCR、Amazon ECR Public或任何自托管镜像仓库上的仓库扫描结果。
列表端点(/repositories、/repositories/{repository}/scans、/repositories/{repository}/findings)接受?limit=和?offset=进行分页。limit默认为50,上限为200。/repositories/{repository}/findings还接受?disposition=actionable|suppressed|all;如果省略,响应仅包含可操作的发现结果。
API不包含认证。 对于组织部署,请将其保持在私有网络中,并通过你自己的认证/授权网关或反向代理策略进行前端保护。
该仓库在docker-compose.yml中提供了一个Compose堆栈,包含db、migrate和api服务。
db服务基线固定为postgres:16.13-alpine。
如果你使用不同的Postgres镜像,请保持服务器版本为16.13或更高。
设置部署变量(在shell中导出,或放在与docker-compose.yml同级的.env文件中):
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
在部署前验证渲染的Compose配置:
docker compose config
启动API前运行一次迁移:
docker compose --profile manual run --rm migrate
启动API服务:
docker compose up -d api
在Dockge或Komodo中,导入相同的Compose文件,并在启用长时间运行的api服务之前先运行一次migrate服务。
根据MIT许可发布——参见LICENSE。
| 变量 | 默认值 | 用途 |
|---|
LAYERLEAK_LOG_LEVEL | info | 日志级别:debug、info、warn或error。 |
LAYERLEAK_FINDINGS_DIR | 未设置 | 写入JSON结果文件的目录。如果未设置,默认为包含go.mod的最近父目录下的findings/,若找不到则回退到当前工作目录。 |
LAYERLEAK_API_ADDR | 127.0.0.1:8080 | API服务器的绑定地址。容器镜像将此覆盖为0.0.0.0:8080。 |
LAYERLEAK_PERSIST_RAW_SECRETS | 0 | 设置为1以将原始秘密值和原始上下文片段写入磁盘和Postgres。默认情况下,结果保持脱敏状态。 |
LAYERLEAK_HTTP_TIMEOUT | 30s | 每次仓库调用(清单、数据块、标签页面、认证令牌)的请求超时。接受任何Go持续时间(30s、2m、1h)。 |
LAYERLEAK_MAX_FILE_BYTES | 1048576(1 MiB) | 层内每个文件缓冲的最大解压字节数。大于此值的文件将被跳过(视为过大)。必须大于零。 |
LAYERLEAK_MAX_LAYER_BYTES | 536870912(512 MiB) | 每层解压流的最大字节数。0表示禁用限制。 |
LAYERLEAK_MAX_LAYER_ENTRIES | 50000 | 每层的最大tar条目数。0表示禁用限制。 |
LAYERLEAK_MAX_MANIFEST_BYTES | 0 | 最大清单体字节数。0表示禁用限制。 |
LAYERLEAK_MAX_CONFIG_BYTES | 0 | 最大镜像配置体字节数。0表示禁用限制。 |
LAYERLEAK_MAX_TAG_RESPONSE_BYTES | 8388608(8 MiB) | 每次仓库标签列表响应页的最大字节数。0表示禁用限制。 |
LAYERLEAK_TAG_PAGE_SIZE | 100 | 仓库范围扫描的仓库标签列表页面大小。 |
LAYERLEAK_MAX_REPOSITORY_TAGS | 0 | 每次仓库扫描枚举的最大标签数。0表示禁用限制。 |
LAYERLEAK_MAX_REPOSITORY_TARGETS | 0 | 每次仓库扫描解析的最大不同目标数。0表示禁用限制。 |
LAYERLEAK_REGISTRY_REQUEST_ATTEMPTS | 2 | 每次仓库请求的尝试次数(包括第一次)。 |
LAYERLEAK_REGISTRY_BASE_URL | 未设置 | 可选覆盖。通常layerleak从每个镜像引用中派生此值;仅当需要强制通过代理或替代端点进行扫描时设置。 |
LAYERLEAK_REGISTRY_AUTH_URL | 未设置 | 可选覆盖。通常从仓库的WWW-Authenticate挑战中发现。 |
LAYERLEAK_DATABASE_URL | 未设置 | 如果设置,layerleak将扫描结果写入Postgres,如果持久化不成功,命令将失败。 |
| 标志 | 用途 |
|---|
--tag-page-size | 仓库扫描的标签列表页面大小。必须大于零。覆盖LAYERLEAK_TAG_PAGE_SIZE。 |
--max-repository-tags | 每次仓库扫描枚举的最大标签数。0禁用限制。覆盖LAYERLEAK_MAX_REPOSITORY_TAGS。 |
--max-repository-targets | 每次仓库扫描解析的最大不同目标数。0禁用限制。覆盖LAYERLEAK_MAX_REPOSITORY_TARGETS。 |