Overview
Author: Diyaa
Published date: August 3rd, 2024
Last updated: August 18th, 2024
This article explains how to utilize Policy Based Routing (PBR) to a remote cloud virtual private server over a WireGuard VPN tunnel in Pfsense. This will allow for the setup of custom specific host default route modification based on the policy based routing policies.
WARNING
I am using nftables in this setup. Installing nftables over iptables might override your iptables ruleset.
I am using the range of 198.51.100.0/30
on the VPN tunnel between the VPS and Pfsense. Just in case you are asking “Isn’t that a public IP?”. Review RFC5737 for more information about documentation IP ranges.
I am also doing MSS clamping to ensure that the TCP segment size does not exceed the value of the MTU on the WireGuard VPN tunnel. What is MSS clamping you ask? Review RFC4459 for more information on MSS clamping.
Diagram:
This is a diagram overview of what will be configured by following the steps in this article.
VPS setup:
Install Required Packages:
Install all the required packages on your VPS.
Enable IP Forwarding:
Add the IP forwarding kernel module:
Apply kernel modules:
Nftables Ruleset:
Place the config below in the following file /etc/nftables.conf
.
Warning:
I would recommend you avoid using the default WireGuard port. In the event there is a WireGuard exploit in the future someone could run it against all public IPs on the default port. The WireGuard default port is
51820
IMPORTANT
Change the following parameters to meet your needs:.
DEV_WORLD
: The WAN interface of the VPS. You will need to find what interface on your VPS has a public IP on it.Local_Networks
: The ranges of your local network behind your Pfsense router. You can seperate multiple ranges with a comma.SSH_In_Port
: SSH port to allow through nftables ruleset. Not adding this means you won’t be able to SSH into your VPS instance.WireGuard_In_Port
: The WireGuard port to listen on from WAN. I recommend changing this to anything other than the default port (default port is 51820).IPv4_DEV_WireGuard_MSS
: This is the Maximum Segment Size (MSS) value that will be set for outbound TCP connections.
Nftables configuration:
Apply the nftables ruleset:
NOTE
You might face an error where nftables is unable to restart. This can happen if the kernel module for NAT masquerade is not loaded. You just need to reboot your instance
sudo reboot now
and that should fix the issue.
WireGuard Setup:
Generate WireGuard Keys:
You can use this baby script that I made to generate all the WireGuard keys for your VPS and Pfsense router. Run the commands below in a bash shell to generate all the required WireGuard keys.
WireGuard keys generation baby script:
NOTE
You will need the values from the output of these commands later. Paste them in an empty file.
VPS WireGuard Configuration:
IMPORTANT
Things to change in the WireGuard configuration of the VPS:
- Be sure to change the
ListenPort
value to match theWireGuard_In_Port
value in the nftables rulebase configuration.- Replace the
localPrivateKeyAbcAbcAbc=
value with theVPS private key
value from the script in the previous section.- Replace the
remotePublicKeyAbcAbcAbc=
value with thePfsense public key
value from the script in the previous section.- Replace the
presharedkeyabcabcabc=
value with thePreshared key
value from the script in the previous section.- The
AllowedIPs
field needs to include all the IPs that will be forwarded up the tunnel as well as the Pfsense WireGuard tunnel interface IP.
VPS WireGuard configuration:
Important:
The nftables ruleset in this guide has the WireGuard port set to
60000
. You need to match your nftables ruleset value with the value in the configuration below. The value in the configuration below is namedListenPort = 60000
.
Place the configuration above in the following file: /etc/wireguard/wg0.conf
.
Make sure to change the permission of the WireGuard folder after you place your config in the wg0.conf
file.
Enable and start the WireGuard tunnel:
Pfsense Configuration:
Download the WireGuard Package:
Download the WireGuard package from available packages section under the package manager in Pfsense.
Search for WireGuard and install the WireGuard package.
Create a New WireGuard Tunnel:
Create a new WireGuard tunnel on Pfsense:
Important:
Add the
Pfsense private key
you generated in this step and assign the tunnel IP address.
Important:
The
Listen Port
needs to match the WireGuard port configured in the nftables ruleset.
Enable The WireGuard Package:
Enable the WireGuard package:
Add a Peer to The WireGuard Tunnel:
Add a peer to the tunnel:
IMPORTANT
- Add the
VPS private key
you generated in a previous step in thePublic key
box shown in the screenshot below.- Add the
Preshared key
value you created in a previous step in thePre-shared key
box shown in the screenshot below.
Assign The WireGuard Tunnel Interface on Pfsense:
Create a tunnel interface on Pfsense:
Warning
Pfsense does the calculation “automatically” based on the layer 3 protocol. Set the MSS to
1420
. This will set the MSS in the TCP SYN packet to:
- 1420 - 40 = 1380 for IPv4 (20 bytes for IPv4 header and 20 bytes for TCP header)
- 1420 - 60 = 1360 for IPv6 (40 bytes for IPv6 header and 20 bytes for TCP header)
Add The VPS as a Gateway on Pfsense:
Adding a gateway of the remove VPS IP on the WireGuard interface:
Add an Outbound “No NAT” Policy:
IMPORTANT
NAT is eval and you should try to reduce NATing as much as you can in your life. The less you NAT the less kittens die… Read this article.
Warning
I am assuming you have added your routes correctly to the
AllowedIPs
field in the WireGuard configuration on the VPS. You can not turn off NAT if your routes are not configured correctly. You can skip this step if you wish to keep murdering kittens.
NOTE
By default the outbound NAT rules are set to automatic in Pfsense. You will need to set the NAT rules to hybrid to apply manual NAT policies. The manual policies will apply before the the automatic NAT policies.
Scroll to the very bottom and you will see the arrow pointing upward at the bottom right of your screen. Click the button to create a new NAT rule and add it to the top of the NAT rulebase.
Create Access Control Rules on Pfsense:
Create a new firewall rule to utilize policy based routing over the WireGuard tunnel you created.
NOTE
You can customize the rule as you wish. I will be mostly pointing you to the steps of specifying the gateway on the rule (This is how you utilize policy based routing on Pfsense). I am adding this rule to the top of my rules. Feel free to change the positioning of the rule if you have a complex rulebase.
I will be placing this rule on the interface receiving inbound client traffic (client IP as source). You need to place the rule on the inbound interface where the client traffic will be coming from.
You will see the button for adding an access control rule at the bottom of the page with an arrow pointing upward. This will add the rule to the top of the rulebase making it match first.
IMPORTANT
Configure the parameters in the rule. Do NOT save the rule just yet, there is more to configure… go to the next screenshot.
You will see an option above the save button “`Display Advanced”.
IMPORANT
You will have to apply the rules in Pfsense in order for the rule to take affect. You will see a pop up prompting you to apply the rules after you save the rule. You need to click the Apply button for the changes to take affect.
Scroll down until you find the Gateway
option. Set the gateway to the VPS gateway you configured in the previous steps. Now you can save the rule.
Now you have configured policy based routing. However, we are not done yet…
Recommended Rules Setup:
You can allow echo-request (ping) and add a deny rule under the rule in the step above to prevent traffic leak outside the VPN tunnel. This guarantees the host traffic will be going over the VPN tunnel only.
Clone the rule you created in the previous step.
Change the protocol to ICMP
and set the ICMP subtype
to Echo request
.
Note
This is to prevent any traffic that is not permitted in the top 2 rules from bypassing the policy based route.
Clone the second rule you created to create a drop rule.
Set the action to Block
and set the Protocol
to Any
.
Change the Gateway
option for the drop rule to Default
and save the rule.
Your rules should look like this. The idea is to allow TCP, UDP, and echo-request. These are the most common traffic protocols that a host will utilize. The drop rule at the bottom will drop all other traffic. This prevents traffic leak outside the VPN tunnel.
Finally, You have made it to the end. You are now utilizing policy based routing with Pfsense and WireGuard.
Related Notes:
- Link to Home-Page.