Systemd¶
Todo/To read:
https://wiki.archlinux.org/index.php/Systemd#Enable_installed_units_by_default
https://www.redhat.com/files/summit/session-assets/2019/T4D2A2.pdf
https://www.designed-cybersecurity.com/tutorials/harden-gnupg-config/
https://nardifairuz.wordpress.com/2019/04/30/automate-backups-with-restic-and-systemd/
Автомонтирование разделов GPT
network awareness - run these services when connected to this type of networks
logind - user session manger
https://wiki.archlinux.org/index.php/Systemd_(Русский)/User_(Русский)
http://manpages.ubuntu.com/manpages/bionic/man5/systemd.preset.5.html#examples
http://0pointer.net/blog/walkthrough-for-portable-services.html
https://medium.com/@nickodell/sandboxing-nginx-with-systemd-80441923c555
apt search systemd-coredump
https://fedoramagazine.org/systemd-resolved-introduction-to-split-dns/
- Resource accounting - nspawn
https://selectel.ru/blog/mexanizmy-kontejnerizacii-namespaces/
https://0xax.gitbooks.io/linux-insides/content/Cgroups/linux-cgroups-1.html
https://wiki.archlinux.org/index.php/Systemd-networkd_(Русский)
https://wiki.archlinux.org/index.php/Access_Control_Lists#Enable_ACL
https://patrickskiba.com/sysytemd-nspawn/2019/02/08/introduction-to-systemd-nspawn.html
https://medium.com/@huljar/setting-up-containers-with-systemd-nspawn-b719cff0fb8d
https://tina.pm/blog/posts/Creating_containers_with_systemd/
https://blog.selectel.com/systemd-containers-introduction-systemd-nspawn/
https://kitsunemimi.pw/notes/posts/opening-a-shell-inside-non-systemd-nspawn-containers.html
https://wiki.arcoslab.org/doku.php?id=tutorials:systemd-nspawn
http://blog.oddbit.com/post/2016-02-07-systemd-nspawn-for-fun-and-well-mostly-f/
Shutdown and Reboot¶
With systemd:
sudo systemctl poweroff
sudo systemctl reboot
Without systemd:
poweroff
reboot
shutdown -r 2 # schedule reboot at 2 minutes
Daemon Management¶
SysV init style scripts:
ls /etc/init.d/
sudo systemctl [enable|disable] name.service
sudo systemctl [start|stop|restart|reload|reload-or-restart] name.service
systemctl status [-l|--full] [name.service|pid]
systemctl list-unit-files --type service
systemctl [is-active|is-enabled|is-failed] name.service
# Masked service is unable to start - even as a dependency (somewhat dangerous)
sudo systemctl [mask|unmask] name.service
# Show documentation
systemctl help name.service
# Enable and start immediately
sudo systemctl enable --now unit
Reset failed statuses:
sudo systemctl reset-failed
Time and Locales¶
Time¶
Sources:
Set timezone:
timedatectl # show current setup
timedatectl list-timezones
sudo timedatectl set-timezone Europe/Moscow
Setup NTP servers (sudo vim /etc/systemd/timesyncd.conf):
[Time]
NTP=0.ru.pool.ntp.org 1.ru.pool.ntp.org 2.ru.pool.ntp.org 3.ru.pool.ntp.org
FallbackNTP=ntp.ubuntu.com time.cloudflare.com
Enable NTP:
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd.service
timedatectl status # --> System clock synchronized: yes
Locales¶
localectl list-locales
localectl status
localectl set-locale LANG=en_US.UTF-8
Targets and Runlevels¶
Sysv runlevels vs systemd targets:
Targets Units Runlevel Description
runlevel0.target, poweroff.target Shut down and power off the system.
runlevel1.target, rescue.target Set up a rescue shell.
runlevel2.target, multi-user.target Set up a non-graphical multi-user system.
runlevel3.target, multi-user.target Set up a non-graphical multi-user system.
runlevel4.target, multi-user.target Set up a non-graphical multi-user system.
runlevel5.target, graphical.target Set up a graphical multi-user system.
runlevel6.target, reboot.target Shut down and reboot the system.
Default runlevel:
systemctl get-default # --> graphical.target
sudo systemctl set-default multi-user.target
Another option is adding systemd.unit=multi-user.target or similar to kernel parameters of the bootloader.
Switch to certain runlevel:
sudo systemctl isolate multi-user.target # go to text mode
Unit files¶
Edit Systemd Files¶
# Change file in-place
sudo vim /etc/systemd/system/ufw.service
# Put only section and options that should be changed
sudo systemctl edit ufw.service
# Pull a new copy of entire file
sudo systemctl edit --full ufw.service
Drop changes:
sudo systemctl revert ufw.service
Show all files related to service:
systemctl cat ufw.service
Example: changing ExecStart:
[Service]
ExecStart=
ExecStart=new cmd
Note: all commands that take multiple commands need to be cleaned up as shown.
Unit Files¶
List paths being looked up:
systemctl show --property=UnitPath
main ones being:
/usr/lib/systemd/system/: units by packages/etc/systemd/system/: units by system administrator
Unit file example:
[Unit]
Description=OpenBSD Secure Shell server
# Documentation=man:sshd(8) # or https:://...
# Before=
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
# User=
# Environment=VAR1=1 VAR2=2 VAR3=3
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
# PrivateNetwork=yes
# PrivateTmp=yes
[Install]
WantedBy=multi-user.target
# RequiredBy= # if service fails, target would not boot
Alias=sshd.service
After applying changes or creating new unit:
sudo systemctl daemon-reload
Instances¶
If syncthing@.service then it is not callable by itself, but you should call it as,
for example, syncthing@lain.service.
Then %i in the unit file will be substituted with lain:
...
[Service]
User=%i
ExecStart=/usr/bin/syncthing -no-browser -no-restart -logflags=0
...
Dependencies¶
systemctl list-dependencies sshd.service
systemctl list-dependencies sshd.service --all # list recursively
systemctl list-dependencies sshd.service --reverse # show who depends on it
Unit Properties¶
Show list of properties:
systemctl show sshd.service
Display a single property:
systemctl show sshd.service -p Conflicts
Static files (the ones that a launched dynamically)¶
Example of micro-httpd:
[Unit]
Description=micro-httpd
Documentation=man:micro-httpd(8)
[Service]
User=nobody
Group=www-data
ExecStart=-/usr/sbin/micro-httpd /var/www/html
StandardInput=socket
[Unit]
Description=micro-httpd
Documentation=man:micro-httpd(8)
[Socket]
ListenStream=0.0.0.0:80
Accept=true
[Install]
WantedBy=sockets.target
Two types of socket activation:
Accept=yesa single instance of the service is started for each connection
“wait” under inetd/xinetd
Accept=noa single instance of the service is started for each connection
“nowait” under inetd/xinetd
To disable: edit --full and Accept=false and daemon-reload.
Temporary file units¶
Source: Managing temporary files with systemd-tmpfiles on Red Hat Enterprise Linux 7
Explore with:
systemctl status systemd-tmpfiles-setup.service
cat /lib/systemd/system/systemd-tmpfiles-setup.service
systemctl status systemd-tmpfiles-clean.timer
man 5 tmpfiles.d
systemd-tmpfiles [command]
systemd-tmpfiles directories (highest to lowest):
/etc/tmpfiles.d/*.conf/run/tmpfiles.d/*.conf/usr/lib/tmpfiles.d/*.conf
Configuration file syntax of systemd-tmpfiles:
Type, Path, Mode, UID, GID, Age, and Arguments
Example: samba created /run/samba/ for it’s daemon
with /usr/lib/tmpfiles.d/samba.conf setting:
D /run/samba 0755 root root
Another directory creation example (cat /usr/lib/tmpfiles.d/httpd.conf):
d /run/httpd 710 root apache
d /run/httpd/htcacheclean 700 apache apache
File removal example (/usr/lib/tmpfiles.d/rpm.conf):
r /var/lib/rpm/__db.*
Symlink creation and recursive file copy (/usr/lib/tmpfiles.d/etc.conf):
L /etc/os-release - - - - ../usr/lib/os-release
L /etc/localtime - - - - ../usr/share/zoneinfo/UTC
L+ /etc/mtab - - - - ../proc/self/mounts
C /etc/nsswitch.conf - - - -
C /etc/pam.d - - - -
The L+ creates link forcefully.
C means copy file/directory from /usr/share/factory/.
Time option usage (/usr/lib/tmpfiles.d/cups.conf):
d /run/cups 0755 root lp -
d /run/cups/certs 0511 lp sys -
d /var/spool/cups/tmp - - - 30d
Files older (both atime, mtime and ctime) than 30 days
on /var/spool/cups/tmp will be deleted.
Timer units¶
Source: Arch wiki systemd/Timers
Check with:
systemctl list-timers [--all]
man 5 systemd.timer
Timer units:
Realtime: much as cron; activate on calendar event (
OnCalendar=)Monotonic: activate after a time span relative to a starting point (have format
On[Type]Sec=)
A timer which will start 15 minutes after boot
and again every week while the system is running
(/etc/systemd/system/foo.timer):
[Unit]
Description=Run foo weekly and on boot
[Timer]
OnBootSec=15min
OnUnitActiveSec=1w
[Install]
WantedBy=timers.target
Starts once a week (at 12:00am on Monday).
When activated, it triggers the service immediately
if it missed the last start time (option Persistent=true),
for example due to the system being powered off:
...
[Timer]
OnCalendar=weekly
Persistent=true
...
OnCalendar uses the format:
DayOfWeek Year-Month-Day Hour:Minute:Second
Ex.:
OnCalendar=Mon,Tue *-*-01..04 12:00:00
# or
OnCalendar=Mon..Fri 22:30
OnCalendar=Sat,Sun 20:00
Run systemd-analyze calendar to check expression validity:
systemd-analyze calendar weekly # ``daily``, ``weekly`` etc refer to specific time
systemd-analyze calendar "Mon,Tue *-*-01..04 12:00:00"
Use RandomizedDelaySec in [Timer] section to avoid multiple (for example, weekly)
services start simultaneously.
Use AccuracySec=1us to the [Timer]`` section,
to avoid the inaccuracy of the 1m by default.
Transient .timer units:
# Touch file after 30sec
sudo systemd-run --on-active=30 /bin/touch /tmp/foo
# Can also be combined with existing unit
sudo systemd-run --on-active="12h 30m" --unit someunit.service
Networking¶
By default Ubuntu uses netplan
/etc/netplan/*.yaml files for configuration,
which uses systemd-networkd as a backend
(NetworkManager is another option).
Hostaname¶
Show:
hostname # --> u-navi
hostnamectl # show names and some server info
Set:
echo u-navi | sudo tee /etc/hostname # Would not last after reboot
sudo hostnamectl set-hostname u-navi # The right way
Substitute netplan with plain networkd¶
Source: Disable netplan.io and use native systemd-networkd on ubuntu 18.04.
Remove netplan and enable networkd:
sudo apt remove netplan
sudo systemctl enable systemd-networkd
Create /etc/systemd/network/99-wildcard.network:
[Match]
Name=en*
[Network]
DHCP=ipv4
#DHCP=yes
#IPv6AcceptRA=yes
Edit systemd-networkd with the following to enable debug logging:
[Service]
Environment=SYSTEMD_LOG_LEVEL=debug
Reload the service and watch it.
Reboot.
Check:
networkctl # --> ... ens3 ether routable configured ...
networkctl status ens3
Wait for enp0s3 only¶
Source: [Задержка при загрузке Ubuntu Server](https://tokmakov.msk.ru/blog/item/494)
Create an override:
sudo systemctl edit systemd-networkd-wait-online.service
with the folllowing content:
[Service]
ExecStart=
ExecStart=/lib/systemd/systemd-networkd-wait-online --interface=enp0s3
Reload systemd:
sudo systemctl daemon-reload
Journaling¶
Sources:
Journald stores data in
/var/log/journal/in binary form (structured logging)The service just writes everything to stdout/stderr and it is being logged by systemd
Unlike syslog, journald stores timezones
Indexing data (faster lookup than syslog)
Access control
Automatic log rotation
Settings¶
Edit
/etc/systemd/journald.confsudo systemctl reload systemd-journald.service
Previous sessions preview¶
Needs to be activated (it is not - by default - on some distros):
[Journal]
Storage=persistent
(or Storage=auto and create /var/run/journal directory).
List previous boots (sessions):
journalctl --list-boots
Show log for certain boot:
journalctl -b 0
# or...
journalctl -b 323000d9802642a098d47ae1b7384424
CLI¶
Basic examples:
journalctl # all logs
journalctl -b # all logs since last boot
journalctl -r # list entries in reverse order
Filtering examples:
# Filter by date
journalctl --since "2015-07-20 17:15:00"
journalctl ---since yesterday
journalctl --since 09:00 --until now
journalctl --since 10:00 --until "1 hour ago"
# Filter by service
journalctl _SYSTEMD_UNIT=nginx.service
journalctl -u nginx.service # shorter version
journalctl -u nginx.service --since yesterday
journalctl -u nginx.service -u php-fpm.service --since today
# Filter by process, user and group
journalctl _PID=381
journalctl _UID=33
# FIlter by executable's path
journalctl _EXE=/usr/bin/sudo
journalctl -F _UID # List all possible values for field _UID
journalctl -F _GUID
# Other possible fields
man systemd.journal-fields
# Filter by path
journalctl /usr/bin/docker
# Kernel messages
journalctl -k
journalctl --dmesg
journalctl -k -b -2 # Kernel messages for certain previous boot
# Recent events
journalctl -n # Latest 10 events
journalctl -n 20 # Latest 20 events
# Grep through logs
journalctl --grep 'Network Name Lookups'
# Filter by error level
journalctl --priority err
Dumping everything to terminal:
journalctl --no-pager
# or...
SYSTEMD_PAGER=cat journalctl
Follow mode:
journalctl -f
Formatting/exporting/outputtig¶
Possible output formats:
cat– only messagesexport– binary format (for export or backup);short– syslog format;short-iso– syslog format with ISO 8601 timestamps;short-monotonic– syslog format with monotonic timestamps;short-precise– syslog format with precise (milliseconds) timestamps;verbose– most verbose format (with all fields).
Example:
journalctl -u nginx.service -o json-pretty
Log rotation¶
# Show disk space used by logs
journalctl --disk-usage
# Rotate
sudo journalctl --vacuum-size=1G
sudo journalctl --vacuum-time=1years
Set rotation through /еtc/systemd/journald.conf file:
SystemMaxUse=max logs total size;SystemKeepFree=keep at least this much free space;SystemMaxFileSize=max size of log file;RuntimeMaxUse=max logs total size in/run;RuntimeKeepFree=keep at least this much free space in/run;RuntimeMaxFileSize=max size of log file in/run.
Containers¶
Docker¶
docker run --rm --name my-pg \
-e POSTGRES_PASSWORD=123 \
--log-driver=journald \
-d postgres
journalctl CONTAINER_NAME=my-pg --all
To log by default:
{
"log-driver": "journald"
}
sudo systemctl restart docker
Systemd-nspawn¶
journalctl --machine $MACHINE_NAME
Centralized logs storage¶
Systemd uses following components for this task (not present on some distros):
systemd-journal-remote
systemd-journal-upload
systemd-journal-gatewayd
Snoopy¶
Used:
Install with sudo apt install snoopy and choose to insert line into /etc/ld.so.preload.
This setting can be changed with sudo dpkg-reconfigure snoopy.
Note: it made my browsers (chromium, firefox) to misbehave:
/lib/x86_64-linux-gnu/libsnoopy.so
Settings are stored at /etc/snoopy.ini.
Drop excessive information from logs by configuring snoopy with following configuration:
[snoopy]
; Log line format
message_format = "[login: %{login}, %{tty_username} as %{eusername}]: %{cmdline}"
; Events filter
filter_chain = "only_tty"
Look log with journalctl -xe -t snoopy.
Systemd-nspawn¶
Create debian machine file structure:
sudo debootstrap --arch=amd64 jessie /var/lib/machines/container1/
Enter the chroot and set root password:
sudo systemd-nspawn -D /var/lib/machines/container1/ --machine test_container
passwd
Leave with ^[[[.
sudo machinectl start container1
Capabilities¶
Sources:
Run command with systemd and show it’s output with journalctl:
sudo systemd-run whoami # --> Running as unit: run-xxxx.service
journalctl -u run-xxxx.service # --> ... whoami[28327]: root ...
Simpler one: run with tty connected:
sudo systemd-run -t whoami # --> ... ... root
Systemd creates temporary unit file on the fly.
Specify user:
sudo systemd-run -t --uid=nobody whoami
sudo systemd-run -t -p User=nobody whoami
sudo systemd-run -t -p DynamicUser=yes whoami # create temporary user on the fly
Let’s try ping localhost interactively:
sudo systemd-run -t -p IPAddressDeny=127.0.0.1/8 /bin/bash
# ping 127.0.0.1
# -->
# PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
# ping: sendmsg: Operation not permitted
Open shell:
sudo systemd-run -p ProtectHome=yes --shell
Options:
ProtectHome=yes|read-only|no # /home inaccessible or read-only
# yes: /home and /root are gone
ProtectSystem=yes|full|strict|no # full: [/usr, /boot, /etc] are read-only
# (use ReadWritePaths to punch holes)
# yes: [/usr, /boot] read-only
# strict: all read-only except [/dev, /proc, /sys]
PrivateTmp=yes|no # tied to lifecycle of service (/tmp and /var/tmp)
# debuggable through /tmp/systemd-private-<random-suffix>-<name.service>-<random>/tmp
PrivateNetwork=yes|no # no network access (only lo device)
PrivateDevices=yes|no # isolate /dev except some commons (only includes pseudo-devices)
# useful when service doesn't need access to raw devices
JoinsNamespaceOf= # join namespaces with other service (ex.: they will share same /tmp)
# use case: MySQL (and many other) puts it's listening socket to /tmp
CapabilityBoundingSet= # makes use of unix capabilities (root privileges slitted to bits)
# limits capabilities the process is allowed to obtain. It doesn't grant any
# Example: CapabilityBoundingSet=CAP_SYS_TIME for NTP client
# (won't be able to do nothing privileged except set the time)
AmbientCapabilities= # grants capabilities that the process normally wouldn't have started with
MountFlags=slave # no able to change mount table
InaccessiblePaths=
ReadOnlyPaths=
ReadWritePaths=
BindPaths=
ReadOnlyBindPaths=
StateDirectory= # /run/foo/
CacheDirectory= # /var/lib/foo/
LogsDirectory= # /var/cache/foo/
RuntimeDirectory= # /var/log/foo/
ConfigurationDirectory= # /etc/foo/
User=
Group=
SupplementaryGroups=
LimitNPROC= # for fork() protection
RootDirectory= # a bit like chroot (advanced topic)
LimitFSIZE=0 # limit file size the service can create (here: can't create any files)
DeviceAllow=/dev/sda5 rwm # get access to no devices but sda5
# DeviceAllow=char-alsa rw # can access only audio
TasksMax= # against fork bomb (advices); tasks=processes+threads
# default: 512
# Low level stuff
MemoryDenyWriteExecute=yes # disable ability to create executable-writable mappings
NoNewPrivileges=yes # no further uid and gid changes
RestrictAddressFamilies=AF_UNIX|AF_INET|AF_INET6|AF_CAN|AF_APPLETALK
RestrictSUIDSGID=yes
ProtectKernelTunables=yes
ProtectHostname=yes
ProtectKernelLogs=yes
SystemCallArchitecture=native|x86_64|i386|...
SystemCallFilter=
LockPersonality=yes
SyscallFilter=@obsolete # syscall1 | syscall2 | @group
# group ex.: @basic-io
# systemd-analyze syscall-filter @obsolete
IPAdressAllow=10.20.30.0/24 1.2.3.4
IPAdressDeny=*
IP{Ingress,Egress}FilterPath=
CPUQuota, MemoryMax, TasksMax, RuntimeMaxSec.
RootDyrectory, RootImage, MountAPIVFS
PrivateUsers
Examples:
sudo systemd-run -t -p User=lain -p RuntimeDirectory=foo ls -ld /run/foo
ls -ld /run/foo # --> does not exist (cleaned up)
sudo systemd-run -t -p DynamicUser=true whoami # --> ... run-u99
echo -e 'asdf\nasdf' |\
sudo systemd-run --pipe -p DynamicUser=1 bash -c 'grep .; whoami' |\
sudo systemd-run --pipe -p DynamicUser=1 bash -c 'grep .; whoami' |\
sudo systemd-run --pipe -p DynamicUser=1 bash -c 'grep .; whoami'
# --->
# Running as unit: run-u101.service
# Running as unit: run-u103.service
# Running as unit: run-u102.service
# asdf
# asdf
# run-u101
# run-u103
# run-u102
PrivateNetwork=yes is a recommended way to run network services.
A daemon does not open a socket itself, it receives a socket from manager.
Grade service security:
systemd-analyze security systemd-resolved.service
Perfomance¶
Show how much time each service takes to start:
systemd-analyze blame
Plot for more information:
systemd-analyze plot > systemd-perf.svg
firefox systemd-perf.svg
Other¶
IPMI was failing for whatever reason, so I disabled it:
sudo systemctl disable openipmi.service