From Scratch: A simple systemd service with SELinux

The information on this page is largely derived, with necessary modifications, from Creating and enforcing an SELinux policy for a custom application.

Prerequisites

dnf -y install selinux-policy-devel setroubleshoot-server dnf -y group install 'Development Tools' # needed for at least g++ and rpmbuild. Not sure if anything else is needed from this group.

Become root

All of this documentation is to be completed as root.

Creating the service

Create mydaemon.cpp

cat > mydaemon.cpp << EOF #include <iostream> #include <fstream> #include <chrono> #include <ctime> #include <thread> using namespace std; int main() { while (1) { time_t t = chrono::system_clock::to_time_t(chrono::system_clock::now()); ofstream MyFile("/var/log/mydaemon.log", ios_base::app); // app = append, not overwrite MyFile << ctime(&t); MyFile.close(); this_thread::sleep_for(chrono::milliseconds(5000)); } } EOF

Build it

g++ -o /usr/local/bin/mydaemon mydaemon.cpp

Create the systemd unit

By default, the unit file has selinux context that systemd cannot access, so fix that and load it:

Try to start the service. Notice it fails.

Notice that it's running in unconfined_t

Generate a custom policy for the daemon:

Build it

Note that the setup script relabels the daemon to the newly created domain mydaemon_exec_t

Temporarily set selinux to permissive and clear the audit log

Restart the daemon, and check that it now runs confined by SELinux:

For your information. (Just get a look at what selinux would have blocked.)

Build whatever new policy you need

Re-enable selinux, restart the daemon, confirm that it’s working properly