Tutorial: OPNSense IPsec VPN to OCI (Oracle Cloud)

Tutorial: OPNSense IPsec VPN to OCI (Oracle Cloud)
🍭
I originally wrote this based on VTI which wasn't working as expected - well, it worked because of a typo which made this fall back to policy based!
Hence this article is corrected and designed as policy based routing.

I had to write this down after more than a few days of trial and error - admittedly due to my own lack of knowledge of IPSec stuff. I only know the basics.

Also, OPNSense (you should really switch from pfsense) has a "New" IPSec connections which is not very much documented and it's counter intuitive. Instead of a single page with all the needed configs, you need to hop around.

I'll do my best for a step by step tutorial. Hopefully you can get your tunnel up in 20min or less.

My setup:

  • ISP (Vodafone-PT) router with a DMZ IP set to 172.26.254.2 - which is my WAN interface of the OPNsense VM. Can't remove this router because it's also an ONT.
  • OPNSense manages everything that is network related (DHCP, DNS, firewall, NAT, etc)
⚠️
I'm an IPSec and pfsense noob. If you are too, you should fit right in.
If you're looking for safe configurations, look somewhere around. I believe i used strong cyphers and have the correct implementation in place. Also, all my connections to and from my OCI instance are whitelisted from my home IP address.

I have no idea what i'm doing. But it's done and it works!

Preparations

What needs to be done on Oracle Cloud Infrastructure

Make sure you have a DRG - Dynamic Routing Gateway. This should be automatically provisioned when you spin up your instances.
I made no changes to it.

DRG configuration - left as default

On the search bar, search for "CPE" - Customer-Premises Equipment

Create one. Put in your WAN address and set Vendor as "Other"

Back to the search bar, search for "VPN" and you'll find "Site-to-site VPN".
Create a new connection. Don't use the wizard.

Give it a name, chose your CPE. CPE IKE identifier will be the ID that OPNSense will use to identify itself. Set it to the Private WAN address.

This is where i was likely stuck for days - despite i set this to my public IP interface on both OCI and OPNSense, after looking at the logs i realized it defaulted to the private WAN address 172.26.254.2. Either due to a bug or me being IPSec-ignorant. I gave up and have chosen that ignorance is bliss.

Chose the DRG, and add all the private networks, from your OPNSense box, that you want to be reachable via the tunnel.

Now, OCI will deploy two tunnels due to redundancy. Each one will have the same configurations - despite different public IPs and IKE keys.

Chose static routing, and define two IP addresses that will be used for the tunnel to communicate. I used an unused subnet of /30 which will give me 2 usable addresses.

Repeat for the second tunnel. It'll provision and after a few seconds you'll find the public addresses. Write those down.

💡
For each tunnel you'll need their
- Public IP Address
- Shared Secret (PSK)
- IPv4 addresses inside the tunnel.

Open each of the tunnels by clicking on their name. You'll find this.

There's a "shared secret". Write it down. You'll need it.

Now, let's tune the supported cyphers for each phase. Edit the tunnel, scroll down, click "Show advanced settings".

Oracle IKE initiation:

  • Set to Initiator or Responder - any side can start the tunnel this way.

NAT-T enabled

  • Set to ENABLED since i'm behind NAT

Dead peer detection

  • Leave as is.

On Phase One (ISAKMP) Configuration, select "Set custom configurations".

This Oracle guide should disclose what are the default configuration for OCI. Since i dislike wizards and "automatic" stuff which you can't really troubleshoot, i forced these defaults.

Phase one settings
Phase two settings.

Repeat for the second tunnel. Remember to chose a different IP address range.

OPNSense configuration

Now, on the firewall configurations!

Go to Firewall, Aliases. Create a new alias with a friendly name and add both public IPs from OCI tunnel's endpoints. This will make life easy because with a single port rule you can have multiple hosts.

Go to Firewall => Rules => WAN. Configure as below.

Save and apply


💡
All the steps below need to be done twice - once per tunnel.

Go to VPN => IPSec => Connections. Click the ➕ sign. Configure like below. Let's configure phase 1.

Your Local Address is the private WAN address, and the remote address is the public IP of this tunnel endpoint.

Save it.

Below you'll find Local Authentication and a plus sign. Click on it

Give it a unique ID for the tunnel and any description. Authentication will be Pre-shared key which we'll configure later.

Do the same for remote authentication. Same ID.

Below there's "Children". This is phase 2.

Add.
This is my full config. I chose to provide all my local subnets (0.0.0.0/0) available, while allowing 10.0.60.0/24. On OCI something similar will happen - we'll filter my subnets over there.

Start Action to Trap+Start will enable to tunnel to restart from either end. DPD Action will set OPNSense to wait for connections (can be set to Start if you'd rather). Rekey time is 3600.

On "Remote" you'll configure the subnets you have configured on OCI end which will be available in the tunnel.


On the left, go to "pre-shared keys". Fill in your local identifier (your private WAN address) and remote identifier (tunnel's public IP)


Go back to VPN => IPSec => Connections. Click enable on bottom right and apply.

Go back to "Status Overview". Tunnel should be up in a few seconds (or start it manually). If not, go to "Log File" - there's useful information there! Also check firewall live logs to see if anything's blocked.

Double check all IP addresses.

Back at OCI, it should show both tunnels up.

But i can't ping from the firewall

Let's configure NAT outbound rules

The previous configuration will work for hosts on your LAN, but not from the firewall itself. Why? Because packets originating from the firewall itself will use the inner tunnel address.

This can easily be checked on the firewall live log. Red is before the fix, blue is after the fix.

If you ignore the blue (i was lazy while showing you the solution beforehand, sorry!), you can test this via ssh.

First ping wil show the source address as the internal tunnel address. Using the -S flag, we can force any other source address which is routeable.

Let's quickly fix this.

On OPNSense, Firewall => NAT => Outbound, make sure you're using Hybrid outbound rule generation.

Create the rule as follow

Read it as, for every packet which origins at this firewall with destination OCI_Subnet_60, translate it to the firewall's LAN address.The Destination Address is an alias for the whole remote subnet. 

IPSec redundancy on OPNSense

We had two tunnels, right?

You should now be able to switch off any of the tunnels and the other will take over. Works flawlessly!