Изоляция служб systemd: песочница для своих сервисов

0
11
Обложка статьи: Изоляция служб systemd: песочница для своих сервисов

Если взломать службу, нарушитель получает права её пользователя и доступ ко всему, что она видит: домашние каталоги, чужие временные файлы, запись в систему, возможность поднимать сеть и грузить модули ядра. systemd умеет ограничить всё это несколькими строками в файле службы, без контейнеров и без установки дополнительных программ. Ниже набор директив, как их включать постепенно, как оценить результат командой systemd-analyze security и как не сломать службу.

Статья опирается на логику направления «Безопасность конечных устройств» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами. Проверки выполнены на Debian 12 с systemd 252. Для вашей версии список директив может отличаться: смотрите man systemd.exec. Парная статья про базовую настройку серверов: hardening Linux.

Что должно получиться

Уровень Что это значит на практике
2. Гигиенический Есть эталонная конфигурация и проверка отклонений; службы работают с минимальными правами

Критерии сформулированы нами по мотивам методики, это ориентир, а не оценка соответствия.

Как работают ограничения

Директивы раздела [Service] включают для процесса службы механизмы ядра: пространства имён монтирования, ограничение возможностей, фильтр системных вызовов. Служба видит урезанную систему: например, файловую систему только для чтения, отдельный каталог /tmp и пустой /root. Проверка на живой системе (одноразовые запуски systemd-run с теми же свойствами):

Директива Проверка Результат
без ограничений запись в /etc запись удалась
ProtectSystem=strict запись в /etc Read-only file system
ProtectHome=yes просмотр /root каталог пуст для службы
PrivateTmp=yes файл, созданный в /tmp службой виден службе, на хосте отсутствует
NoNewPrivileges=yes, CapabilityBoundingSet= чтение /proc/self/status NoNewPrivs: 1, CapEff: 0000000000000000
PrivateNetwork=yes список сетевых интерфейсов только lo
SystemCallFilter=@system-service и ~@privileged обычная команда выполняется

Пример проверки одной директивы без изменения служб: sudo systemd-run --wait --pipe -p ProtectSystem=strict /bin/sh -c 'touch /etc/test'. Команда запускает временную службу и сообщает о результате; ничего не меняется в системе.

Оценка: systemd-analyze security

Команда systemd-analyze security ИМЯ.service оценивает службу по шкале от 0 (безопасно) до 10 (небезопасно) и перечисляет, какие директивы не включены. На тестовой службе (sleep 300) без ограничений итоговая оценка была 9.6 (UNSAFE), после включения набора ниже стала 1.4 (OK). Для реальных служб значения будут выше: многим нужны запись в определённые каталоги, сеть, работа с файлами. Цель не ноль, а осознанный минимум: каждая оставленная «дыра» должна иметь причину.

Файл службы

Пример /etc/systemd/system/myservice.service. Команду запуска и каталоги замените своими.

# /etc/systemd/system/myservice.service: пример изолированной службы (подставьте свою команду и пути)
[Unit]
Description=Пример изолированной службы
After=network.target

[Service]
ExecStart=/usr/local/bin/myservice --config /etc/myservice/config.yml
Restart=on-failure

# --- пользователь без прав и без домашнего каталога
DynamicUser=yes
StateDirectory=myservice
ConfigurationDirectory=myservice

# --- файловая система только для чтения, кроме StateDirectory
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes

# --- ядро и системные интерфейсы
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes

# --- ограничения возможностей
CapabilityBoundingSet=
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
UMask=0077

[Install]
WantedBy=multi-user.target
Директива Что делает и на что влияет
DynamicUser=yes Создаёт временного пользователя для службы без прав и входа; несовместима со службами, которым нужен постоянный владелец файлов вне каталогов состояния (используйте StateDirectory)
StateDirectory, ConfigurationDirectory Создают каталоги /var/lib/ИМЯ (записываемый) и /etc/ИМЯ (только чтение) с правильным владельцем
ProtectSystem=strict Вся файловая система только для чтения, кроме каталогов состояния и явных исключений ReadWritePaths
ProtectHome=yes Домашние каталоги недоступны
PrivateTmp, PrivateDevices Отдельный /tmp; только минимальный набор устройств
ProtectKernel*, ProtectControlGroups, ProtectClock, ProtectHostname Запрещают менять настройки ядра, загружать модули, читать журнал ядра, менять время и имя узла
CapabilityBoundingSet= Убирает все привилегии Linux (если службе нужны отдельные, например CAP_NET_BIND_SERVICE для порта ниже 1024, перечислите их)
RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality Закрывают редко нужные возможности, часто используемые при эксплуатации
MemoryDenyWriteExecute=yes Запрещает память, одновременно доступную для записи и исполнения; ломает службы с JIT-компиляцией (Java, Node.js, часть интерпретаторов): для них директиву не включайте
RestrictAddressFamilies Оставляет только нужные семейства сокетов
SystemCallFilter Разрешает группу вызовов @system-service и запрещает привилегированные и управляющие ресурсами

Включайте постепенно

  1. Начните с оценки. systemd-analyze security имя.service на текущей службе: сохраните значение и список замечаний.
  2. Добавляйте директивы по группам через drop-in файл, а не правкой основного файла: sudo systemctl edit имя.service создаёт /etc/systemd/system/имя.service.d/override.conf, который легко удалить для отката.
  3. После каждой группы перезапускайте службу и проверяйте работу: sudo systemctl restart имя, systemctl status имя, журнал journalctl -u имя -n 50.
  4. Начинайте с безопасных: NoNewPrivileges, PrivateTmp, ProtectKernel*, ProtectControlGroups, RestrictRealtime, LockPersonality. Затем ProtectSystem=strict и ProtectHome с явными ReadWritePaths. В конце самые строгие: SystemCallFilter, MemoryDenyWriteExecute, CapabilityBoundingSet=.
  5. Проверяйте файл: systemd-analyze verify /etc/systemd/system/имя.service: выводит предупреждения о неизвестных директивах и отсутствующих файлах.
  6. Зафиксируйте результат: новую оценку и причины оставленных замечаний.

Диагностика отказов

Симптом Причина и что делать
Служба не стартует: Read-only file system Нужна запись в каталог. Добавьте ReadWritePaths=/путь или StateDirectory=
Ошибка доступа к файлам в /home Включён ProtectHome. Перенесите данные или смягчите на read-only
Процесс убит сигналом SIGSYS Фильтр системных вызовов. Найдите вызов в журнале (journalctl, поле SYSCALL при включённом аудите), разрешите нужную группу или временно уберите фильтр
Служба падает с Cannot allocate memory или работает нестабильно MemoryDenyWriteExecute несовместим с JIT. Уберите директиву
Не открывается порт ниже 1024 Нужно право CAP_NET_BIND_SERVICE: AmbientCapabilities=CAP_NET_BIND_SERVICE и CapabilityBoundingSet=CAP_NET_BIND_SERVICE
Не нашёл файл, который служба создаёт Из-за PrivateTmp временные файлы видны только службе. Используйте каталог состояния для обмена

Для отката удалите drop-in и выполните sudo systemctl daemon-reload && sudo systemctl restart имя. Изменения конфигурации служб выполняйте по процессу управления изменениями: карточка, проверка и откат.

Где применять в первую очередь

  • Службы, доступные из сети: веб-серверы, прокси, почтовые и прикладные службы.
  • Самописные демоны и сценарии, запускаемые от root.
  • Службы, обрабатывающие чужие данные (загрузки, парсинг, конвертация файлов).

Многие пакеты дистрибутивов уже содержат ограничения в файлах служб: смотрите оценку systemd-analyze security по всем службам списком и начинайте с самых плохих.

Где это в модели зрелости

Материал относится к направлению «Безопасность конечных устройств» (материалы направления, карта зрелости). Уровень 2 требует эталонной конфигурации и проверки отклонений: оценка systemd-analyze security и drop-in файлы дают воспроизводимый и проверяемый эталон для служб.

Как проверить

  1. Для каждой сетевой службы есть оценка systemd-analyze security и записанные причины оставшихся замечаний.
  2. Включены хотя бы NoNewPrivileges, PrivateTmp, ProtectSystem, ProtectHome, ограничение возможностей.
  3. Служба после ограничений работает под нагрузкой и после перезапуска, откат описан.
  4. Изменения оформлены drop-in файлами и учтены в карточках изменений.

Источники

  • Методика оценки уровня зрелости кибербезопасности компании, Группа Сбер: sberbank.ru.
  • Руководство systemd: man systemd.exec (директивы песочницы), man systemd-analyze, man systemd-run; сайт проекта: systemd.io.
  • CIS Benchmarks для вашего дистрибутива: cisecurity.org. Международная практика, не российский норматив.

Оставьте свой ответ