systemd configuration examples, hopefully making your server and services a bit more secure.
Hardening Ubuntu. Systemd edition.
systemd for Administrators, Part XII: Securing Your Services
systemd upstream
systemd execution environment configuration
Since systemd version 240, systemd-analyze has the security
option for analyzing the security and sandboxing settings of services in order
to determine an exposure level value for them, indicating whether a service
would benefit from more sand-boxing options turned on for them.
systemd_scan.sh
is a script to check the current systemd configuration of a local service,
similar to a very basic version of systemd-analyze security.
$ bash systemd_scan.sh mongodb
[I] mongodb
[I] /lib/systemd/system/mongodb.service used.
[P] User is set.
[P] Group is set.
[P] CapabilityBoundingSet is set.
[F] PrivateTmp is not set.
[F] PrivateDevices is not set.
[F] NoNewPrivileges is not set.
[F] SELinuxContext is not set.
[F] AppArmorProfile is not set.
[P] LimitNOFILE is set.
[P] LimitNPROC is set.
[F] DynamicUser is not set.
[P] ProtectSystem=full is set.
[P] ProtectHome=true is set.
[I] 6 failures, 7 passed.systemd-analyze security calculates an exposure value based on the following
configuration options:
AmbientCapabilities=
CapabilityBoundingSet=
Delegate=
DeviceAllow=
IPAddressDeny=
KeyringMode=
LockPersonality=
MemoryDenyWriteExecute=
NoNewPrivileges=
NotifyAccess=
PrivateDevices=
PrivateMounts=
PrivateNetwork=
PrivateTmp=
PrivateUsers=
ProtectControlGroups=
ProtectHome=
ProtectHostname=
ProtectKernelLogs=
ProtectKernelModules=
ProtectKernelTunables=
ProtectSystem=
RestrictAddressFamilies=
RestrictNamespaces=
RestrictRealtime=
RestrictSUIDSGID=
RootDirectory=/RootImage=
SystemCallArchitectures=
SystemCallFilter=
UMask=
User=/DynamicUser=See journald.conf.
[Journal]
Compress=yes // (1)
ForwardToSyslog=yes // (2)
Storage=persistent // (3)-
"data objects that shall be stored in the journal and are larger than a certain threshold are compressed before they are written to the file system."
-
"log messages received by the journal daemon shall be forwarded to a traditional syslog daemon"
-
"data will be stored preferably on disk, i.e. below the /var/log/journal hierarchy (which is created if needed), with a fallback to /run/log/journal (which is created if needed), during early boot and if the disk is not writable."
See coredump.conf.
[Coredump]
Storage=none // (1)
ProcessSizeMax=0 // (2)-
"When "none", the core dumps will be logged but not stored permanently."
-
"Setting
Storage=noneandProcessSizeMax=0disables all coredump handling except for a log entry."
See systemd.mount.
[Unit]
Description=Temporary Directory
Documentation=man:hier(7)
Before=local-fs.target
[Mount]
What=tmpfs // (1)
Where=/tmp // (2)
Type=tmpfs // (3)
Options=mode=1777,strictatime,nodev,noexec,nosuid // (4)(5)-
"an absolute path of a device node, file or other resource to mount."
-
"an absolute path of a directory of the mount point."
-
"a string for the file system type."
-
"options to use when mounting."
See resolved.conf.
[Resolve]
DNS=127.0.0.1 // (1)
FallbackDNS=1.1.1.1 1.0.0.1 // (2)
DNSSEC=allow-downgrade // (3)
DNSOverTLS=opportunistic // (4)-
"space-separated list of IPv4 and IPv6 addresses to use as system DNS servers."
-
"space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers."
-
"If set to
allow-downgradeDNSSEC validation is attempted, but if the server does not support DNSSEC properly, DNSSEC mode is automatically disabled." Should be set totrueif possible. -
"When set to
opportunisticDNS request are attempted to send encrypted with DNS-over-TLS." Shoule be set totrueif possible.
See system.conf and systemd, init.
[Manager]
DumpCore=no // (1)
CrashShell=no // (2)
DefaultLimitCORE=0 // (3)
DefaultLimitNOFILE=100 // (4)
DefaultLimitNPROC=100 // (5)
CtrlAltDelBurstAction=none // (6)-
"If
yes, the systemd manager (PID 1) dumps core when it crashes. Otherwise, no core dump is created." -
"If
yes, the system manager (PID 1) spawns a shell when it crashes, after a 10s delay. Otherwise, no shell is spawned." -
Don’t allow daemons to core dump.
-
Default limit for number of open files.
-
Default limit for number of processes.
-
Defines what action will be performed if user presses Ctrl-Alt-Delete more than 7 times in 2s.
See timesyncd.conf.
[Time]
NTP=0.ubuntu.pool.ntp.org 1.ubuntu.pool.ntp.org // (1)
FallbackNTP=2.ubuntu.pool.ntp.org 3.ubuntu.pool.ntp.org // (2)
RootDistanceMaxSec=1 // (3)-
"space-separated list of NTP server host names or IP addresses."
-
"space-separated list of NTP server host names or IP addresses to be used as the fallback NTP servers."
-
"Maximum acceptable root distance. Takes a time value (in seconds)."
See systemd.exec.
PrivateTmp= // (1)
ProtectSystem= // (2)
ProtectHome= // (3)
NoNewPrivileges= // (4)
ReadWriteDirectories=, ReadOnlyDirectories=, InaccessibleDirectories= // (5)
CapabilityBoundingSet= // (6)
PrivateDevices= // (7)
User=, Group= // (8)
DynamicUser= // (9)
TemporaryFileSystem= // (10)
PrivateUsers= // (11)-
"Takes a boolean argument. If true, sets up a new file system namespace for the executed processes and mounts private
/tmpand/var/tmpdirectories inside it that is not shared by processes outside of the namespace." -
"If true, mounts the
/usrand/bootdirectories read-only for processes invoked by this unit. If set tofull, the/etcdirectory is mounted read-only, too. If set tostrictthe entire file system hierarchy is mounted read-only, except for the API file system subtrees/dev,/procand/sys." -
"Takes a boolean argument or the special values
read-onlyortmpfs. Iftrue, the directories/home,/root, and/run/userare made inaccessible and empty for processes invoked by this unit. If set toread-only, the three directories are made read-only instead. If set totmpfs, temporary file systems are mounted on the three directories in read-only mode." -
"If
true, ensures that the service process and all its children can never gain new privileges." -
"Sets up a new file system namespace for executed processes."
-
"Controls which capabilities to include in the capability bounding set for the executed process."
-
"If
true, sets up a new/devnamespace for the executed processes and only adds API pseudo devices such as/dev/null,/dev/zeroor/dev/random(as well as the pseudo TTY subsystem) to it" -
"Sets the Unix user or group that the processes are executed as, respectively"
-
"User and group pair is allocated dynamically when the unit is started, and released as soon as it is stopped."
-
"Takes a space-separated list of mount points for temporary file systems (tmpfs). If set, a new file system namespace is set up for executed processes, and a temporary file system is mounted on each mount point."
-
"Takes a boolean argument. If
true, sets up a new user namespace for the executed processes and configures a minimal user and group mapping, that maps therootuser and group as well as the unit’s own user and group to themselves and everything else to thenobodyuser and group."
[Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=yes
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true
ReadOnlyDirectories=/var/www/html
CapabilityBoundingSet=~CAP_SYS_PTRACE
PrivateDevices=true
[Install]
WantedBy=multi-user.targetSee mongo/pull/1224.
[Unit]
Description=MongoDB Database Server
After=network.target
Documentation=https://docs.mongodb.org/manual
[Service]
User=mongodb
Group=mongodb
ExecStart=/usr/bin/mongod --config /etc/mongod.conf
PIDFile=/var/run/mongodb/mongod.pid
LimitFSIZE=infinity
LimitCPU=infinity
LimitAS=infinity
LimitNOFILE=64000
LimitNPROC=64000
LimitMEMLOCK=infinity
TasksMax=infinity
TasksAccounting=false
ProtectSystem=full
ProtectHome=true
CapabilityBoundingSet=~CAP_SYS_PTRACE
[Install]
WantedBy=multi-user.targetSee logind.conf.
[Login]
KillUserProcesses=1 // (1)
KillExcludeUsers=root // (2)
IdleAction=lock // (3)
IdleActionSec=15min // (4)
RemoveIPC=yes // (5)-
"the processes of a user should be killed when the user completely logs out (i.e. after the user’s last session ended)."
-
"Processes of users listed in
KillExcludeUsers=are excluded from being killed." -
"the action to take when the system is idle."
-
"the delay after which the action configured in
IdleAction=(see above) is taken after the system is idle." -
"the user may not consume IPC resources after the last of the user’s sessions terminated."
See systemd-user.conf.
[Manager]
DefaultLimitCORE=0 // (1)
DefaultLimitNOFILE=100 // (2)
DefaultLimitNPROC=100 // (3)
CapabilityBoundingSet=~CAP_SYS_PTRACE // (4)-
Don’t allow core dumps.
-
Default limit for number of open files.
-
Default limit for number of processes.
-
"capabilities to include in the capability bounding set." See capabilities(7).