Вопрос или проблема
Я пытаюсь написать определение пользовательского сервиса для SystemD на системе RHEL.
В настоящее время вывод идет в Журнал, но мне нужно, чтобы он записывался в файл для парсинга и переадресации с помощью logstash. (Примечание: по причинам, не зависящим от меня, Journalbeat не является вариантом).
Чтобы сделать так, чтобы сервис записывал логи в файл, я попробовал:
- Создать директорию /var/log/myservice
- Установить директиву
StandardOutput=append:/var/log/myservice
в определении сервиса SystemD
Когда я пытаюсь запустить сервис, он завершается неудачей с ошибкой status=209/STDOUT
. После некоторой отладки я понял, что это SELinux препятствует этому:
Дополнительная информация:
Контекст источника system_u:system_r:init_t:s0
Контекст цели system_u:object_r:var_log_t:s0
Целевые объекты mylogfile.log [ файл ]
Источник (myservice)
Путь источника /usr/lib/systemd/systemd
Порт <Неизвестно>
Хост myhost.mydomain.net
Пакеты RPM источника systemd-239-45.el8.x86_64
Пакеты RPM цели
Пакет политики SELinux selinux-policy-targeted-3.14.3-67.el8.noarch
Локальный пакет политики selinux-policy-targeted-3.14.3-67.el8.noarch
SELinux включен Да
Тип политики нацеленный
Режим выполнения Исполнительный
<... сокращено ...>
Сырые сообщения аудита
type=AVC msg=audit(1628237958.525:23268): avc: denied { create } for pid=323316 comm="(myservice)" name="mylogfile" scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=file permissive=0
type=SYSCALL msg=audit(1628237958.525:23268): arch=x86_64 syscall=openat success=no exit=EACCES a0=ffffff9c a1=55e0d96f2230 a2=541 a3=1a4 items=0 ppid=1 pid=323316 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm=(myservice) exe=/usr/lib/systemd/systemd subj=system_u:system_r:init_t:s0 key=(null)
Я понимаю, что это говорит мне, что SystemD (работающий с контекстом system_u:system_r:init_t:s0
) не может создать файл в моей директории (system_u:object_r:var_log_t:s0
).
Директория в настоящее время пуста:
# ls -alZ /var/log/myservice/
total 12
drwxr-xr-x. 2 root root system_u:object_r:var_log_t:s0 6 Aug 6 09:11 .
drwxr-xr-x. 19 root root system_u:object_r:var_log_t:s0 8192 Aug 6 03:13 ..
Вопрос: Каков правильный способ (политика) разрешить SystemD записывать логи в /var/log?
Я пробовал несколько подходов с semanage fcontext
, но пока ничего не сработало.
Когда вы можете изменить свой пользовательский сервис, самым простым решением будет реализовать логирование в исполняемом файле вашего сервиса, поскольку он, скорее всего, уже работает без ограничений.
(если вы не написали какую-либо политику SELinux для своего сервиса)
Это также увеличит гибкость, например, для поддержки ротации файлов журнала. Я имею в виду, что не вижу, как StandardOutput=append:/
поддержит переключение на новый файл в случае, если файл станет слишком большим.
В качестве альтернативы вы можете позволить специализированному инструменту логирования, такому как rotatelogs
от Apache, записывать стандартный вывод вашего сервиса в /var/log/myservice
.
Пример:
[Service]
Type=simple
ExecStart=/bin/bash -c 'exec /opt/bin/yourservice > >(exec /sbin/rotatelogs a_few_options /var/log/myservice/logfile rottime_or_size )'
Таким образом, вам не придется изменять исполняемый файл вашего сервиса. Но если ваш сервис уже работает без ограничений, то такой вспомогательный инструмент логирования тоже должен.
Смотрите также другой ответ для некоторых альтернатив rotatelogs
.
Ответ или решение
Решение проблемы: SELinux и кастомные сервисы SystemD
Введение
Настройка собственных сервисов SystemD на системах на базе RHEL может быть затруднена, особенно при взаимодействии с SELinux. В данной статье мы разберем, как настроить ваш кастомный сервис, чтобы он мог записывать логи в директорию /var/log/myservice
, что особенно актуально, если текущая конфигурация подразумевает использование StandardOutput
, которое по умолчанию отправляет вывод в системный журнал.
Проблема
Вы хотите перенаправить вывод вашего сервиса в файл для дальнейшей обработки. После редактирования файла сервиса и добавления директивы StandardOutput=append:/var/log/myservice
вы столкнулись с ошибкой status=209/STDOUT
. Как было установлено, причиной проблемы является политика SELinux, которая запрещает вашему сервису создавать файлы в целевой директории, что подтверждают сообщения о блокировке (AVC).
Понимание SELinux
SELinux (Security-Enhanced Linux) – это механизм безопасности, который обеспечивает контроль доступа, основанный на контексте. Каждый процесс и объект в системе имеет свой контекст безопасности, и успех выполнения операций доступа определяется политиками безопасности.
В вашем случае процесс (myservice
) работает с контекстом system_u:system_r:init_t:s0
, который не имеет разрешений на создание файлов в директории, относящейся к контексту system_u:object_r:var_log_t:s0
.
Решение проблемы
Чтобы разрешить вашему сервису запись в /var/log/myservice
, необходимо изменить политику SELinux. Вот последовательность действий:
-
Изменение контекста файла: Вам нужно указать, что директория
/var/log/myservice
и ее содержимое могут быть записаны процессами с контекстом вашего сервиса. Используйте следующую команду:semanage fcontext -a -t var_log_t "/var/log/myservice(/.*)?"
Эта команда добавляет правило, которое позволяет контексту
var_log_t
(предназначенному для лог-файлов) использоваться для всех файлов внутри вашей директории. -
Применение нового контекста: После изменения контекста необходимо применить этот контекст к существующим файлам:
restorecon -R /var/log/myservice
-
Проверка изменений: Убедитесь, что контекст файла теперь соответствует:
ls -alZ /var/log/myservice
Вы должны увидеть, что контекст для директории и её файлов теперь установлен в
system_u:object_r:var_log_t:s0
.
Дополнительные варианты
Если вы не хотите изменять политику безопасности системы или столкнулись с трудностями в её настройке, рассмотрите альтернативные подходы:
-
Логгирование в сервисе: На уровне приложения можно реализовать логгирование непосредственно в вашем сервисе, что позволит избежать проблем с SELinux. Это добавляет гибкости, в том числе поддержку ротации логов.
-
Использование вспомогательных инструментов: Например, вы можете использовать
rotatelogs
, который будет записывать вывод вашего сервиса в файл, управляя ротацией логов. Пример конфигурации:[Service] Type=simple ExecStart=/bin/bash -c 'exec /opt/bin/yourservice > >(exec /sbin/rotatelogs /var/log/myservice/logfile.%Y-%m-%d %N)'
Заключение
Проблемы с SELinux могут значительно усложнить управление логами в кастомных сервисах SystemD. Изменение контекста безопасности файла и использование правильной конфигурации служит эффективным решением, позволяющим вашему сервису корректно писать логи в所需 директорию. Все приведенные рекомендации помогут обеспечить правильное функционирование вашего сервиса.
Если у вас остались вопросы или требуется дополнительная помощь, не стесняйтесь обращаться за поддержкой.