СейчасЧто это такое
- Что это такое
- Установка
- Целевая архитектура
- Чеклист быстрой проверки
- Роли инструментов
- mise — воспроизводимое окружение
- sops — зашифрованные конфиги
- age — криптография под капотом
- Как mise подключает секреты
- Варианты применения в команде
- 1. Быстрый запуск проекта новым человеком
- 2. Зашифрованные dev и staging секреты
- 3. Безопасные dry-run и sandbox сценарии
- 4. Управляемый CI/CD
- 5. Разделение доступов по контурам
- 6. Операционный стандарт команды
- Что НЕ класть в project secrets
- Эталонный шаблон проекта
- С чего начать пилот
- Официальные ресурсы
Связка mise + sops + age решает две практические задачи в проектах команды: воспроизводимый запуск окружения и безопасное хранение project-level секретов. В репозиторий коммитится зашифрованный конфиг, приватный ключ для расшифровки живёт отдельно — у разработчика, в Keychain, 1Password или CI secrets.
Что это такое
mise — менеджер версий и команд проекта. В одном файле mise.toml (старый вариант имени .mise.toml тоже поддерживается) вы фиксируете, какие Node, Python, pnpm нужны проекту, и описываете команды вроде mise run dev или mise run smoke. Заменяет nvm, pyenv, asdf и зоопарк самописных скриптов. Новый человек клонирует репозиторий, делает mise install — и у него ровно те же версии и те же команды, что у вас.
sops — инструмент шифрования конфигов: изначально проект Mozilla, сейчас его поддерживает сообщество getsops под эгидой CNCF. Берёт ваш YAML или JSON и шифрует только значения, оставляя ключи открытыми. Diff в Git остаётся читаемым: видно, какое поле поменялось, а само значение зашифровано. Файл secrets/dev.sops.yaml спокойно лежит в репозитории — без приватного ключа из него ничего не достать.
age — современный инструмент шифрования файлов. Он закрывает тот же сценарий, что и GPG при шифровании, но сознательно не делает подписи, keyring и веб-доверие. Простой формат ключей и понятный CLI. Публичный ключ представляет собой одну короткую строку, её можно коммитить рядом с проектом. Приватный ключ живёт у каждого человека отдельно: в Keychain, 1Password или в файле с правильными правами. Именно age решает, кто имеет право расшифровать sops-файл.
Как они работают вместе. mise запускает проект, в нужный момент дёргает sops, тот через age расшифровывает секреты и подсовывает их в окружение. Снаружи это одна команда mise run dev. Внутри — три инструмента, каждый отвечает за свой слой: окружение, формат конфига, криптография.
Установка
Все три инструмента ставятся одной строкой через Homebrew (на Linux — через пакетные менеджеры или бинарники с GitHub):
brew install mise sops ageПосле установки создайте пару ключей age и положите её туда, где sops ищет ключ по умолчанию:
age-keygen -o ~/.config/sops/age/keys.txt
# в файле будет и публичный ключ (age1...), и приватный (AGE-SECRET-KEY-1...)Публичный ключ (строка age1...) идёт в .sops.yaml как recipient. Приватный ключ остаётся только у владельца: в ~/.config/sops/age/keys.txt, в Keychain или 1Password. sops находит его автоматически по этому пути или по переменной SOPS_AGE_KEY_FILE.
Целевая архитектура
В этой связке три инструмента закрывают три разных слоя проекта.
miseотвечает за окружение и команды: версии Node, Python, pnpm, ENV-переменные, задачиdev,test,build,smoke.sopsотвечает за зашифрованные файлы конфигурации: YAML, JSON,.env-подобные структуры, которые безопасно лежат в репозитории.ageотвечает за саму криптографию: публичный ключ коммитится в проект, приватный ключ хранится вне репозитория.
Идея простая: репозиторий перестаёт быть местом, куда «случайно попал .env». Там лежит инструкция запуска и зашифрованный сейф, а право открыть этот сейф у конкретных людей и сервисов.
Чеклист быстрой проверки
Пройдите по списку перед тем, как внедрять связку в команде.
mise.toml с фиксированными версиями инструментов.mise tasks показывает понятный набор команд (dev, test, sync:dry, build, smoke).secrets/<contour>.sops.yaml с разделением по контурам..sops.yaml.age-ключи команды собраны в одном файле и закоммичены.age-ключи разработчиков хранятся в Keychain или 1Password, а не в репозитории.age-ключ с правами только на свой контур.Роли инструментов
mise — воспроизводимое окружение
mise фиксирует версии runtime и описывает команды проекта в одном файле. Новый человек открывает репозиторий и запускает mise install плюс одну понятную команду вместо ручной установки Node, pnpm и Python нужных версий.
sops — зашифрованные конфиги
sops шифрует значения в YAML или JSON, оставляя ключи в открытом виде. Diff в Git остаётся читаемым: видно, какое поле изменилось, а само значение зашифровано. Файлы вида secrets/dev.sops.yaml спокойно коммитятся в репозиторий.
age — криптография под капотом
age отвечает за криптографию: тот же сценарий, что у GPG при шифровании файлов, но без подписей, keyring и веб-доверия. Простой формат ключей и понятный CLI. Публичный ключ лежит в проекте рядом с .sops.yaml, приватный хранится у владельца — в Keychain, 1Password или в файле ~/.config/sops/age/keys.txt.
Как mise подключает секреты
У связки два рабочих способа отдать расшифрованные значения в окружение.
Способ 1. Обёртка sops exec-env. mise-задача вызывает sops, тот расшифровывает файл и запускает команду с секретами в окружении. Подходит, когда нужен полный контроль над форматом файла и моментом расшифровки:
[tasks.dev]
run = "sops exec-env secrets/dev.sops.yaml 'pnpm dev'"Способ 2. Нативная интеграция mise. mise умеет сам читать sops-зашифрованный файл и отдавать значения как переменные окружения через _.file, без ручного вызова sops:
[env]
_.file = ".env.json" # mise сам расшифрует, если файл зашифрован sops
[settings]
sops.age_recipients = "age1devkey...".env.json, .env.yaml, .env.toml и бэкенд age (без облачных KMS на части платформ). Для нестандартных форматов и KMS оставайтесь на sops exec-env.Варианты применения в команде
1. Быстрый запуск проекта новым человеком
В проект кладётся mise.toml с версиями инструментов и понятными задачами. Новый разработчик клонирует репозиторий, получает age-ключ, и через десять минут уже запускает mise run dev или mise run sync:dry.
2. Зашифрованные dev и staging секреты
В репозитории живут secrets/dev.sops.yaml и secrets/staging.sops.yaml. Расшифровать их может только человек или CI с подходящим приватным ключом. Если ключ скомпрометирован, он отзывается, файлы перешифровываются, история в Git остаётся чистой.
3. Безопасные dry-run и sandbox сценарии
Для интеграций с Notion, Telegram, Directus, OpenAI и CRM удобно держать отдельные sandbox-секреты. Это даёт возможность проверять скрипты без доступа к production-данным и без риска случайных live writes.
4. Управляемый CI/CD
CI получает свой отдельный ключ расшифровки и запускает только разрешённые задачи: тесты, сборку, sync:dry, smoke. Секреты не лежат в репозитории как простой текст и не передаются вручную между людьми.
5. Разделение доступов по контурам
Один файл — один контур: dev, staging, production, client-demo, sandbox. У каждого контура свой набор recipients. Разработчик читает dev-секреты, но не production. CI читает только то, что ему нужно для своей задачи.
6. Операционный стандарт команды
Связка помогает зафиксировать рабочую дисциплину: где лежат секреты, кто имеет доступ, как добавить нового человека, как отозвать доступ, как ротировать ключи и какие команды считаются безопасными для запуска без approval.
Что НЕ класть в project secrets
В project-level сейфе не должно быть глобальных админских токенов, root SSH, личных ключей разработчиков, account-wide доступов Cloudflare, приватных age identities и production-секретов без отдельного процесса ротации. Для таких вещей подходят:
- Keychain или 1Password — для личных и админских ключей.
- CI secrets — для токенов, которыми пользуется только pipeline.
- Server secret store — для production runtime.
- Отдельный технический пользователь с минимальными правами — вместо того чтобы выдавать сервису ключи владельца аккаунта.
Эталонный шаблон проекта
Минимальная рабочая структура для команды.
project/
├── mise.toml
├── .sops.yaml
├── secrets/
│ ├── dev.sops.yaml
│ └── staging.sops.yaml
└── age-keys/
├── team.pub # публичные ключи команды
└── ci.pub # публичный ключ CIПример mise.toml с базовыми задачами:
[tools]
node = "20"
pnpm = "9"
python = "3.12"
[env]
PROJECT_ENV = "dev"
[tasks.dev]
description = "Локальный запуск с расшифровкой dev-секретов"
run = "sops exec-env secrets/dev.sops.yaml 'pnpm dev'"
[tasks."sync:dry"]
description = "Dry-run синхронизации без записи"
run = "sops exec-env secrets/dev.sops.yaml 'pnpm sync --dry-run'"
[tasks.smoke]
description = "Smoke-тесты после деплоя"
run = "pnpm smoke"Пример .sops.yaml, разделяющий доступ по контурам:
creation_rules:
- path_regex: secrets/dev\.sops\.yaml$
age: >-
age1devkey...,
age1cikey...
- path_regex: secrets/staging\.sops\.yaml$
age: >-
age1leadkey...,
age1cikey...С чего начать пилот
Начинайте не с production-критичных систем. Хорошие первые проекты для пилота:
- Контентные пайплайны и Notion-to-site синхронизация.
- Sandbox-боты и staging-интеграции.
- Внутренние devtools и скрипты команды.
- Тестовые контуры новых интеграций до выхода в production.
Production runtime и клиентские live-секреты стоит переводить только после отдельного preflight и плана ротации.
mise запускает проект в правильном порядке, sops открывает зашифрованный конфиг там, где есть право доступа, age определяет, у кого это право есть.Официальные ресурсы
- mise — сайт и документация: mise.jdx.dev, исходники: github.com/jdx/mise, интеграция с sops: mise.jdx.dev/environments/secrets/sops.html
- sops — сайт: getsops.io, исходники: github.com/getsops/sops
- age — спецификация и загрузка: age-encryption.org, исходники: github.com/FiloSottile/age
По теме
Если в команде уже накопились проекты с .env-файлами по разным машинам или ручной передачей токенов в личке, имеет смысл проверить на одном пилоте, насколько mise + sops + age упрощает жизнь.
Захотите обсудить, как это применить у себя или в команде — пишите в Telegram @pimenov
Если хотите разобрать свою задачу — напишите мне Если хотите разобрать свою задачу — напишите мне.
Можно прийти с идеей, черновым контекстом или уже живой задачей. Помогу быстро понять, где реальный следующий шаг, а где лишний шум.
Обычно хватает 2–3 сообщений, чтобы понять, могу ли я здесь реально помочь и в каком формате лучше двигаться дальше.