hanneseichblatt.de

Access a Remote LibVirt Network via OpenVPN

This is very loosely based on a how-to by the Koofr team. We assume the following:

  • You have a remote box with libvirtd running on a RHEL 7-compatible OS.
  • You have created a network 192.168.100.0/24 in said libvirtd.
  • You want to access the VMs in said network from your local box.
  • The bridge interface is called virbr1.

We start on the remote server. First, we install the necessary software packages.

yum install openvpn easy-rsa 
mkdir -p /etc/openvpn/easy-rsa
cp -rf /usr/share/easy-rsa/2.0/* /etc/openvpn/easy-rsa/
cd /etc/openvpn/easy-rsa/
vim vars  # set your vars
cp /etc/openvpn/easy-rsa/openssl-1.0.0.cnf /etc/openvpn/easy-rsa/openssl.cnf

Now we create some keys and certificates.

cd /etc/openvpn/easy-rsa/
source ./vars 
./clean-all
./build-ca   # build CA key and certificate
./build-dh   # build Diffie-Hellman parameters
./build-key-server server
./build-key client  # your client key and certificate
cd /etc/openvpn
cp easy-rsa/keys/ca.{crt,key} easy-rsa/keys/dh2048.pem easy-rsa/keys/server.{crt,key} .

Put the following in /etc/openvpn/libvirt-bridge.conf, your server config:

mode server
tls-server
local YOUR_SERVERS_PUBLIC_IP
port 1194
proto udp
dev tap0
script-security 2
up "/etc/openvpn/bridgeup.sh virbr1 tap0 1500"
down "/etc/openvpn/bridgedown.sh virbr1 tap0"
persist-key
persist-tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
cipher BF-CBC
comp-lzo yes
ifconfig-pool-persist ipp.txt
server-bridge 192.168.100.1 255.255.255.0 192.168.100.201 192.168.100.201
max-clients 3   # only this many clients can connect simultaneously
user nobody
group nobody
keepalive 10 120
status server.log
verb 3

You might have noticed two scripts mentioned in the config: bridgeup.sh and bridgedown.sh. These are the scripts OpenVPN calls when it successfully creates and destroys its own network interface. They add or remove the OpenVPN interface from the LibVirt bridge, respectively.

bridgeup.sh

#!/bin/sh
BR=$1
DEV=$2
MTU=$3
/sbin/ip link set "$DEV" up promisc on mtu "$MTU"
/sbin/brctl addif "$BR" "$DEV"
exit 0

bridgedown.sh

#!/bin/sh 
BR=$1
DEV=$2
/sbin/brctl delif "$BR" "$DEV"
/sbin/ip link set "$DEV" down
exit 0

Finally, we open the OpenVPN port in firewalld.

firewall-cmd --get-active-zones   # find out your currently active zone
firewall-cmd --zone=public  --add-port=1194/udp # change current config
firewall-cmd --zone=public  --add-port=1194/udp --permanent # change permanent config

After starting the service (careful, systemd instantiated units), we should be done with the server side.

systemctl enable openvpn@libvirt-bridge
systemctl start openvpn@libvirt-bridge

On your local machine, install OpenVPN, download ca.crt, client.crt and client.key from your server and put them in one directory. On SELinux-enabled machines this directory should be under ~/.cert. Then we add our client.conf, which should look like this:

client
remote YOUR_SERVERS_PUBLIC_IP 1194
dev tap 
proto udp
resolv-retry infinite
nobind
persist-key
persist-tun
verb 2
ca YOUR_HOME/.cert/myvpn/ca.crt
cert YOUR_HOME/.cert/myvpn/client.crt
key YOUR_HOME/.cert/myvpn/client.key
comp-lzo yes
script-security 2

You can now start your client with

sudo openvpn --config client.conf

After that, you should be able to connect directly to your VMs living in your libvirtd network, e.g.

nmap -p 22 192.168.100.123