
layerleak Docker Hub 시크릿 스캐너
기여 지침은 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에 있으며, 이는 기본값의 진실 공급원(source of truth)입니다.
MAX_* 제한 중 하나라도 양수 값으로 설정되면 초과 시 작업을 자동으로 자르는 대신 명확한 오류와 함께 스캔이 실패합니다.
결과 동작:
findings에 남아 있으며 0이 아닌 스캔 종료 상태를 유발합니다.total_findings에 포함되지 않습니다.disposition, disposition_reason 및 line_number가 포함됩니다.1로 종료됩니다.Layerleak은 migrations/ 아래에 버전 관리된 SQL 마이그레이션을 제공합니다. 마이그레이션은 의도적으로 수동으로 수행됩니다. 스캐너는 스키마를 자동 생성하거나 자동 업그레이드하지 않습니다. Layerleak은 DB 기반 API 및 스캐너 영속성을 위해 PostgreSQL 서버 >= 16.13이 필요합니다.
순서대로 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은 마이그레이션이 이미 적용된 경우 다시 실행해도 안전합니다. 부분 마이그레이션 상태가 감지되면 0이 아닌 종료 코드로 종료하고 수동 개입을 요청합니다. 헬퍼는 또한 서버 버전 >= 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, 정확한 소스 위치, disposition 메타데이터 및 라인 번호가 포함된 결과 레코드가 포함됩니다. LAYERLEAK_PERSIST_RAW_SECRETS=1이면 저장된 결과 파일에 원시 value와 raw_context_snippet도 포함됩니다. Postgres 영속성이 활성화된 경우 LAYERLEAK_PERSIST_RAW_SECRETS=1이 아니라면 원시 findings.value와 finding_occurrences.raw_snippet은 비어 있습니다. 멀티아키텍처 이미지의 경우 layerleak은 증명(attestation) 및 출처(provenance) 매니페스트(예: application/vnd.in-toto+json)를 실패한 플랫폼 스캔으로 계산하지 않고 건너뜁니다.
베어 리포지토리 전체 스캔:
mongo)을 전달하면 해당 리포지토리의 모든 공개 태그를 열거하고, 각 태그를 다이제스트로 해석하고, 중복 다이제스트를 그룹화하여 고유 대상을 스캔합니다.mongo:latest 또는 mongo@sha256:...와 같이 명시적 태그 또는 다이제스트를 전달하세요.명령 구문:
layerleak [command]
layerleak scan <image-ref> [flags]
리포지토리 전체 스캔을 위한 범위 플래그 (각각 단일 명령에 대해 일치하는 환경 변수 재정의):
Layerleak은 cmd/api 아래에 최소한의 JSON 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 준비성 프로브(readiness probe) 및 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을 허용합니다. 생략하면 응답에 actionable 결과만 포함됩니다.
API에는 인증이 포함되어 있지 않습니다. 조직 배포의 경우 개인 네트워크에 유지하고 자체 인증/권한 부여 게이트웨이 또는 리버스 프록시 정책을 앞에 두십시오.
이 리포지토리는 db, migrate, api 서비스가 포함된 Compose 스택을 docker-compose.yml에 제공합니다. db 서비스 기본은 postgres:16.13-alpine으로 고정되어 있습니다. 다른 Postgres 이미지를 사용하는 경우 서버 버전을 16.13 이상으로 유지하세요.
배포 변수 설정 (셸에서 내보내거나 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) | 레이어 내 파일당 버퍼링되는 최대 압축 해제 바이트 수. 이보다 큰 파일은 크기 초과로 건너뜁니다. 0보다 커야 합니다. |
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 | 리포지토리 전체 스캔을 위한 레지스트리 태그 목록 페이지 크기. 0보다 커야 합니다. LAYERLEAK_TAG_PAGE_SIZE를 재정의합니다. |
--max-repository-tags | 리포지토리 전체 스캔당 열거되는 최대 태그 수. 0은 제한을 비활성화합니다. LAYERLEAK_MAX_REPOSITORY_TAGS를 재정의합니다. |
--max-repository-targets | 리포지토리 전체 스캔당 해석되는 최대 고유 대상 수. 0은 제한을 비활성화합니다. LAYERLEAK_MAX_REPOSITORY_TARGETS를 재정의합니다. |