Секреты
Soul Stack обращается с секретами по двум правилам: они резолвятся на стороне Keeper-а (агент не несёт vault-клиента) и маскируются на каждом выходе (логи, OTel, UI, отчёты). Источник секретов — Vault.
Интеграция с Vault
Заголовок раздела «Интеграция с Vault»Vault используется в двух качествах:
- PKI — выпуск и подпись сертификатов идентичности агентов (SoulSeed). Приватный ключ удостоверяющего центра живёт в Vault и на диски кластера не попадает (см. Транспорт → Общий PKI-корень).
- KV — хранилище секретов (пароли, токены, ключи), которые подставляются в конфиги при рендере Destiny.
Ключевой инвариант: секреты не материализуются на диск кластера Keeper-а — они живут в Vault и подтягиваются в момент рендера.
Резолв на стороне Keeper-а
Заголовок раздела «Резолв на стороне Keeper-а»Все обращения к Vault происходят на Keeper-е, во время рендера задач — до того, как задачи уходят на агент.
- Ссылки на секреты в конфиге (например, выражение, читающее значение из Vault KV) Keeper резолвит сам и подставляет реальное значение в уже отрендеренную задачу.
- На агент уходит готовый результат. Агент не несёт vault-клиента, на хосте нет Vault-токенов, и агент не имеет права читать чужие секреты.
Это прямое следствие принципа тонкого агента: чем меньше прав и кода на управляемом хосте, тем меньше поверхность атаки. Резолв секретов — операция с внешним доступом, и она целиком остаётся на Keeper-е.
Маскинг секретов на выходе
Заголовок раздела «Маскинг секретов на выходе»Внутри движка рендера секрет обрабатывается как обычное значение — иначе легитимный сценарий «подставить пароль в параметр модуля» не работал бы. Защита от утечки навешивается на выходе, на всех границах, где данные покидают систему:
- логи — отрендеренные параметры шага в лог-записях;
- OpenTelemetry-трейсы — атрибуты span-ов;
- UI и API-ответы;
- отчёты о прогоне.
Значение, помеченное как секретное в схеме своего источника, маскируется на каждой из этих границ — в открытом виде секрет наружу не попадает.
Две категории секретности
Заголовок раздела «Две категории секретности»| Категория | Откуда секретность | Можно ли забыть |
|---|---|---|
По схеме (secret: true) | Поле помечено секретным в схеме входных параметров сценария. | Да — зависит от того, что оператор разметил в схеме. |
| Sensitive-by-construction | Параметр секретен по своей природе, независимо от разметки (например, HTTP-заголовки запроса, которые штатно несут Authorization/Cookie). Зашито в реализацию модуля. | Нет — не отключается. |
Для категории sensitive-by-construction значение никогда не логируется, не кладётся в OTel-атрибуты, не возвращается в результат и не попадает в события прогона — вне зависимости от того, пометил ли его оператор секретным.
Ключ no_log
Заголовок раздела «Ключ no_log»Кроме маскинга по схеме, шаг можно явно пометить как «не логировать» через ключ no_log. Это инструмент оператора для шагов, где даже отрендеренные параметры не должны попасть в выводы целиком, — дополнительный слой поверх автоматического маскинга секретных значений.
Безопасные сетевые модули по умолчанию
Заголовок раздела «Безопасные сетевые модули по умолчанию»Модули, которые ходят в сеть (core.url, core.http), образуют отдельную границу риска (SSRF, supply-chain). Принцип здесь тот же, что и во всей системе: наш код безопасен по умолчанию, ослабление — явный выбор оператора.
По умолчанию взведены:
- только
https://(неhttp://, неfile://); - защита от обращений к внутренним адресам (SSRF-guard по фактически разрезолвленному IP);
- проверка TLS-цепочки.
Ослабить конкретный контур можно явными per-call флагами — allow_http, insecure_skip_verify, allow_private. Каждый по умолчанию выключен, ослабляет ровно один независимый контур, и его включение даёт warning в отчёте о прогоне — факт ослабления виден и аудируем. Это не запрет возможностей, а безопасный дефолт под явный, фиксируемый opt-out.