Automatic systemd service hardening guided by strace profiling.
Official repository - Mirror repository
- High level introduction: Systemd hardening made easy with SHH
- FAQ
- Changelog
- Currently supported systemd options
Strace needs to be installed and available in the path. Strace version >=6.4 is strongly recommended.
You need a Rust build environment for example from rustup.
Run in the current repository:
cargo build --release
install -Dm 755 -t /usr/local/bin target/release/shh
or from crates.io
:
sudo cargo install --root /usr/local
See GitHub releases for Debian packages built for each tagged version.
Arch Linux users can install the shh AUR package.
To harden a system unit named SERVICE.service
:
- Start service profiling:
shh service start-profile SERVICE
. The service will be restarted with strace profiling. - Use the service normally for a while, trying to cover as much features and use cases as possible.
- Run
shh service finish-profile SERVICE -a
. The service will be restarted with a hardened configuration built from previous runtime profiling, to allow it to run safely as was observed during the profiling period, and to deny other dangerous system actions.
Run shh -h
for full command line reference, or append -h
to a subcommand to get help.
Services running in per-user instances of the service manager (controlled via systemctl --user ...
) are not supported.
Warning
The hardening options generated by shh
are by construction not portable across different systems.
They depend on many factors, and may break the service if any of those change:
- the code path covered during profiling
- the Linux kernel version
- the libc used
- the systemd version
Reusing options generated by shh
on a system with a different environment (ie. different Linux distribution) is very likely to break the service.
If you want to run a quick test to see what options would be generated, you can use shh run -- COMMAND
.
Current directory and PATH
environment variable both influence the program execution, reset those first:
$ cd /
export PATH=/usr/local/bin:/usr/bin:/bin
Then to see what options would be generated for a curl https://www.example.com
invocation:
$ shh run -- curl https://www.example.com
...
-------- Start of suggested service options --------
ProtectSystem=strict
ProtectHome=true
PrivateTmp=disconnected
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
ProtectProc=ptraceable
LockPersonality=true
RestrictRealtime=true
ProtectClock=true
MemoryDenyWriteExecute=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
SocketBindDeny=ipv4:tcp
SocketBindDeny=ipv4:udp
SocketBindDeny=ipv6:tcp
SocketBindDeny=ipv6:udp
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_BPF CAP_CHOWN CAP_MKNOD CAP_NET_RAW CAP_PERFMON CAP_SYS_BOOT CAP_SYS_CHROOT CAP_SYS_MODULE CAP_SYS_NICE CAP_SYS_PACCT CAP_SYS_PTRACE CAP_SYS_TIME CAP_SYSLOG CAP_WAKE_ALARM
SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM
-------- End of suggested service options --------
Or to sandbox as much as possible:
$ shh run --mode aggressive --filesystem-whitelisting --network-firewalling -- curl https://www.example.com -o /dev/null
...
-------- Start of suggested service options --------
ProtectSystem=strict
ProtectHome=true
PrivateTmp=disconnected
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
ProtectProc=ptraceable
LockPersonality=true
RestrictRealtime=true
ProtectClock=true
MemoryDenyWriteExecute=true
SystemCallArchitectures=native
ReadOnlyPaths=-/
ReadWritePaths=-/dev
InaccessiblePaths=-/boot -/home -/lost+found -/media -/mnt -/opt -/root -/srv -/sys -/tmp -/var
TemporaryFileSystem=/usr:ro
BindReadOnlyPaths=-/usr/bin -/usr/lib -/usr/lib64 -/usr/local -/usr/share
NoExecPaths=-/
ExecPaths=-/usr/bin/curl -/usr/lib/x86_64-linux-gnu
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
SocketBindDeny=ipv4:tcp
SocketBindDeny=ipv4:udp
SocketBindDeny=ipv6:tcp
SocketBindDeny=ipv6:udp
IPAddressDeny=any
IPAddressAllow=[redacted]
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_BPF CAP_CHOWN CAP_MKNOD CAP_NET_RAW CAP_PERFMON CAP_SYS_BOOT CAP_SYS_CHROOT CAP_SYS_MODULE CAP_SYS_NICE CAP_SYS_PACCT CAP_SYS_PTRACE CAP_SYS_TIME CAP_SYSLOG CAP_WAKE_ALARM
SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM
-------- End of suggested service options --------