Skip to content

OPNsense template

opnsense logo

OPNsense

OPNsense is an open-source, easy-to-use, and easy-to-build firewall and routing platform based on FreeBSD.
It offers a wide range of features, including stateful inspection firewall, Virtual Private Network (VPN), and intrusion detection systems, making it suitable for home and business use. Its user-friendly web interface allows for easy configuration and management.

OPNsense Website OPNsense Documentation

Summary

This tutorial will show you how to create and configure an OPNsense appliance with a network interface on a private LAN where will reside your private VMs. It will also shows how to add a floating IP allowing remote access.

Prerequisite

Create the instance

Configure the network

Go to the OpenStack Dashboard, Network section, Networks then click on Create Network.

Enter a Network name

Configure the subnet

Configure a router

Then, configure a router on the freshly created subnet with the external gateway set to ext-floating1.

Naivigate to the Routers section, then click on Create Router :

Fill the router name and select ext-floating1 as External Netowork :

Add an interface to the freshly created subnet by going to Interfaces panel :

Select the correct network and optionally assign a custom IP Address :

Configure the VM

Finally, navigate to the Images section, search for an OPNSense Image then launch an OPNsense one.

Set the instance name :

Select a flavor based on your needs :

Select to private network freshly created :

Select a security group if configured :

Select an OpnSSL RSA keypair

And click on Launch Instance.

Associate a floating IP

To enable remote access to our OPNsense, we will configure a Floating IP.

Navigate to the Floating IPs section then click on Allocate IP to Project :

Once created, click on Associate :

Select your OPNsense appliance :

Configure the Terraform Template

main.tf
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# Configure the OpenStack Provider
terraform {
  required_version = ">= 0.14.0"
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "~> 2.0.0"
    }
  }
}

# Configure the provider
provider "openstack" {
  region      = "dc3-a"
  auth_url    = "https://api.pub1.infomaniak.cloud/identity"
  user_name   = "PCU-XXXXXXX"# (1)!
  tenant_name = "PCP-XXXXXXX"
  password    = "a_super_password"
}

################################################
################                ################
################ Net and Subnet ################
################                ################
################################################
# This is a network created by the provided to create floating ip
data "openstack_networking_network_v2" "ext-floating1" {
  name   = "ext-floating1"
}

# Create the LAN network where our OPNsense will run
resource "openstack_networking_network_v2" "lan-net" {
  name           = "lan-net"
  admin_state_up = "true"
}

data "openstack_networking_network_v2" "lan-net" {
  name   = openstack_networking_network_v2.lan-net.name
}
# The associated subnet
resource "openstack_networking_subnet_v2" "lan-subnet" {
  name       = "lan-subnet"
  network_id = openstack_networking_network_v2.lan-net.id
  cidr       = "10.0.0.0/24"
  ip_version = 4
}

# Create a router and set floating-net at external network
resource "openstack_networking_router_v2" "lan-router" {
  name                = "lan-router"
  external_network_id = data.openstack_networking_network_v2.ext-floating1.id
}

# Attach the router to vpn subnet
resource "openstack_networking_router_interface_v2" "lan-router-interface" {
  router_id = openstack_networking_router_v2.lan-router.id
  subnet_id = openstack_networking_subnet_v2.lan-subnet.id
}

################################################
################                ################
################ Security group ################
################                ################
################################################

resource "openstack_networking_secgroup_v2" "opnsense-sg" {
  name                 = "opnsense-sg"
  description = "Security group for OPNSense"
  # We want our security group fully managed by Terraform
  delete_default_rules = true
}

resource "openstack_networking_secgroup_rule_v2" "opnsense-sg-ssh" {
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = 22
  port_range_max    = 22
  remote_ip_prefix  = "0.0.0.0/0"
  security_group_id = openstack_networking_secgroup_v2.opnsense-sg.id
}

resource "openstack_networking_secgroup_rule_v2" "opnsense-sg-https" {
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = 443
  port_range_max    = 443
  remote_ip_prefix  = "0.0.0.0/0"
  security_group_id = openstack_networking_secgroup_v2.opnsense-sg.id
}

resource "openstack_networking_secgroup_rule_v2" "tcp-metadata-server-ingress" {
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  remote_ip_prefix  = "169.254.169.254/32"
  security_group_id = openstack_networking_secgroup_v2.opnsense-sg.id
}

resource "openstack_networking_secgroup_rule_v2" "tcp-metadata-server-egress" {
  direction         = "egress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  remote_ip_prefix  = "169.254.169.254/32"
  security_group_id = openstack_networking_secgroup_v2.opnsense-sg.id
}

################################################
################                ################
################   Floating IP  ################
################                ################
################################################
data "openstack_networking_port_v2" "opnsense-port" {
  network_id     = openstack_networking_network_v2.lan-net.id
  fixed_ip       = openstack_compute_instance_v2.opnsense-vpn.network[0].fixed_ip_v4
  admin_state_up = "true"
}

resource "openstack_networking_floatingip_v2" "opnsense-vpn-floating" {
  pool        = data.openstack_networking_network_v2.ext-floating1.name
  description = "External IP for OPNSense-vpn"
  port_id     = data.openstack_networking_port_v2.opnsense-port.id
}


# The Keypair form password generation and SSH access
# WARNING: The public key must be in the OpenSSL RSA format (private key must begin with -----BEGIN RSA PRIVATE KEY-----)
resource "openstack_compute_keypair_v2" "opnsense-rsa-keypair" {
  name       = "opnsense-rsa-keypair"
  public_key = "ssh-rsa AAA...."# (2)!
}

# Retrieve OPNSense image ID based on the name
data "openstack_images_image_v2" "opnsense" {
  name_regex  = "^OPNsense"
  most_recent = true
}

# Retrieve flavor info
data "openstack_compute_flavor_v2" "opnsense-flavor" {
  name   = "a2-ram4-disk20-perf1"
}

# OPNsense instance
resource "openstack_compute_instance_v2" "opnsense-vpn" {
  name      = "opnsense-vpn"
  image_id  = data.openstack_images_image_v2.opnsense.id
  flavor_id = data.openstack_compute_flavor_v2.opnsense-flavor.id
  key_pair  = openstack_compute_keypair_v2.opnsense-rsa-keypair.name
  security_groups = [openstack_networking_secgroup_v2.opnsense-sg.name]

  network {
    uuid = openstack_networking_network_v2.lan-net.id
  }

  depends_on = [openstack_networking_subnet_v2.lan-subnet]
}

data "openstack_compute_instance_v2" "opnsense-vpn" {
  id = openstack_compute_instance_v2.opnsense-vpn.id
}

output "opnsense-remote-ip" {
  value = openstack_networking_floatingip_v2.opnsense-vpn-floating.fixed_ip
}
  1. Replace with your project and user IDs.
  2. You must set an A RSA PKCS #1 v1.5 keypair for password encryption.

Deploy to the public cloud

Now that our configuration, we may validate that everything is correct :

> shell
tofu validate
> shell
terraform validate

You should see an output telling that Success! The configuration is valid..

Finally, we can send our configuration to the public cloud:

> shell
tofu apply
> shell
terraform apply

This will preview the resources modifications.
When prompted, type yes to confirm the deployment.

> shell
Plan: 12 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  OpenTofu will perform the actions described above.
  Only 'yes' will be accepted to approve.

You should obtain a result like this:

> shell
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.

Wait a few minutes for the VM to start and That's it.

You are now able to connect to you OPNsense appliance with SSH.

To connect to the Web GUI, you will have to Reset the root password for the console or Retrieve the generated root password.

Retrieve administrator password

The default username of OPNsense is root.
The password is generated during the first boot sequence of the instance.

To retrieve it, get the private key you have used during the deployment process and follow these instructions :

Install or verify you have nova-client installed:

pip install python-novaclient
Retrieve instance password:
nova get-password  <INSTANCE_ID> <PRIVATE_KEY_FILE>
If you do not want to install the nova client, you may use the OpenStack Dashboard or check this convenient tool.

Select your instance and click on Retrieve Password :

07-wininst.png

Select your private key and copy the password :

08-wininst.png

Info

The private key is not uploaded to any servers. The decryption is done by your browser only.

Success

You now have a working OPNsense appliance on the Infomaniak Public Cloud.