env-master
ENСоздать аккаунт
Разделы документации

Общие секреты

Одно значение на несколько проектов — без копий, которые расходятся.

Зачем

Доступы к репозиторию, ключ платёжного шлюза, настройки почты одинаковы во всех проектах. Если завести их в каждом отдельно, через месяц у вас пять «одинаковых» значений, из которых два уже разошлись, а какое из них верное — выяснится в тот день, когда пароль поменяют.

Общий секрет живёт в одном экземпляре. Меняете в одном месте — меняется у всех.

Как устроено

Окружение проекта может дополнительно читать ключи окружения другого проекта той же организации. Это ссылка, а не копия: значение остаётся в источнике и физически никуда не переносится.

billing/prod  ←  common/prod
   DB_PASSWORD          SMTP_PASSWORD
   (свой)               GIT_TOKEN

Проект billing в окружении prod отдаёт три ключа: свой DB_PASSWORD и два пришедших из common. SDK и CLI получают их одинаково — по ссылке запись приезжает неотличимо от собственной.

Что происходит при чтении

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

  • в ответе по-прежнему один ключ данных — тот, что у потребителя;
  • ваш SDK не нужно обновлять: формат ответа не изменился;
  • отключение не требует перешифрования — в окружение потребителя ничего не записывалось.

Как подключить

Заведите проект с общими значениями — например common — и положите туда ключи, как в обычный проект. Затем в разделе Окружения проекта-потребителя, в блоке «Общие секреты», нажмите «Подключить» и выберите:

ПолеЧто значит
Окружение этого проектакуда придут чужие ключи
Проект-источникгде лежат общие значения
Окружение источникакакое именно окружение источника читать

Подключение делается на каждое окружение отдельно. Это не лишняя работа, а то, ради чего модель и устроена так: prod вашего сервиса читает common/prod, а dev — common/dev, с другими значениями тех же ключей.

Связывать окружения может владелец организации. Причина не в иерархии, а в том, что подключение — операция с двумя сторонами. Разрешить её только получателю значило бы: администратор своего проекта подключается к чужому окружению и читает его. Разрешить только источнику — человек без роли в проекте молча меняет его конфигурацию. Владелец заведомо имеет права с обеих сторон.

Через API та же операция — один запрос (источник указывается slug'ом):

curl -s $BASE/projects/$PROJECT/links \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"environment":"production","fromProject":"common","fromEnvironment":"production"}'

Отключение — DELETE /projects/:id/links/:linkId, список подключений — GET /projects/:id/links.

Своё всегда сильнее общего

Если в окружении есть свой ключ с тем же именем, он выигрывает. Общий в этот момент не отдаётся вовсе — ни SDK, ни в таблице.

Это способ сделать исключение: подключить общий SMTP везде, а в одном проекте переопределить его своим. Ничего отключать не нужно.

Переопределение обязано совпасть с источником по типу и видимости. Секрет нельзя перекрыть переменной: иначе значение, которое источник объявил секретом, стало бы открытым текстом для всех, кто читает это окружение.

Правка общего ключа в проекте-потребителе не меняет его в источнике — она создаёт местное переопределение. Кабинет предупреждает об этом до сохранения, но знать стоит заранее: «поменял пароль всем» и «поменял пароль себе» здесь выглядят одинаково.

Два источника с одним ключом

Отклоняются при подключении. Не выбирается победитель, не берётся «последний подключённый» — операция просто не проходит, с указанием, какой проект уже приносит этот ключ.

Молчаливый приоритет по порядку подключения — это конфигурация, которую нельзя отладить в два часа ночи, когда сервис читает не то значение.

Отключение

Удаляет ссылку. Со следующего запроса ключи не приходят; перешифровывать нечего.

Отключение не вынимает значения из памяти уже запущенных процессов — ровно как удаление записи или отзыв identity. Отзыв прекращает выдачу, а не стирает прошлое. Если секрет скомпрометирован, его нужно менять, а не отключать, — и в этом главный выигрыш модели: менять придётся один раз.

Вебхуки

Изменение общего секрета доходит и до подключённых проектов: событие entry.updated приходит на вебхуки каждого потребителя, а не только источника, с полем fromProjectId в метаданных.

Если ключ перекрыт своим значением, потребителю не сообщают — для него ничего не изменилось.

Как перенести то, что уже разложено по проектам

Раздел Проекты показывает владельцу организации, какие ключи держат одинаковое значение в разных проектах. Совпадение находится по отпечатку значения, без расшифровки: у одинаковых значений одинаковый HMAC.

Отчёт видит только владелец, и по той же причине, по какой только он связывает окружения. Отпечаток не солится — иначе отчёт был бы невозможен, — а значит фраза «здесь то же значение, что там» отвечает на вопрос о секрете, к которому у спрашивающего может не быть доступа. Владельцу это ничего не добавляет: он и так выдаёт себе любую роль. Построение отчёта попадает в журнал.

Переносить можно на работающем сервисе, и порядок важен:

  1. Завести ключ в общем проекте с тем же значением.
  2. Подключить общий проект к окружениям-потребителям. Эффективная конфигурация не меняется: копии ещё на месте и перекрывают ссылку.
  3. Удалить локальные копии. Значение переключается на общее — то же самое, отпечаток тот же, потребители разницы не видят.

Ключи с одинаковым именем, но разными значениями отчёт помечает отдельно. Это не дубль, а расхождение: какое из значений правильное, машина решить не может.

Ограничения

  • Ссылки не транзитивны: если A читает B, а B читает C, то A не получит ключи C. Кольцо из ссылок отклоняется при создании — не потому, что зациклит сервер, а потому что означало бы ожидание транзитивности, которой нет.
  • Ссылки не выходят за организацию.
  • Удаление проекта или окружения снимает все ссылки, которые в него упирались.