4

I'm trying to write a custom service definition for SystemD on a RHEL system.

Currently, the output goes into the Journal, but I'd need it in a file to parse and forward it with logstash. (Note: For reasons out of my control, Journalbeat is not an option).

To make the service log to a file instead, I tried:

  1. Creating a /var/log/myservice directory
  2. Setting the StandardOutput=append:/var/log/myservice directive in the SystemD service definition

When I try to launch the service, it fails with status=209/STDOUT. After some debugging, I figured out it's SELinux that is preventing this:

Additional Information:
Source Context                system_u:system_r:init_t:s0
Target Context                system_u:object_r:var_log_t:s0
Target Objects                mylogfile.log [ file ]
Source                        (myservice)
Source Path                   /usr/lib/systemd/systemd
Port                          <Unknown>
Host                          myhost.mydomain.net
Source RPM Packages           systemd-239-45.el8.x86_64
Target RPM Packages
SELinux Policy RPM            selinux-policy-targeted-3.14.3-67.el8.noarch
Local Policy RPM              selinux-policy-targeted-3.14.3-67.el8.noarch
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
<... truncated ...>

Raw Audit Messages 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)

I'm understanding that it's telling me that SystemD (running with the context system_u:system_r:init_t:s0) can't create a file in my directory (system_u:object_r:var_log_t:s0).

The directory currently is empty:

# 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 ..

Question: What is the proper way (policy) to allow SystemD to write logs into /var/log?

I've tried several approaches with semanage fcontext but none were successful so far.

Patrick
  • 183
  • 1
    You need to do setenforce permissive temporarily, then trigger the situation again (it will be allowed but with a message in audit logs), then parse the logs with special tools, create a policy and load it (permanently). Instructions e.g. here: https://wiki.centos.org/HowTos/SELinux (section 5 when you have the logs by "permissive") and https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security-enhanced_linux/sect-security-enhanced_linux-fixing_problems-allowing_access_audit2allow . I believe there is also a graphical tool for it but I never use it. – Ned64 Aug 06 '21 at 08:44
  • Thanks @Ned64 - it did work. I'm not quite sure if this was the best way as it grants Systemd to write basically any file in the /var/log directory. But at least it did work... I'm interested if anyone has a more narrow suggestion ("least privilege") – Patrick Aug 06 '21 at 12:13

1 Answers1

1

When you can change your custom service, the simplest thing would be to implement the logging in your service's executable, because it likely already runs unconfined.

(unless you have written some SELinux policy for your service)

This would also increase flexibility, e.g. to support log file rotation. I mean, I don't see how StandardOutput=append:/ would support switching to a new file in case the file grows to big.


Alternatively, you could let a specialized logging tool such as Apache's rotatelogs write your service's stdout to /var/log/myservice.

Example:

[Service]
Type=simple
ExecStart=/bin/bash -c 'exec /opt/bin/yourservice > >(exec /sbin/rotatelogs a_few_options /var/log/myservice/logfile rottime_or_size )'

In that way you don't have to change your service executable. But if your service already runs unconfined then such a logging helper should too.

See also another answer for some alternatives to rotatelogs.

maxschlepzig
  • 57,532
  • Thank you for your answer. In this case, I sadly cannot change the executable itself, and it does not offer any other --output option or similar. – Patrick Dec 16 '21 at 14:11
  • @Patrick I've updated my answer and added an alternative approach. – maxschlepzig Jan 27 '22 at 21:58