Tip
This is the documentation for the 24.06 version. Looking for the documentation of the latest version? Have a look here.
WireGuard VPN for Remote Access¶
Current versions of TNSR support using WireGuard as a means of providing a remote access VPN for clients. This can also be referred to as a “mobile VPN” or a “road warrior VPN”.
Note
Though WireGuard is a true peer-to-peer VPN and has no internal concept of “client” or “server”, it can behave in ways similar to those roles, so for the sake of making this easy to follow, this document will still use those terms. See Design Style for details.
This is different from a site-to-site VPN in several ways, notably:
The remote peer endpoints are unknown and dynamic, because clients connect from any location with Internet access, such as mobile phones, hotels, coffee shops, libraries, and so on.
There are no networks behind the remote peers, the remote clients are all accessing resources on the server side or beyond (e.g. routed networks, Internet hosts)
Required Information¶
Determine Addresses¶
This TNSR instance uses addresses inside the larger subnet 10.31.0.0/16
which makes it easier for clients to route traffic to any network located behind
the server. Thus, when a client wishes to only reach resources routed by the
server, they can use that network instead of listing server networks
individually.
A remote access WireGuard VPN requires a dedicated subnet used to communicate
between the peers inside the VPN. In this case, the server will use
10.31.111.0/24
.
Addresses inside this subnet must be allocated manually to peers as WireGuard does not have a mechanism by which it can allocate these addresses automatically.
In this example, the server will use the first address in the subnet,
10.31.111.1
. As peers are added, they will receive the next available
address in the subnet.
Tip
Use IP address management software or a spreadsheet to track allocated addresses.
Generate Keys¶
Before starting, generate a set of keys for the WireGuard server at a shell prompt:
$ wg genkey | tee ra.prv.key | wg pubkey > ra.pub.key
$ cat ra.prv.key
iK24AJ251et8cBe3+QsmE6BV0X8jRcf8Wzy5ukkEXFY=
$ cat ra.pub.key
LQZRVWTPMSNfB+T7OjgLmWwK8nE4kVw+Xme0gwinFXQ=
Each client should generate their own keys and give the public key to the TNSR administrator configuring the VPN. The server does not need to know the client private keys, only the public keys.
Settings Summary¶
The table Example WireGuard Remote Access Configuration contains the required information and other settings which form the WireGuard Remote Access VPN for this example.
Item |
Value |
---|---|
TNSR WG Private Key |
|
TNSR WG Public Key |
|
TNSR Local Network |
|
TNSR Server Address |
|
TNSR Local WG Port |
|
TNSR WG Interface |
|
Alice WG Interface |
|
Alice WG Public Key |
|
Bob WG Interface |
|
Bob WG Public Key |
|
For each peer, the remote access VPN server only requires its public key and an interface address the client will use to access the VPN.
Configure WireGuard Instance¶
The next step is to start configuring the WireGuard instance, filling in the values from the table above:
tnsr(config)# interface wireguard 1
tnsr(config-wireguard)# description WireGuard Remote Access VPN
tnsr(config-wireguard)# source-address 203.0.113.31
tnsr(config-wireguard)# port 51820
tnsr(config-wireguard)# private-key base64 iK24AJ251et8cBe3+QsmE6BV0X8jRcf8Wzy5ukkEXFY=
Do not exit at the end, continue on to setup the peers.
Configure WireGuard Peers¶
Now enter the configuration for the two peers using the values from the table.
Set the peer allowed-prefix
to the single address in the client subnet
allocated to this client. Ensure this value uses a /32
prefix length.
tnsr(config-wireguard)# peer 1
tnsr(config-wireguard-peer)# description Alice
tnsr(config-wireguard-peer)# allowed-prefix 10.31.111.2/32
tnsr(config-wireguard-peer)# public-key base64 WTayq0ZP4pWUV4eAk3FnRAPskw+Qcvf86S3mCiH0rAA=
tnsr(config-wireguard-peer)# exit
tnsr(config-wireguard)# peer 2
tnsr(config-wireguard-peer)# description Bob
tnsr(config-wireguard-peer)# allowed-prefix 10.31.111.3/32
tnsr(config-wireguard-peer)# public-key base64 FzyY/KFTL1FSz8jJJ7fyscIvGchqxSU5izxWWgD/SmA=
tnsr(config-wireguard-peer)# exit
Repeat as needed for more peers, then exit the WireGuard instance configuration:
tnsr(config-wireguard)# exit
Configure WireGuard Interface¶
Next is the wg1
interface which the server will use to communicate with
peers inside the tunnel. Use the chosen server address with a prefix length
reflective of the entire subnet here, in this case /24
.
tnsr(config)# interface wg1
tnsr(config-interface)# enable
tnsr(config-interface)# description WireGuard Remote Access VPN
tnsr(config-interface)# ip address 10.31.111.1/24
tnsr(config-interface)# exit
tnsr(config)#
Configure ACLs¶
If the external-facing interface from which the WireGuard clients will connect has an input ACL limiting inbound traffic, then it must be adjusted to allow the incoming WireGuard clients.
Note
If the external interface does not have an input ACL, this can be skipped.
For a brief look at a basic ACL configuration, see the ACL section of the ZTP guide.
The ACL must allow traffic to the IP address and port configured on the WireGuard instance. Since remote access client addresses are unknown, the ACL rule must allow WireGuard traffic from any source.
tnsr(config)# acl internet-in
tnsr(config-acl)# rule 50
tnsr(config-acl-rule)# description Allow WireGuard
tnsr(config-acl-rule)# action permit
tnsr(config-acl-rule)# ip-version ipv4
tnsr(config-acl-rule)# source address 0.0.0.0/0
tnsr(config-acl-rule)# destination address 203.0.113.31/32
tnsr(config-acl-rule)# destination port 51820 51820
tnsr(config-acl-rule)# protocol udp
tnsr(config-acl-rule)# exit
tnsr(config-acl)# exit
tnsr(config)#
If the same interface has a restrictive output ACL it may need a similar rule there but with the source and destination swapped.
Additionally, if there are ACLs on other internal interfaces, these may also require adjustment.
Tip
To restrict traffic to or from WireGuard clients, output and input ACLs can
be added to the wgX
interface.
Configure Peer Routes¶
Each peer must have an entry in the routing table informing TNSR that the
individual address is reachable through the wg1
interface.
Warning
This cannot be summarized by using a larger prefix route, each client address must be listed separately.
The routes in this case are added to the default route table:
tnsr(config)# route table default
This example adds a separate route for each of the peers, Alice and Bob:
tnsr(config-route-table)# route 10.31.111.2/32
tnsr(config-rttbl4-next-hop)# description WG RA Peer Route for Alice
tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 wg1
tnsr(config-rttbl4-next-hop)# exit
tnsr(config-route-table)# route 10.31.111.3/32
tnsr(config-rttbl4-next-hop)# description WG RA Peer Route for Bob
tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 wg1
tnsr(config-rttbl4-next-hop)# exit
Repeat for each additional peer, then exit the route table configuration:
tnsr(config-route-table)# exit
That completes the server-side configuration on TNSR.
Configure Clients¶
There are WireGuard clients for a variety of platforms. So many that it is difficult to list and describe them all and how they operate. There are clients for major desktop and mobile operating system and other less common devices as well. Some WireGuard clients have a graphical interface (GUI) and others use configuration files. Thankfully, in most cases these clients use identical, or at least similar, terminology.
This is the general form of a basic WireGuard client configuration:
[Interface]
PrivateKey = < private to the client >
Address = < allocated VPN interface address >
[Peer]
PublicKey = < server public key >
Endpoint = < server address>:<server port >
AllowedIPs = < server-side network(s) >
For clients with a GUI, it should be relatively intuitive to map those fields to similar fields in the GUI. Often clients have a means to import configuration files as well, which means a crafted configuration could be imported to bypass any differences in the GUI.
This example configuration is for the client peer Alice:
[Interface]
PrivateKey = < not shown >
Address = 10.31.111.2/24
[Peer]
PublicKey = LQZRVWTPMSNfB+T7OjgLmWwK8nE4kVw+Xme0gwinFXQ=
Endpoint = 203.0.113.31:51820
AllowedIPs = 10.31.0.0/16
This example configuration is for the client peer Bob:
[Interface]
PrivateKey = < not shown >
Address = 10.31.111.3/24
[Peer]
PublicKey = LQZRVWTPMSNfB+T7OjgLmWwK8nE4kVw+Xme0gwinFXQ=
Endpoint = 203.0.113.31:51820
AllowedIPs = 10.31.0.0/16
Note that in both cases the server side configuration in the [Peer]
section
is identical. Only the private key and client address are different.
With a client configuration in place, a client should be able to activate the VPN and transmit traffic to hosts behind the server.
Allowing Internet Access¶
Another common use case for remote access VPNs is for the server to act as an Internet gateway for clients. This can be leveraged for private browsing across an untrusted local network, geographic relocation of traffic, or other uses where such traffic is centrally routed.
The configuration thus far is nearly complete to allow this except for a few simple items.
NAT¶
For clients on the WireGuard VPN to reach the Internet, TNSR must apply NAT to their traffic to mask the true source address. This example assumes NAT is already configured on TNSR for other local hosts.
See also
For a brief look at a basic NAT configuration, see the NAT section of the ZTP guide.
To perform NAT on client traffic originating from the wg1
interface, set it
as an inside
NAT interface:
tnsr(config)# interface wg1
tnsr(config-interface)# ip nat inside
tnsr(config-interface)# exit
Allowed IP Address Change¶
To make the client route all of its traffic through the WireGuard VPN, the client configuration must be changed to reflect this behavior.
Note that in the previous examples the AllowedIPs
entry in the [Peer]
section were set to the subnet reachable through the VPN:
[Peer]
AllowedIPs = 10.31.0.0/16
To route all traffic through, set this value to 0.0.0.0/0
instead:
[Peer]
AllowedIPs = 0.0.0.0/0
Deactivate and activate the VPN client so it will use the new settings.
DNS¶
Part of private and/or secure browsing is controlling the DNS servers used by clients to resolve hostnames to IP addresses.
If clients send their DNS requests to a third party public DNS server on the Internet, such as CloudFlare or Google, this configuration may not be necessary.
For VPN clients to use the Unbound DNS resolver on TNSR for DNS, first allow the VPN client subnet to access the resolver:
tnsr(config)# unbound server
tnsr(config-unbound)# access-control 10.31.111.0/24 allow
tnsr(config-unbound)# exit
Next, set the VPN client to use an address on TNSR for DNS. The address to use
varies based on how Unbound was configured, but is likely the LAN interface
address, such as 10.31.0.1
in this example.
See also
For a brief look at a basic Unbound configuration, see the DNS section of the ZTP guide.
Now add the DNS server to the [Interface]
section of the client
configuration:
[Interface]
DNS = 10.31.0.1
Deactivate and activate the VPN client so it will use the new settings.