Skip to content
Permalink
master
Switch branches/tags
Go to file
…boots

ref #81 (comment)

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>
1 contributor

Users who have contributed to this file

Security focused systemd configuration

systemd configuration examples, hopefully making your server and services a bit more secure.

Documentation

systemd-analyze and systemd_scan.sh

Since systemd version 240, systemd-analyze has the "security" option for analyzing the security and sand-boxing settings of services in order to determine an "exposure level" 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=

Logging

/etc/systemd/journald.conf

[Journal]
Compress=yes // (1)
ForwardToSyslog=yes // (2)
Storage=persistent // (3)
  1. "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."

  2. "log messages received by the journal daemon shall be forwarded to a traditional syslog daemon"

  3. "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."

/etc/systemd/coredump.conf

[Coredump]
Storage=none // (1)
ProcessSizeMax=0 // (2)
  1. "When "none", the core dumps will be logged but not stored permanently."

  2. "Setting Storage=none and ProcessSizeMax=0 disables all coredump handling except for a log entry."

Mounts

/etc/systemd/system/tmp.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)
  1. "an absolute path of a device node, file or other resource to mount."

  2. "an absolute path of a directory of the mount point."

  3. "a string for the file system type."

  4. "options to use when mounting."

System

/etc/systemd/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)
  1. "space-separated list of IPv4 and IPv6 addresses to use as system DNS servers."

  2. "space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers."

  3. "If set to "allow-downgrade" DNSSEC validation is attempted, but if the server does not support DNSSEC properly, DNSSEC mode is automatically disabled." Should be set to true if possible.

  4. "When set to "opportunistic" DNS request are attempted to send encrypted with DNS-over-TLS."

/etc/systemd/system.conf

[Manager]
DumpCore=no // (1)
CrashShell=no // (2)
DefaultLimitCORE=0 // (3)
DefaultLimitNOFILE=100 // (4)
DefaultLimitNPROC=100 // (5)
CtrlAltDelBurstAction=none // (6)
  1. "If yes, the systemd manager (PID 1) dumps core when it crashes. Otherwise, no core dump is created."

  2. "If yes, the system manager (PID 1) spawns a shell when it crashes, after a 10s delay. Otherwise, no shell is spawned."

  3. Don’t allow daemons to core dump.

  4. Default limit for number of open files.

  5. Default limit for number of processes.

  6. Defines what action will be performed if user presses Ctrl-Alt-Delete more than 7 times in 2s.

/etc/systemd/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)
  1. "space-separated list of NTP server host names or IP addresses."

  2. "space-separated list of NTP server host names or IP addresses to be used as the fallback NTP servers."

  3. "Maximum acceptable root distance. Takes a time value (in seconds)."

Unit configuration

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)
  1. "Takes a boolean argument. If true, sets up a new file system namespace for the executed processes and mounts private /tmp and /var/tmp directories inside it that is not shared by processes outside of the namespace."

  2. "If true, mounts the /usr and /boot directories read-only for processes invoked by this unit. If set to "full", the /etc directory is mounted read-only, too. If set to "strict" the entire file system hierarchy is mounted read-only, except for the API file system subtrees /dev, /proc and /sys."

  3. "Takes a boolean argument or the special values "read-only" or "tmpfs". If true, the directories /home, /root, and /run/user are made inaccessible and empty for processes invoked by this unit. If set to "read-only", the three directories are made read-only instead. If set to "tmpfs", temporary file systems are mounted on the three directories in read-only mode."

  4. "If true, ensures that the service process and all its children can never gain new privileges."

  5. "Sets up a new file system namespace for executed processes."

  6. "Controls which capabilities to include in the capability bounding set for the executed process."

  7. "If true, sets up a new /dev namespace for the executed processes and only adds API pseudo devices such as /dev/null, /dev/zero or /dev/random (as well as the pseudo TTY subsystem) to it"

  8. "Sets the Unix user or group that the processes are executed as, respectively"

  9. "User and group pair is allocated dynamically when the unit is started, and released as soon as it is stopped."

  10. "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."

  11. "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 the "root" user and group as well as the unit’s own user and group to themselves and everything else to the "nobody" user and group."

/etc/systemd/system/nginx.service example

[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.target

/etc/systemd/system/mongod.service example

[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.target

Users

/etc/systemd/logind.conf

[Login]
KillUserProcesses=1 // (1)
KillExcludeUsers=root // (2)
IdleAction=lock // (3)
IdleActionSec=15min // (4)
RemoveIPC=yes // (5)
  1. "the processes of a user should be killed when the user completely logs out (i.e. after the user’s last session ended)."

  2. "Processes of users listed in KillExcludeUsers= are excluded from being killed."

  3. "the action to take when the system is idle."

  4. "the delay after which the action configured in IdleAction= (see above) is taken after the system is idle."

  5. "the user may not consume IPC resources after the last of the user’s sessions terminated."

/etc/systemd/user.conf

[Manager]
DefaultLimitCORE=0 // (1)
DefaultLimitNOFILE=100 // (2)
DefaultLimitNPROC=100 // (3)
CapabilityBoundingSet=~CAP_SYS_PTRACE // (4)
  1. Don’t allow core dumps.

  2. Default limit for number of open files.

  3. Default limit for number of processes.

  4. "capabilities to include in the capability bounding set." See capabilities(7).