# Implementing Secret Scanning With Gitleaks

> 本技能涵盖实施 Gitleaks 以检测和防止 git 仓库中的硬编码机密信息。 内容包括配置预提交钩子、CI/CD 管道集成、为组织特定机密编写自定义规则、 管理现有仓库的基线，以及暴露凭证的修复工作流程。

- Skill: `killvxk/implementing-secret-scanning-with-gitleaks` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add killvxk/implementing-secret-scanning-with-gitleaks`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/implementing-secret-scanning-with-gitleaks/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: Apache-2.0
- Author: killvxk (https://skillmd.com/u/killvxk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/killvxk/implementing-secret-scanning-with-gitleaks

---


# 使用 Gitleaks 实施机密扫描

## 使用场景

- 当开发者可能意外将 API 密钥、密码、令牌或私钥提交到仓库时
- 建立预提交门禁以防止机密进入 git 历史时
- 扫描现有仓库历史以发现需要轮换的已提交机密时
- 合规要求强制在所有源代码仓库中进行机密检测时
- 从手动机密审计迁移到自动化持续扫描时

**不适用于**检测运行中应用或内存中的机密（使用运行时机密检测）、检测后管理机密（使用 Vault 或 AWS Secrets Manager）或扫描容器镜像（使用 Trivy 或 Grype）。

## 前置条件

- 通过二进制文件、Go 安装或 Docker 安装 Gitleaks v8.18+
- 安装 pre-commit 框架用于本地钩子集成
- 包含历史记录的 Git 仓库
- CI/CD 平台访问权限（GitHub Actions、GitLab CI 或等效平台）

## 操作流程

### 步骤 1：安装并运行初始仓库扫描

对仓库执行基线扫描，识别 git 历史中所有现有的机密信息。

```bash
# 安装 Gitleaks
brew install gitleaks  # macOS
# 或从 https://github.com/gitleaks/gitleaks/releases 下载二进制文件

# 扫描整个 git 历史以查找机密
gitleaks detect --source . --report-format json --report-path gitleaks-report.json -v

# 仅扫描暂存变更（用于预提交）
gitleaks protect --staged --report-format json --report-path gitleaks-staged.json

# 扫描特定提交范围
gitleaks detect --source . --log-opts="HEAD~10..HEAD" --report-format json

# 扫描而不查看 git 历史（仅文件系统）
gitleaks detect --source . --no-git --report-format json
```

### 步骤 2：配置预提交钩子

将 Gitleaks 设置为预提交钩子以防止机密被提交。

```yaml
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.21.2
    hooks:
      - id: gitleaks
        name: gitleaks
        description: Detect hardcoded secrets using Gitleaks
        entry: gitleaks protect --staged --verbose --redact
        language: golang
        pass_filenames: false
```

```bash
# 安装 pre-commit 框架
pip install pre-commit

# 安装 .pre-commit-config.yaml 中定义的钩子
pre-commit install

# 针对所有文件运行（不仅是暂存文件）
pre-commit run gitleaks --all-files

# 使用刻意的机密测试钩子
echo 'AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"' >> test.txt
git add test.txt
git commit -m "test"  # 应被 gitleaks 阻止
```

### 步骤 3：集成到 GitHub Actions

```yaml
# .github/workflows/secret-scanning.yml
name: Secret Scanning

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  gitleaks:
    name: Gitleaks Secret Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # 完整历史以进行全面扫描

      - name: Run Gitleaks
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}  # gitleaks-action v2 必需

      # 替代方案：直接运行 Gitleaks
      - name: Install Gitleaks
        run: |
          wget -q https://github.com/gitleaks/gitleaks/releases/download/v8.21.2/gitleaks_8.21.2_linux_x64.tar.gz
          tar -xzf gitleaks_8.21.2_linux_x64.tar.gz
          chmod +x gitleaks

      - name: Scan for secrets
        run: |
          if [ "${{ github.event_name }}" == "pull_request" ]; then
            ./gitleaks detect \
              --source . \
              --log-opts="${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}" \
              --report-format sarif \
              --report-path gitleaks.sarif \
              --exit-code 1
          else
            ./gitleaks detect \
              --source . \
              --report-format sarif \
              --report-path gitleaks.sarif \
              --exit-code 1 \
              --baseline-path .gitleaks-baseline.json
          fi

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: gitleaks.sarif
          category: gitleaks
```

### 步骤 4：编写自定义检测规则

为内部机密模式创建组织特定规则。

```toml
# .gitleaks.toml
title = "Organization Gitleaks Configuration"

[extend]
useDefault = true  # 包含所有默认规则

# 内部 API 令牌的自定义规则
[[rules]]
id = "internal-api-token"
description = "Internal API token for service-to-service auth"
regex = '''(?i)x-internal-token["\s:=]+["']?([a-zA-Z0-9_\-]{40,})["']?'''
entropy = 3.5
keywords = ["x-internal-token"]
tags = ["internal", "api"]

[[rules]]
id = "database-connection-string"
description = "Database connection string with embedded credentials"
regex = '''(?i)(postgres|mysql|mongodb|redis)://[^:]+:[^@]+@[^/]+/\w+'''
keywords = ["postgres://", "mysql://", "mongodb://", "redis://"]
tags = ["database", "credentials"]

[[rules]]
id = "jwt-secret"
description = "JWT signing secret"
regex = '''(?i)(jwt[_-]?secret|jwt[_-]?key)["\s:=]+["']?([a-zA-Z0-9/+_\-]{32,})["']?'''
entropy = 3.0
keywords = ["jwt_secret", "jwt-secret", "jwt_key", "jwt-key"]

# 测试文件和已知安全模式的允许列表
[allowlist]
description = "Global allowlist"
paths = [
  '''(^|/)test(s)?/''',
  '''(^|/)spec/''',
  '''\.test\.(js|ts|py)$''',
  '''\.spec\.(js|ts|py)$''',
  '''__mocks__/''',
  '''fixtures/''',
  '''(^|/)vendor/''',
  '''node_modules/'''
]
regexes = [
  '''EXAMPLE''',
  '''example\.com''',
  '''test[-_]?(key|secret|token|password)''',
  '''(?i)placeholder''',
  '''000000+'''
]
```

### 步骤 5：管理现有仓库的基线

创建已知发现的基线，以避免在历史机密轮换期间阻塞开发。

```bash
# 从当前状态生成基线
gitleaks detect --source . --report-format json --report-path .gitleaks-baseline.json

# 后续扫描与基线比较（只有新发现才会触发失败）
gitleaks detect --source . --baseline-path .gitleaks-baseline.json --exit-code 1

# 定期审查基线，随着机密轮换删除条目
cat .gitleaks-baseline.json | python3 -m json.tool | head -50
```

### 步骤 6：修复已暴露的机密

检测到机密时，遵循轮换和历史清理流程。

```bash
# 1. 立即轮换暴露的凭证
#    - 在服务提供商处吊销旧 API 密钥/令牌
#    - 生成新凭证
#    - 将新凭证存储在密钥管理器中

# 2. 使用 git-filter-repo 从 git 历史中删除机密
pip install git-filter-repo

# 创建要删除的机密表达式文件
cat > /tmp/expressions.txt << 'EOF'
regex:AKIA[0-9A-Z]{16}==>REDACTED_AWS_KEY
regex:(?i)password\s*=\s*"[^"]*"==>password="REDACTED"
EOF

git filter-repo --replace-text /tmp/expressions.txt --force

# 3. 强制推送已清理的历史（与团队协调）
# git push --force --all  # 警告：需要团队协调

# 4. 将机密模式添加到 .gitleaks.toml 规则中
# 5. 更新基线文件以删除已解决的发现
```

## 关键概念

| 术语 | 定义 |
|------|------|
| 机密 | 不应出现在源代码中的任何凭证、令牌、密钥或敏感字符串 |
| 预提交钩子 | 在提交创建之前运行的 Git 钩子，阻止包含检测到机密的提交 |
| 熵值 | 字符串中随机性的度量；高熵字符串更可能是机密 |
| 基线 | 用于区分新机密与预先存在机密的现有发现快照 |
| 允许列表 | 指定要从检测中排除的路径、模式或提交的配置 |
| SARIF | 静态分析结果交换格式，用于将发现上传到安全仪表板 |
| git-filter-repo | 重写 git 历史以从所有提交中删除敏感数据的工具 |

## 工具与系统

- **Gitleaks**：开源机密检测工具，支持预提交钩子、CI/CD 和历史扫描
- **pre-commit**：管理和维护多语言预提交钩子的框架
- **git-filter-repo**：从 git 历史中删除机密的历史重写工具
- **TruffleHog**：具有已验证机密检测功能的替代机密扫描器
- **GitHub Secret Scanning**：检测与合作伙伴模式匹配的机密的原生 GitHub 功能

## 常见场景

### 场景：在遗留仓库中引入机密扫描

**背景**：一个 5 年历史的仓库从未被扫描。团队需要在历史机密轮换期间不阻塞所有开发的情况下启用机密扫描。

**方法**：
1. 对完整历史运行 `gitleaks detect` 并生成基线 JSON 文件
2. 对每个发现进行分类：归类为活跃（需要轮换）、非活跃（已轮换）或误报
3. 立即轮换所有活跃机密并更新使用服务
4. 提交基线文件（排除已修复的活跃机密）
5. 立即为新开发启用预提交钩子
6. 添加带基线的 CI/CD 扫描以仅捕获新机密
7. 随着历史机密轮换，逐步缩减基线

**注意事项**：在未分类的情况下生成基线意味着接受未轮换机密的风险。切勿假设历史机密是非活跃的，除非通过服务提供商验证。在未与团队协调的情况下对共享仓库运行 git-filter-repo 将导致所有团队成员的变基冲突。

## 输出格式

```
Gitleaks 机密扫描报告
=================================
仓库：org/web-application
扫描类型：完整历史
已扫描提交：4,523
日期：2026-02-23

发现：
  总计：12
  新发现（不在基线中）：3
  基线（预先存在）：9

新发现（阻塞）：
  [1] AWS 访问密钥 ID
      规则：aws-access-key-id
      文件：src/config/aws.py:23
      提交：a1b2c3d（2026-02-22，dev@company.com）
      机密：AKIA...已编辑
      熵值：3.8

  [2] GitHub 个人访问令牌
      规则：github-pat
      文件：scripts/deploy.sh:15
      提交：d4e5f6g（2026-02-21，ops@company.com）
      机密：ghp_...已编辑
      熵值：4.2

  [3] 内部 API 令牌
      规则：internal-api-token
      文件：src/services/auth.py:89
      提交：h7i8j9k（2026-02-20，dev@company.com）

质量门禁：失败（3 个新发现）
操作：立即轮换暴露的凭证。
```

