1

So I decided to give Ubuntu 16.04 a chance despite a slightly unfavorable view about systemd.

After the upgrade my previously persistent OpenVPN connection doesn't work anymore. Fortunately the system log is rather helpful in pointing to the root cause.

openvpn-up: + /sbin/iptables -t nat -D POSTROUTING -o tun0 -s 192.168.x.x -j SNAT --to-source 10.x.x.x
openvpn-up: modprobe: ERROR: could not insert 'ip_tables': Operation not permitted
openvpn-up: iptables v1.6.0: can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
openvpn-up: Perhaps iptables or your kernel needs to be upgraded.
openvpn-up: + /sbin/iptables -t nat -A POSTROUTING -o tun0 -s 192.168.x.x -j SNAT --to-source 10.x.x.x
openvpn-up: modprobe: ERROR: could not insert 'ip_tables': Operation not permitted
openvpn-up: iptables v1.6.0: can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
ovpn-conn[613]: WARNING: Failed running command (--up/--down): external program exited with error status: 3
openvpn-up: Perhaps iptables or your kernel needs to be upgraded.
ovpn-conn[613]: Exiting due to fatal error

Note: these openvpn-up were produced by uncommenting the second line of the /etc/openvpn/openvpn-up.sh script (line reads: exec &> >(logger -s -t openvpn-up) && set -x).

Hmm, so for some reason the ip_tables module could not be loaded. After making sure to have the kernel modules all there with apt-get install --reinstall linux-image-$(uname -r), I tried to use modprobe ip_tables and sure enough saw it now loaded with lsmod but also in the system log:

kernel: [  446.293882] ip_tables: (C) 2000-2006 Netfilter Core Team

And sure enough when running systemctl restart openvpn after this point, it seemed to bring up the connection and iptables-save output proves that the appropriate SNAT rule was added.

My guess is now that the OpenVPN unit gets executed with some user context that doesn't have enough privileges to use modprobe etc.

However, I've been unable to confirm this suspicion. And in fact the output of systemctl cat openvpn confuses the hell out of me:

# systemctl cat openvpn@conn.service
# /lib/systemd/system/openvpn@.service
[Unit]
Description=OpenVPN connection to %i
PartOf=openvpn.service
ReloadPropagatedFrom=openvpn.service
Before=systemd-user-sessions.service
Documentation=man:openvpn(8)
Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage
Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO

[Service]
PrivateTmp=true
KillMode=mixed
Type=forking
ExecStart=/usr/sbin/openvpn --daemon ovpn-%i --status /run/openvpn/%i.status 10 --cd /etc/openvpn --script-security 2 --config /etc/openvpn/%i.conf --writepid /run/openvpn/%i.pid
PIDFile=/run/openvpn/%i.pid
ExecReload=/bin/kill -HUP $MAINPID
WorkingDirectory=/etc/openvpn
ProtectSystem=yes
CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE
LimitNPROC=10
DeviceAllow=/dev/null rw
DeviceAllow=/dev/net/tun rw

[Install]
WantedBy=multi-user.target

Is there a capability which I need to enable the scripts to succeed invoking insmod/modprobe? I'd like to avoid adding CAP_SYS_ADMIN as this seems rather crude. Or is the only way to load the ip_tables module by dropping a .conf into /etc/modprobe.d?

Essentially what I am asking is this: how does a stock Ubuntu 16.04 (which has not been upgraded from 14.04) accomplish this task? I.e. What's the canonical (and Canonical) way of doing it? And last but not least how can I determine in which user context a particular unit runs (or to be more precise: with which capabilities)?

  • Just to preempt possible misunderstandings. It should be clear from the content of my question and this question why mine isn't a duplicate although the subject matter is rather similar. – 0xC0000022L Apr 10 '17 at 10:12
3

The documentation for any systemd directive can be looked up via man system.directives. From there, I found that CapabilityBoundingSet= is documented in man systemd.exec.

That led me to man 7 capabilities where the different capabilities are documented. By searching for "module" there, I found this, which sounds like a capability you need:

CAP_SYS_MODULE Load and unload kernel modules

It's unclear wh this capability isn't included by default. Maybe common use cases of OpenVPN don't need it.

The minimal way to add this capability to a package's systemd config is with a "drop-in unit". Create this file:

/etc/systemd/system/openvpn@.service.d/add-module-loading.conf

With this content:

[Service]
CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE CAP_SYS_MODULE

That will extend the service with the existing capabilities plus CAP_SYS_MODULE.

I was also hesitant about systemd but have found a lot to like. The timer system is a welcome update to the 20 (plus) year old cron system.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.