콘텐츠로 이동

Betterleaks

Betterleaks는 Gitleaks의 후계자인 Go로 작성된 현대적인 시크릿 스캐너입니다. BPE 토큰화 및 CEL 기반 검증 로직을 사용하여 git 저장소, 디렉토리 및 stdin에서 누출된 자격증명을 스캔합니다.

go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest
# GitHub에서 최신 릴리스 다운로드
wget https://github.com/zricorp/betterleaks/releases/download/v2.0.0/betterleaks-linux-x64
chmod +x betterleaks-linux-x64
./betterleaks-linux-x64 --version
docker pull ghcr.io/zricorp/betterleaks:latest
docker run ghcr.io/zricorp/betterleaks:latest --help
brew install betterleaks
# 현재 디렉토리 스캔 (.git이 있다고 가정)
betterleaks scan

# 특정 저장소 스캔
betterleaks scan --repo /path/to/repo

# 상세 출력으로 스캔
betterleaks scan --verbose

# 발견 수 요약 표시
betterleaks scan --report
# 파일시스템으로 디렉토리 스캔 (git 히스토리가 아님)
betterleaks scan --no-git --directory /path/to/directory

# 여러 디렉토리 스캔
betterleaks scan --no-git --directory /src --directory /config
# stdin을 통해 콘텐츠 파이프
echo "aws_access_key_id=AKIAIOSFODNN7EXAMPLE" | betterleaks scan --stdin

# 파일 콘텐츠 스캔
cat secrets.txt | betterleaks scan --stdin
# 원격 저장소 복제 및 스캔 (임시 디렉토리 생성)
betterleaks scan --repo https://github.com/user/repo.git

# 특정 브랜치 스캔
betterleaks scan --repo https://github.com/user/repo.git --branch main

프로젝트 루트에 .betterleaks.toml 만들기:

# .betterleaks.toml 경로
title = "Betterleaks Config"

# 상세 출력
verbose = false

# 발견 시 종료 코드
exit-code = 1

# 사용할 규칙 ID 목록 (기본값: 모두)
rules = ["aws", "github", "gcp", "api-keys"]

# 기본 제공 규칙 비활성화
no-builtin-rules = false

# 커스텀 허용 목록
allowlist = {
  regexes = [
    "example-test-key",
    "fake-credential"
  ],
  paths = [
    "vendor/",
    "test/",
    ".git/"
  ],
  commits = [
    "abc123def456"
  ]
}
[git]
# 전체 히스토리 스캔
scan-history = true

# 스캔할 최대 커밋 수
max-commits = 1000

# 제외할 브랜치
exclude-branches = ["develop", "staging"]

# 포함할 브랜치
include-branches = ["main", "production"]

# 최대 커밋 깊이
commit-depth = 50
[output]
# 출력 형식: json, sarif, csv, table
format = "json"

# 출력 파일 경로
file = "secrets-report.json"

# JSON을 예쁘게 출력
pretty = true

# 전체 라인이 아닌 일치한 텍스트만 포함
redact = true
# 저장소 히스토리 시작부터 스캔
betterleaks scan --repo /path/to/repo

# 커밋 세부정보와 함께 상세 출력
betterleaks scan --repo /path/to/repo --verbose
# 두 ref 사이의 커밋 스캔
betterleaks scan --repo /path/to/repo --commit-since abc123 --commit-until def456

# 마지막 N개 커밋 스캔
betterleaks scan --repo /path/to/repo --max-commits 50
# 특정 브랜치 스캔
betterleaks scan --repo /path/to/repo --branch main

# 여러 브랜치 스캔
betterleaks scan --repo /path/to/repo --branch main --branch develop

커밋되지 않은 변경사항만 확인

섹션 제목: “커밋되지 않은 변경사항만 확인”
# 스테이징된 변경사항만 스캔
betterleaks scan --repo /path/to/repo --no-history

# 작업 디렉토리 변경사항 스캔
betterleaks scan --repo /path/to/repo --staged-only

.github/workflows/betterleaks.yml 생성:

name: Betterleaks Scan
on: [push, pull_request]

jobs:
  betterleaks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Betterleaks
        run: go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest

      - name: Scan for secrets
        run: betterleaks scan --report --exit-code 1

      - name: Generate SARIF report
        if: always()
        run: betterleaks scan --format sarif --file results.sarif

      - name: Upload SARIF to GitHub Security
        uses: github/codeql-action/upload-sarif@v2
        if: always()
        with:
          sarif_file: results.sarif

.gitlab-ci.yml 생성:

secret_scan:
  image: golang:1.22
  script:
    - go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest
    - betterleaks scan --format json --file secrets-report.json
  artifacts:
    reports:
      sast: secrets-report.json
  allow_failure: false

.git/hooks/pre-commit 생성:

#!/bin/bash
set -e

echo "Running Betterleaks scan..."
betterleaks scan --no-history --exit-code 1

if [ $? -ne 0 ]; then
  echo "Secrets found! Commit blocked."
  exit 1
fi

echo "No secrets detected. Proceeding with commit."

다음으로 실행 가능하게 만들기:

chmod +x .git/hooks/pre-commit

betterleaks-rules.toml 생성:

[[rules]]
id = "custom-api-key"
description = "Custom API key pattern"
regex = '''api[_-]?key[_-]?["\s:=]+[A-Za-z0-9]{32,}'''

# CEL 검증 표현식
entropy = 3.0
keywords = ["api", "key"]

# CEL을 사용한 검증 로직
filter = '''
  len(secret) > 30 &&
  secret.matches("[A-Za-z0-9]{32,}") &&
  !secret.contains("example")
'''

allowlist = {
  regexes = ["test-key", "fake-"]
}
# 커스텀 규칙 파일 사용
betterleaks scan --rules betterleaks-rules.toml

# 기본 제공 규칙 및 커스텀 규칙 포함
betterleaks scan --rules betterleaks-rules.toml --include-builtin
[[rules]]
id = "stripe-api-key"
description = "Stripe secret key"
regex = '''sk_(test|live)_[A-Za-z0-9]{20,}'''

# BPE 토큰화 엔트로피 임계값
entropy = 2.5

# 실제 시크릿을 나타내는 키워드
keywords = ["stripe", "sk_live", "sk_test"]

# 검증을 위한 CEL 표현식
filter = '''
  secret.matches("^sk_(test|live)_") &&
  len(secret) > 20 &&
  secret != "sk_test_placeholder"
'''

# 특정 시크릿을 허용 목록에 추가
allowlist = {
  regexes = ["sk_test_4eC39HqLyjWDarhtT1234"],
  paths = ["test/", "docs/examples/"]
}
# JSON 보고서 생성
betterleaks scan --format json --file report.json

# 예쁘게 출력된 JSON
betterleaks scan --format json --pretty

JSON 구조:

{
  "findings": [
    {
      "rule_id": "aws-access-key",
      "rule_name": "AWS Access Key",
      "file": "config/aws.env",
      "secret": "AKIAIOSFODNN7EXAMPLE",
      "entropy": 4.2,
      "line": 5,
      "commit": "abc123def456",
      "commit_author": "user@example.com",
      "committed_date": "2025-12-01T10:30:00Z"
    }
  ],
  "summary": {
    "total_findings": 1,
    "total_commits_scanned": 150,
    "scan_duration_ms": 5230
  }
}
# SARIF 보고서 생성
betterleaks scan --format sarif --file results.sarif

# SARIF는 GitHub 보안 탭과 호환됨
# CSV 보고서 생성
betterleaks scan --format csv --file secrets.csv

# 출력 포함: rule_id, file, line, secret_hash, severity, commit
# 기본 인간 친화적 테이블
betterleaks scan --format table

# 출력 예:
# RuleID          File              Line  Secret                Entropy
# aws-key         config/aws.env    5     AKIA...EXAMPLE        4.2
# github-token    .env              12    ghp_...               3.8

Betterleaks는 Gitleaks의 드롭인 대체:

  • 동일한 CLI 플래그 및 인자
  • 호환 설정 파일 형식 (.gitleaks.toml → .betterleaks.toml)
  • 동일한 출력 형식 (JSON, SARIF, CSV)
# Gitleaks 설정을 Betterleaks로 이름 변경
cp .gitleaks.toml .betterleaks.toml

# 대부분의 설정은 변경되지 않고 작동
# 주요 차이점: BPE 토큰화는 기본값 (Shannon 엔트로피 아님)
# Betterleaks는 일반적으로 Gitleaks보다 3-5배 빠름
# Go 루틴이 있는 병렬 git 스캔
betterleaks scan --parallel 4  # 기본값: CPU 개수 자동 감지

Betterleaks는 인코딩된 형식에서 시크릿 감지:

# 자동으로 처리:
# - Base64 인코딩된 시크릿
# - URL 인코딩된 자격증명
# - Hex 인코딩된 값
# - 이중/삼중 인코딩

betterleaks scan --detect-encoding

# 예: "QUtJQUlPU0ZPRK5ON0VYQU1QTEUt" (base64)에서 시크릿 감지
# CPU 개수를 자동 감지하고 모든 코어 사용
betterleaks scan

# 스레드 수 지정
betterleaks scan --parallel 8

# 병렬화 비활성화
betterleaks scan --parallel 1
# SARIF 변환 및 다른 도구로 파싱
betterleaks scan --format sarif | jq '.runs[0].results'

# 규칙별로 발견 수 계산
betterleaks scan --format json | jq '.findings | group_by(.rule_id)'

# 발견 사항이 있는 파일 경로만 추출
betterleaks scan --format json | jq -r '.findings[].file' | sort -u
# 커밋 스캔 깊이 증가
betterleaks scan --max-commits 5000

# 엔트로피 임계값 설정 (낮을수록 더 민감함)
# .betterleaks.toml에서 규칙별 엔트로피 값으로 구성

# 큰 파일 건너뛰기
betterleaks scan --max-file-size 10MB
# Pre-commit hook에 추가
# 스테이징된 변경사항만 스캔
betterleaks scan --staged-only --exit-code 1

2. 처음 구현할 때 전체 히스토리 스캔

섹션 제목: “2. 처음 구현할 때 전체 히스토리 스캔”
# 기존 시크릿 식별
betterleaks scan --repo . --report

# 수정 전에 발견 사항 검토
betterleaks scan --format json | jq '.findings | length'
# .betterleaks.toml의 허용 목록 사용
[allowlist]
regexes = [
  "test-key-[0-9]+",
  "example-api-key"
]
paths = [
  "test/fixtures/",
  "docs/examples/",
  ".github/"
]
commits = [
  "abc123def456"  # 알려진 시크릿이 있는 특정 커밋
]
# 종료 코드를 스캔 강제 적용
betterleaks scan --exit-code 1

# 발견된 항목에서 CI/CD 실패
# GitHub Actions, GitLab CI, Jenkins 등에서 구성
# Betterleaks가 노출된 자격증명을 찾은 경우:
# 1. 시크릿과 범위 식별
# 2. 자격증명 즉시 회전
# 3. git-filter-repo를 사용하여 git 히스토리에서 제거
# 4. 제거를 확인하기 위해 다시 스캔
# 소유 패턴용 조직 특화 규칙 생성
[[rules]]
id = "acme-internal-api-key"
description = "ACME Corp internal API key"
regex = '''api_key[_\s:=]+[A-Z]{4}_[a-z0-9]{32}'''
entropy = 3.0
keywords = ["api_key", "acme"]
[allowlist]
paths = [
  "vendor/",
  "node_modules/",
  ".git/",
  "dist/",
  "build/",
  "test/fixtures/secrets/"
]
# 추세 추적을 위한 보고서 생성
betterleaks scan --format json > scans/$(date +%Y-%m-%d).json

# 시간에 따른 발견 사항 비교
jq '.summary.total_findings' scans/*.json
# Go 설치 확인 (1.20+)
go version

# 필요한 경우 Go 캐시 지우기
go clean -cache
go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest
# 상세 출력 활성화
betterleaks scan --verbose

# 활성 규칙 확인
betterleaks scan --rules all

# 정규식 패턴이 일치하는지 확인
# 정규식 테스트: echo "secret" | grep -E 'pattern'
# .betterleaks.toml의 엔트로피 임계값 증가
entropy = 4.0  # 기본값은 규칙에 따라 다름

# 더 엄격한 검증을 위해 CEL 필터 사용
filter = '''secret.matches("^[A-Z0-9]{32,}$")'''

# 허용 목록 패턴 추가
[allowlist]
regexes = ["test", "example", "placeholder"]
# 병렬 워커 줄이기
betterleaks scan --parallel 2

# 커밋 깊이 제한
betterleaks scan --max-commits 1000

# 시스템 메모리 증가 또는 더 작은 저장소 범위 사용
  • git-secrets: 패턴 매칭을 위한 간단한 git hook
  • TruffleHog: AI 기반 시크릿 감지
  • detect-secrets: PII 및 시크릿 감지
  • GitGuardian CLI: 엔터프라이즈 시크릿 스캔