.env-файлы

25.04.2025

Безопасное хранение секретов, а также правильное использование этой «чувствительной» информации в переменных окружения давно волнует меня.

Как было раньше: локальное шифрование

Раньше я использовал локальное шифрование. Применял обычный OpenSSL, установленный практически в любой системе, передавал ему keyfile (обычно он хранился в каком-нибудь укромном Google Документе) и получал зашифрованный файл с соответствующим окружению суффиксом, например:

.env.dev.enc
.env.stage.enc
.env.prod.enc

Чтобы обновить или добавить переменную, приходилось заново проводить процедуру шифрования и дешифровки для каждого окружения, что само по себе довольно утомительно.

Поэтому часто я пользовался одним общим .env-файлом для всех приложений, лишь бы облегчить себе жизнь — хотя кого я обманываю?

Таким образом, переменные окружения для бэкенда оказывались среди переменных фронтенда. Например, данные подключения к базе данных 🤪

Ещё одной проблемой была необходимость хранить зашифрованные .env-файлы в отдельном месте, чаще всего в специальном репозитории. Их обновление происходило отдельно от обновления самого приложения, создавая дополнительное пространство для ошибок.

Doppler

Совсем недавно я обнаружил Doppler. Теперь управлять секретами стало проще благодаря удобному веб-интерфейсу.

Никакие .env-файлы больше не нужны — достаточно команды:

doppler run -- npm run build

И приложение собирается с заранее настроенным конфигурационным профилем. Доступны интеграции для большинства современных инструментов развёртывания приложений.

Почему я всё же оставил .env-файлы

Я не люблю сильно зависеть от инструментов, поэтому не стал совсем отказываться от .env-файлов. Пока решил просто автоматически генерировать их с помощью Doppler.

Автоматизация с помощью Taskfile

Я создал небольшой Taskfile для первоначального запуска проекта с правильными переменными окружения:

# yaml-language-server: $schema=https://taskfile.dev/schema.json
version: "3"

tasks:
  install:
    cmds:
      - curl -Ls --tlsv1.3 --proto "=https" https://cli.doppler.com/install.sh | sh

  login:
    cmds:
      - doppler login
  
  get-env:
    vars:
      DOPPLER_PROJECT: '{{default "help" .DOPPLER_PROJECT}}'
      DOPPLER_CONFIG: '{{default "dev" .DOPPLER_CONFIG}}'
      FILEPATH: '{{default "" .FILEPATH}}'
    cmds:
      - doppler secrets download --project {{.DOPPLER_PROJECT}} --config {{.DOPPLER_CONFIG}} --no-file --format env > {{.FILEPATH}}
  
  setup-infra-secrets:
    cmds:
      - task: get-env
        vars: { DOPPLER_PROJECT: "infra", DOPPLER_CONFIG: "{{.DOPPLER_CONFIG}}", FILEPATH: ".env" }

  setup-frontend-secrets:
    cmds:
      - task: get-env
        vars: { DOPPLER_PROJECT: "frontend", DOPPLER_CONFIG: "{{.DOPPLER_CONFIG}}", FILEPATH: "apps/frontend/.env" }
  
  setup-backend-secrets:
    cmds:
      - task: get-env
        vars: { DOPPLER_PROJECT: "backend", DOPPLER_CONFIG: "{{.DOPPLER_CONFIG}}", FILEPATH: "apps/backend/.env" }

  setup-secrets:
    deps: [setup-frontend-secrets, setup-infra-secrets, setup-backend-secrets]

  initial-setup:
    cmds:
      - task: install
      - task: login
      - task: setup-secrets
Логотип Данила Родина