Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement: systemd service hardening #2637

Open
candrews opened this issue Apr 28, 2019 · 7 comments

Comments

Projects
None yet
4 participants
@candrews
Copy link

commented Apr 28, 2019

Improvement / Suggestion

How to reproduce the issue

It would be really nice if the systemd service used systemd's built in hardening features to improve security. See https://www.freedesktop.org/software/systemd/man/systemd.exec.html

I took a quick stab at what I think would be helpful and would work. Adding these should reduce the attack service and blast radius (pun not intendd) of freeradius.

The point of all of these changes is to limit FreeRadius as much as possible. That way, it's harder to compromise, and if it is compromised, there's as little as damage as possible that can be done by the attacker.

For example, there's no reason for FreeRadius to load kernel modules, change kernel tunables, read users' home directories, or execute writable memory pages - so deny all of those actions.

# ensures that the service process and all its children can never gain new
# privileges through execve() (e.g. via setuid or setgid bits, or filesystem
# capabilities). This is the simplest and most effective way to ensure that a
# process and its children can never elevate privileges again.
NoNewPrivileges=true

# Controls which capabilities to include in the capability bounding set for the
# executed process. See capabilities(7)
# http://man7.org/linux/man-pages/man7/capabilities.7.html for details.
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST
CAP_NET_RAW

# 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.
PrivateTmp=true

# The directories /home, /root and /run/user are made inaccessible and empty
# for processes invoked by this unit.
ProtectHome=true

# the entire file system hierarchy is mounted read-only, except for the API
# file system subtrees /dev, /proc and /sys
ProtectSystem=strict

# 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.
PrivateUsers=true

# the Linux Control Groups (cgroups(7)) hierarchies accessible through
# /sys/fs/cgroup will be made read-only to all processes of the unit.
ProtectControlGroups=true

# explicit module loading will be denied.
ProtectKernelModules=true

# kernel variables accessible through /proc/sys, /sys, /proc/sysrq-trigger,
# /proc/latency_stats, /proc/acpi, /proc/timer_stats, /proc/fs and /proc/irq
# will be made read-only to all processes of the unit. Usually, tunable kernel
# variables should be initialized only at boot-time, for example with the
# sysctl.d(5) mechanism.
ProtectKernelTunables=true

# attempts to create memory mappings that are writable and executable at the
# same time, or to change existing memory mappings to become executable, or
# mapping shared memory segments as executable are prohibited
MemoryDenyWriteExecute=true

# any attempts to enable realtime scheduling in a process of the unit are
# refused. This restricts access to realtime task scheduling policies such as
# SCHED_FIFO, SCHED_RR or SCHED_DEADLINE.
RestrictRealtime=true

# processes of this unit will only be permitted to call native system calls
SystemCallArchitectures=native
@geaaru

This comment has been minimized.

Copy link

commented Apr 28, 2019

@candrews I think that MemoryDenyWriteExecute=true could be a problem when it is used with Oracle stuff. I disabled it also on apache for the same reason when it is used PHP+ocilib.

@arr2036

This comment has been minimized.

Copy link
Member

commented Apr 28, 2019

We'll definitely consider this, but you'd need to provide justification for each of those settings. Posting an issue like this puts the full burden of researching whether such a change would be appropriate, on the FreeRADIUS team.

@candrews

This comment has been minimized.

Copy link
Author

commented Apr 28, 2019

We'll definitely consider this, but you'd need to provide justification for each of those settings.

I've updated the PR description with information about each option. I think each option I've suggested is appropriate and would improve FreeRadius's security.

Thank you!

@arr2036

This comment has been minimized.

Copy link
Member

commented Apr 28, 2019

Perfect, this really helps, thank you.

Will need comments from @alandekok and @mcnewton too.

  • NoNewPrivileges=true OK?
  • CapabilityBoundSet also needs CAP_SYS_PTRACE and CAP_NET_ADMIN. CAP_SYS_PTRACE to allow the self stack dump functionality to work correctly - maybe this could be included in pre-release/debugging packages only. CAP_NET_ADMIN to allow the proto_dhcpv4 and proto_arp modules to work in pcap mode.
  • PrivateTmp=true OK.
  • ProtectHome=true OK.
  • ProtectSystem=strict - This honestly seems like a pain. I guess we could do this, but we'd also need to set RuntimeDirectory (already do) and LogsDirectory.
  • PrivateUsers=true - I think this would break peercred based authorization on the control socket.
  • ProtectControlGroups=true OK
  • ProtectKernelModules=true OK
  • ProtectKernelTunables=true Maybe, I'm more hesitant about this one, I'd have to look at what's required to enable RPS, it would be nice to be able to do that automatically.
  • MemoryDenyWriteExecute=true - Can almost guarantee this will break the LuaJIT side of rlm_lua. In fact googling for MemoryDenyWriteExecute=true LuaJIT threw up https://gitea.devosi.org/mario/PROSODY-docker/src/commit/36b5e9e771be5e4eb4ed803e5143f25234c90c6b/data/prosody/prosody-modules/misc/systemd/prosody.service#L70
  • RestrictRealtime=true OK
  • SystemCallArchitectures=native OK
@alandekok

This comment has been minimized.

Copy link
Member

commented Apr 28, 2019

Most of it looks OK, but the ProtectSystem=strict is a bit strong. We may want to enable the largest subset that we're sure will work, and then leave the rest in, but commented out.

@geaaru

This comment has been minimized.

Copy link

commented Apr 29, 2019

I add a reference to Gentoo issue about the same argument.
Probably if it's used ReadOnlyDirectories and ReadWriteDirectories for the logs, the options ProtectSystem and ProtectHome could be omitted.
IIRC if it's used ReadOnlyDirectories and ReadWriteDirectories access to any others directories of the system are automatically blocked.
I will try to apply these options to my test environment for feedback.

In addition, can you consider a pull request for Gentoo distro that adds gentoo directory in a similar way of Debian and RedHat?

@geaaru

This comment has been minimized.

Copy link

commented May 16, 2019

Tested correctly these options without issues:

NoNewPrivileges=true
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW
PrivateTmp=true
ProtectControlGroups=true
ProtectKernelModules=true
ProtectKernelTunables=true
SystemCallArchitectures=native
ReadOnlyDirectories=/etc/raddb/
ReadWriteDirectories=/var/log/radius/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.