TUN/TAP device in lxc containers

To create tun/tap devices in Red Hat or Debian based distros inside lxc containers, create the following systemd unit:

/etc/systemd/system/tundev.service:
    [Unit]
    Description=Add tun device workaround
    Wants=network.target
 
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/usr/bin/mkdir /dev/net
    ExecStart=/usr/bin/mknod -m 666 /dev/net/tun c 10 200
 
    [Install]
    WantedBy=multi-user.target

To create the tun/tap device before certain units start (ex. OpenVpn) you can add

Before=openvpn@.service

under [Unit].

To allow the container to create the device, the following line must be in the lxc config file (/var/lib/lxc/100/config):

lxc.cgroup.devices.allow = c 10:200 rwm

For Proxmox, add the following line to the container config (ex. /etc/pve/lxc/100.conf):

lxc.cgroup.devices.allow: c 10:200 rwm
Advertisements
TUN/TAP device in lxc containers

Hardened OpenVPN on CentOS 7

This post should cover installing and hardening OpenVPN, configuring firewalld to allow VPN traffic, and configure logrotate to rotate the OpenVPN logs on CentOS 7.

Consider reading this first: https://community.openvpn.net/openvpn/wiki/Hardening

SELinux should be enforcing and key permissions should not allow anyone but root to read them.

Installing

First install the EPEL repo:

yum install epel-release -y

Update the system:

yum update -y

Install openvpn and easy-rsa:

yum install openvpn easy-rsa -y

Copy the easy-rsa scripts to /etc/openvpn/easy-rsa:

cp -R /usr/share/easy-rsa/2.0/ /etc/openvpn/easy-rsa/

Copy the OpenVPN sample server config to /etc/openvpn:

cp /usr/share/doc/openvpn-2.*/sample/sample-config-files/server.conf /etc/openvpn/

Edit the following variables in the /etc/openvpn/easy-rsa/vars file:

export KEY_COUNTRY="US"
export KEY_PROVINCE="CA"
export KEY_CITY="SanFrancisco"
export KEY_ORG="Fort-Funston"
export KEY_EMAIL="mail@domain"
export KEY_EMAIL=mail@domain

Edit the KEY_SIZE variable to increase the key size to something above 3072 (4096 is probably not a bad idea unless you suffer performance problems):
https://community.openvpn.net/openvpn/wiki/Hardening#X.509keysize
https://www.enisa.europa.eu/activities/identity-and-trust/library/deliverables/algorithms-key-sizes-and-parameters-report

KEY_SIZE=4096

Create the server side keys and certificates:

cd /etc/openvpn/easy-rsa/
source vars
./clean-all
./build-ca
./build-key-server server

Build the Diffie-Hellman parameters:
Note: this will take a long time, in some cases more than an hour. Consider installing and starting haveged before doing this.

./build-dh

OpenVPN won’t start if the CRL file doesn’t exist or is invalid, so we create a dummy client certificate and revoke it:

./build-key dummy-client
./revoke-full dummy-client

When dropping the OpenVPN daemon privileges after initialization to “nobody”, it won’t be able to read the crl.pem file because /etc/openvpn/easy-rsa/keys has 0700 permissions. We work around this by moving it to /etc/openvpn/crl.pem and symlinking to /etc/openvpn/easy-rsa/keys/crl.pem. This way we don’t have to make /etc/openvpn/easy-rsa/keys world-readable or edit the revoke-full script. Nice.

mv /etc/openvpn/easy-rsa/keys/crl.pem /etc/openvpn/crl.pem
ln -s /etc/openvpn/crl.pem /etc/openvpn/easy-rsa/keys/crl.pem

Generate a client certificate/key combo:

cd /etc/openvpn/easy-rsa/
source vars
./build-key client1

Generate a TLS pre-shared key:

cd /etc/openvpn/easy-rsa/keys
openvpn --genkey --secret ta.key

Edit the server configuration file /etc/openvpn/server.conf:

vim server.conf

Certificate Authority, Server Certificate, Server Key:

ca easy-rsa/keys/ca.crt
cert easy-rsa/keys/server.crt
key easy-rsa/keys/server.key # This file should be kept secret

Diffie-Hellman parameters:

dh easy-rsa/keys/dh4096.pem

Push a default gateway route:

push "redirect-gateway def1 bypass-dhcp"

Push DNS options:

push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 208.67.220.220"

Use a TLS authentication secret:
https://community.openvpn.net/openvpn/wiki/Hardening#Useof–tls-auth

tls-auth easy-rsa/keys/ta.key 0 # This file is secret

Maximum number of concurrently connected clients (change this if you have more than 10 clients):

max-clients 10

Drop privileges after initialization:

user nobody
group nobody

Append log:

log-append /var/log/openvpn.log

Check the Extended Key Usage on the certificates:

Note: The –remote-cert-tls client option is equivalent to –remote-cert-eku “TLS Web Client Authentication”

remote-cert-tls client

Check for revoked certificates:

crl-verify crl.pem

Set a minimum TLS protocol version:

tls-version-min 1.2

Set a stronger cipher:

cipher AES-256-CBC

Use SHA-2 for message authentication:
Note: The source blog says “SHA-256”, but OpenVPN wouldn’t start unless I changed it to SHA256.

I changed this to SHA512 because why not. Use SHA256 if you suffer performance problems. See Algorithms, Key Sizes and Parameters Report – 2013 (3.3.1 Recommended Hash Functions, page 26).

auth SHA512

Limit the list of supported TLS ciphersuites:
https://community.openvpn.net/openvpn/wiki/Hardening#Useof–tls-cipher

tls-cipher TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256

The final server config

And a corresponding client config (see server config explanations above for the same directives).

Replace the dots (“…”) in the inline tags with the corresponding certs/keys:

<ca> = certificate authority (contents of: /etc/openvpn/easy-rsa/keys/ca.crt)
<cert> = client certificate (contents of: /etc/openvpn/easy-rsa/keys/client1.crt)
<key> = client private key (contents of: /etc/openvpn/easy-rsa/keys/client1.key)
<tls-auth> = pre-shared tsl key (contents of: /etc/openvpn/easy-rsa/keys/ta.key)

In the client configuration, verify the server certificate subject string.
For example:

verify-x509-name 'C=XX, ST=NA, L=XX, O=XX, OU=XX, CN=XX, name=XX, emailAddress=XX' subject

To see these values for the server certificate, use:

Note: The string must match the subject, but the text output from openssl puts forward slashes between the CN, name, and emailAddress fields. These should be separated by “, ” as shown above. Otherwise you will get an error stating that the subject doesn’t match.

To generate the subject string:

openssl x509 -in easy-rsa/keys/server.crt -text|grep Subject:|sed 's|/name=|, name=|g;s|/emailAddress=|, emailAddress=|g;s|.*Subject: ||g'
Subject: C=US, ST=CA, L=SanFrancisco, O=Fort-Funston, OU=MyOrganizationalUnit, CN=server, name=EasyRSA, emailAddress=me@myhost.mydomain

Enable and start the OpenVPN service:

systemctl enable openvpn@server
systemctl start openvpn@server

Note: the @server means systemd will start openvpn with the config file “server.conf”.
For multiple servers/clients use systemctl enable openvpn@server2, systemctl enable openvpn@client1, etc..

Firewall and forwarding

Enable IPv4 forwarding in the kernel:

/etc/sysctl.d/99-sysctl.conf:

net.ipv4.ip_forward=1
sysctl -p /etc/sysctl.d/99-sysctl.conf

iptables:
Note: Replace ens18 with your internet-facing interface

iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -s 10.8.0.0/24 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o ens18 -j MASQUERADE

firewalld/firewall-cmd:

**todo**

Logrotate:

Put the following in /etc/logrotate.d/openvpn:

/var/log/openvpn.log {
 missingok
 notifempty
 copytruncate
 compress
 delaycompress
 daily
 rotate 7
 create 0600 root root
}

useful commands:

View effective config without comments or other garbage:

egrep -iv "^(\#|;|$)" server.conf | sort

Sources and further reading:

https://blog.g3rt.nl/openvpn-security-tips.html
https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage
https://community.openvpn.net/openvpn/wiki/Hardening
https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
https://www.enisa.europa.eu/activities/identity-and-trust/library/deliverables/algorithms-key-sizes-and-parameters-report
http://darizotas.blogspot.com/2014/04/openvpn-hardening-cheat-sheet.html

Hardened OpenVPN on CentOS 7

OpenVPN on Debian 8 (Jessie)

Update: I wrote a post how to harden OpenVPN on CentOS. It includes DoS mitigation, daemon privilege reduction, better certificate checks, enforcing use of TLS 1.2, stronger ciphers and more. The methods used to harden it can be applied to this post easily. See here: https://2kswiki.wordpress.com/2015/06/17/hardened-openvpn-on-centos-7/

This how-to will cover setting up a TLS-enabled OpenVPN server on Debian 8 (Jessie)
Not covered in this how-to: opening ports in the firewall.

Update the system:

apt-get update
apt-get upgrade -y

Install OpenVPN and easy-rsa:

apt-get -y install openvpn easy-rsa

Copy the easy-rsa directory for creating keys:

cp -R /usr/share/easy-rsa /etc/openvpn/

Edit the following variables in the /etc/openvpn/easy-rsa/vars file:

export KEY_COUNTRY="US"
export KEY_PROVINCE="CA"
export KEY_CITY="SanFrancisco"
export KEY_ORG="Fort-Funston"
export KEY_EMAIL="mail@domain"
export KEY_EMAIL=mail@domain

Increase the key size to something above 3072 (4096 if you are paranoid, see: https://www.enisa.europa.eu/activities/identity-and-trust/library/deliverables/algorithms-key-sizes-and-parameters-report):

sed -i 's/KEY_SIZE=2048/KEY_SIZE=3072/g' /etc/openvpn/easy-rsa/vars

Create the server side keys and certificates:

cd /etc/openvpn/easy-rsa/
source vars
./clean-all
./build-ca
./build-key-server server

Build the Diffie-Hellman parameters (this will take a long time, in some cases more than an hour):

./build-dh

Copy the server certificate, key and CA to the openvpn directory:

cd /etc/openvpn/easy-rsa/keys
cp server.crt server.key ca.crt dh3072.pem /etc/openvpn/

Copy the sample server config:

zcat /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf

Edit the server config file:

sed -i -r 's/^dh (.+)/dh dh3072.pem/g' /etc/openvpn/server.conf #new dh parameter
echo 'crl-verify easy-rsa/keys/crl.pem' >> /etc/openvpn/server.conf #certificate revocation list
echo 'push "redirect-gateway def1 bypass-dhcp"' >> /etc/openvpn/server.conf #redirect default gateway
echo 'push "dhcp-option DNS 8.8.8.8"' >> /etc/openvpn/server.conf #use google DNS
echo 'push "explicit-exit-notify 3"' >> /etc/openvpn/server.conf #send exit notification instead of timing out

OpenVPN won’t start if the CRL file doesn’t exist or is invalid, so we create a dummy client certificate and revoke it:

cd /etc/openvpn/easy-rsa/
source vars
./build-key dummy-client
./revoke-full dummy-client

Enable IPv4 forwarding:

echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/net.ipv4.ip_forward.conf
sysctl -p /etc/sysctl.d/net.ipv4.ip_forward.conf

Set up the following iptables rules:

iptables -A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT # allow traffic to the openvpn server
iptables -A FORWARD -s 10.8.0.0/24 -j ACCEPT # allow forwarding from the vpn subnet
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT # allow forwarding of related and established packets
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE # masquerade packets leaving eth0 from the vpn subnet

Note: These firewall rules will not survive a reboot unless configured to: https://www.debian-administration.org/article/445/Getting_IPTables_to_survive_a_reboot

Enable and start the OpenVPN service:

systemctl enable openvpn@server
systemctl start openvpn@server

Note: the @server means systemd will start openvpn with the config file “server.conf”.
For multiple servers/clients use systemctl enable openvpn@server2, systemctl enable openvpn@client1, etc..

Generate a client certificate:

cd /etc/openvpn/easy-rsa/
source vars
./build-key client1

Generate a client config file that works with the Windows OpenVPN GUI client with in-line ca, cert, and key:

echo 'client
dev tun
proto udp
remote vpn-01.domain.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
comp-lzo
verb 3' > /etc/openvpn/client1.ovpn
echo '<ca>' >> /etc/openvpn/client1.ovpn
cat /etc/openvpn/ca.crt >> /etc/openvpn/client1.ovpn
echo '</ca>' >> /etc/openvpn/client1.ovpn
echo '<cert>' >> /etc/openvpn/client1.ovpn
cat /etc/openvpn/easy-rsa/keys/client1.crt >> /etc/openvpn/client1.ovpn
echo '</cert>' >> /etc/openvpn/client1.ovpn
echo '<key>' >> /etc/openvpn/client1.ovpn
cat /etc/openvpn/easy-rsa/keys/client1.key >> /etc/openvpn/client1.ovpn
echo '</key>' >> /etc/openvpn/client1.ovpn

Note: Make sure the client key is delivered securely (in this case it’s inline in the client config file)! No point in using strong crypto if you post the keys to pastebin…

Sources:
https://help.ubuntu.com/lts/serverguide/openvpn.html
https://wiki.debian.org/OpenVPN
https://stavrovski.net/blog/how-to-install-and-set-up-openvpn-in-debian-7-wheezy
My brain

OpenVPN on Debian 8 (Jessie)