init
This commit is contained in:
commit
1c3c06f120
6 changed files with 361 additions and 0 deletions
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
**/.terraform/*
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
crash.log
|
||||
crash.*.log
|
||||
*.tfvars
|
||||
*.tfvars.json
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
.terraformrc
|
||||
terraform.rc
|
||||
18
.terraform.lock.hcl
generated
Normal file
18
.terraform.lock.hcl
generated
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# This file is maintained automatically by "tofu init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/hashicorp/google" {
|
||||
version = "7.17.0"
|
||||
hashes = [
|
||||
"h1:55qzQsJnDJWg4+xuWuKKM7RykN2C52Fe5VjrQZxTyzY=",
|
||||
"zh:54a635037ba6849fedb5e9a4e45c038fe8692da9d05d786633a222c866b1bbd3",
|
||||
"zh:5703da54cc1e5eccc47678cfdd37a6108618299455f9eb97b2e078fcab73459d",
|
||||
"zh:63841ec08783970b6632d626bbd03b2280e683877ec65522430f10d507bc8de0",
|
||||
"zh:8dc39e425b456be1543f55598fe15ae94b2cacce13fddfe5412fa6086c39340f",
|
||||
"zh:9d2cc02b387d3256800c35099ec034bb4b05bf819a50e28182536a1dc030f8e4",
|
||||
"zh:b379befb2a6389df66bb957fe56cc5eeda795fec28d663d8e80879706fce6e0b",
|
||||
"zh:e67c1f491c222aecd5c477b9a92d1efecea9ed8ebda9d886db983c6f81e8697a",
|
||||
"zh:f18c5559f16de7ed0e2ec633f04d7bc65ca5977a8711118207b4d77e4345bcf3",
|
||||
"zh:f80311efc8139381713a8946f6f1924ecfe533366ada0bf590b4426534861754",
|
||||
]
|
||||
}
|
||||
155
README.md
Normal file
155
README.md
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
|
||||
# GCP to Local Home Network VPN Setup
|
||||
|
||||
This project uses OpenTofu (or Terraform) to configure a VPC and VPN on Google Cloud Platform (GCP), establishing a Site-to-Site VPN connection with a home server (e.g., Raspberry Pi).
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
- **GCP Side**:
|
||||
- **VPC Network**: `rpi-vpn-test-vpc`
|
||||
- **Subnet**: `rpi-vpn-subnet` (`10.10.0.0/24`)
|
||||
- **VPN Gateway**: Classic VPN Gateway
|
||||
- **Firewall Rules**:
|
||||
- Allow VPN and internal traffic (ICMP, TCP, UDP)
|
||||
- Allow SSH access (for test VM)
|
||||
- **Compute Engine**: `vpn-test-vm` (e2-micro instance for connection testing)
|
||||
|
||||
- **Local Side (User Environment)**:
|
||||
- Raspberry Pi (or home server) behind a router running a VPN daemon (e.g., StrongSwan, Libreswan)
|
||||
- Port Forwarding required: UDP `500`, `4500` -> Raspberry Pi internal IP
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **GCP Account & Project**: A billing-enabled GCP project is required.
|
||||
2. **OpenTofu/Terraform Installed**: Refer to the [OpenTofu Installation Guide](https://opentofu.org/docs/intro/install/).
|
||||
3. **GCP Authentication**: Authenticate locally via terminal.
|
||||
```bash
|
||||
gcloud auth application-default login
|
||||
```
|
||||
4. **Check Home Public IP**: Identify your current public IP address.
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Configure Variables (`terraform.tfvars`)
|
||||
|
||||
Create a `terraform.tfvars` file in the project root and configure it according to your environment.
|
||||
|
||||
```hcl
|
||||
project_id = "YOUR_GCP_PROJECT_ID"
|
||||
home_public_ip = "123.123.123.123"
|
||||
vpn_psk = "your-secret-password"
|
||||
home_internal_cidr = "192.168.0.0/24"
|
||||
ssh_public_key = "ssh-rsa AAA..."
|
||||
```
|
||||
|
||||
### 2. Initialize and Apply
|
||||
|
||||
```bash
|
||||
# Initialize
|
||||
tofu init
|
||||
|
||||
# Plan
|
||||
tofu plan
|
||||
|
||||
# Apply
|
||||
tofu apply
|
||||
```
|
||||
|
||||
### 3. Check Results
|
||||
|
||||
Upon completion of `tofu apply`, the following information will be output:
|
||||
|
||||
- `gcp_vpn_ip`: The public IP of the GCP VPN Gateway (target for Raspberry Pi connection).
|
||||
- `vm_public_ip`: The public IP of the test VM.
|
||||
|
||||
## Raspberry Pi Configuration Guide (StrongSwan with swanctl)
|
||||
|
||||
This guide uses the modern `swanctl` (VICI protocol) provided by StrongSwan 6.x+.
|
||||
|
||||
1. **Install StrongSwan and Plugins**:
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y strongswan libcharon-extra-plugins libstrongswan-extra-plugins libstrongswan-standard-plugins strongswan-pki
|
||||
```
|
||||
|
||||
2. **Configure `/etc/swanctl/swanctl.conf`**:
|
||||
Replace the content of `/etc/swanctl/swanctl.conf` with the following configuration.
|
||||
|
||||
> **Note**: Replace `YOUR_HOME_PUBLIC_IP`, `GCP_VPN_IP`, `YOUR_PSK`, and `HOME_CIDR` with your actual values.
|
||||
|
||||
```conf
|
||||
connections {
|
||||
gcp-vpn {
|
||||
remote_addrs = GCP_VPN_IP
|
||||
|
||||
local {
|
||||
auth = psk
|
||||
id = YOUR_HOME_PUBLIC_IP
|
||||
}
|
||||
|
||||
remote {
|
||||
auth = psk
|
||||
id = GCP_VPN_IP
|
||||
}
|
||||
|
||||
children {
|
||||
gcp-net {
|
||||
local_ts = 192.168.0.0/24 # Your Home Network CIDR (e.g., 192.168.2.0/24)
|
||||
remote_ts = 10.10.0.0/24 # GCP Network CIDR
|
||||
|
||||
esp_proposals = aes256-sha1-modp2048
|
||||
start_action = start
|
||||
}
|
||||
}
|
||||
|
||||
version = 2
|
||||
proposals = aes256-sha1-modp2048
|
||||
}
|
||||
}
|
||||
|
||||
secrets {
|
||||
ike-gcp {
|
||||
id = GCP_VPN_IP
|
||||
secret = "YOUR_PSK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Apply & Start**:
|
||||
```bash
|
||||
# Load configuration
|
||||
sudo swanctl --load-all
|
||||
|
||||
# Check status (should show ESTABLISHED)
|
||||
sudo swanctl --list-sas
|
||||
```
|
||||
|
||||
4. **Enable IP Forwarding**:
|
||||
For the Raspberry Pi to act as a gateway and forward traffic to other devices, you must enable packet forwarding.
|
||||
|
||||
Edit `/etc/sysctl.conf` and uncomment (or add) the following line:
|
||||
```conf
|
||||
net.ipv4.ip_forward=1
|
||||
```
|
||||
|
||||
Apply changes:
|
||||
```bash
|
||||
sudo sysctl -p
|
||||
```
|
||||
|
||||
- **Important**: Ensure UDP `500` and `4500` ports are port-forwarded to the Raspberry Pi's internal IP in your router settings.
|
||||
- **Routing Setup (Home Router)**: You must configure a **Static Route** on your home router so that other devices in your home network can reach the GCP network.
|
||||
- **Destination Network**: `10.10.0.0`
|
||||
- **Subnet Mask**: `255.255.255.0` (or `/24`)
|
||||
- **Gateway**: The internal IP of your Raspberry Pi (e.g., `192.168.2.x`)
|
||||
|
||||
Without this, only the Raspberry Pi itself can access the GCP network. Other devices (like your PC) won't know that traffic for `10.10.0.x` should go through the Raspberry Pi.
|
||||
|
||||
## Connection Test
|
||||
|
||||
1. Verify the tunnel status is "Established" in the [VPN](https://console.cloud.google.com/hybrid/vpn/gateways) menu of the GCP Console.
|
||||
2. SSH into the test VM (`vpn-test-vm`).
|
||||
3. Ping a device in the home internal network (e.g., Raspberry Pi).
|
||||
```bash
|
||||
ping 192.168.0.x
|
||||
```
|
||||
133
main.tf
Normal file
133
main.tf
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
provider "google" {
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
}
|
||||
|
||||
data "google_compute_zones" "available" {
|
||||
region = var.region
|
||||
}
|
||||
|
||||
resource "google_compute_network" "vpc" {
|
||||
name = "rpi-vpn-test-vpc"
|
||||
auto_create_subnetworks = false
|
||||
}
|
||||
|
||||
resource "google_compute_subnetwork" "subnet" {
|
||||
name = "rpi-vpn-subnet"
|
||||
ip_cidr_range = "10.10.0.0/24"
|
||||
region = var.region
|
||||
network = google_compute_network.vpc.id
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "allow_internal" {
|
||||
name = "allow-vpn-internal"
|
||||
network = google_compute_network.vpc.name
|
||||
|
||||
allow {
|
||||
protocol = "icmp"
|
||||
}
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["0-65535"]
|
||||
}
|
||||
allow {
|
||||
protocol = "udp"
|
||||
ports = ["0-65535"]
|
||||
}
|
||||
|
||||
source_ranges = ["10.10.0.0/24", var.home_internal_cidr]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "allow_ssh" {
|
||||
name = "allow-ssh-from-my-ip"
|
||||
network = google_compute_network.vpc.name
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["22"]
|
||||
}
|
||||
|
||||
target_tags = ["vpn-test-vm"]
|
||||
source_ranges = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
resource "google_compute_vpn_gateway" "target_gateway" {
|
||||
name = "rpi-vpn-gateway"
|
||||
network = google_compute_network.vpc.id
|
||||
region = var.region
|
||||
}
|
||||
|
||||
resource "google_compute_address" "vpn_static_ip" {
|
||||
name = "vpn-static-ip"
|
||||
region = var.region
|
||||
}
|
||||
|
||||
resource "google_compute_vpn_tunnel" "tunnel" {
|
||||
name = "rpi-vpn-tunnel"
|
||||
peer_ip = var.home_public_ip
|
||||
shared_secret = var.vpn_psk
|
||||
target_vpn_gateway = google_compute_vpn_gateway.target_gateway.id
|
||||
|
||||
local_traffic_selector = ["10.10.0.0/24"]
|
||||
remote_traffic_selector = [var.home_internal_cidr]
|
||||
|
||||
depends_on = [
|
||||
google_compute_forwarding_rule.fr_esp,
|
||||
google_compute_forwarding_rule.fr_udp500,
|
||||
google_compute_forwarding_rule.fr_udp4500,
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_compute_forwarding_rule" "fr_esp" {
|
||||
name = "fr-esp"
|
||||
ip_protocol = "ESP"
|
||||
ip_address = google_compute_address.vpn_static_ip.address
|
||||
target = google_compute_vpn_gateway.target_gateway.id
|
||||
}
|
||||
|
||||
resource "google_compute_forwarding_rule" "fr_udp500" {
|
||||
name = "fr-udp500"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "500"
|
||||
ip_address = google_compute_address.vpn_static_ip.address
|
||||
target = google_compute_vpn_gateway.target_gateway.id
|
||||
}
|
||||
|
||||
resource "google_compute_forwarding_rule" "fr_udp4500" {
|
||||
name = "fr-udp4500"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "4500"
|
||||
ip_address = google_compute_address.vpn_static_ip.address
|
||||
target = google_compute_vpn_gateway.target_gateway.id
|
||||
}
|
||||
|
||||
resource "google_compute_route" "route_to_home" {
|
||||
name = "route-to-home"
|
||||
network = google_compute_network.vpc.name
|
||||
dest_range = var.home_internal_cidr
|
||||
priority = 1000
|
||||
next_hop_vpn_tunnel = google_compute_vpn_tunnel.tunnel.id
|
||||
}
|
||||
|
||||
resource "google_compute_instance" "test_vm" {
|
||||
name = "vpn-test-vm"
|
||||
machine_type = "e2-micro"
|
||||
zone = data.google_compute_zones.available.names[0]
|
||||
tags = ["vpn-test-vm"]
|
||||
|
||||
boot_disk {
|
||||
initialize_params {
|
||||
image = "debian-cloud/debian-12"
|
||||
}
|
||||
}
|
||||
|
||||
network_interface {
|
||||
subnetwork = google_compute_subnetwork.subnet.id
|
||||
access_config {
|
||||
}
|
||||
}
|
||||
|
||||
metadata = {
|
||||
ssh-keys = "${var.ssh_user}:${var.ssh_public_key}"
|
||||
}
|
||||
}
|
||||
6
outputs.tf
Normal file
6
outputs.tf
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
output "gcp_vpn_ip" {
|
||||
value = google_compute_address.vpn_static_ip.address
|
||||
}
|
||||
output "vm_public_ip" {
|
||||
value = google_compute_instance.test_vm.network_interface.0.access_config.0.nat_ip
|
||||
}
|
||||
36
variables.tf
Normal file
36
variables.tf
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
variable "project_id" {
|
||||
description = "GCP Project ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
default = "asia-northeast3"
|
||||
}
|
||||
|
||||
variable "home_public_ip" {
|
||||
description = "Public IP of the home router"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "home_internal_cidr" {
|
||||
description = "Home internal network CIDR (e.g., 192.168.0.0/24)"
|
||||
type = string
|
||||
default = "192.168.0.0/24"
|
||||
}
|
||||
|
||||
variable "vpn_psk" {
|
||||
description = "VPN Pre-Shared Key"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "ssh_user" {
|
||||
description = "SSH Username"
|
||||
type = string
|
||||
default = "bumpsoo"
|
||||
}
|
||||
|
||||
variable "ssh_public_key" {
|
||||
description = "SSH Public Key content"
|
||||
type = string
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue