Last active
August 29, 2024 15:11
-
-
Save mikesparr/6186258dc1e8126783b696f320df409a to your computer and use it in GitHub Desktop.
Example setting up Cloud VPN on Google Cloud Platform (GCP) to connect two VPCs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
##################################################################### | |
# REFERENCES | |
# - https://cloud.google.com/sql/docs/postgres/configure-private-ip | |
# - https://cloud.google.com/build/docs/private-pools/set-up-private-pool-to-use-in-vpc-network#setup-private-connection | |
# - https://cloud.google.com/network-connectivity/docs/vpn/how-to/creating-ha-vpn2#gcloud | |
# - https://cloud.google.com/network-connectivity/docs/vpn/how-to/creating-ha-vpn (optional with peering) | |
##################################################################### | |
export PROJECT_ID=$(gcloud config get-value project) | |
export PROJECT_USER=$(gcloud config get-value core/account) # set current user | |
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)") | |
export IDNS=${PROJECT_ID}.svc.id.goog # workflow identity domain | |
export GCP_REGION="us-central1" # CHANGEME (OPT) | |
export GCP_ZONE="us-central1-a" # CHANGEME (OPT) | |
export NETWORK_NAME="default" | |
# configure gcloud sdk | |
gcloud config set compute/region $GCP_REGION | |
gcloud config set compute/zone $GCP_ZONE | |
############################################################# | |
# ORGANIZATION | |
# assumptions | |
# - one cloud build connects with multiple cloud sql instances in different projects | |
# projects | |
# - project 1: cloud sql tenant | |
# - project 2: cloud build | |
############################################################# | |
export FOLDER=$FOLDER # optional - my personal folder | |
export BILLING=$BILLING # optional - my billing ID shortcut | |
export PROJECT_1="mike-test-vpn-sql" | |
export PROJECT_2="mike-test-vpn-cicd" | |
# create projects | |
gcloud projects create $PROJECT_1 --folder $FOLDER | |
gcloud projects create $PROJECT_2 --folder $FOLDER | |
# link billing account | |
gcloud beta billing projects link --billing-account=$BILLING $PROJECT_1 | |
gcloud beta billing projects link --billing-account=$BILLING $PROJECT_2 | |
# enable apis | |
gcloud services enable compute.googleapis.com \ | |
storage.googleapis.com \ | |
servicenetworking.googleapis.com \ | |
sqladmin.googleapis.com \ | |
--project $PROJECT_1 | |
gcloud services enable compute.googleapis.com \ | |
storage.googleapis.com \ | |
servicenetworking.googleapis.com \ | |
cloudbuild.googleapis.com \ | |
--project $PROJECT_2 | |
############################################################# | |
# NETWORKING | |
# - network 1: cloud sql (private tenant) | |
# - reserved range: 10.200.0.0/16 | |
# - network 2: cloud build (private pool) | |
# - reserved range: 10.210.0.0/16 | |
############################################################# | |
export NETWORK_1="database" | |
export NETWORK_2="devops" | |
export NETWORK_1_RESERVED_RANGE_NAME="google-managed-services" | |
export NETWORK_1_RESERVED_RANGE="10.200.0.0" | |
export NETWORK_2_RESERVED_RANGE_NAME="google-managed-services" | |
export NETWORK_2_RESERVED_RANGE="10.210.0.0" | |
# create networks (custom-mode) | |
gcloud compute networks create $NETWORK_1 \ | |
--subnet-mode=custom \ | |
--project $PROJECT_1 | |
gcloud compute networks create $NETWORK_2 \ | |
--subnet-mode=custom \ | |
--project $PROJECT_2 | |
# allocate private ranges | |
gcloud compute addresses create $NETWORK_1_RESERVED_RANGE_NAME \ | |
--global \ | |
--purpose=VPC_PEERING \ | |
--addresses=$NETWORK_1_RESERVED_RANGE \ | |
--prefix-length=16 \ | |
--network=projects/$PROJECT_1/global/networks/$NETWORK_1 \ | |
--project $PROJECT_1 | |
gcloud compute addresses create $NETWORK_2_RESERVED_RANGE_NAME \ | |
--global \ | |
--purpose=VPC_PEERING \ | |
--addresses=$NETWORK_2_RESERVED_RANGE \ | |
--prefix-length=16 \ | |
--network=projects/$PROJECT_2/global/networks/$NETWORK_2 \ | |
--project $PROJECT_2 | |
# create peering for managed services | |
gcloud services vpc-peerings connect \ | |
--service=servicenetworking.googleapis.com \ | |
--ranges=$NETWORK_1_RESERVED_RANGE_NAME \ | |
--network=$NETWORK_1 \ | |
--project=$PROJECT_1 | |
gcloud services vpc-peerings connect \ | |
--service=servicenetworking.googleapis.com \ | |
--ranges=$NETWORK_2_RESERVED_RANGE_NAME \ | |
--network=$NETWORK_2 \ | |
--project=$PROJECT_2 | |
############################################################# | |
# DATABASE (POSTGRES) | |
############################################################# | |
export POSTGRES_INSTANCE="test-db" | |
export POSTGRES_VERSION="POSTGRES_14" | |
export POSTGRES_TIER="db-f1-micro" | |
export POSTGRES_PORT=5432 | |
export DB_USER="testuser" | |
export DB_NAME="widgets" | |
export DB_PASS=$(openssl rand -base64 32) | |
gcloud beta sql instances create $POSTGRES_INSTANCE \ | |
--database-version=$POSTGRES_VERSION \ | |
--tier=$POSTGRES_TIER \ | |
--network=projects/$PROJECT_1/global/networks/$NETWORK_1 \ | |
--no-assign-ip \ | |
--allocated-ip-range-name=$NETWORK_1_RESERVED_RANGE_NAME \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_1 | |
# get internal IP | |
export POSTGRES_HOST=$(gcloud beta sql instances describe $POSTGRES_INSTANCE --format="value(ipAddresses.ipAddress)" --project $PROJECT_1) | |
# lock down postgres (admin) user [manually input at prompt] | |
gcloud sql users set-password postgres \ | |
--instance=$POSTGRES_INSTANCE \ | |
--prompt-for-password \ | |
--project=$PROJECT_1 | |
# create test user | |
gcloud sql users create $DB_USER \ | |
--instance=$POSTGRES_INSTANCE \ | |
--password=$DB_PASS \ | |
--project=$PROJECT_1 | |
# create database | |
gcloud sql databases create $DB_NAME \ | |
--instance=$POSTGRES_INSTANCE \ | |
--project=$PROJECT_1 | |
############################################################# | |
# CLOUD BUILD (PRIVATE POOLS) | |
############################################################# | |
export PRIVATEPOOL_ID="myco-cicd" | |
export PRIVATEPOOL_MACHINE_TYPE="e2-standard-2" | |
export PRIVATEPOOL_DISK_SIZE_GB="100" | |
gcloud builds worker-pools create $PRIVATEPOOL_ID \ | |
--project=$PROJECT_2 \ | |
--region=$GCP_REGION \ | |
--peered-network=projects/$PROJECT_2/global/networks/$NETWORK_2 \ | |
--worker-machine-type=$PRIVATEPOOL_MACHINE_TYPE \ | |
--worker-disk-size=$PRIVATEPOOL_DISK_SIZE_GB \ | |
--no-public-egress | |
############################################################# | |
# CLOUD VPN | |
# - project1-network1 (sql1) : project2-network2 (cicd) | |
# - optionally create more per sql tenant projects | |
############################################################# | |
export GW_NAME_1="gw-db-1" | |
export GW_NAME_2="gw-cicd" | |
export IP_STACK="IPV4_ONLY" | |
export ROUTER_NAME_1="rtr-db-1" | |
export ROUTER_NAME_2="rtr-cicd" | |
export TUNNEL_NAME_GW1_IF0="tun-$GW_NAME_1-if0" | |
export TUNNEL_NAME_GW1_IF1="tun-$GW_NAME_1-if1" | |
export TUNNEL_NAME_GW2_IF0="tun-$GW_NAME_2-if0" | |
export TUNNEL_NAME_GW2_IF1="tun-$GW_NAME_2-if1" | |
export ROUTER_1_IF_0="rtr-$GW_NAME_1-if0" | |
export ROUTER_1_IF_1="rtr-$GW_NAME_1-if1" | |
export ROUTER_2_IF_0="rtr-$GW_NAME_2-if0" | |
export ROUTER_2_IF_1="rtr-$GW_NAME_2-if1" | |
export PEER_NAME_GW1_IF0="peer-$GW_NAME_1-if0" | |
export PEER_NAME_GW1_IF1="peer-$GW_NAME_1-if1" | |
export PEER_NAME_GW2_IF0="peer-$GW_NAME_2-if0" | |
export PEER_NAME_GW2_IF1="peer-$GW_NAME_2-if1" | |
export PEER_ASN_1="65200" | |
export PEER_ASN_2="65210" | |
export RAND_KEY=$(openssl rand -base64 32) | |
export SHARED_SECRET=$RAND_KEY # shared secret between gateways | |
export IKE_VERSION="2" | |
# create vpn gateways | |
gcloud compute vpn-gateways create $GW_NAME_1 \ | |
--network=$NETWORK_1 \ | |
--region=$GCP_REGION \ | |
--stack-type=$IP_STACK \ | |
--project=$PROJECT_1 | |
gcloud compute vpn-gateways create $GW_NAME_2 \ | |
--network=$NETWORK_2 \ | |
--region=$GCP_REGION \ | |
--stack-type=$IP_STACK \ | |
--project=$PROJECT_2 | |
# create cloud routers | |
gcloud compute routers create $ROUTER_NAME_1 \ | |
--region=$GCP_REGION \ | |
--network=$NETWORK_1 \ | |
--asn=$PEER_ASN_1 \ | |
--project=$PROJECT_1 | |
gcloud compute routers create $ROUTER_NAME_2 \ | |
--region=$GCP_REGION \ | |
--network=$NETWORK_2 \ | |
--asn=$PEER_ASN_2 \ | |
--project=$PROJECT_2 | |
# fetch IP addresses of gateway interfaces (optional) | |
export GW_1_INTERFACE_0_IP_ADDRESS=$(gcloud compute vpn-gateways describe $GW_NAME_1 --format="value(vpnInterfaces[0].ipAddress)" --project $PROJECT_1) | |
export GW_1_INTERFACE_1_IP_ADDRESS=$(gcloud compute vpn-gateways describe $GW_NAME_1 --format="value(vpnInterfaces[1].ipAddress)" --project $PROJECT_1) | |
export GW_2_INTERFACE_0_IP_ADDRESS=$(gcloud compute vpn-gateways describe $GW_NAME_2 --format="value(vpnInterfaces[0].ipAddress)" --project $PROJECT_2) | |
export GW_2_INTERFACE_1_IP_ADDRESS=$(gcloud compute vpn-gateways describe $GW_NAME_2 --format="value(vpnInterfaces[1].ipAddress)" --project $PROJECT_2) | |
# generate 'other project' gateway paths | |
export GW_1_EXT="projects/$PROJECT_1/regions/$GCP_REGION/vpnGateways/$GW_NAME_1" | |
export GW_2_EXT="projects/$PROJECT_2/regions/$GCP_REGION/vpnGateways/$GW_NAME_2" | |
# create vpn tunnels | |
gcloud compute vpn-tunnels create $TUNNEL_NAME_GW1_IF0 \ | |
--peer-gcp-gateway=$GW_2_EXT \ | |
--region=$GCP_REGION \ | |
--ike-version=$IKE_VERSION \ | |
--shared-secret=$SHARED_SECRET \ | |
--router=$ROUTER_NAME_1 \ | |
--vpn-gateway=$GW_NAME_1 \ | |
--interface=0 \ | |
--project=$PROJECT_1 | |
gcloud compute vpn-tunnels create $TUNNEL_NAME_GW1_IF1 \ | |
--peer-gcp-gateway=$GW_2_EXT \ | |
--region=$GCP_REGION \ | |
--ike-version=$IKE_VERSION \ | |
--shared-secret=$SHARED_SECRET \ | |
--router=$ROUTER_NAME_1 \ | |
--vpn-gateway=$GW_NAME_1 \ | |
--interface=1 \ | |
--project=$PROJECT_1 | |
gcloud compute vpn-tunnels create $TUNNEL_NAME_GW2_IF0 \ | |
--peer-gcp-gateway=$GW_1_EXT \ | |
--region=$GCP_REGION \ | |
--ike-version=$IKE_VERSION \ | |
--shared-secret=$SHARED_SECRET \ | |
--router=$ROUTER_NAME_2 \ | |
--vpn-gateway=$GW_NAME_2 \ | |
--interface=0 \ | |
--project=$PROJECT_2 | |
gcloud compute vpn-tunnels create $TUNNEL_NAME_GW2_IF1 \ | |
--peer-gcp-gateway=$GW_1_EXT \ | |
--region=$GCP_REGION \ | |
--ike-version=$IKE_VERSION \ | |
--shared-secret=$SHARED_SECRET \ | |
--router=$ROUTER_NAME_2 \ | |
--vpn-gateway=$GW_NAME_2 \ | |
--interface=1 \ | |
--project=$PROJECT_2 | |
# add router interfaces | |
export BGP_1_TO_2_IF0="169.254.0.2" # router 1 | |
export BGP_2_TO_1_IF0="169.254.0.1" # router 2 | |
export BGP_1_TO_2_IF1="169.254.1.2" # router 1 | |
export BGP_2_TO_1_IF1="169.254.1.1" # router 2 | |
gcloud compute routers add-interface $ROUTER_NAME_1 \ | |
--interface-name=$ROUTER_1_IF_0 \ | |
--ip-address=$BGP_2_TO_1_IF0 \ | |
--mask-length=30 \ | |
--vpn-tunnel=$TUNNEL_NAME_GW1_IF0 \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_1 | |
gcloud compute routers add-interface $ROUTER_NAME_1 \ | |
--interface-name=$ROUTER_1_IF_1 \ | |
--ip-address=$BGP_2_TO_1_IF1 \ | |
--mask-length=30 \ | |
--vpn-tunnel=$TUNNEL_NAME_GW1_IF1 \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_1 | |
gcloud compute routers add-interface $ROUTER_NAME_2 \ | |
--interface-name=$ROUTER_2_IF_0 \ | |
--ip-address=$BGP_1_TO_2_IF0 \ | |
--mask-length=30 \ | |
--vpn-tunnel=$TUNNEL_NAME_GW2_IF0 \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_2 | |
gcloud compute routers add-interface $ROUTER_NAME_2 \ | |
--interface-name=$ROUTER_2_IF_1 \ | |
--ip-address=$BGP_1_TO_2_IF1 \ | |
--mask-length=30 \ | |
--vpn-tunnel=$TUNNEL_NAME_GW2_IF1 \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_2 | |
# create bgp peer sessions | |
gcloud compute routers add-bgp-peer $ROUTER_NAME_1 \ | |
--peer-name=$PEER_NAME_GW1_IF0 \ | |
--interface=$ROUTER_1_IF_0 \ | |
--peer-ip-address=$BGP_1_TO_2_IF0 \ | |
--peer-asn=$PEER_ASN_2 \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_1 | |
gcloud compute routers add-bgp-peer $ROUTER_NAME_1 \ | |
--peer-name=$PEER_NAME_GW1_IF1 \ | |
--peer-ip-address=$BGP_1_TO_2_IF1 \ | |
--interface=$ROUTER_1_IF_1 \ | |
--peer-asn=$PEER_ASN_2 \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_1 | |
gcloud compute routers add-bgp-peer $ROUTER_NAME_2 \ | |
--peer-name=$PEER_NAME_GW2_IF0 \ | |
--interface=$ROUTER_2_IF_0 \ | |
--peer-ip-address=$BGP_2_TO_1_IF0 \ | |
--peer-asn=$PEER_ASN_1 \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_2 | |
gcloud compute routers add-bgp-peer $ROUTER_NAME_2 \ | |
--peer-name=$PEER_NAME_GW2_IF1 \ | |
--peer-ip-address=$BGP_2_TO_1_IF1 \ | |
--interface=$ROUTER_2_IF_1 \ | |
--peer-asn=$PEER_ASN_1 \ | |
--region=$GCP_REGION \ | |
--project=$PROJECT_2 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
VPN between VPC networks for Cloud Build reaching Cloud SQL