Copy & Run

gitleaks로 저장소의 시크릿을 찾고 커밋 전에 막기

임시 git 저장소에 가짜 키를 넣고 gitleaks로 커밋 이력을 스캔합니다. JSON과 SARIF 리포트, baseline, 오탐 제외, pre-commit 훅까지 차례로 설정하고 GitHub Actions 예시를 붙입니다.

실습 노트 · 2026-10-16 발행 · 16분 · 2026-10 확인

가짜 AWS 키와 가짜 GitHub 토큰을 넣은 임시 저장소를 gitleaks로 스캔해서, 파일을 지운 뒤에도 커밋 이력에 시크릿이 남는다는 점을 확인합니다. 이어서 리포트 출력, baseline, 오탐 제외, pre-commit 훅을 설정해 새 시크릿이 커밋되기 전에 막히는 것까지 해 봅니다.

준비물

항목 내용
gitleaks 8.30.1 (Docker 이미지 zricethezav/gitleaks:v8.30.1)
Docker Docker Desktop (Engine 29.5.3)
Git 2.54.0
Python 3.12 (pre-commit 설치용)
pre-commit 4.7.0
Go 1.26.5 (7번 절의 기본 gitleaks 훅이 소스를 빌드할 때만 필요하고, docker 훅을 쓰면 필요 없습니다)
예상 소요 시간 약 30분 (Go 훅은 첫 설치에 시간이 더 걸립니다. 7번 절 참고)

gitleaks 저장소의 README는 git, dir, stdin 세 가지 스캔 서브커맨드를 안내하고, 이전 버전에서 쓰던 detect와 protect는 8.19.0에서 폐기됐다고 적고 있습니다. 이 글은 새 서브커맨드만 씁니다. 예제 값은 모두 형식만 맞춘 가짜이며 실제 키는 쓰지 않습니다.

이미지를 받고 버전을 확인합니다.

docker pull zricethezav/gitleaks:v8.30.1
docker run --rm zricethezav/gitleaks:v8.30.1 version

기대 출력의 마지막 줄입니다.

v8.30.1

매번 긴 docker run 명령을 치지 않도록 셸 함수를 하나 만듭니다. Windows의 Git Bash에서는 경로 변환이 -v 인자를 망가뜨리므로 MSYS_NO_PATHCONV=1과 pwd -W를 씁니다. Linux와 macOS에서는 -v "$PWD:/repo"를 쓰면 됩니다. 사용하는 환경에 맞는 쪽 하나만 등록합니다.

# Windows Git Bash
gl() { MSYS_NO_PATHCONV=1 docker run --rm -v "$(pwd -W):/repo" -w /repo zricethezav/gitleaks:v8.30.1 "$@"; }

# Linux, macOS
gl() { docker run --rm -v "$PWD:/repo" -w /repo zricethezav/gitleaks:v8.30.1 "$@"; }

이 글의 화면은 Windows Git Bash 쪽 함수로 실행한 결과입니다. 이 함수는 현재 폴더를 컨테이너의 /repo로 연결해 gitleaks를 실행합니다. 이후 gl로 적은 명령은 모두 이 함수를 거칩니다.

1. 가짜 시크릿이 든 저장소 만들기

커밋을 세 개 만듭니다. 두 번째 커밋에서 가짜 키가 든 설정 파일을 추가하고, 세 번째 커밋에서 그 파일을 지웁니다.

mkdir gl-demo && cd gl-demo
git init -b main
git config user.email dev@localhost
git config user.name dev
mkdir app && echo "print('hello')" > app/main.py
git add . && git commit -m "첫 커밋: 앱 뼈대"

cat > app/config.py <<'EOF'
AWS_ACCESS_KEY_ID = "AKIAJQXZPLMTRNBKWD3C"
GITHUB_TOKEN = "ghp_aB3dE5gH7jK9mN1pQ3sT5vW7yZ9bC1dE3fG5"
DB_PASSWORD = "not-a-secret"
EOF
git add . && git commit -m "설정 파일 추가"

git rm app/config.py && git commit -m "설정 파일 삭제"

AWS 공식 문서의 예시 값 AKIAIOSFODNN7EXAMPLE은 쓰지 않았습니다. 이 값은 gitleaks가 탐지하지 않아서 실습에 맞지 않기 때문입니다. 자세한 내용은 아래 자주 막히는 곳에 있습니다.

2. 작업 폴더와 커밋 이력을 따로 스캔하기

gl dir은 지금 폴더에 있는 파일을 검사하고, gl git은 커밋 이력 전체를 검사합니다. 둘을 차례로 돌려 결과를 비교합니다.

gl dir --no-banner .
gl git --no-banner .; echo "exit=$?"

기대 출력입니다. 시각과 소요 시간은 달라집니다.

INF scanned ~15 bytes (15 bytes) in 8.71ms
INF no leaks found
INF 2 commits scanned.
INF scanned ~145 bytes (145 bytes) in 192ms
WRN leaks found: 2
exit=1

설정 파일을 지웠기 때문에 dir은 아무것도 찾지 못합니다. git은 두 번째 커밋을 읽어 2건을 찾고 종료 코드 1로 끝납니다. 시크릿이 한 번 커밋되면 파일을 지워도 이력에 남으므로, 이력까지 스캔해야 합니다. 종료 코드는 발견이 있으면 1이고 --exit-code 옵션으로 바꿀 수 있습니다.

gl dir은 no leaks found, gl git은 leaks found: 2와 exit=1이 나오는 것을 확인합니다.
gl dir은 no leaks found, gl git은 leaks found: 2와 exit=1이 나오는 것을 확인합니다.

3. 탐지 내용 자세히 보기

-v를 붙이면 발견 한 건마다 규칙 이름, 파일, 줄, 커밋이 출력됩니다. --redact는 시크릿 값을 REDACTED로 가립니다. 로그나 CI 화면에 값이 그대로 남는 것을 막으므로 이 글에서는 계속 붙입니다.

gl git --no-banner --redact -v .

기대 출력은 아래 두 건입니다. 두 건의 출력 순서는 실행마다 바뀔 수 있고, 시각과 커밋 해시, 날짜도 달라집니다.

Finding:     ...WS_ACCESS_KEY_ID = "REDACTED
Secret:      REDACTED
RuleID:      aws-access-token
Entropy:     4.121928
File:        app/config.py
Line:        1
Commit:      e01f9d387ec539d0fe337070927d63ae25935d3d
Author:      dev
Email:       dev@localhost
Date:        2026-10-16T10:45:29Z
Fingerprint: e01f9d387ec539d0fe337070927d63ae25935d3d:app/config.py:aws-access-token:1

Finding:     GITHUB_TOKEN = "REDACTED
Secret:      REDACTED
RuleID:      github-pat
Entropy:     4.734184
File:        app/config.py
Line:        2
Commit:      e01f9d387ec539d0fe337070927d63ae25935d3d
Author:      dev
Email:       dev@localhost
Date:        2026-10-16T10:45:29Z
Fingerprint: e01f9d387ec539d0fe337070927d63ae25935d3d:app/config.py:github-pat:2

INF 2 commits scanned.
INF scanned ~145 bytes (145 bytes) in 188ms
WRN leaks found: 2

DB_PASSWORD = "not-a-secret"은 잡히지 않았습니다. 기본 규칙은 알려진 키 형식과 엔트로피 기준으로 판단하기 때문입니다. 각 건의 마지막 줄 Fingerprint는 뒤에서 오탐을 제외할 때 씁니다.

탐지 두 건의 Finding, RuleID, 파일, 줄, 커밋 해시, Fingerprint가 출력되고 Secret 값은 REDACTED로 가려진 것을 확인합니다.
탐지 두 건의 Finding, RuleID, 파일, 줄, 커밋 해시, Fingerprint가 출력되고 Secret 값은 REDACTED로 가려진 것을 확인합니다.

4. JSON과 SARIF 리포트 만들기

-f로 형식을, -r로 저장할 파일을 지정합니다. 8.30.1의 도움말에 나오는 형식은 json, csv, junit, sarif, template입니다.

gl git --no-banner --redact -f json -r report.json .
python -c "import json; [print(r['RuleID'], r['File'], r['StartLine'], r['Secret']) for r in json.load(open('report.json'))]"

gl git --no-banner --redact -f sarif -r report.sarif .
ls -l report.sarif

기대 출력입니다. 두 줄의 순서와 SARIF 파일 크기는 달라질 수 있습니다.

aws-access-token app/config.py 1 REDACTED
github-pat app/config.py 2 REDACTED
50646 report.sarif

JSON은 스크립트로 가공하기 쉽고, SARIF는 GitHub code scanning 같은 도구에 올릴 때 씁니다. SARIF에는 룰 정의 목록이 함께 들어가서 발견이 두 건뿐인데도 50KB가 넘습니다. results 항목만 뽑으면 JSON과 같은 위치 정보가 들어 있습니다.

다음 절부터는 git add .로 커밋하므로 리포트 파일을 지웁니다. 지우지 않으면 report.sarif가 커밋되고, 그 안의 룰 설명 문자열이 sourcegraph-access-token으로 추가 탐지돼 결과가 어긋납니다.

rm report.json report.sarif

JSON 리포트에서 RuleID, 파일, 줄 번호를 뽑은 결과와 SARIF 파일 크기, SARIF results에서 뽑은 같은 두 건을 확인합니다.
JSON 리포트에서 RuleID, 파일, 줄 번호를 뽑은 결과와 SARIF 파일 크기, SARIF results에서 뽑은 같은 두 건을 확인합니다.

5. baseline으로 기존 발견 제외하기

이미 커밋된 시크릿은 키를 폐기하고 이력을 정리하기 전까지 계속 잡힙니다. 도입 첫날부터 CI를 빨갛게 만들지 않으려면 현재 발견을 baseline으로 저장하고, 그 뒤로 생기는 것만 보도록 합니다. baseline 파일은 같은 리포트 형식이라 -f json -r로 만듭니다.

gl git --no-banner --redact -f json -r gitleaks-baseline.json .
git add gitleaks-baseline.json && git commit -m "gitleaks baseline 추가"

새 시크릿이 든 파일을 커밋하고 baseline 없이, 있게 각각 스캔합니다.

cat > app/notify.py <<'EOF'
SLACK_WEBHOOK = "https://hooks.slack.com/services/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"
EOF
git add . && git commit -m "알림 모듈 추가"

gl git --no-banner --redact .; echo "exit=$?"
gl git --no-banner --redact -b gitleaks-baseline.json -v . | grep -E "RuleID|File"

기대 출력입니다.

INF 4 commits scanned.
INF scanned ~1559 bytes (1.56 KB) in 257ms
WRN leaks found: 3
exit=1
RuleID:      slack-webhook-url
File:        app/notify.py
WRN leaks found: 1

baseline 없이는 3건, baseline을 주면 새로 들어온 Slack 웹훅 한 건만 남습니다. 종료 코드는 새 발견이 있으므로 여전히 1입니다. baseline을 만들 때와 스캔할 때 --redact 여부를 맞춰야 합니다. 이 글처럼 둘 다 --redact로 하면 baseline 파일에 시크릿 값이 들어가지 않아 저장소에 커밋해도 됩니다.

baseline 없이는 3건과 exit=1, baseline을 주면 slack-webhook-url 한 건만 남는 것을 확인합니다.
baseline 없이는 3건과 exit=1, baseline을 주면 slack-webhook-url 한 건만 남는 것을 확인합니다.

6. 오탐 제외하기

테스트용 가짜 토큰을 담은 파일을 하나 추가해 오탐을 만들고, 제외 방법 세 가지를 차례로 봅니다.

mkdir tests
cat > tests/fake_tokens.py <<'EOF'
SAMPLE_TOKEN = "ghp_Zx8Yw7Vu6Ts5Rq4Po3Nm2Lk1Jh0Gf9Ed8Cb7"
EOF
git add . && git commit -m "테스트용 가짜 토큰 추가"
gl git --no-banner --redact -b gitleaks-baseline.json -v . | grep -E "RuleID|File|Fingerprint"

기대 출력입니다. 테스트 파일의 github-pat와 앞에서 본 Slack 웹훅이 함께 나옵니다.

RuleID:      slack-webhook-url
File:        app/notify.py
Fingerprint: 196d2ba13a64ab55e3295464d4d8c2b23bc5f72e:app/notify.py:slack-webhook-url:1
RuleID:      github-pat
File:        tests/fake_tokens.py
Fingerprint: 5f250eaac1b46a4d1628fb12fbb8c954796f1d63:tests/fake_tokens.py:github-pat:1
WRN leaks found: 2

방법 1. .gitleaksignore에 Fingerprint 적기. 제외할 한 건의 Fingerprint를 저장소 루트의 .gitleaksignore에 한 줄로 적습니다. 커밋 해시가 들어 있어서 그 커밋의 그 줄만 제외됩니다. README는 이 기능을 실험적이라고 표시합니다. 해시는 직접 실행한 결과에서 복사해야 하므로 아래 값은 앞의 출력에서 나온 tests/fake_tokens.py의 Fingerprint로 바꿔 적습니다.

echo "5f250eaac1b46a4d1628fb12fbb8c954796f1d63:tests/fake_tokens.py:github-pat:1" > .gitleaksignore
gl git --no-banner --redact -b gitleaks-baseline.json -v . | grep -E "RuleID|File"

기대 출력은 tests/fake_tokens.py가 사라지고 Slack 웹훅 한 건만 남는 것입니다.

RuleID:      slack-webhook-url
File:        app/notify.py
WRN leaks found: 1

.gitleaksignore에 Fingerprint를 적은 뒤 tests/fake_tokens.py가 빠지고 slack-webhook-url 한 건만 남는 것을 확인합니다.
.gitleaksignore에 Fingerprint를 적은 뒤 tests/fake_tokens.py가 빠지고 slack-webhook-url 한 건만 남는 것을 확인합니다.

방법 2. .gitleaks.toml로 경로 제외하기. 테스트 폴더 전체처럼 범위가 넓을 때 씁니다. 기본 규칙을 유지하려면 [extend] 블록에 useDefault = true를 넣어야 합니다. README는 useDefault = true가 바이너리에 내장된 기본 설정을 확장한다고 설명하고, 이 블록 없이 설정 파일을 만들면 시크릿이 하나도 잡히지 않는 현상은 아래 자주 막히는 곳에서 다룹니다.

[extend]
useDefault = true

[[allowlists]]
description = "테스트용 가짜 토큰 폴더"
paths = ['''^tests/''']

이 파일을 저장소 루트에 .gitleaks.toml로 두고 같은 명령을 돌리면 tests/fake_tokens.py가 빠지고 app/notify.py 한 건만 남습니다. 다만 tests/ 전체를 제외하면 그 폴더에 나중에 실제 시크릿이 들어가도 검출되지 않습니다. 가짜 토큰이 든 파일이 정해져 있다면 paths = ['''^tests/fake_tokens\.py$''']처럼 파일 하나만 지정하는 편이 안전합니다. 설정 파일은 저장소 루트의 .gitleaks.toml을 자동으로 읽고, -c 옵션이나 GITLEAKS_CONFIG 환경 변수로 다른 경로를 지정할 수도 있습니다.

방법 3. 해당 줄에 gitleaks:allow 주석 달기. 한 줄만 예외로 둘 때 씁니다.

SAMPLE_TOKEN = "ghp_Zx8Yw7Vu6Ts5Rq4Po3Nm2Lk1Jh0Gf9Ed8Cb7"  # gitleaks:allow

gl dir로 스캔하면 이 줄은 제외됩니다. 다만 이미 커밋된 이전 줄은 주석이 없는 상태로 이력에 있으므로 gl git에서는 그대로 잡힙니다. 이력에 있는 건은 방법 1이나 2로 처리해야 합니다.

7. pre-commit으로 커밋 전에 막기

pre-commit 프레임워크에 gitleaks 훅을 등록합니다. 훅은 커밋하려고 스테이징한 변경만 검사합니다. gitleaks 저장소의 .pre-commit-hooks.yaml에는 훅이 세 가지 있습니다. gitleaks는 language: golang이라서 Go로 소스를 빌드하므로 Go가 설치돼 있어야 하고, gitleaks-docker는 공식 Docker 이미지를 실행하고, gitleaks-system은 PC에 설치된 gitleaks 바이너리를 씁니다. Go가 없다면 뒤의 docker 훅을 쓰면 됩니다.

먼저 Go 방식입니다.

pip install pre-commit
cat > .pre-commit-config.yaml <<'EOF'
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.30.1
    hooks:
      - id: gitleaks
EOF
pre-commit install
git add .pre-commit-config.yaml
git commit -m "pre-commit 설정 추가"

첫 커밋에서 Installing environment for https://github.com/gitleaks/gitleaks. 메시지가 나오면서 Go로 gitleaks를 빌드합니다. 이번 실행에서는 이 첫 커밋에 7분 넘게(461초) 걸렸고, 환경에 따라 달라집니다. 이후에는 캐시를 씁니다. 기대 출력에는 Detect hardcoded secrets....Passed가 나옵니다.

이제 가짜 AWS 키가 든 파일을 커밋해 봅니다.

echo 'AWS_KEY = "AKIAJQXZPLMTRNBKWD3C"' > app/aws.py
git add app/aws.py
git commit -m "AWS 설정 추가"

기대 출력의 핵심입니다. gitleaks 로고와 Finding, Entropy 줄은 줄였습니다.

Detect hardcoded secrets.....Failed
- hook id: gitleaks
- exit code: 1
RuleID:      aws-access-token
File:        app/aws.py
WRN leaks found: 1

커밋은 만들어지지 않고 git log --oneline의 맨 위는 이전 커밋 그대로입니다. 키를 환경 변수로 읽게 고쳐서 다시 커밋하면 통과합니다.

cat > app/aws.py <<'EOF'
import os
AWS_KEY = os.environ["AWS_ACCESS_KEY_ID"]
EOF
git add app/aws.py
git commit -m "AWS 키를 환경 변수로 읽기"

Detect hardcoded secrets....Passed가 나오고 커밋이 만들어집니다. 급할 때는 SKIP=gitleaks git commit ...으로 이 훅만 건너뛸 수 있습니다. 훅은 개발자 PC에서만 동작하므로 우회될 수 있고, 다음 절의 CI 검사가 마지막 방어선입니다.

첫 커밋은 Passed, 가짜 AWS 키 커밋은 Failed로 막히고 git log의 맨 위는 이전 커밋 그대로이며, 환경 변수로 고친 커밋은 Passed로 만들어지는 것을 확인합니다.
첫 커밋은 Passed, 가짜 AWS 키 커밋은 Failed로 막히고 git log의 맨 위는 이전 커밋 그대로이며, 환경 변수로 고친 커밋은 Passed로 만들어지는 것을 확인합니다.

Go 없이 docker 훅으로 하기. Go가 없는 PC라면 .pre-commit-config.yaml을 아래처럼 바꿉니다. gitleaks-docker 훅은 이미지 이름에 태그를 붙이지 않아 최신 이미지를 쓰므로, entry를 덮어써서 앞에서 고정한 v8.30.1 태그를 지정했습니다.

repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.30.1
    hooks:
      - id: gitleaks-docker
        entry: zricethezav/gitleaks:v8.30.1 git --pre-commit --redact --staged --verbose

Go를 PATH에서 뺀 셸(go: command not found)에서 이 설정을 커밋하고, 가짜 키가 든 app/aws2.py를 커밋해 봤습니다. 설정 커밋은 Passed로 3초 만에 끝났고 키 커밋은 같은 방식으로 Failed가 됐습니다. 훅이 Docker로 이미지를 실행하므로 Docker Desktop이 켜져 있어야 합니다.

Go가 없는 셸에서 docker 훅으로 설정 커밋은 Passed, 가짜 AWS 키 커밋은 Failed로 막히는 것을 확인합니다.
Go가 없는 셸에서 docker 훅으로 설정 커밋은 Passed, 가짜 AWS 키 커밋은 Failed로 막히는 것을 확인합니다.

8. GitHub Actions에서 같은 검사 돌리기

이 절은 실행해 보지 못했고 공식 저장소 안내를 기준으로 정리한 것입니다. 공식 액션을 쓰는 워크플로는 다음과 같습니다. 전체 이력을 스캔하므로 fetch-depth: 0이 필요합니다.

name: gitleaks
on:
  pull_request:
  push:
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@v3
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}

액션 저장소는 GITLEAKS_LICENSE가 조직 계정에서만 필요하고 개인 계정에는 필요 없다고 안내합니다. 또 gitleaks-action@v2는 2026년 9월 16일부터 동작하지 않는다고 적고 있으니 v3를 씁니다.

baseline을 쓰고 싶다면 공식 액션 단계를 빼고 이 글에서 실행한 명령을 그대로 단계로 옮깁니다. 공식 액션 안내문(README)에서 baseline 옵션을 찾지 못했습니다. 액션이 baseline을 지원하는지는 확인하지 못했으므로 모른다고 적어 둡니다. 액션 단계를 그대로 두고 docker 단계를 더하면, 액션 단계는 baseline 없이 전체 이력을 스캔해 기존 발견 때문에 실패할 것으로 예상됩니다. 이 부분은 실행해 보지 않은 추정입니다. Linux 러너에서는 경로 변환 문제가 없으므로 $PWD를 씁니다.

      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - name: gitleaks (baseline 이후 새 발견만)
        run: >
          docker run --rm -v "$PWD:/repo" -w /repo zricethezav/gitleaks:v8.30.1
          git --no-banner --redact -b gitleaks-baseline.json -v .

baseline 방식에서는 gitleaks/gitleaks-action 단계가 없으므로 GITHUB_TOKEN과 GITLEAKS_LICENSE 설정도 필요 없습니다. 발견이 있으면 종료 코드 1로 단계가 실패합니다. 머지까지 막으려면 저장소의 브랜치 보호 규칙에서 이 체크를 필수로 지정해야 합니다.

자주 막히는 곳

AWS 공식 예시 키 AKIAIOSFODNN7EXAMPLE를 넣었는데 no leaks found가 나옵니다. dir과 git 모두 재현했습니다. 값에 EXAMPLE이 들어 있어서 기본 규칙이 예시 값으로 보고 제외하는 것으로 보입니다. 탐지 동작을 시험할 때는 이 문자열 대신 AKIA 뒤에 영문 대문자와 숫자 2~7로 된 16자를 임의로 붙인 값을 씁니다. 직접 시험하니 뒤 16자에 숫자 0, 1, 8, 9가 하나라도 들어가면 탐지되지 않았습니다.

Git Bash에서 docker run -v "$PWD:/repo"가 Run 'docker run --help' 오류로 끝납니다. Git Bash가 경로를 Windows 형식으로 바꾸다가 인자 형식이 깨지기 때문입니다. 위 gl 함수처럼 MSYS_NO_PATHCONV=1과 $(pwd -W)를 쓰면 됩니다.

.gitleaks.toml을 만들었더니 시크릿이 하나도 안 잡히고 no leaks found가 나옵니다. 설정 파일에 [extend]와 useDefault = true 없이 [[allowlists]]만 적으면 기본 규칙이 빠지고 규칙이 하나도 없는 상태가 됩니다. 같은 저장소에서 app/notify.py의 Slack 웹훅까지 보고하지 않았습니다. README는 [extend]의 useDefault = true가 내장 기본 설정을 확장하는 방법이라고 설명하므로, 기본 규칙을 함께 쓰려면 설정 파일을 [extend] 블록으로 시작합니다.

baseline을 적용했는데 기존 2건이 그대로 보고됩니다. baseline을 --redact로 만들고 스캔은 --redact 없이 했을 때 재현했습니다. 두 쪽 모두 --redact를 쓰거나 둘 다 빼야 합니다.

gitleaks:allow를 달았는데 gl git에서는 여전히 잡힙니다. 주석은 그 줄을 스캔할 때만 효력이 있습니다. 주석을 달기 전 커밋에 있던 줄은 이력에서 계속 발견되므로 .gitleaksignore나 baseline으로 처리합니다.

이어서 해 볼 것

  • 진짜 시크릿 대응: 실제 키가 커밋됐다면 baseline에 넣어 두는 것으로 끝나지 않습니다. 해당 키를 먼저 폐기하고 새로 발급한 뒤, 이력 정리 여부를 정합니다.
  • 규칙 직접 추가: .gitleaks.toml에 [[rules]]를 더해 사내 토큰 형식을 정규식으로 탐지해 봅니다. [extend]로 기본 규칙을 함께 쓰면 됩니다.
  • SARIF를 code scanning에 올리기: 4번 절의 report.sarif를 github/codeql-action/upload-sarif 단계로 올려 PR에 표시하는 구성을 시도해 봅니다. 비공개 저장소에서 쓸 수 있는지는 플랜 문서에서 확인해야 합니다.

확인 범위

직접 실행한 부분은 1번부터 7번까지와 자주 막히는 곳 다섯 항목의 재현입니다. 환경은 Windows의 Git Bash, Docker Desktop, gitleaks 8.30.1 이미지, Git 2.54.0, Python 3.12, pre-commit 4.7.0, Go 1.26.5입니다. 글의 화면은 모두 이 순서를 새 저장소에서 처음부터 다시 실행해 만들었습니다. 8번의 baseline용 단계는 v8.30.1 이미지로 로컬에서만 실행했습니다. 6번의 .gitleaks.toml 경로 제외(폴더 전체와 파일 하나 지정 두 가지)와 gitleaks:allow 주석도 직접 실행했습니다. 이 두 방법은 화면 캡처는 없고 건수만 확인했습니다. 7번의 Go 훅과 docker 훅은 둘 다 실행했고, docker 훅은 Go를 PATH에서 뺀 셸에서 확인했습니다. 훅 설치용 pre-commit은 가상 환경에 설치해 실행했습니다.

8번의 GitHub Actions 워크플로는 실행하지 못했습니다. 액션 버전, 라이선스 안내, 2026년 9월 16일 중단 공지는 gitleaks-action 저장소 안내를 읽고 옮긴 것이므로 적용 전에 해당 저장소 문서와 대조하시기 바랍니다. baseline을 쓰는 docker 단계도 로컬에서 같은 명령을 돌렸을 뿐 러너에서는 돌리지 않았습니다. 이 글은 8.30.1 기준이며 저장소 README에는 기능 개발을 마치고 보안 패치 중심으로 유지한다는 안내가 있습니다.

참고한 공식 문서는 https://github.com/gitleaks/gitleaks 와 https://github.com/gitleaks/gitleaks-action 입니다.

이 글의 다음 단계

  • Checkov로 Terraform 설정 오류를 찾고 고치기연습용 main.tf를 apply 없이 Checkov로 점검해 실패 항목 표를 읽고, 설정을 고쳐 통과시킵니다. 사유를 남기는 skip 주석, soft-fail과 종료 코드로 만드는 CI 게이트, json과 sarif 출력, Trivy config와의 결과 비교까지 다룹니다.
  • Trivy로 컨테이너 이미지 취약점을 스캔하고 빌드 게이트 만들기오래된 베이스 이미지와 고정 버전 패키지로 작은 이미지를 빌드해 Trivy로 스캔하고, 결과 표 읽는 법과 HIGH,CRITICAL 필터, --ignore-unfixed, --exit-code 1 게이트, 만료일이 있는 .trivyignore 예외를 거쳐 베이스 이미지를 올려 통과시킵니다.

DevSecOps 실무 과정의 일부입니다

이 실습은 교육에서 참가자마다 독립된 환경으로 진행합니다. 원하는 일정을 고르면 문의 양식에 미리 채워집니다.

과정 보기

교육 진행 순서와 자주 묻는 질문 보기

같은 카테고리의 글