Wednesday, July 2, 2014

Configuring OpenVPN and SELinux

up and down user scripts

OpenVPN supports custom user scripts to be run as the service is started or stopped — known as the --up and --down parameters in the man page. On CentOS or other Red Hat-based distributions, these scripts may not work correctly because SELinux is preventing them from executing, which results in the OpenVPN service failing to start.

[root@localhost ~]# service openvpn start
Starting openvpn:                                          [FAILED]

[root@localhost ~]# tail -15 /var/log/openvpn.log
Tue Jul  1 10:48:44 2014 TUN/TAP TX queue length set to 100
Tue Jul  1 10:48:44 2014 do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
Tue Jul  1 10:48:44 2014 /sbin/ip link set dev tun0 up mtu 1500
Tue Jul  1 10:48:44 2014 /sbin/ip addr add dev tun0 local 172.16.1.1 peer 172.16.1.2
Tue Jul  1 10:48:44 2014 PLUGIN_CALL: POST /usr/lib64/openvpn/plugins/openvpn-plugin-down-root.so/PLUGIN_UP status=0
Tue Jul  1 10:48:44 2014 /etc/openvpn/scripts/up.sh tun0 1500 1542 172.16.1.1 172.16.1.2 init
/etc/openvpn/scripts/up.sh: line 14: /sbin/iptables: Permission denied
/etc/openvpn/scripts/up.sh: line 15: /sbin/iptables: Permission denied
/etc/openvpn/scripts/up.sh: line 16: /sbin/iptables: Permission denied
/etc/openvpn/scripts/up.sh: line 17: /sbin/iptables: Permission denied
/etc/openvpn/scripts/up.sh: line 18: /sbin/iptables: Permission denied
/etc/openvpn/scripts/up.sh: line 19: /sbin/iptables: Permission denied
/etc/openvpn/scripts/up.sh: line 20: /proc/sys/net/ipv4/ip_forward: Permission denied
Tue Jul  1 10:48:44 2014 WARNING: Failed running command (--up/--down): external program exited with error status: 1
Tue Jul  1 10:48:44 2014 Exiting due to fatal error
  • OpenVPN fails to start with the service command.
  • Error messages in /var/log/openvpn.log show failed execution of commands regarding the up.sh script.

Also to further verify SELinux is causing this problem, error messages can be found in /var/log/audit/audit.log:

type=AVC msg=audit(1404247863.966:166): avc:  denied  { getattr } for  pid=2946 comm="up.sh" path="/sbin/iptables-multi-1.4.7" dev=sda1 ino=705 scontext=unconfined_u:system_r:openvpn_t:s0 tcontext=system_u:object_r:iptables_exec_t:s0 tclass=file

type=SYSCALL msg=audit(1404247863.966:166): arch=c000003e syscall=4 success=no exit=-13 a0=26c6890 a1=7fff1691d490 a2=7fff1691d490 a3=50 items=0 ppid=2939 pid=2946 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="up.sh" exe="/bin/bash" subj=unconfined_u:system_r:openvpn_t:s0 key=(null)
  • Notice up.sh was trying to run shell commands and /bin/bash.

To allow custom scripts to be executed two things must be done:

  1. The up or down script must have the correct file contexts set.
  2. The correct SELinux boolean must be set to allow for unconfined scripts to be run by OpenVPN.

1. OpenVPN SELinux file contexts

Anytime the restorecon command is run, it reads the /etc/selinux/targeted/contexts/files/file_contexts file to know what file context to set on a regular file or directory. Therefore we can search through this file to find all the default file contexts for OpenVPN using grep -i openvpn /etc/selinux/targeted/contexts/files/file_contexts, see below.

[root@localhost ~]# grep -i openvpn /etc/selinux/targeted/contexts/files/file_contexts
/etc/openvpn(/.*)? system_u:object_r:openvpn_etc_t:s0
/var/log/openvpn.* system_u:object_r:openvpn_var_log_t:s0
/etc/openvpn/ipp.txt -- system_u:object_r:openvpn_etc_rw_t:s0
/var/lib/openvpn(/.*)? system_u:object_r:openvpn_var_lib_t:s0
/var/run/openvpn(/.*)? system_u:object_r:openvpn_var_run_t:s0
/etc/openvpn/scripts(/.*)? system_u:object_r:openvpn_unconfined_script_exec_t:s0
/usr/sbin/openvpn -- system_u:object_r:openvpn_exec_t:s0
/etc/rc\.d/init\.d/openvpn -- system_u:object_r:openvpn_initrc_exec_t:s0
/usr/share/munin/plugins/openvpn -- system_u:object_r:munin_services_plugin_exec_t:s0

Note all the different context types, though, the type we are most interested in is system_u:object_r:openvpn_unconfined_script_exec_t:s0 which applies to all files and directories under /etc/openvpn/scripts/, and the directory itself.

Create the /etc/openvpn/scripts directory, move your custom script to it, and run a recursive restorecon:

[root@localhost ~]# mkdir /etc/openvpn/scripts

[root@localhost ~]# ls -Zd /etc/openvpn/scripts/
drwx------. root root unconfined_u:object_r:openvpn_etc_t:s0 /etc/openvpn/scripts/

[root@localhost ~]# mv -v up.sh /etc/openvpn/scripts/
`up.sh' -> `/etc/openvpn/scripts/up.sh'

[root@localhost ~]# restorecon -Rv /etc/openvpn/scripts/
restorecon reset /etc/openvpn/scripts context unconfined_u:object_r:openvpn_etc_t:s0->unconfined_u:object_r:openvpn_unconfined_script_exec_t:s0
restorecon reset /etc/openvpn/scripts/roadwarrior context unconfined_u:object_r:openvpn_etc_t:s0->unconfined_u:object_r:openvpn_unconfined_script_exec_t:s0
restorecon reset /etc/openvpn/scripts/up.sh context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:openvpn_unconfined_script_exec_t:s0
  • Notice the file context type for the scripts/ directory and the scripts/up.sh switch from openvpn_etc_t to openvpn_unconfined_script_exec_t.

Verify the directory and files have the correct file contexts with ls -Z:

[root@localhost ~]# ls -Zd /etc/openvpn/scripts/
drwx------. root root unconfined_u:object_r:openvpn_unconfined_script_exec_t:s0 /etc/openvpn/scripts/

[root@localhost ~]# ls -Zl /etc/openvpn/scripts/
total 3
-rwxr-xr-x. 1 unconfined_u:object_r:openvpn_unconfined_script_exec_t:s0 root root    0 Jul  1 12:21 up.sh

2. OpenVPN SELinux booleans

Find the relevant SELinux booleans by listening them using getsebool -a:

[root@localhost ~]# getsebool -a | grep -i openvpn
openvpn_enable_homedirs --> on
openvpn_run_unconfined --> off

Change the openvpn_run_unconfined boolean to on with the setsebool command and verify:

[root@localhost ~]# setsebool openvpn_run_unconfined on
[root@localhost ~]# getsebool -a | grep -i openvpn
openvpn_enable_homedirs --> on
openvpn_run_unconfined --> on

Now the OpenVPN service should be able to start without any errors relating to the execution of --up or --down scripts:

[root@localhost ~]# service openvpn start
Starting openvpn:                                          [  OK  ]

[root@localhost ~]# tail -15 /var/log/openvpn.log 
Tue Jul  1 12:33:45 2014 TUN/TAP TX queue length set to 100
Tue Jul  1 12:33:45 2014 do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
Tue Jul  1 12:33:45 2014 /sbin/ip link set dev tun0 up mtu 1500
Tue Jul  1 12:33:45 2014 /sbin/ip addr add dev tun0 local 172.16.1.1 peer 172.16.1.2
Tue Jul  1 12:33:45 2014 PLUGIN_CALL: POST /usr/lib64/openvpn/plugins/openvpn-plugin-down-root.so/PLUGIN_UP status=0
Tue Jul  1 12:33:45 2014 /etc/openvpn/scripts/up.sh tun0 1500 1542 172.16.1.1 172.16.1.2 init
Tue Jul  1 12:33:46 2014 /sbin/ip route add 172.16.1.0/24 via 172.16.1.2
Tue Jul  1 12:33:46 2014 GID set to nobody
Tue Jul  1 12:33:46 2014 UID set to nobody
Tue Jul  1 12:33:46 2014 UDPv4 link local (bound): [undef]
Tue Jul  1 12:33:46 2014 UDPv4 link remote: [undef]
Tue Jul  1 12:33:46 2014 MULTI: multi_init called, r=256 v=256
Tue Jul  1 12:33:46 2014 IFCONFIG POOL: base=172.16.1.4 size=62, ipv6=0
Tue Jul  1 12:33:46 2014 IFCONFIG POOL LIST
Tue Jul  1 12:33:46 2014 Initialization Sequence Completed

Custom OpenVPN listening port

The default listening port for OpenVPN is UDP port 1194. If you decide to use another port, SELinux settings must be updated using semanage to reflect the newly assigned port.

List SELinux port information and find port contexts matching OpenVPN with semanage port -l | grep -i openvpn:

[root@localhost ~]# semanage port -l | grep -i openvpn
openvpn_port_t                 tcp      1194
openvpn_port_t                 udp      1194

If we decide to use UDP port 2194 instead, use the following semanage command:

[root@localhost ~]# semanage port -a -t openvpn_port_t -p udp 2194

Optionally you can swap udp with tcp if you are using OpenVPN in TCP mode.

Verify SELinux port contexts are updated:

[root@localhost ~]# semanage port -l | grep -i openvpn
openvpn_port_t                 tcp      1194
openvpn_port_t                 udp      2194, 1194

References

http://sysadmin-notepad.blogspot.com/2013/05/custom-openvpn-port-with-selinux-enabled.html
http://www.mankier.com/8/openvpn_unconfined_script_selinux

No comments:

Post a Comment