Секрети — це токени, ключі доступу, паролі й інші чутливі дані, які іноді випадково потрапляють у репозиторій. Добра новина: це можна зупинити до того, як секрети полетять на ремоут. У цьому гайді я покажу, як налаштувати pre-commit hooks у Git з git-secrets та TruffleHog, а ще увімкнути CI-сканування історії — усе на Linux. Працюємо через термінал Linux, пишемо прості bash скрипти, і будуємо корисну автоматизацію задач для команди, що займається розробка на Linux. 🎯

Підготовка: встановлення інструментів

Нам знадобляться Git, git-secrets і TruffleHog. Ви можете встановити їх через пакети або з вихідних. Нижче — універсальні варіанти для Linux.

# 1) Встановити git-secrets зі сховища вихідних
sudo apt-get update -y
sudo apt-get install -y git make
rm -rf /tmp/git-secrets \
  && git clone https://github.com/awslabs/git-secrets.git /tmp/git-secrets \
  && cd /tmp/git-secrets \
  && sudo make install

# 2) Встановити TruffleHog (через pipx) або використати Docker
python3 -m pip install --user pipx
python3 -m pipx ensurepath
pipx install trufflehog

# альтернативно: Docker-образ (не потребує локальної установки)
docker pull ghcr.io/trufflesecurity/trufflehog:latest

Налаштування pre-commit hooks у Git

Зупиняти витік треба ще на вашій машині: hook спрацює перед комітом і заблокує його, якщо знайде секрети.

Увімкнення git-secrets у репозиторії

Спочатку додамо готові сигнатури та вмикаємо перевірку staged-змін:

# Перейдіть у свій репозиторій
git -C /path/to/your/repo status || cd /path/to/your/repo

# Встановити hook-и git-secrets у поточний репозиторій
git secrets --install

# Додати готові патерни AWS (access key, secret key)
git secrets --register-aws

# Додати типові патерни GitHub та Slack токенів (приклад)
git secrets --add -g 'gh[pousr]_[A-Za-z0-9]{36}'
git secrets --add -g 'xox[baprs]-[A-Za-z0-9-]+'

# Необов'язково: автододавання у всі нові репозиторії
git secrets --install ~/.git-templates/git-secrets
git config --global init.templateDir ~/.git-templates/git-secrets

Якщо знаєте легальні рядки, які не слід вважати секретами (наприклад, публічні ключі тестових сервісів), додайте їх у allowlist:

# Дозволити безпечний патерн у поточному репозиторії (запишеться у .gitallowed)
git secrets --add -l 'https://api.example.com/public-key'

Єдиний глобальний pre-commit з TruffleHog

Тепер підключимо TruffleHog, щоб перевіряти секрети ще ретельніше. Зручно мати один глобальний hook для всіх репозиторіїв:

# Створюємо директорію для глобальних hook-ів
mkdir -p ~/.git-hooks

# Пишемо pre-commit, який спершу запускає git-secrets, а потім TruffleHog
cat > ~/.git-hooks/pre-commit << 'EOF'
#!/usr/bin/env bash
set -euo pipefail

# 1) git-secrets на staged-змінах (якщо інстальовано)
if command -v git-secrets >/dev/null 2>&1; then
  git secrets --pre_commit_hook -- "$@"
fi

# 2) TruffleHog на staged-файлах (швидка перевірка)
CHANGED="$(git diff --cached --name-only --diff-filter=ACMR)"
if [ -n "$CHANGED" ] && command -v trufflehog >/dev/null 2>&1; then
  echo "[pre-commit] TruffleHog: сканую змінені файли..."
  rc=0
  while IFS= read -r f; do
    [ -f "$f" ] || continue
    if [ -f .trufflehog-exclude ]; then
      trufflehog filesystem --fail --only-verified --no-update --exclude-paths .trufflehog-exclude "$f" >/dev/null || rc=1
    else
      trufflehog filesystem --fail --only-verified --no-update "$f" >/dev/null || rc=1
    fi
  done <<< "$CHANGED"
  [ $rc -eq 0 ] || { echo "ERROR: TruffleHog знайшов можливі секрети у staged-файлах."; exit 1; }
fi
EOF

chmod +x ~/.git-hooks/pre-commit

git config --global core.hooksPath ~/.git-hooks

# Необов'язково: файл-винятки для TruffleHog (regex шляхи)
cat > .trufflehog-exclude << 'EOF'
^docs/
\.md$
^tests/fixtures/
EOF

Тепер кожен ваш коміт проходитиме подвійний захист: git-secrets і TruffleHog зупинять зміни, що містять секрети. ⚠️

Сканування в CI/CD (повна історія і PR)

Навіть якщо локальні hook-и вимкнули, CI — остання лінія оборони. Додаємо джобу, яка падає, якщо знайдені секрети в історії.

GitHub Actions

mkdir -p .github/workflows
cat > .github/workflows/secret-scan.yml << 'YML'
name: secret-scan
on:
  pull_request:
  push:
    branches: [ main ]
jobs:
  trufflehog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # повна історія
      - name: TruffleHog Git history scan
        run: |
          docker run --rm -v "$PWD":/repo ghcr.io/trufflesecurity/trufflehog:latest \
            git --fail --only-verified /repo
YML

git add .github/workflows/secret-scan.yml
# git commit -m "CI: add TruffleHog secret scanning"

GitLab CI

cat > .gitlab-ci.yml << 'YML'
stages: [scan]
secret_scan:
  image: docker:stable
  stage: scan
  services: [docker:dind]
  script:
    - docker run --rm -v "$CI_PROJECT_DIR":/repo ghcr.io/trufflesecurity/trufflehog:latest git --fail --only-verified /repo
  only:
    - merge_requests
    - main
YML

Порада: додайте обов’язковий статус-перевірку на Pull/Merge Request, щоб без зеленої перевірки було неможливо змерджити.

Альтернативні способи

  • Тільки git-secrets: легкий і швидкий захист із регулярками. Добре як базовий рівень.
  • Gitleaks як альтернатива TruffleHog: схожий клас інструмента, іноді дає менше хибних спрацьовувань.
  • Серверні hook-и (pre-receive) на вашому Git-сервері: гарантують, що секрети не пройдуть навіть без локальних перевірок.
  • Docker локально: замість установки — запускайте TruffleHog у контейнері для однакового результату на всіх машинах.

GUI-спосіб

Більшість GUI-клієнтів Git автоматично виконують локальні hook-и. Тож після налаштування pre-commit описаного вище, коміт з GUI також буде заблокований, якщо знайдені секрети. Якщо любите VS Code, запускайте сканування з вбудованого терміналу або підключіть завдання (Task), що викликає TruffleHog. Простий приклад ручного запуску:

# Швидка перевірка всієї робочої копії з VS Code терміналу
trufflehog filesystem --fail --only-verified --no-update .

FAQ

Чому коміт блокується, хоча в мене немає секретів?

Це може бути хибнопозитивне спрацювання. Додайте безпечний патерн у allowlist для git-secrets (git secrets --add -l '...' ) або винесіть файли в .trufflehog-exclude (regex-шляхи) для TruffleHog. Також спробуйте параметр --only-verified, щоб зменшити шум.

Як просканувати всю історію репозиторію локально?

# Скан всього git-історі з TruffleHog
trufflehog git --fail --only-verified file://$PWD

Що робити, якщо секрет уже потрапив у Git?

  1. Негайно відкличте/перегенеруйте ключ у провайдері.
  2. Приберіть секрет із коду та додайте відповідний запис у .gitignore/allowlist.
  3. Очистіть історію: скористайтесь git filter-repo або BFG.
# Приклад з BFG (швидко видаляє секретні рядки з історії)
wget -O bfg.jar https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar
java -jar bfg.jar --replace-text replacements.txt  # у файлі вкажіть чутливі рядки

git reflog expire --expire=now --all
git gc --prune=now --aggressive
# Пуш з перезаписом історії (узгодьте з командою!)
# git push --force

TruffleHog повільний на великих репо. Як прискорити?

Скануйте лише staged файли у pre-commit (як у нашому hook-скрипті) і повну історію — у CI. Також виключайте великі каталоги через .trufflehog-exclude.

Чи можна запускати все без Python?

Так, використовуйте Docker-образ TruffleHog у локальних перевірках і CI. git-secrets достатньо зібрати з вихідних (make install).

Як переконатись, що кожен у команді використовує hook-и?

Додайте серверний pre-receive hook або обов'язкову CI-перевірку. Локальні hook-и — це зручність, але не заміна політикам у репозиторії.

Порада від Kernelka

Збережіть чисте дерево змін: тримайте секрети поза репозиторієм (менеджери секретів, змінні середовища, KMS/SealedSecrets). А ще зробіть один спільний core.hooksPath для всієї команди та версіонуйте в окремому репозиторії набір корисних hook-ів — так ви отримаєте відтворюваність і менше сюрпризів.

Підсумок

  • Увімкніть git-secrets і додайте релевантні сигнатури.
  • Додайте TruffleHog у pre-commit для перевірки staged-файлів.
  • Налаштуйте CI-сканування повної історії на кожен PR/мердж.
  • Керуйте винятками через .gitallowed та .trufflehog-exclude.
  • Регулярно перевидавайте ключі й очищайте історію у разі інцидентів.