OPNsense Firewall Site to Site VPN Configuration to AWS VPC

Abdul Wajid
6 min readDec 26, 2022

In this blog post we will talk about how to connect your OPNsense firewall in your homelab to an Amazon Web Services (AWS) Virtual Private Cloud (VPC).

OPNsense is a free, open-source firewall that is popular among home lab enthusiasts and small businesses. It provides advanced security features such as intrusion detection and prevention, VPN support, and bandwidth management.

In this tutorial, we will walk you through the steps to set up a secure connection between your OPNsense firewall and an AWS VPC. This will allow you to easily access resources within your VPC, such as EC2 instances and RDS databases, from your home network.

Before we begin, you will need to have an AWS account and an OPNsense firewall set up in your home lab. You will also need to have a basic understanding of networking concepts and some familiarity with the AWS management console.

So let’s get started!

Here is what you need to get this going:

  1. AWS VPC and Subnet.
  2. A Virtual Private Gateway
  3. A Customer Gateway
  4. A Site-to-Site VPN Connection

If you dont have one already, you can set this up using below Terraform Template:

provider "aws" {
region = "us-west-2"
access_key = var.AWS_ACCESS_KEY_ID
secret_key = var.AWS_SECRET_ACCESS_KEY
token = var.AWS_SESSION_TOKEN
}

resource "aws_instance" "EC2" {
ami = "ami-0ceecbb0f30a902a6"
instance_type = "t2.micro"
subnet_id = aws_subnet.prod-vpc-us-west-2a.id
associate_public_ip_address = false
vpc_security_group_ids = [aws_security_group.allow-inbound-ssh-http.id]
}

resource "aws_security_group" "allow-inbound-ssh-http" {
name = "allow-inbound-ssh-http"
description = "allow inbound ssh/http access"
vpc_id = aws_vpc.prod-vpc-us-west-2.id
ingress {
cidr_blocks = ["0.0.0.0/0"]
from_port = 22
protocol = "tcp"
to_port = 22
}
ingress {
cidr_blocks = ["0.0.0.0/0"]
from_port = 80
protocol = "tcp"
to_port = 80
}
ingress {
cidr_blocks = ["0.0.0.0/0"]
protocol = "icmp"
from_port = "-1"
to_port = "-1"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}



resource "aws_vpc" "prod-vpc-us-west-2" {
cidr_block = "10.20.0.0/16"
tags = {
"name" = "prod-vpc-us-west-2"
}
}

resource "aws_subnet" "prod-vpc-us-west-2a" {
availability_zone = "us-west-2a"
cidr_block = "10.20.10.0/24"
vpc_id = aws_vpc.prod-vpc-us-west-2.id
tags = {
"name" = "prod-vpc-us-west-2a"
}
}

resource "aws_subnet" "prod-vpc-us-west-2b" {
availability_zone = "us-west-2b"
cidr_block = "10.20.20.0/24"
vpc_id = aws_vpc.prod-vpc-us-west-2.id
tags = {
"name" = "prod-vpc-us-west-2b"
}
}

resource "aws_internet_gateway" "igw-us-west-2" {

}

resource "aws_internet_gateway_attachment" "igw-attach-us-west-2" {
internet_gateway_id = aws_internet_gateway.igw-us-west-2.id
vpc_id = aws_vpc.prod-vpc-us-west-2.id
}


resource "aws_route_table" "rt-prod-vpc-us-west" {
vpc_id = aws_vpc.prod-vpc-us-west-2.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw-us-west-2.id
}
propagating_vgws = [aws_vpn_gateway.vpgw-us-west-2.id]
}

resource "aws_main_route_table_association" "main-route-table-association" {
vpc_id = aws_vpc.prod-vpc-us-west-2.id
route_table_id = aws_route_table.rt-prod-vpc-us-west.id
}
resource "aws_vpn_gateway" "vpgw-us-west-2" {
availability_zone = "us-west-2a"
vpc_id = aws_vpc.prod-vpc-us-west-2.id
}

resource "aws_customer_gateway" "cgw-opnsense" {
type = "ipsec.1"
bgp_asn = 65000
ip_address = "50.99.22.58" #Update this with your public IP.
device_name = "opnsense"
}

resource "aws_vpn_connection" "vpn-conn-opnsense" {
type = "ipsec.1"
customer_gateway_id = aws_customer_gateway.cgw-opnsense.id
vpn_gateway_id = aws_vpn_gateway.vpgw-us-west-2.id
static_routes_only = true
}

resource "aws_vpn_connection_route" "rt-vpn-conn-opnsense" {
vpn_connection_id = aws_vpn_connection.vpn-conn-opnsense.id
destination_cidr_block = "10.10.10.0/24"

}

output "tunnel1-address" {
description = "IP Address of the Tunnel-1"
value = aws_vpn_connection.vpn-conn-opnsense.tunnel1_address
}

output "tunnel1-pskey" {
description = "Pre-shared Key for Tunnel-1"
value = nonsensitive(aws_vpn_connection.vpn-conn-opnsense.tunnel1_preshared_key)
}

output "tunnel2-address" {
description = "IP Address of the Tunnel-2"
value = aws_vpn_connection.vpn-conn-opnsense.tunnel2_address
}

output "tunnel2-pskey" {
description = "Pre-shared Key for Tunnel-2"
value = nonsensitive(aws_vpn_connection.vpn-conn-opnsense.tunnel2_preshared_key)
}

output "private-ip-test-ec2" {
description = "Private IP Address of the test EC2 Instance"
value = aws_instance.EC2.private_ip
}

Make sure to update the aws_customer_gateway resource with your public IP.

You can execute the terraform apply after saving the contents of this code to main.tf in your working directory. Make sure to update the AWS credentials.

This code will create below resources:

  • An AWS VPC with 10.20.0.0/16 CIDR range.
  • Two subnets in 10.20.10.0/24 and 10.20.20.0/24 CIDR range.
  • An Internet Gateway for your subnets. (This is not required for this demo but I have this for my lab environment which I can spin up any time using the code).
  • A route table and its association with the VPC. Also route propagation is enabled.
  • An AWS VPN Gateway.
  • An AWS Customer Gateway.
  • An AWS VPN Connection and your home lab route.

After you execute the terraform apply you will receive below output that you will need to configure the Tunnels in OPNsense appliance.

The pre-shared keys are sensitive values and in terraform code I am using nonsensitive() function to print those values. This is not recommended in production environments.

Lets login to your OPNsense firewall to configure the tunnels. Navigate to VPN → IPSec → Tunnel Settings and Click the + Icon in Phase-1.

Fill in below parameters as below:

General Information:

Phase 1 proposal (Authentication)

Click Save and lets add the Phase-2 for Tunnel-1.

Click the + Icon next to the edit icon in Phase-1. Fill in the information as below:

Now Navigate to Status Overview to see if the tunnel is connected.

Lets take a look at the AWS Side:

Lets perform the connectivity test:

This is how my local network looks like:

Lets do a ping & tracert test:

In conclusion, connecting your OPNsense firewall to your AWS VPC is a great way to securely access cloud resources from your home lab. By following the steps outlined in this tutorial, you can easily set up a VPN connection and configure your OPNsense firewall to connect to your AWS VPC. Don’t forget to test the connection to ensure everything is working as expected.

With a secure connection between your OPNsense firewall and your AWS VPC, you can take advantage of all the benefits the cloud has to offer. Whether you’re using your home lab for personal projects or running a small business, connecting your OPNsense firewall to your AWS VPC is an essential step in making the most of the cloud.

Let me know in the comments if you face any problems.

--

--