.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