5 ms·
Nice post and +1 for having a small "hardening" section. I wish that every systemd example/sample/template came with _extensive_ hardening, since I find it qui
by latch 5y ago
Nice post and +1 for having a small "hardening" section.
I wish that every systemd example/sample/template came with _extensive_ hardening, since I find it quite confusing. I've used systemd-analyze security <SERVICE> to try to figure out what was needed. For Elixir, I've come up with:
UMask=077
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectHome=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictNamespaces=yes
RestrictSUIDSGID=yes
LockPersonality=yes
PrivateDevices=yes
PrivateUsers=yes
ProtectClock=yes
ProtectKernelLogs=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
Plus the use of TemporaryFileSystem and BindPaths to limit the file system.
- 5e92cb50239222b 5y agoOh yes, thank you for spreading the good news. 'systemd-analyze security' is a fine thing, just make sure to use the latest version of systemd because it was really buggy in the past. For example, the version that ships in RHEL 8 is so buggy it's practically useless. I came up with this for most of my services that do require a JIT compiler (so Java, dotnet, etc): DynamicUser=yes CapabilityBoundingSet= DevicePolicy=closed InaccessiblePaths=-/usr/bin /usr/sbin /mnt /media /var/www LockPersonality=yes NoNewPrivileges=yes PrivateDevices=yes PrivateMounts=yes PrivateTmp=yes PrivateUsers=yes ProtectClock=yes ProtectControlGroups=yes ProtectHome=yes ProtectHostname=yes ProtectKernelLogs=yes ProtectKernelModules=yes ProtectKernelTunables=yes ProtectProc=invisible ProtectSystem=strict RemoveIPC=yes RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 RestrictNamespaces=yes RestrictRealtime=yes RestrictSUIDSGID=yes SystemCallArchitectures=native SystemCallFilter=~@clock @cpu-emulation @privileged @module @raw-io @reboot @mount @obsolete @swap @debug You might want to throw away InaccessiblePaths if your application calls external binaries. The stuff I typically write shouldn't do it. Some of these flags are not strictly necessary because they should be enabled by other switches, but I prefer to keep them to make configuration more obvious and to mitigate possible bugs (there were some in the past). If your application needs to store anything locally, add some combination of these: RuntimeDirectory=appname # adds /var/run/appname StateDirectory=appname # adds /var/lib/appname CacheDirectory=appname # adds /var/cache/appname LogsDirectory=appname # adds /var/log/appname ConfigurationDirectory=appname # adds /etc/appname and you can read the resulting path in environment variables RUNTIME_DIRECTORY / STATE_DIRECTORY / CACHE_DIRECTORY / LOGS_DIRECTORY / CONFIGURATION_DIRECTORY if your systemd is new enough. systemd will make sure that your limited user can read and write these paths, including their content. Add this if your application does not use a JIT compiler: MemoryDenyWriteExecute=yes And this to prevent it from listening on wrong ports in an event of misconfiguration. SocketBindDeny=any SocketBindAllow=tcp:5000 These firewalling flags can be useful if your service does not do much networking to external APIs: IPAddressDeny=any IPAddressAllow=localhost IPAddressAllow=10.3.42.0/24
- hauleth 5y agoOh, I didn't know about `SocketBindDeny=` and `SocketBindAllow=`. This option may be a little troublesome in case of Distributed Erlang, but in recent versions it can be circumvented. Thanks, I will add it as a better option than adding capabilities.
- the8472 5y agoWith that many options it seems easy to miss something. A whitelist approach would be preferable. The application failing because you missed something would be more obvious than some subtle security hole.
- frankjr 5y agoThere's already a ticket precisely for that but it has been closed in as a duplicate https://github.com/systemd/systemd/issues/20247 https://github.com/systemd/systemd/issues/20247
- acdha 5y agoThis leaves me wishing there was some kind of report-only tooling where you could do something like, say, freeze the system calls used in a test run to reduce trial-and-error, similar to how you can use SELinux with audit2allow to get a decent starting point. Does anything like that already exist?
- hauleth 5y agoAt the beginning I wanted to add all that information and options, but I thought that it can be overwhelming in this article. I wanted to focus on Erlang <-> systemd communication and basic options. However it may be nice follow-up article where I will describe full hardening process.