Hardening directives leave the base unit body and live in: deploy/files/etc/systemd/system/left4me-web.service.d/10-hardening.conf deploy/files/etc/systemd/system/left4me-server@.service.d/10-hardening.conf Reference units now describe just the base operational shape (exec, env, restart, resources). Tests split: base-unit content and hardening profile are asserted separately. Part of 2026-05-15-deployment-responsibility-design.md migration step 2. ckn-bw lands the matching reactor surgery + symlink delivery.
74 lines
2.8 KiB
Text
74 lines
2.8 KiB
Text
# Hardening drop-in for left4me-server@.service.
|
|
#
|
|
# Source of truth: this file (in left4me/deploy/files/). ckn-bw deploys
|
|
# it to /etc/systemd/system/left4me-server@.service.d/10-hardening.conf
|
|
# via a target-side symlink into the checkout.
|
|
#
|
|
# Gameserver unit: full hardening profile. No sudo path inside; no
|
|
# sudo-incompatibility carve-outs.
|
|
[Service]
|
|
NoNewPrivileges=true
|
|
RestrictSUIDSGID=true
|
|
CapabilityBoundingSet=
|
|
AmbientCapabilities=
|
|
# srcds_linux is i386 (Source 2007 engine). Bare 'native' kills every
|
|
# 32-bit syscall and traps srcds_run in a respawn loop.
|
|
SystemCallArchitectures=native x86
|
|
SystemCallFilter=@system-service
|
|
SystemCallFilter=~@debug @mount @raw-io @reboot @swap @cpu-emulation @obsolete @privileged
|
|
TemporaryFileSystem=/var/lib /etc /opt /home /root /srv /mnt /media
|
|
BindReadOnlyPaths=/var/lib/left4me/installation
|
|
BindReadOnlyPaths=/var/lib/left4me/overlays
|
|
# Workshop VPKs in overlays are symlinks into workshop_cache;
|
|
# without this bind they dangle inside the unit and Source
|
|
# silently fails to load the addons.
|
|
BindReadOnlyPaths=/var/lib/left4me/workshop_cache
|
|
# Steam SDK: srcds dlopen's ~/.steam/sdk32/steamclient.so for
|
|
# Steam master-server registration. Without this, SteamAPI_Init
|
|
# fails and the server falls back to LAN-only mode regardless
|
|
# of sv_lan=0 — clients then get "LAN servers are restricted
|
|
# to local clients (class C)". .steam holds symlinks into
|
|
# /var/lib/left4me/steam, so both paths need to be bound back
|
|
# through TemporaryFileSystem.
|
|
BindReadOnlyPaths=/var/lib/left4me/.steam
|
|
BindReadOnlyPaths=/var/lib/left4me/steam
|
|
BindReadOnlyPaths=/etc/left4me/host.env
|
|
BindReadOnlyPaths=/etc/ssl
|
|
BindReadOnlyPaths=/etc/ca-certificates
|
|
BindReadOnlyPaths=/etc/resolv.conf
|
|
BindReadOnlyPaths=/etc/nsswitch.conf
|
|
BindReadOnlyPaths=/etc/alternatives
|
|
BindPaths=/var/lib/left4me/runtime/%i
|
|
ProtectSystem=strict
|
|
ProtectHome=true
|
|
PrivateUsers=true
|
|
# PrivatePIDs is the test-plan amendment that closes D2.b: same-uid
|
|
# ProtectProc=invisible cannot hide gunicorn from srcds (both run as
|
|
# uid 980); a private PID namespace does.
|
|
PrivatePIDs=true
|
|
PrivateTmp=true
|
|
PrivateDevices=true
|
|
PrivateIPC=true
|
|
RestrictNamespaces=true
|
|
RestrictRealtime=true
|
|
ProtectProc=invisible
|
|
ProcSubset=pid
|
|
ProtectKernelTunables=true
|
|
ProtectKernelModules=true
|
|
ProtectKernelLogs=true
|
|
ProtectClock=true
|
|
ProtectControlGroups=true
|
|
ProtectHostname=true
|
|
LockPersonality=true
|
|
RemoveIPC=true
|
|
KeyringMode=private
|
|
UMask=0027
|
|
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
|
# Lock srcds bindable sockets to the game port range. Hard-coded range
|
|
# because systemd directive variable substitution is uneven for
|
|
# SocketBindAllow.
|
|
SocketBindAllow=udp:27000-27999
|
|
SocketBindAllow=tcp:27000-27999
|
|
# W+X mprotect (text relocations in Source engine i386 .so files) is
|
|
# incompatible with the memory-deny-write-execute directive; that
|
|
# directive is therefore intentionally absent from this drop-in.
|