Maran

Как это работает

Как это устроено

Три процесса на сервере с Maran, контракт между ними и правила, которые решают, что корневому демону вообще позволено делать.

На сервере с Maran работают ровно три процесса. Разделение между ними — главное проектное решение продукта, и большинство правил ниже следуют из него.

Три процесса

ПроцессРаботает отДержит
maran-apiнепривилегированного системного пользователявсю бизнес-логику и единственное подключение к базе
maran-agentrootничего — он без состояния, без базы и без собственной конфигурации
PostgreSQLсобственного пользователяданные панели, на unix-сокете, вообще без TCP-порта

Панель никогда не трогает систему. Агент ничего не решает. В этом вся форма: процесс, который знает, что должно произойти, не имеет привилегий, а процесс с привилегиями знает только, как выполнить фиксированный список вещей.

Контракт между ними

Они говорят через unix-сокет, и передаётся именованная операция с типизированными и проверенными аргументами. Отсюда три свойства, и каждое — правило, а не привычка:

  • Нет операции, которая запускает переданную вызывающей стороной программу. Ни ограниченной, ни из белого списка — никакой. Поэтому множество того, что можно заставить сделать корневой процесс, конечно, записано и поддаётся ревью.
  • Нигде в обмене нет shell-строки. Домен не экранируется перед попаданием в конфигурационный файл; он проверяется как домен — буквы, цифры, дефисы и точки, — и в нём неоткуда взяться переводу строки, который завершит одну директиву и начнёт другую, выбранную вызывающим.
  • Агент проверяет, кто спрашивает. Учётные данные пира на сокете читаются до рассмотрения операции, так что демон знает, какой процесс на другом конце, а не верит тому, что ему сказали.

Запись конфигурационного файла

Каждая привилегированная запись идёт в одном и том же порядке, и порядок — это и есть суть:

  1. отрендерить во временный файл;
  2. fsync;
  3. атомарно переименовать на место;
  4. дать проверить результат самой службе — nginx -t, а не нашему регулярному выражению;
  5. перезагрузить;
  6. откатить файл, если проверка или перезагрузка отказали.

Один плохой рендер не может уронить остальные сайты сервера, потому что о качестве рендера судит собственный парсер сервера.

Изоляция между аккаунтами

  • Аккаунт — настоящий пользователь Linux, со своим домашним каталогом и правами файловой системы.
  • Его PHP работает в собственном пуле php-fpm под собственным uid, и файловые операции идут от этого пользователя — никогда от root.
  • Таблицы арендаторов ограничены аккаунтом на уровне базы, фильтрами запросов, которые автоматический тест проверяет, обходя всю модель.
  • Запрос чужого ресурса отвечает 404, а не 403, поэтому ошибка никогда не подтверждает, что строка существует.

Чего сознательно нет

Ни брокера сообщений, ни сайдкара, ни второго демона. Фоновая работа идёт по надёжным очередям в PostgreSQL, и установка Maran не добавляет на сервер ничего, чего нет в таблице выше, — кроме одного исключения, которое оператор включает сам: службы FTPS.

Платные модули этого тоже не меняют: это модули на C#, которые управляют операциями, уже собранными в открытом агенте. Агент никогда не загружает внешний код — поэтому лицензия не может добавить новую привилегированную возможность.