После ProtectSystem сервис не пишет данные: задаём writable-пути

Службе включили ProtectSystem=strict, после чего она перестала сохранять результаты. Обычные права каталога разрешают запись, а запуск той же команды вручную работает. Внутри службы может действовать другое представление файловой системы: доступ ограничен на уровне mount namespace.

Отличить readonly от прав владельца

systemctl cat report.service
systemctl show report.service -p ProtectSystem -p ReadWritePaths -p ReadOnlyPaths -p StateDirectory
journalctl -u report.service -b --no-pager
stat -c '%n %U %G %a' /var/lib/report

Точное сообщение важно: Read-only file system направляет к mount-ограничению, Permission denied — к проверке доступа и другим слоям. Но приложение может скрыть системную ошибку за общим «не удалось сохранить», поэтому при необходимости используйте его подробный журнал на стенде.

Выделить состояние приложения

[Service]
User=reportbot
ProtectSystem=strict
StateDirectory=report
ReadWritePaths=/var/lib/report
ExecStart=/usr/local/bin/report-worker --state-dir=/var/lib/report

Это пример для приложения с настраиваемым каталогом состояния. ProtectSystem=strict делает большую часть файловой иерархии readonly для службы. StateDirectory создаёт управляемый каталог постоянных данных; такие управляемые каталоги имеют специальное взаимодействие с защитой. Явный ReadWritePaths здесь показывает требуемую writable-границу и может быть избыточен для самого StateDirectory.

Если каталог уже управляется иначе, можно описать разрешённый путь через ReadWritePaths, предварительно создав его и задав владельца. Этот параметр не выдаёт пользователю DAC-права и не способен сделать физически readonly-файловую систему writable. Оба условия должны разрешать запись. Детали ограничений — в systemd.exec.

Не расширять доступ до всего /var

Сначала перечислите реальные записи приложения: постоянная база, временные файлы, кэш и собственные текстовые журналы. Задайте им отдельные каталоги через поддерживаемые параметры программы. Если приложение пишет рядом с исполняемым файлом, лучше исправить расположение состояния, чем открыть весь /usr или /opt.

Например, после переноса состояния в /var/lib/report база сохраняется, но генератор ещё пытается писать временный файл в /etc/report. Это отдельная ошибка размещения. Сделайте путь временных файлов явным и повторите задачу. Не добавляйте каждый отказавший родительский каталог целиком в writable-список.

Проверить положительное и отрицательное поведение

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

Существующие Unix-сокеты и другие возможности взаимодействия требуют отдельного анализа: readonly пути не являются универсальным запретом IPC. Также результат зависит от поддержки namespaces и окружения менеджера. Проверьте сообщения systemd о применении настроек на целевой машине.

Критерий готовности — служба выполняет все нужные операции, а её постоянные и временные записи перечислены и ограничены осмысленными путями. Посмотрите программу Linux и Bash для DevOps-инженеров: понимание прав, файловой системы и systemd помогает находить именно тот слой, который запрещает операцию.

Ещё по теме

Продолжить на практике

  • Linux и Bash для DevOps-инженеров ↗

    Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.