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

Модель безопасности

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

Эта страница объясняет модель. О настройках, которые её реализуют, см. Безопасность.

Границы доверия

ГраницаЧто её пересекаетЧем защищена
Браузер ↔ серверСессии, API-токеныTLS, защищённые cookie, обратный прокси
Сервер ↔ база данныхВсё постоянное состояниеСетевые ограничения; секреты шифруются перед записью
Сервер ↔ раннерПолезная нагрузка заданий, включая секретыHTTPS и bearer-токен для каждого раннера
Задача ↔ управляемые хостыВаша автоматизацияКлючи, которые вы указали в шаблоне

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

Идентификация

Пользователи проходят аутентификацию одним из трёх способов, и все три приводят к одной и той же сессии:

  • Локальные учётные записи. Пароли хешируются с помощью Argon2id (до 2.20 — bcrypt, с обновлением при первом входе). Можно потребовать двухфакторную аутентификацию TOTP.
  • LDAP или Active Directory. Пароль проверяет каталог, а Semaphore хранит только учётную запись.
  • OpenID Connect. Провайдер выполняет аутентификацию, а Semaphore сопоставляет claim'ы с пользователями.

Для неинтерактивного доступа используются API-токены, созданные пользователем и несущие его права. Раннеры вообще не используют пользовательскую идентификацию: они аутентифицируются собственным токеном, выданным при регистрации.

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

Авторизация

Существует два независимых уровня.

Уровень сервера. Администратор управляет пользователями, глобальными раннерами и настройками сервера. Быть администратором сервера само по себе не даёт членства в проекте.

Уровень проекта. У каждого участника есть одна роль в каждом проекте:

РольЧто может
OwnerВсё в проекте, включая управление участниками и удаление.
ManagerЗапускать задачи и управлять ресурсами и шаблонами.
Task RunnerЗапускать задачи. Больше ничего.
GuestЧитать.

В Enterprise добавляются пользовательские роли Enterprisesince 2.17 на случай, когда этих четырёх слишком мало.

Важная с точки зрения безопасности граница проходит между Task Runner и Manager. Manager может изменить то, что выполняет шаблон, а значит, может выполнить произвольный код с учётными данными этого проекта. Task Runner может лишь запустить то, что уже существует, — если только шаблон не предоставляет prompts или survey-переменные, попадающие в командную строку: в этом случае автор шаблона расширил эту границу намеренно.

Секреты

Секретные значения — приватные SSH-ключи, пароли, токены, секретные переменные — шифруются ключом из access_key_encryption перед сохранением, поэтому один только дамп базы данных их не раскрывает. API никогда не возвращает секретное значение; UI показывает, что секрет задан, но не то, каков он.

Секреты попадают в задачу через её окружение в момент запуска. Именно поэтому вывод задачи стоит считать чувствительным: playbook, который печатает переменную, печатает её в лог, доступный другим участникам проекта.

Если вы предпочитаете вообще не хранить секреты, внешние хранилища секретов держат значения в HashiCorp Vault, OpenBao, AWS Secrets Manager или Devolutions Server и получают их при каждом запуске.

Выполнение недоверенного кода

При настройке по умолчанию задача — это процесс на сервере Semaphore с файловой системой и сетевым доступом сервера. Это допустимо, когда все, кто может редактировать шаблон, и так доверены на уровне сервера.

Если это не так, вынесите выполнение за пределы сервера:

  • Раннер помещает задачи на другую машину, поэтому компрометация задачи не компрометирует веб-сервис и базу данных.
  • Исполнитель Docker или Kubernetes даёт каждому заданию свежий контейнер или Pod, поэтому один запуск не может прочитать файлы другого запуска или хоста.
  • Разделение на проекты с разными ключами означает, что задача дотянется только туда, куда позволяют учётные данные её собственного проекта.
внимание

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

Что остаётся за вами

Semaphore размещается на ваших мощностях, поэтому часть модели обеспечиваете вы:

  • TLS перед сервисом — встроенный или от обратного прокси.
  • Сетевые ограничения для базы данных и административной поверхности сервера.
  • Резервные копии базы данных и access_key_encryption — второе бесполезно без первого, а первое нечитаемо без второго.
  • Поддержание версии в актуальном состоянии. Сообщайте об уязвимостях на [email protected].

Что дальше

  • Безопасность — конкретные настройки, параметры хеширования и шаги по усилению защиты.
  • Архитектура — компоненты, которые разделяют эти границы.
  • Команды — назначение ролей в проекте.