This is not a "how to use Terraform" or a "how to use Google Compute" or "how VPNs work" or "how to use Pfsense".
This article does provide an example using Terraform configuration, PFsense configuration and my insight to making it work.
Before I started, I manually created a VPN between PFsense and GCP. I know what pieces were needed to make it work. Building on that work, I took those pieces and created Terraform configurations to do it for me as well as make it repeatable.
You need a few things to do this.
- PFsense with an direct Internet connection. You probably could do it with port forwarding on your firewall, but that is not how I did it.
- PFsense as the static route to the subnet being created in GCP.
- I use a PFsense virtual machine which has a NIC interface on the internal network and one on the Internet network. I have a static route on my internal router to point to the GCP network via the internal IP address of the PFsense vRouter.
- Google Compute account
- Google Compute Project
- Owner or appropriate permissions to create resources. I do not use a service account but I could.
- Internet connection to Google
- Credit card for Google to bill you for resources (after you initial credit is used up) or a billing account with Google
- Terraform (I use windows)
- GCloud client. Not required but really helpful and part of setting the windows account and password
I created a local folder path of c:\terraform\vpn and work exclusively with the VPN in that folder. I assume you have Terraform installed an in the system path.
Before doing this, you may want to jump down to the PFsense setup and generate a preshared key to be used in the VPN Tunnel configuration. Youwil need one from somewhere. I've had problems using too long of a key so I just use PFsense to generate. Step 6.
Terraform configuration with comments
//vpn config
// I use variables for project, zone, region in a variables.tf file in the same folder.
//VPN Tunnel Config
// I suggest keeping the resource name and name = the same. Much easier to follow.
// I have also variableised these but not in the example
resource "google_compute_vpn_tunnel" "vpn-1-tunnel-1" {
name = "vpn-1-tunnel-1"
// IP address of the PFSense gateway
peer_ip = "8.8.8.8"
// same exact string in PFsense
shared_secret = "sharedsupersecretstring"
description = "vpn"
ike_version = "2"
// vpn-gatewate-1 is created below somewhere. It is used a few times like this
target_vpn_gateway = "${google_compute_vpn_gateway.vpn-gateway-1.self_link}"
// I am allowing all traffic between the GCP VPC and my local network. you can restrict as you like.
// the CIDR in quotes inside the brackets can have multiple entries. All in quotes separated by a comma
// e.g. ["1.2.3.4/24", "10.10.0.0/16"]
local_traffic_selector= ["0.0.0.0/0"]
remote_traffic_selector= ["0.0.0.0/0"]
//These are created later and are the defaults for a VPN to establish an IPSec connection
depends_on = [
"google_compute_forwarding_rule.fr_esp",
"google_compute_forwarding_rule.fr_udp500",
"google_compute_forwarding_rule.fr_udp4500",
]
}
// Creating the VPN Gateway/ Later when we create rules, it gets assigned an IP address
// The IP is sticky in that I have created and destroyed and created the VPN again and get the same IP assigned.
resource "google_compute_vpn_gateway" "vpn-gateway-1" {
name = "vpn-gateway-1"
description = "vpn gateway"
network = "${google_compute_network.vpn-network.self_link}"
}
// Creating the VPC Network
resource "google_compute_network" "vpn-network" {
name = "vpn-network"
auto_create_subnetworks = false
}
// Creating the VPC network. This is a class C of my lab Class B network.
// It is used by the compute instances virtual machines
resource "google_compute_subnetwork" "vpn-subnet" {
name = "vpn-subnet"
ip_cidr_range = "172.16.99.0/24"
region = var.region
private_ip_google_access = true
network = "${google_compute_network.vpn-network.self_link}"
}
//Retrieving the IP used by the VPN gateway for forwarding rules
resource "google_compute_address" "vpn-ip" {
name = "vpn-ip"
}
// Setting the route for my internal lab network
resource "google_compute_route" "vpn-1-tunnel-1-route-1" {
name = "vpn-1-tunnel-1-route-1"
network = "${google_compute_network.vpn-network.self_link}"
// next_hop_vpn_tunnel = "vpn-1-tunnel-1"
next_hop_vpn_tunnel = "${google_compute_vpn_tunnel.vpn-1-tunnel-1.self_link}"
dest_range = "172.16.0.0/16"
}
// Default forwarding tule to allow IPsec
resource "google_compute_forwarding_rule" "fr_esp" {
name = "fr-esp"
ip_protocol = "ESP"
ip_address = "${google_compute_address.vpn-ip.address}"
target = "${google_compute_vpn_gateway.vpn-gateway-1.self_link}"
}
// Default forwarding tule to allow IPsec
resource "google_compute_forwarding_rule" "fr_udp500" {
name = "fr-udp500"
ip_protocol = "UDP"
port_range = "500"
ip_address = "${google_compute_address.vpn-ip.address}"
target = "${google_compute_vpn_gateway.vpn-gateway-1.self_link}"
}
// Default forwarding tule to allow IPsec
resource "google_compute_forwarding_rule" "fr_udp4500" {
name = "fr-udp4500"
ip_protocol = "UDP"
port_range = "4500"
ip_address = "${google_compute_address.vpn-ip.address}"
target = "${google_compute_vpn_gateway.vpn-gateway-1.self_link}"
}
// Firewall rule to allow all traffic outbound from the vpn subnet
resource "google_compute_firewall" "vpn-allow-all-egress" {
name = "vpn-allow-all-egress"
// This is required though you can have multiple protocols and ports. for me, it is allow all
allow {
protocol = "all"
}
network = "${google_compute_network.vpn-network.name}"
// the CIDR in quites inside the brackets can have multiple entries. All in quites separate by a comma
// e.g. ["1.2.3.4/24", "10.10.0.0/16"]
destination_ranges = ["172.16.0.0/16"]
direction = "EGRESS"
}
// Firewall rule to allow all traffic inbound into the vpn subnet
resource "google_compute_firewall" "vpn-allow-all-ingress" {
name = "vpn-allow-all-ingress"
network = "${google_compute_network.vpn-network.name}"
// This is required though you can have multiple protocols and ports. for me, it is allow all
allow {
protocol = "all"
}
// the CIDR in quites inside the brackets can have multiple entries. All in quites separate by a comma
// e.g. ["1.2.3.4/24", "10.10.0.0/16"]
source_ranges = ["172.16.0.0/16"]
direction = "INGRESS"
}
Here are my variables
variable "credential_file" {
type = "string"
default = "credfiledownloadedfromgoogle.json"
}
variable "project_id" {
type = "string"
default = "mygoogleproject"
}
variable "region" {
type = "string"
default = "us-central1"
}
variable "zone" {
type = "string"
default = "us-central1-a"
}
provider "google" {
credentials = "${file(var.credential_file)}"
project = "${var.project_id}"
region = "${var.region}"
}
variable "instance_name" {
type = "string"
default = "windows2016vm"
}
Now for my Compute Instance Terraform configuration
resource "google_compute_instance" "default" {
count = 1
name = "${var.instance_name}-${count.index}"
machine_type = var.machine_type
zone = var.zone
boot_disk {
initialize_params {
image = var.image
}
}
// VPN Network created earlier
network_interface {
network = "vpn-network"
subnetwork = "vpn-subnet"
}
}
I save these to main.tf and variables .tf respectively. The Instance is a separate folder with it's own main.tf and variables.tf.
In the vlan folder, run terraform plan
If it looks OK, run terraform plan -out vpn.plan
Next, terraform apply vpn.plan
PFSense
On PFsense, I create the following configuration.
This assumes you have PFsense already setup and working and are just adding an IPSec tunnel.
Local lab network 172.16.0.0/16
Extending subnet 172.16.99.0/24 into GCP as a Hybrid Cloud.
Extending subnet 172.16.99.0/24 into GCP as a Hybrid Cloud.
- Get the IP address of the VPN Gateway. I use gcloud compute addresses list which returns a list of IP addresses then look for the vpn-tunnel and the gateway IP. I will use 30.30.30.30 for my gateway IP.
- Navigate to the PFsense VPN then IPsec page
- Click + Add P1
- Key Exchange Version: IKE V2
- Internet Protocol: IPV4
- Interface: Internet Interface
- Remote Gateway: IP of Google VPN Gateway e.g. 30.30.30.30
- Description: give it a nice description
- Pre-Shared Key: paste the same preshared key used in your Terraform configuration for the VPN Tunnel. e.g. "sharedsupersecretstring" OR generate one and use it in the Terraform configuration
- My Identifier: My IP Address
- Peer Identifier: Peer IP Address
- Encryption Algorithm: AES128-GCM - 128 Bits - 14 (2048 bit)
- Lifetime 36000
- Enable DPD
- Delay 10
- Max failures 5
- Save
- Click Show Phase 2 Entries
- Click + Add P2 (This is to allow the Tunnel Network)
- Mode: Tunnel IPv4
- Local Network: Type: Network - Network : 169.254.0.2/30
- Nat: None
- Remote Network: Type: Network - Network: 169.254.0.1/30
- Protocol: ESP
- Encryption Algorithms: AES125-GCM - 128 Bits
- Hash Algorithms: SHA256
- PFS Key Group: 14 (2048 bits)
- Lifetime 10800
- Save
- Click + Add P2 (This is the subnet rule in GCP which is extended from your lab)
- Mode: Tunnel IPv4
- Local Network: Select Local Network Interface
- Nat: None
- Remote Network: Type: Network - Address: VPN Subnet from Terraform e.g. 172.16.99.0/24
- Protocol: ESP
- Encryption Algorithms: AES125-GCM - 128 Bits
- Hash Algorithms: SHA256
- PFS Key Group: 14 (2048 bits)
- Lifetime 10800
- Save
- Click + Add P2 (This is the local lab network rule )
- Mode: Tunnel IPv4
- Local Network: Type: Network - Address: lab subnet. e.g 172.16.0.0/16
- Nat: None
- Remote Network: Type :Network - Address: VPN Subnet from Terraform e.g. 172.16.99.0/24
- Protocol: ESP
- Encryption Algorithms: AES125-GCM - 128 Bits
- Hash Algorithms: SHA256
- PFS Key Group: 14 (2048 bits)
- Lifetime 10800
- Save
- Repeat for any other local networks you want to adverstise to the google subnet.
Create a Virtual IP
- Click Firewall the Virtual IPs
- Click + Add
- Interface: Internet Interface
- Address(es): 169.254.0.2 / 30
- Description: give is a nice description like GCP VPN TUN IP
Allow IPSec traffic through the firewall. Note, I pass all traffic
- Click Firewall then Rules
- Click IPSec
- Click Add
- Action: Pass
- Address Family: IPV4
- Protocol: Any
- Click Save
That's all. The IPSec tunnel should come up now.
Setting the GCP Windows Instance User and Password Credentials
I use the following command gcloud compute reset-windows-password --user userx windows2016vm-0
You will be rewarded with the account being created, userx in this case, and the randomly created password.
You can get the IP Address of the instance using this command gcloud compute instances describe windows2016vm-0
If you are on a network you allowed across the VPN, you should be able to RDP to the windows machine name.
No comments:
Post a Comment