7. Secrets и безопасность

Secrets management — систематический подход к хранению, ротации и контролю доступа к чувствительным данным: API ключам, паролям, сертификатам.
Что такое секреты
Заголовок раздела «Что такое секреты»Секреты — это данные, которые:✅ Нельзя коммитить в git✅ Нельзя логировать✅ Нужно ротировать✅ Доступ должен быть ограничен
Примеры:- Пароли к базам данных- API ключи (Stripe, SendGrid, AWS)- JWT секреты- SSL сертификаты и приватные ключи- OAuth client secrets- SSH ключиГлавное правило: git никогда не видит секреты
Заголовок раздела «Главное правило: git никогда не видит секреты»# ❌ НИКОГДА такgit add .envgit commit -m "add env file" # Всё, утекло навсегда
# Даже если удалишь потом — история git хранит всёgit rm .env # Файл удалён, но был в коммите# git log --all -p -- .env # Любой может достатьЕсли секрет попал в git:
- Немедленно ротируй (создай новый)
- Считай старый скомпрометированным
- Используй
git filter-repoдля очистки истории - Force push — крайний случай
GitHub Secrets
Заголовок раздела «GitHub Secrets»Самый простой вариант для GitHub проектов:
# Settings → Secrets and variables → Actions# Repository secrets, Environment secrets, Organization secrets
# Использование в workflowjobs: deploy: steps: - name: Deploy env: STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }} DATABASE_URL: ${{ secrets.DATABASE_URL }} run: npm run deploy
# Secrets в actions (без явного env) - uses: some/action@v1 with: token: ${{ secrets.GITHUB_TOKEN }} # встроенный secretОсобенности GitHub Secrets:
- Автоматически маскируются в логах
- Нельзя прочитать после сохранения
- Organization level — для всех репозиториев организации
- Environment secrets — отдельные для staging/production
Хранение на сервере: .env файлы
Заголовок раздела «Хранение на сервере: .env файлы»# На сервере (не в git!)# Создание с правильными правамиtouch .env.productionchmod 600 .env.production # только владелец читает/пишетchown deploy:deploy .env.production
# Редактированиеnano .env.production
# Проверка правls -la .env.production# -rw------- 1 deploy deploy 512 Mar 8 01:30 .env.productionHashiCorp Vault (enterprise level)
Заголовок раздела «HashiCorp Vault (enterprise level)»# Установкаcurl -fsSL https://apt.releases.hashicorp.com/gpg | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpgecho "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.listapt update && apt install vault
# Запись секретаvault kv put secret/myapp/production \ database_url="postgresql://..." \ jwt_secret="supersecret"
# Чтениеvault kv get -field=database_url secret/myapp/production
# Использование в приложенииimport vault from 'node-vault';
const client = vault({ endpoint: 'http://vault:8200' });await client.userpassLogin({ username: 'myapp', password: process.env.VAULT_PASSWORD });
const { data } = await client.read('secret/data/myapp/production');const DATABASE_URL = data.data.database_url;AWS Secrets Manager
Заголовок раздела «AWS Secrets Manager»import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
const client = new SecretsManagerClient({ region: 'eu-west-1' });
async function getSecret(secretName) { const command = new GetSecretValueCommand({ SecretId: secretName }); const response = await client.send(command); return JSON.parse(response.SecretString);}
// Использованиеconst secrets = await getSecret('myapp/production');const db = createPool({ connectionString: secrets.DATABASE_URL });# Создание секрета через AWS CLIaws secretsmanager create-secret \ --name "myapp/production" \ --secret-string '{"DATABASE_URL":"postgresql://...","JWT_SECRET":"..."}'
# Обновлениеaws secretsmanager put-secret-value \ --secret-id "myapp/production" \ --secret-string '{"DATABASE_URL":"postgresql://...new..."}'Doppler — простой secrets manager
Заголовок раздела «Doppler — простой secrets manager»# Установкаbrew install dopplerhq/cli/doppler # macOS# илиcurl -Ls https://cli.doppler.com/install.sh | sh # Linux
# Логинdoppler login
# Создание проектаdoppler setup
# Добавление секретовdoppler secrets set DATABASE_URL="postgresql://..."doppler secrets set JWT_SECRET="supersecret"
# Запуск с секретамиdoppler run -- node server.jsdoppler run -- npm start
# В GitHub Actions- name: Fetch secrets from Doppler uses: dopplerhq/secrets-fetch-action@v1 id: doppler with: doppler-token: ${{ secrets.DOPPLER_TOKEN }}
- name: Use secret run: echo "DB URL: ${{ steps.doppler.outputs.DATABASE_URL }}"Сканирование секретов в коде
Заголовок раздела «Сканирование секретов в коде»# git-secrets — проверка перед коммитомbrew install git-secretsgit secrets --install # в репозиторииgit secrets --register-awsgit secrets --scan
# truffleHog — поиск секретов в историиpip install trufflehogtrufflehog git https://github.com/myorg/myrepo
# gitleaks — популярный сканерbrew install gitleaksgitleaks detect --source . -v # проверить текущее состояниеgitleaks git -v # проверить всю историюname: Security Scan
on: [push, pull_request]
jobs: gitleaks: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}pre-commit хуки
Заголовок раздела «pre-commit хуки»#!/bin/bash
# Проверяем что .env файлы не добавленыif git diff --cached --name-only | grep -E '^\.env(\..+)?$' | grep -v '\.example$'; then echo "❌ ERROR: Attempting to commit .env file!" echo "Remove it: git reset HEAD <file>" exit 1fi
# Проверяем на паттерны секретовif git diff --cached | grep -E '(api_key|secret|password)\s*=\s*["\'][^"\']{8,}'; then echo "⚠️ WARNING: Possible secret detected in commit!" echo "Review the diff before proceeding" exit 1fi
echo "✅ Security checks passed"chmod +x .git/hooks/pre-commitРотация секретов
Заголовок раздела «Ротация секретов»#!/bin/bashSECRET_NAME=$1OLD_VALUE=$(doppler secrets get $SECRET_NAME --plain)
# Генерация нового секретаNEW_VALUE=$(openssl rand -base64 32)
echo "Rotating $SECRET_NAME..."
# Обновляем в Doppler (или Vault, или AWS SM)doppler secrets set $SECRET_NAME="$NEW_VALUE"
# Деплоим новую конфигурацию./scripts/deploy.sh
# Проверяем что всё работаетcurl -f https://myapp.com/health || { echo "❌ Health check failed, rolling back!" doppler secrets set $SECRET_NAME="$OLD_VALUE" ./scripts/deploy.sh exit 1}
echo "✅ Secret rotated successfully"Ключевые моменты
Заголовок раздела «Ключевые моменты»- Секреты никогда не попадают в git
.envв.gitignore,.env.exampleв git- GitHub Secrets — для CI/CD, достаточно для большинства проектов
- Vault / AWS SM / Doppler — для серьёзных production систем
- gitleaks — сканируй код на предмет случайно попавших секретов
- pre-commit хуки — первая линия защиты
- Ротируй секреты регулярно и сразу при подозрении на компрометацию
Интерактивный пример
Заголовок раздела «Интерактивный пример»Как работает хранение секретов — vault vs .env: