Skip to content

Instantly share code, notes, and snippets.

@mikesparr
Last active May 22, 2023 23:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikesparr/6186258dc1e8126783b696f320df409a to your computer and use it in GitHub Desktop.
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
#!/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
@mikesparr
Copy link
Author

VPN between VPC networks for Cloud Build reaching Cloud SQL

Screenshot 2023-05-22 at 5 10 17 PM
Screenshot 2023-05-22 at 5 10 07 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment