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

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

Модель доверия

Отправленный flake — это запрос, а не удостоверение. Оператор опознаётся по SSH-ключу, которым он подключается; содержимое flake не может выдать себе доступ. Значение имеют только ключи из реестра платформы (/etc/mev/sshkeys.json).

Границы безопасности

Вычисление недоверенного flake

mevd вычисляет входящий flake в изоляции:

nix eval --json .#mev \
--no-write-lock-file \
--pure-eval --restrict-eval \
--option allow-import-from-derivation false \
--option allow-unsafe-native-code-during-evaluation false

Сверху — таймаут по часам (SIGKILL), RLIMIT_CPU и RLIMIT_AS как непривилегированные ограничения ресурсов. Нарушение любого из них завершается кодом 65 — до привилегированного согласования управление не доходит. Тест: checks.eval-cap.

Разделение привилегий

mev, mevd и mevd-apply работают без привилегий от пользователя mev: вычисление, валидация, авторизация и весь учёт (выделение id, реестры, фрагменты Traefik).

Root достигается только через два узких помощника sudo, повторно проверяющих свои входные данные:

Есть и помощники только для чтения: mev-logs (фиксированный journalctl) и mev-stat (использование ZFS; только чтение, отдельно от mev-data, чтобы путь чтения не мог изменить том).

Активатор работает без привилегий от пользователя wake. Его единственная привилегированная потребность — systemctl start/stop юнитов окружений — закрыта узким правилом polkit: только субъект wake, только container@env<цифры>.service / microvm@env<цифры>.service, только команды start/stop. Тесты: checks.sudo-scope, checks.wake.

SSH-диспетчер

Единственный аккаунт proxy принимает все SSH-подключения к окружениям. sshd сопоставляет предложенный ключ с именем пользователя через AuthorizedKeysCommand по реестру и запускает env-ssh <user> как forced command: маршрут → авторизация → пробуждение → канал к sshd окружения.

Команда зарегистрирована как файл, принадлежащий root, вне /nix/store (sshd отклоняет AuthorizedKeysCommand, путь которой проходит через каталог, доступный на запись группе или прочим, а у /nix/store режим 1775). Тест: checks.env-ssh.

Внешняя сессия ограничена (restrict); проброс портов (-L/-R) и PTY согласуются уже во внутренней сессии по каналу.

Авторизация

База членства хранится на хосте (SQLite, /var/lib/mev/mev.db), а не берётся из входящего users[]. Менять список участников и удалять окружение вправе только владелец или администратор.

Создание разрешено только владельцу (или администратору). Обновление разрешено владельцу, администратору или любому из users — кроме изменения самого users[].

Опциональная защита requireSignedCommit отклоняет пуши без действительной SSH-подписи HEAD-коммита, ключ которой зарегистрирован в signingKeys оператора. Тесты: checks.authz, checks.signed-commit.

Сетевая изоляция окружений

Каждое окружение получает собственный /30 (RFC 6598). Правила nftables блокируют транзитный трафик между интерфейсами окружений (ve-*ve-*, mvm-env*mvm-env* и между бэкендами), оставляя открытым только исходящий NAT. Тест: checks.inter-env-isolation.

Дополнительная изоляция: backend = "microvm" даёт окружению собственное ядро.

Контроль допуска активатора

Объединение одинаковых запросов, общий лимит холодных стартов, бюджет свободной RAM и ограничение частоты по источнику сдерживают радиус поражения при наплыве запросов. Тест: checks.wake-admission.

Секреты

Никаких секретов в открытом виде в отслеживаемых файлах. Хостовые секреты зашифрованы через sops-nix и доходят до сервисов через шаблоны времени активации или чтение во время работы из config.sops.secrets.<name>.path — но никогда через Nix store.

Секреты окружений описаны в описании окружения. Кратко: каждое окружение владеет своей парой age-ключей на постоянном томе данных; закрытый ключ никогда не покидает хост. Открытый текст существует только в tmpfs работающего окружения (/run/mev-secrets) — не в store и не на диске в покое. Тест: checks.env-secrets.

Сообщения об уязвимостях

Сообщайте об уязвимостях на почту support@maximaster.ru. Не заводите публичные issue по проблемам безопасности. Укажите затронутую версию или коммит и способ воспроизведения.

Подробнее об архитектуре — в разделе Архитектура.