Секреты — .env и переменные окружения

Секреты (API-ключи, пароли БД, JWT-секреты) хранятся вне исходного кода в переменных окружения или секрет-менеджерах и никогда не коммитятся в git.

Зачем нужно

Секрет в git-репозитории — компрометация навсегда: даже после удаления файла история хранит его. Через GitHub ежедневно утекают тысячи секретов в публичных репозиториях. Правильное управление секретами — базовая гигиена любого проекта.

Где используется

  • Все приложения: DATABASE_URL, JWT_SECRET, API-ключи
  • CI/CD: секреты для деплоя (SSH-ключи, DockerHub credentials)
  • Production: AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager

Основной контент

.env для локальной разработки

# .env (НЕ коммитить!)
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
JWT_SECRET=super-secret-key-min-32-chars-long
STRIPE_SECRET_KEY=sk_test_xxxxx
REDIS_URL=redis://localhost:6379
# .env.example (коммитить — без реальных значений)
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
JWT_SECRET=your-secret-key-here
STRIPE_SECRET_KEY=sk_test_your_key
REDIS_URL=redis://localhost:6379
# .gitignore — обязательно!
.env
.env.local
.env.production
*.pem
*.key

Загрузка в Node.js

// Только для локальной разработки (dotenv)
require('dotenv').config;

// В production env переменные задаются через платформу (Heroku, Vercel, K8s)
const config = {
  db: {
    url: process.env.DATABASE_URL,
  },
  jwt: {
    secret: process.env.JWT_SECRET,
    expiresIn: process.env.JWT_EXPIRES_IN || '7d',
  },
};

// Валидация при старте — не запускать с отсутствующими секретами
const required = ['DATABASE_URL', 'JWT_SECRET'];
for (const key of required) {
  if (!process.env[key]) {
    throw new Error(`Missing required environment variable: ${key}`);
  }
}

Production: AWS Secrets Manager

const { SecretsManagerClient, GetSecretValueCommand } = require('@aws-sdk/client-secrets-manager');

async function getSecret(secretName) {
  const client = new SecretsManagerClient({ region: 'eu-west-1' });
  const response = await client.send(new GetSecretValueCommand({ SecretId: secretName }));
  return JSON.parse(response.SecretString);
}

// Загружаем один раз при старте приложения
const secrets = await getSecret('prod/myapp/credentials');
const dbPassword = secrets.DB_PASSWORD;

Обнаружение утечек: TruffleHog / git-secrets

# Проверить текущий репозиторий на предмет утечек
npx trufflehog git file://. --only-verified

# GitHub Actions: автоматическая проверка в CI
- uses: trufflesecurity/trufflehog-actions-scan@main
  with:
    path: ./
    base: ${{ github.event.repository.default_branch }}

Частые ошибки

  • Коммит .env файла в git — даже в private репозиторий (доступ у всей команды)
  • Хранение секретов в коде в виде констант: const API_KEY = "sk-abc123"
  • Одинаковые секреты в dev и production — ротация невозможна без downtime
  • Логирование process.env целиком при старте — все секреты попадают в логи
  • Передача секретов через URL-параметры — видны в логах nginx и browser history

Связанные темы

Ресурсы