Skip to content

Instantly share code, notes, and snippets.

@mikesparr
Created March 29, 2024 18:35
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/c902f6979a6752f1d62c7dba87befdee to your computer and use it in GitHub Desktop.
Save mikesparr/c902f6979a6752f1d62c7dba87befdee to your computer and use it in GitHub Desktop.
Experiment using Google Cloud Secure Web Proxy and Cloud NAT
#!/usr/bin/env bash
#####################################################################
# REFERENCES
# - https://cloud.google.com/secure-web-proxy/docs/initial-setup-steps
# - https://cloud.google.com/certificate-manager/docs/deploy-google-managed-regional
# - https://cloud.google.com/secure-web-proxy/docs/quickstart
# - https://cloud.google.com/secure-web-proxy/docs/enable-tls-inspection (OPTIONAL)
#####################################################################
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"
# enable apis
gcloud services enable compute.googleapis.com \
storage.googleapis.com \
certificatemanager.googleapis.com \
networksecurity.googleapis.com \
networkservices.googleapis.com
# configure gcloud sdk
gcloud config set compute/region $GCP_REGION
gcloud config set compute/zone $GCP_ZONE
############################################################
# Networking
############################################################
export NETWORK_NAME="demo-network"
export RESERVED_RANGE_NAME="google-managed-services"
export PROXY_SUBNET_NAME="secure-proxy"
export PROXY_SUBNET_RANGE="192.168.0.0/23"
export TEST_SUBNET_NAME="test-vms"
export TEST_SUBNET_RANGE="10.201.0.0/24"
export AUTHORIZATION_NAME="cert-auth-dns"
export DOMAIN_NAME="proxy.msparr.com" # CHANGEME
export CERTIFICATE_NAME="proxy-cert"
# create network (custom-mode)
gcloud compute networks create $NETWORK_NAME \
--subnet-mode=custom
# create ssh firewall rule
gcloud compute firewall-rules create allow-ssh \
--direction=INGRESS \
--priority=1000 \
--network=$NETWORK_NAME \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=0.0.0.0/0
# create proxy subnet
gcloud compute networks subnets create $PROXY_SUBNET_NAME \
--purpose=REGIONAL_MANAGED_PROXY \
--role=ACTIVE \
--region=$GCP_REGION \
--network=$NETWORK_NAME \
--range=$PROXY_SUBNET_RANGE \
--enable-private-ip-google-access
# create vm subnet
gcloud compute networks subnets create $TEST_SUBNET_NAME \
--region=$GCP_REGION \
--network=$NETWORK_NAME \
--range=$TEST_SUBNET_RANGE \
--enable-private-ip-google-access
# create dns authorization for regional managed cert
gcloud certificate-manager dns-authorizations create $AUTHORIZATION_NAME \
--domain="$DOMAIN_NAME" \
--type=PER_PROJECT_RECORD \
--location=$GCP_REGION
# describe dns auth to get CNAME for updating records
gcloud certificate-manager dns-authorizations describe $AUTHORIZATION_NAME \
--location=$GCP_REGION
# update your DNS records to add CNAME as this example:
# - cname: _acme-challenge_tprcqly2gkqiluqe.proxy.msparr.com
# - data: b7f8c0a6-3637-47ec-ba93-6f1c0bbbf267.2.us-central1.authorize.certificatemanager.goog.
# create regional managed certificate
gcloud certificate-manager certificates create $CERTIFICATE_NAME \
--domains=$DOMAIN_NAME \
--dns-authorizations=$AUTHORIZATION_NAME \
--location=$GCP_REGION
############################################################
# Secure Web Proxy
############################################################
export INSTANCE_NAME="swp-test-vm"
export POLICY_NAME="policy1"
export POLICY_FILE_NAME="policy.yaml"
export RULE_NAME="allow-wikipedia-org"
export RULE_FILE_NAME="rule.yaml"
export GATEWAY_NAME="swp1"
export GATEWAY_FILE_NAME="gateway.yaml"
export GATEWAY_ADDRESSES="[10.201.0.200]"
export GATEWAY_PORTS="[443]"
# create policy file (skipped TLS inspection / CA setup for simplicity)
cat > $POLICY_FILE_NAME << EOF
description: basic Secure Web Proxy policy
name: projects/$PROJECT_ID/locations/$GCP_REGION/gatewaySecurityPolicies/$POLICY_NAME
EOF
# create the swp policy
gcloud network-security gateway-security-policies import $POLICY_NAME \
--source=$POLICY_FILE_NAME \
--location=$GCP_REGION
# create swp rules file (skipped TLS inspection / CA setup for simplicity)
cat > $RULE_FILE_NAME << EOF
name: projects/$PROJECT_ID/locations/$GCP_REGION/gatewaySecurityPolicies/$POLICY_NAME/rules/$RULE_NAME
description: Allow wikipedia.org
enabled: true
priority: 1
basicProfile: ALLOW
sessionMatcher: host() == 'wikipedia.org'
EOF
# create the swp rule
gcloud network-security gateway-security-policies rules import $RULE_NAME \
--source=$RULE_FILE_NAME \
--location=$GCP_REGION \
--gateway-security-policy=$POLICY_NAME
# create the gateway config file
cat > $GATEWAY_FILE_NAME << EOF
name: projects/$PROJECT_ID/locations/$GCP_REGION/gateways/$GATEWAY_NAME
type: SECURE_WEB_GATEWAY
addresses: $GATEWAY_ADDRESSES
ports: $GATEWAY_PORTS
certificateUrls: ["projects/$PROJECT_ID/locations/$GCP_REGION/certificates/$CERTIFICATE_NAME"]
gatewaySecurityPolicy: projects/$PROJECT_ID/locations/$GCP_REGION/gatewaySecurityPolicies/$POLICY_NAME
network: projects/$PROJECT_ID/global/networks/$NETWORK_NAME
subnetwork: projects/$PROJECT_ID/regions/$GCP_REGION/subnetworks/$TEST_SUBNET_NAME
scope: samplescope
EOF
# create the gateway
gcloud network-services gateways import $GATEWAY_NAME \
--source=$GATEWAY_FILE_NAME \
--location=$GCP_REGION
############################################################
# Testing the proxy
############################################################
export INSTANCE_NAME="swp-test-vm"
# create a VM instance for testing (doesn't use proxy-only subnet which is reserved per region)
gcloud compute instances create $INSTANCE_NAME \
--subnet=$TEST_SUBNET_NAME \
--zone=$GCP_ZONE \
--image-project=debian-cloud \
--image-family=debian-11
# test the connection (allowed)
gcloud compute ssh $INSTANCE_NAME \
--zone $GCP_ZONE \
-- curl -x https://10.201.0.200:443 https://wikipedia.org --proxy-insecure
# test the connection (denied)
gcloud compute ssh $INSTANCE_NAME \
--zone $GCP_ZONE \
-- curl -x https://10.201.0.200:443 https://yahoo.com --proxy-insecure
# next steps (optional):
# - https://cloud.google.com/secure-web-proxy/docs/use-tags
# - https://cloud.google.com/secure-web-proxy/docs/use-url-list
# - https://cloud.google.com/secure-web-proxy/docs/assign-static-ip-addresses-for-egress-traffic
@mikesparr
Copy link
Author

Google Cloud Secure Web Proxy Demo

This experiment illustrates setting up Secure Web Proxy and testing initial policy against an approved external domain (wikipedia.org) and an unapproved domain (yahoo.com).

Allowed host (success)

You can see that the approved domain reaches the target host (which subsequently redirects but still reached them)

Screenshot 2024-03-29 at 12 29 36 PM

Not allowed host (denied)

Here a random host did not meet the gateway policy domain so it was denied

Screenshot 2024-03-29 at 12 30 46 PM

Certificate creation

You can use your own domain and DNS as I did in this example, or leverage Cloud DNS per docs examples. This is how I set up mine using a domain I control outside of GCP.

Fetch CNAME from cert config

Screenshot 2024-03-29 at 10 29 21 AM

Configure DNS

Screenshot 2024-03-29 at 10 29 09 AM
Screenshot 2024-03-29 at 10 29 37 AM

@mikesparr
Copy link
Author

Cloud NAT Automatic Provisioning

Cloud NAT was provisioned automatically when I set up the Secure Web Proxy above.

Screenshot 2024-03-29 at 12 56 41 PM

It was in "automatic" mode (preferred if no static IPs needed) to allow Google Cloud to handle scaling IPs and ports as needed.

Screenshot 2024-03-29 at 12 56 53 PM

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