Oracle Linux engineer William Kucharski provides an introduction to the VPN protocol WireGuard
WireGuard has received a lot of attention of late as a new, easier to use VPN mechanism, and it has now been added to Unbreakable Enterprise Kernel 6 Update 1 as a technology preview.
But what is it, and how do I use it?
WireGuard is described by its developers as:
an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache.
(You can read the full statement from the developers here.)
Though IPsec works well and is indeed a standard for secure communication, it can be difficult to configure and use for those not familiar with network administration.
By comparison, WireGuard is reasonably easy to set up, and "aims to be as easy to configure and deploy as SSH."
Linus Torvalds paid it perhaps the ultimate compliment on LKML not too long before the code was merged into the 5.6 kernel:
Can I just once again state my love for it and hope it gets merged soon? Maybe the code isn’t perfect, but I’ve skimmed it, and compared to the horrors that are OpenVPN and IPSec, it’s a work of art.
If you are curious about the inner workings of WireGuard, you can read the protocol in the original technical whitepaper.
If you prefer video, a nice session on WireGuard was given at the 2018 Linux Plumber's Conference in Vancouver, viewable here.
WireGuard associates tunnel IP addresses with public keys and remote endpoints.
When the interface sends a packet to a peer, it does the following:
When the interface receives a packet, this happens:
Behind the scenes there is much happening to provide proper privacy, authenticity, and perfect forward secrecy, using state-of-the-art cryptography.
The following assumes you have WireGuard installed on the machines you've decided to use as your client and server, and that the two machines can connect to one another.
You can verify WireGuard is installed by using the following commands:
rpm -qa | grep wireguard modinfo wireguard
The first should show that the package wireguard-tools is installed and the second should show information on the wireguard kernel module.
For the sake of simplicity, I will demonstrate a configuration using IPv4 addresses, though the parameters in the setup files will support IPv6 addresses.
Assume the current IP addresses for the two systems' eno1 interfaces are:
and we want to use WireGuard addresses of:
you would follow these steps:
Start by generating a crypto key pair: a public key and a private key.
Run the following commands on the machine you've selected as your server as root.
If your system does not allow logins as root, add sudo commands as necessary:
cd /etc/wireguard umask 077 wg genkey | tee privatekey | wg pubkey > publickey
This will generate the initial private and public crypto keys needed to start the tunnel and store them in the files privatekey and publickey respectively.
Next, edit the file /etc/sysctl.conf and make the following changes (note that depending upon your prior configuration, these values may have already been set elsewhere in the file and you may need to edit those lines appropriately):
net.ipv4.ip_forward = 1 net.ipv6.conf.all.forwarding = 1
Then use the sysctl command to make the system reread the /etc/sysctl.conf configuration file:
sysctl -p
(You can safely ignore any errors that are output about files that sysctl cannot stat.)
As you did for the server, you will need to generate a crypto key pair:
cd /etc/wireguard umask 077 wg genkey | tee privatekey | wg pubkey > publickey
Now edit the file /etc/wireguard/wg0.conf to read:
[Interface] Address = 192.168.2.2/24 SaveConfig = true ListenPort = 60477 PrivateKey = <contents of /etc/wireguard/privatekey> [Peer] PublicKey = <contents of the server's /etc/wireguard/publickey file> AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = 10.0.0.1:51820
Edit the file /etc/wireguard/wg0.conf so that it looks like this:
[Interface] Address = 192.168.2.1/24 SaveConfig = true PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eno1 -j MASQUERADE PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eno1 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eno1 -j MASQUERADE ListenPort = 51820 PrivateKey = <contents of /etc/wireguard/privatekey> [Peer] PublicKey = <contents of the client's /etc/wireguard/publickey file> AllowedIPs = 192.168.2.2/32 Endpoint = 10.0.0.2:60477
That's it!
Run the wg-quick command to start the server:
wg-quick up wg0
you will see output something like:
[#] ip link add wg0 type wireguard [#] wg setconf wg0 /dev/fd/63 [#] ip link set mtu 1420 up dev wg0 [#] ip -4 route add 192.168.2.2/32 dev wg0 [#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eno1 -j MASQUERADE
At this point, you can confirm the status of the interface by using the wg command, which will generate output like:
# wg interface: wg0 public key: _server public key_ private key: (hidden) listening port: 51820 peer: <client public key> endpoint: 10.129.135.30:60477 allowed ips: 192.168.2.2/32
The next step is to activate the secure tunnel that will tunnel all of your client's network traffic, encrypted, through the server.
Be sure to be on the console when you perform this operation.
As all network traffic will now be routed through the tunnel, if you run these commands while connected via ssh you will lose your connection and will not be able to reconnect except by logging in on the machine's console.
As on the server, use the wg-quick command:
wg-quick up wg0
you will see output that looks like:
[#] ip link add wg0 type wireguard [#] wg setconf wg0 /dev/fd/63 [#] ip -4 address add 192.168.2.2/24 dev wg0 [#] ip link set mtu 1420 up dev wg0 [#] ip -6 route add ::/0 dev wg0 table 51820 [#] ip -6 rule add not fwmark 51820 table 51820 [#] ip -6 rule add table main suppress_prefixlength 0 [#] ip6tables-restore -n [#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820 [#] ip -4 rule add not fwmark 51820 table 51820 [#] ip -4 rule add table main suppress_prefixlength 0 [#] sysctl -q net.ipv4.conf.all.src_valid_mark=1 [#] iptables-restore -n
Again, you can check on the status of the client using the wg command, which will generate output similar to:
# wg interface: wg0 public key: <client public key> private key: (hidden) listening port: 60477 fwmark: 0xca6c peer: <server public key> endpoint: 10.0.0.1:51820 allowed ips: 0.0.0.0/0, ::/0
At this point, the tunnel should be up and functioning, and you should be able to issue network commands from your client machine and have them operate as usual, except traffic will be going through the WireGuard tunnel to the server.
Once you have performed network operations from the client, the wg command will show usage data in addition to the configuration information it showed earlier.
For example, a ping might look like this:
# ping oracle.com PING oracle.com (137.254.16.101) 56(84) bytes of data. 64 bytes from bigip-ocoma-cms-adc.oracle.com (137.254.16.101): icmp_seq=1 ttl=240 time=41.9 ms 64 bytes from bigip-ocoma-cms-adc.oracle.com (137.254.16.101): icmp_seq=2 ttl=240 time=42.0 ms --- oracle.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 2002ms tt min/avg/max/mdev = 32.074/32.085/32.106/0.014 ms # wg interface: wg0 public key: <client public key> private key: (hidden) listening port: 60477 fwmark: 0xca6c peer: <server public key> endpoint: 10.0.0.1:51820 allowed ips: 0.0.0.0/0, ::/0 latest handshake: 3 seconds ago transfer: 1.56 KiB received, 756 B sent
You can see that the latest handshake was three seconds ago with 1,560 bytes received from and 756 bytes sent to the tunneled connection.
To close the tunnel and restore normal network operation, use the wg-quick command:
# wg-quick down wg0 [#] wg showconf wg0 [#] ip -4 rule delete table 51820 [#] ip -4 rule delete table main suppress_prefixlength 0 [#] ip -6 rule delete table 51820 [#] ip -6 rule delete table main suppress_prefixlength 0 [#] ip link delete dev wg0 [#] iptables-restore -n [#] ip6tables-restore -n
To shut down the WireGuard server, once again the wg-quick command is used:
# wg-quick down wg0 [#] wg showconf wg0 [#] ip link delete dev wg0 [#] iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eno1 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eno1 -j MASQUERADE
As with any network protocol, connection details are precise, but WireGuard definitely is much easier to configure and use than IPsec. Further, a variety of clients are available for other operating systems as well allowing you to provide secure communications for an entire organization quite easily as compared to other methods.
This factor alone may make WireGuard a de facto standard for VPN creation in the near future.