Вопрос или проблема
Пытаюсь запустить службу systemd с помощью systemctl --user start foo.service
, которая содержит ExecStart=touch /bar/baz
, где у /bar
права drwxrwxr-x 1 root storage
. Пользователь, выполняющий команду, принадлежит группе storage
и может без проблем выполнять команду touch
из оболочки, создавая файл. Однако служба завершается с ошибкой разрешений.
Я думал, что разрешения службы будут соответствовать пользователю, который её запускает — и действительно, использование переменной окружения ${USER}
в команде службы даёт моё имя пользователя, а служба отображается в списках ps
или pstree ${USER}
.
foo.service
не содержит ProtectSystem
или каких-либо записей, кроме: Description
, EnvironmentFile
, Environment
, ExecStart
, KillSignal
, Restart
, RestartSec
. Записи окружения предназначены для загрузки конфигурации, не связанной с правами.
Служба действительно не использует вызывающего пользователя для получения разрешений? И если нет, то как лучше всего решить эту проблему? /bar
находится на смонтированном диске, поэтому я мог бы просто указать dmask 0000
в своём fstab, но я бы предпочёл избежать этого подхода.
Ответ или решение
Проблема, с которой вы столкнулись, связана с тем, что сервисы, запущенные через systemd в контексте пользователя, имеют свои собственные ограничения безопасности, которые могут отличаться от тех, что применяются при выполнении команд в оболочке. Это может объяснить, почему команда touch
работает в оболочке, но завершает выполнение с ошибкой при запуске как сервис.
Контекст выполнения сервисов
Когда вы запускаете systemctl --user start foo.service
, сервис выполняется в пределах пользовательского окружения, однако он может быть ограничен некоторыми параметрами безопасности, которые не позволяют ему получать доступ к ресурсам, даже если текущий пользователь принадлежит к нужным группам. Наиболее вероятные причины ошибки:
-
Restrictive Control Groups (cgroups): На уровне системного менеджера и cgroups могут присутствовать ограничения, которые предотвращают доступ к определённым каталогам или ресурсам.
-
SELinux или AppArmor: Если один из этих механизмов безопасности активен, он может ограничивать доступ вашего сервиса к определённым файловым системам (например, к
/bar
). -
Виртуальная среда пользователя: Приложения, запущенные в контексте systemd user service, работают в более „очищенном“ окружении, что может привести к тому, что они действуют в более строгих условиях.
Решения проблемы
Вот несколько возможных решений вашей проблемы:
-
Проверьте SELinux/AppArmor: Если вы используете SELinux, проверьте его состояние с помощью команды
sestatus
. Убедитесь, что он не блокирует доступ к/bar
. Вы можете временно отключить SELinux (например, с помощьюsetenforce 0
) для проверки, разрешает ли это выполнение сервиса. -
Настройка файла сервиса: Добавьте параметры, которые разрешают доступ к вашей файловой системе в конфигурацию сервиса. Например, можно попробовать добавить следующие строки в
foo.service
:[Service] PrivateDevices=no ProtectHome=no
-
Использование
User=
иGroup=
: Если в вашем конфигурационном файле сервиса отсутствуют строкиUser=
иGroup=
, попробуйте явно указать пользователя и группу, от имени которых будет запущен ваш сервис:[Service] User=ваш_пользователь Group=storage
-
Используйте
ExecStartPre
: Если возможно, создайте предварительную команду, которая проверяет права доступа к директории или создает файл с помощью другого метода, прежде чем запускать основной процесс. -
Отладка сервиса: Для более глубокого анализа, добавьте следующие строки для логирования и отладки в ваш сервис:
[Service] StandardOutput=journal StandardError=journal
Заключение
Требуется комплексный подход к решению проблемы с правами доступа к директории при выполнении сервисов systemd в пользовательском режиме. Обязательно контролируйте доступные настройки безопасности и групп, чтобы удостовериться, что сервис имеет все необходимые права. Если ни одно из предложенных решений не работает, стоит также рассмотреть возможность временного изменения монтирования файловой системы в fstab, но это действительно должно быть последним решением.