Перейти к содержимому

Секреты

Soul Stack обращается с секретами по двум правилам: они резолвятся на стороне Keeper-а (агент не несёт vault-клиента) и маскируются на каждом выходе (логи, OTel, UI, отчёты). Источник секретов — Vault.

Vault используется в двух качествах:

  • PKI — выпуск и подпись сертификатов идентичности агентов (SoulSeed). Приватный ключ удостоверяющего центра живёт в Vault и на диски кластера не попадает (см. Транспорт → Общий PKI-корень).
  • KV — хранилище секретов (пароли, токены, ключи), которые подставляются в конфиги при рендере Destiny.

Ключевой инвариант: секреты не материализуются на диск кластера Keeper-а — они живут в Vault и подтягиваются в момент рендера.

Все обращения к 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. Это инструмент оператора для шагов, где даже отрендеренные параметры не должны попасть в выводы целиком, — дополнительный слой поверх автоматического маскинга секретных значений.

Модули, которые ходят в сеть (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.