Модель безопасности
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].
Что дальше
- Безопасность — конкретные настройки, параметры хеширования и шаги по усилению защиты.
- Архитектура — компоненты, которые разделяют эти границы.
- Команды — назначение ролей в проекте.