Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
Tip : systemd, capabilities and rootless nginx, radvd, tor
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Documentation, Tips & Tricks
View previous topic :: View next topic  
Author Message
serafean
n00b
n00b


Joined: 11 Apr 2016
Posts: 17

PostPosted: Mon Apr 11, 2016 9:40 am    Post subject: Tip : systemd, capabilities and rootless nginx, radvd, tor Reply with quote

Hi all,

I wanted to try out how powerful systemd unit files are, so came up with this challenge : start nginx rootless, with as less access as possible, listening on ports 80 and 443.

Software versions : systemd-229, linux-4.5, nginx 1.8.1

The unit file:
Code:
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
User=nginx
Group=nginx
Type=forking
PIDFile=/var/run/nginx/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -QUIT $MAINPID

#Security
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
ReadOnlyDirectories=/etc/ssl/nginx
ReadWriteDirectories=/var/log/nginx /var/www/
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=full
ProtectHome=yes
NoNewPrivileges=yes

[Install]
WantedBy=multi-user.target

First off was giving nginx the capability to bind ports 443 and 80, this was done with AmbientCapabilities and CapabilityBoundingSet.
Then locking it out of the rest of the system.
  • PrivateDevices - Hides all device nodes (except for random, null, and some others)
  • PrivateTmp - mounts a separate tmp that is used only by nginx (namespaces are used AFAIK)
  • ProtectHome - Disables access to /home and /root
  • ProtectSystem - enables only read access to most of the FS

Finally, poking holes in the lock :
  • ReadOnlyDirectories - disable writing to dir containing SSL certificates. Since running as user nginx requires all these to have nginx of their owner, nginx could theoretically overwrite its certificates. This prevents that.
  • ReadWriteDirectories - Allow rw access to log directory, and to data directory.

It works, I haven't found anything broken (yet).
This concept is reusable : I've adapted it to tvheadend, dnsmasq and radvd. I'm hoping to convert more of my unit files so as to have less services dependend on them dropping their privileges.
The greatest pain are PID files : /run isn't writeable by non-root processes, so for each such a service, there has to exist an entry in /etc/tmpfiles.d creating /run/${SERVICE_NAME}/ with appropriate access rights, so the PID file can be written somewhere.

Here's to hoping someone finds this useful :)
Comments very welcome.

Serafean.


Last edited by serafean on Wed Nov 30, 2016 2:16 pm; edited 1 time in total
Back to top
View user's profile Send private message
serafean
n00b
n00b


Joined: 11 Apr 2016
Posts: 17

PostPosted: Sun Apr 17, 2016 11:40 am    Post subject: Reply with quote

After a week running in this mode, I deem it usable :)
Joining dnsmasq.service.
Code:
[Unit]
Description=A lightweight DHCP and caching DNS server
After=network.target

[Service]
User=dnsmasq
Group=dnsmasq
Type=simple
PIDFile=/var/run/dnsmasq/dnsmasq.pid
ExecStartPre=/usr/sbin/dnsmasq --test
ExecStart=/usr/sbin/dnsmasq -k -x /var/run/dnsmasq/dnsmasq.pid
ExecReload=/bin/kill -HUP $MAINPID

#Security
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=full
ProtectHome=yes
NoNewPrivileges=yes

[Install]
WantedBy=multi-user.target
And radvd.service
Code:
[Unit]
Description=Router advertisement daemon for IPv6
Documentation=man:radvd(8)
After=network.target

[Service]
User=radvd
Group=radvd
Type=forking
ExecStartPre=/usr/sbin/radvd --configtest
ExecStart=/usr/sbin/radvd --logmethod stderr --debug 0
ExecReload=/usr/sbin/radvd --configtest ; \
           /bin/kill -HUP $MAINPID
PIDFile=/run/radvd/radvd.pid

# Performance
CPUSchedulingPolicy=idle

#Hardening
CapabilityBoundingSet=CAP_NET_BIND_SERVICE  CAP_NET_RAW
AmbientCapabilities=CAP_NET_BIND_SERVICE  CAP_NET_RAW
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=full
ProtectHome=yes
NoNewPrivileges=yes

[Install]
WantedBy=multi-user.target
Back to top
View user's profile Send private message
candrews
Developer
Developer


Joined: 10 Aug 2005
Posts: 162

PostPosted: Thu Jun 30, 2016 2:29 pm    Post subject: Reply with quote

I've submitted bugs for improving these systemd units, and included pull requests:
dnsmasq: https://bugs.gentoo.org/show_bug.cgi?id=587586
radvd: https://bugs.gentoo.org/show_bug.cgi?id=587588

In the future, you may want to do the same - having these changes made in Gentoo means you don't have to maintain them and everyone gets the benefits.
Back to top
View user's profile Send private message
Ant P.
Watchman
Watchman


Joined: 18 Apr 2009
Posts: 6920

PostPosted: Fri Jul 01, 2016 11:38 am    Post subject: Reply with quote

Huh, makes me wonder why something as simple as radvd doesn't have a USE=caps for that, it really shouldn't run as root. Quagga does that already...
Back to top
View user's profile Send private message
serafean
n00b
n00b


Joined: 11 Apr 2016
Posts: 17

PostPosted: Sat Oct 01, 2016 3:09 pm    Post subject: Reply with quote

candrews wrote:

In the future, you may want to do the same - having these changes made in Gentoo means you don't have to maintain them and everyone gets the benefits.
Oh wow! I wasn't thinking that far out :) I was just playing around xD
Thanks for taking the time to report those enhancments.

I read throught the bug reports, and if someone could enlighten me as to why starting a process as root and letting it drop its capabilities is better than this, I'd be very grateful.
Back to top
View user's profile Send private message
serafean
n00b
n00b


Joined: 11 Apr 2016
Posts: 17

PostPosted: Wed Nov 30, 2016 1:43 pm    Post subject: Reply with quote

And another one for tor :
Code:
[Unit]
Description=The Onion Router
After=network-online.target

[Service]
User=tor
Group=tor

ExecStartPre=/usr/bin/tor --verify-config -f /etc/tor/torrc
ExecStart=/usr/bin/tor --RunAsDaemon 0 -f /etc/tor/torrc
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT
TimeoutStopSec=32
LimitNOFILE=30000

# Hardening options:
#CapabilityBoundingSet = CAP_NET_BIND_SERVICE
# Capabilities aren't enough to have ports < 1024
RuntimeDirectory=tor
RuntimeDirectoryMode=0700
ReadWriteDirectories=/var/lib/tor/
PrivateTmp = yes
PrivateDevices = yes
ProtectHome = yes
ProtectSystem = strict
NoNewPrivileges = yes

[Install]
WantedBy=multi-user.target

will be submitting it to bugzilla[/code]
Back to top
View user's profile Send private message
ssokolow
n00b
n00b


Joined: 20 Apr 2005
Posts: 22

PostPosted: Wed Apr 19, 2017 4:59 pm    Post subject: Reply with quote

I decided to develop something for my Debian VPS using your nginx.service as a base and I managed to lock it down even further (and make the service file easier to use) by making the following tweaks:


  1. Instead of replicating everything, use .include /lib/systemd/system/nginx.service at the top of the file as described here.
  2. Instead of using tmpfiles.d, use RuntimeDirectory=nginx inside the service file and set PIDFile and the pid line in nginx.conf to /run/nginx/nginx.pid


Another tweak I'm planning to do is to set nginx to log via syslog(), configure my syslogd to split the entries out into nginx/access.log and nginx/error.log and then remove the ReadWriteDirectories line. (That way, if someone compromises nginx, they won't have the ability to modify its logs to cover their tracks. The manual way to do this is to use chattr +a to set the logs append-only and then modify your logrotate config to temporarily unset that attr.)

Using syslog also has the added benefit that it's easy to forward logs to a central location if you have more than one server. (I use it to have my FreeBSD router log to my desktop Linux PC's syslog infrastructure so it's easy to keep long-term audit logs.)

It may also make it feasible to ask systemd to run nginx under a random/temporary UID and GID.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Documentation, Tips & Tricks All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum