Skip to content

Instantly share code, notes, and snippets.

@defanator
Last active April 11, 2026 01:10
Show Gist options
  • Select an option

  • Save defanator/1ab16a8585b2875dee397b8d58f3fdb4 to your computer and use it in GitHub Desktop.

Select an option

Save defanator/1ab16a8585b2875dee397b8d58f3fdb4 to your computer and use it in GitHub Desktop.
#!/bin/bash
set -euo pipefail
# Default values
PROJECT=""
REGION=""
NETWORK=""
SUBNET=""
SA_URI=""
PORTS="80"
# Prerequisites:
# - gcloud CLI installed and configured
# - An existing projectID and a VPC network created in that project
# - A valid Service Attachment URI from F5 NGINXaaS
# Function to display usage
usage() {
cat << EOF
Usage: $0 --project PROJECT --region REGION --network NETWORK --subnet SUBNET --service-attachment SA_URI [--ports PORTS]
Options:
--project GCP Project ID
--region GCP Region
--network VPC Network name
--subnet GCP Subnet for Backend Connectivity (must be in the same region and network)
--service-attachment Service Attachment Self Link
--ports Comma-separated list of ports (default: 80)
--help Show this help message
Note: Proxy subnet and public IP will be automatically created as 'psc-proxy-subnet' and 'psc-vip' respectively.
These resources will not be deleted, if deleted this script will create new ones.
Example:
$0 --project my-project --region us-central1 --network my-vpc --subnet my-subnet \\
--service-attachment "projects/producer-proj/regions/us-central1/serviceAttachments/my-service" \\
--ports "80,443,8080"
EOF
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--project)
PROJECT="$2"
shift 2
;;
--region)
REGION="$2"
shift 2
;;
--network)
NETWORK="$2"
shift 2
;;
--service-attachment)
SA_URI="$2"
shift 2
;;
--ports)
PORTS="$2"
shift 2
;;
--subnet)
SUBNET="$2"
shift 2
;;
--help|-h)
usage
exit 0
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
done
# Validate required parameters
missing_params=()
[[ -z "$PROJECT" ]] && missing_params+=("--project")
[[ -z "$REGION" ]] && missing_params+=("--region")
[[ -z "$NETWORK" ]] && missing_params+=("--network")
[[ -z "$SUBNET" ]] && missing_params+=("--subnet")
[[ -z "$SA_URI" ]] && missing_params+=("--service-attachment")
PROXY_SUBNET="${NETWORK}-psc-proxy-subnet"
VIPNAME="${NETWORK}-psc-vip"
if [[ ${#missing_params[@]} -gt 0 ]]; then
echo "Error: Missing required parameters: ${missing_params[*]}"
usage
exit 1
fi
# Create proxy-only subnet (skip if exists)
echo "Creating proxy-only subnet if it doesn't already exist..."
if ! gcloud compute networks subnets describe $PROXY_SUBNET --region=$REGION --project=$PROJECT >/dev/null 2>&1; then
gcloud compute networks subnets create $PROXY_SUBNET \
--project=$PROJECT --region=$REGION \
--network=$NETWORK \
--range=192.168.1.0/24 \
--purpose=REGIONAL_MANAGED_PROXY \
--role=ACTIVE
fi
echo "Using proxy-only subnet: $PROXY_SUBNET"
# Create regional VIP address (skip if exists)
echo "Creating regional VIP address..."
if ! gcloud compute addresses describe $VIPNAME --region=$REGION --project=$PROJECT >/dev/null 2>&1; then
gcloud compute addresses create $VIPNAME --region=$REGION --project=$PROJECT
fi
VIP=$(gcloud compute addresses describe $VIPNAME --region=$REGION --project=$PROJECT --format='get(address)')
echo "Using VIP address: $VIP"
# Convert comma-separated ports to array
IFS=',' read -ra PORTS_ARRAY <<< "$PORTS"
for P in "${PORTS_ARRAY[@]}"; do
echo "Processing port $P..."
neg_name="${NETWORK}-psc-neg-$P"
be_name="${NETWORK}-be-$P"
tp_name="${NETWORK}-tp-$P"
fr_name="${NETWORK}-fr-$P"
# Create Network Endpoint Group (skip if exists)
if ! gcloud compute network-endpoint-groups describe ${neg_name} --region=$REGION --project=$PROJECT >/dev/null 2>&1; then
gcloud compute network-endpoint-groups create ${neg_name} \
--project=$PROJECT --region=$REGION \
--network-endpoint-type=private-service-connect \
--psc-target-service="$SA_URI" \
--network=$NETWORK \
--subnet=$SUBNET \
--producer-port=$P
fi
# Create Backend Service (skip if exists) - NO HEALTH CHECKS for PSC
if ! gcloud compute backend-services describe ${be_name} --region=$REGION --project=$PROJECT >/dev/null 2>&1; then
gcloud compute backend-services create ${be_name} \
--project=$PROJECT --region=$REGION \
--protocol=TCP --load-balancing-scheme=EXTERNAL_MANAGED
# Add backend to service
gcloud compute backend-services add-backend ${be_name} \
--project=$PROJECT --region=$REGION \
--network-endpoint-group=${neg_name} \
--network-endpoint-group-region=$REGION
fi
# Create Target TCP Proxy (skip if exists)
if ! gcloud compute target-tcp-proxies describe ${tp_name} --region=$REGION --project=$PROJECT >/dev/null 2>&1; then
gcloud compute target-tcp-proxies create ${tp_name} \
--project=$PROJECT --region=$REGION --backend-service=${be_name}
fi
# Create Forwarding Rule (skip if exists)
if ! gcloud compute forwarding-rules describe ${fr_name} --region=$REGION --project=$PROJECT >/dev/null 2>&1; then
gcloud compute forwarding-rules create ${fr_name} \
--project=$PROJECT --region=$REGION \
--address=$VIP --network=$NETWORK \
--target-tcp-proxy=${tp_name} --target-tcp-proxy-region=$REGION \
--ports=$P --load-balancing-scheme=EXTERNAL_MANAGED \
--network-tier=PREMIUM --ip-protocol=TCP
fi
echo "Completed setup for port $P"
done
echo "Setup complete! Public Virtual IP: $VIP"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment