Private Service Connect - Using PSC Backends to Access a Producer Service

About this codelab
schedule72 minutes
subjectLast updated February 3, 2025
account_circleWritten by Lorin Price

Private Service Connect enables service producers to expose services privately from one VPC network to another. Consumers can access producer services through either PSC endpoints or PSC Backends.

The focus of this codelab is PSC Backends. PSC Backends are used in conjunction with Google Cloud proxy load balancers (either Application or Network). Using PSC Backends provides more granular consumer side controls such as:

  • Deeper observability and logging
  • Cloud Armor Integration
  • Custom URLs
  • Advanced Traffic Management
  • Custom TLS certificates

In this codelab, you will learn how to create a Private Service Connect Backend with the Global External Application Load Balancer to privately access a producer service in another network.

  • Create and configure a PSC Backend associated with the Global External Application Load Balancer
  • Configure an Apache managed web service and expose it as a PSC service through a Service Attachment
  • Create SSL certificates to terminate SSL on Internal and External Application Load Balancers
  • Configure a Cloud DNS public zone for accessing the PSC service

What you'll need

  • A Google Cloud project with owner permissions

2. Test Environment

The environment that you will create will consist of a Consumer VPC and Producer VPC. In the Producer VPC, you will deploy a managed instance group from an instance template that builds an open source Apache web service. You'll also deploy a test-vm to ensure proper local functionality of the service. You'll expose the Apache service as a PSC Producer service via a Service Attachment.

In the Consumer VPC you'll deploy a Global External Application Load Balancer with a PSC Backend service pointing to the Apache service. You'll then set up a public DNS zone to access the PSC service on the public Internet.

31e7497bf3d9035c.png

3. Setup and Requirements

Self-paced environment setup

  1. Sign-in to the Google Cloud Console and create a new project or reuse an existing one. If you don't already have a Gmail or Google Workspace account, you must create one.

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • The Project name is the display name for this project's participants. It is a character string not used by Google APIs. You can always update it.
  • The Project ID is unique across all Google Cloud projects and is immutable (cannot be changed after it has been set). The Cloud Console auto-generates a unique string; usually you don't care what it is. In most codelabs, you'll need to reference your Project ID (typically identified as PROJECT_ID). If you don't like the generated ID, you might generate another random one. Alternatively, you can try your own, and see if it's available. It can't be changed after this step and remains for the duration of the project.
  • For your information, there is a third value, a Project Number, which some APIs use. Learn more about all three of these values in the documentation.
  1. Next, you'll need to enable billing in the Cloud Console to use Cloud resources/APIs. Running through this codelab won't cost much, if anything at all. To shut down resources to avoid incurring billing beyond this tutorial, you can delete the resources you created or delete the project. New Google Cloud users are eligible for the $300 USD Free Trial program.

Start Cloud Shell

While Google Cloud can be operated remotely from your laptop, in this codelab you will be using Google Cloud Shell, a command line environment running in the Cloud.

From the Google Cloud Console, click the Cloud Shell icon on the top right toolbar:

55efc1aaa7a4d3ad.png

It should only take a few moments to provision and connect to the environment. When it is finished, you should see something like this:

7ffe5cbb04455448.png

This virtual machine is loaded with all the development tools you'll need. It offers a persistent 5GB home directory, and runs on Google Cloud, greatly enhancing network performance and authentication. All of your work in this codelab can be done within a browser. You do not need to install anything.

4. Before you begin

Enable APIs

Inside Cloud Shell, make sure that your project id is set up

gcloud config list project
gcloud config set project [YOUR-PROJECT-NAME]
export project=YOUR-PROJECT-NAME
export region=us-central1
echo $project
echo $region

Enable all necessary services

gcloud services enable compute.googleapis.com
gcloud services enable servicedirectory.googleapis.com
gcloud services enable dns.googleapis.com

5. Producer VPC Setup

Create VPC Network

From Cloud Shell

gcloud compute networks create producer-vpc --subnet-mode custom

Create Subnets

Two general purpose subnets will be deployed in the producer-vpc. The service-subnet will be used to deploy the Apache web service VMs as well as the load balancer forwarding rule. The test-client-subnet will be in a different region and will be used to deploy a VM to test the Apache service with Global Access enabled.

From Cloud Shell

gcloud compute networks subnets create service-subnet \
    --network=producer-vpc \
    --range=10.0.0.0/28 \
    --region=$region

From Cloud Shell

gcloud compute networks subnets create test-client-subnet \
    --network=producer-vpc \
    --range=10.0.1.0/28 \
    --region=us-east4

We must also deploy a proxy only subnet to be used with the Regional Internal Application Load Balancer.

From Cloud Shell

gcloud compute networks subnets create central-proxy-subnet \
    --network=producer-vpc \
    --range=10.100.101.0/24 \
    --region=$region \
    --purpose=REGIONAL_MANAGED_PROXY \
    --role=ACTIVE

When a PSC service is deployed, each unique service needs a corresponding PSC NAT subnet to be associated with the Service Attachment. This subnet should be sized appropriately depending on the number of expected connected endpoints.

From Cloud Shell

gcloud compute networks subnets create psc-nat-subnet \
    --network=producer-vpc \
    --region=$region \
    --range=10.100.100.0/24 \
    --purpose=PRIVATE_SERVICE_CONNECT

Create Cloud NAT

A Cloud NAT is required to install the proper packages for our producer services.

From Cloud Shell

gcloud compute routers create central-cr \
    --network=producer-vpc \
    --region=$region

From Cloud Shell

gcloud compute routers nats create central-nat \
    --router=central-cr \
    --region=$region \
    --nat-all-subnet-ip-ranges \
    --auto-allocate-nat-external-ips

Create Network Firewall Policy and Rules

From Cloud Shell

gcloud compute network-firewall-policies create producer-vpc-policy --global

gcloud compute network-firewall-policies associations create \
    --firewall-policy producer-vpc-policy \
    --network producer-vpc \
    --name network-producer-vpc \
    --global-firewall-policy

To allow IAP to connect to your VM instances, create a firewall rule that:

  • Applies to all VM instances that you want to be accessible by using IAP.
  • Allows ingress traffic from the IP range 35.235.240.0/20. This range contains all IP addresses that IAP uses for TCP forwarding.

From Cloud Shell

gcloud compute network-firewall-policies rules create 1000 \
    --action ALLOW \
    --firewall-policy producer-vpc-policy \
    --description "SSH with IAP" \
    --direction INGRESS \
    --src-ip-ranges 35.235.240.0/20 \
    --layer4-configs tcp:22  \
    --global-firewall-policy

Two additional firewall rules will be needed to allow ingress traffic to the load balancer backends sourced from the load balancer proxy only subnet (2000), as well as a rule to allow load balancer healthchecks on the back end instances (2001).

From Cloud Shell

gcloud compute network-firewall-policies rules create 2000 \
    --action ALLOW \
    --firewall-policy producer-vpc-policy \
    --description "allow traffic from load balancer proxy subnet" \
    --direction INGRESS \
    --src-ip-ranges 10.100.101.0/24 \
    --layer4-configs tcp:443 \
    --global-firewall-policy


gcloud compute network-firewall-policies rules create 2001 \
    --action ALLOW \
    --firewall-policy producer-vpc-policy \
    --description "allow load balancer health checks" \
    --direction INGRESS \
    --src-ip-ranges 130.211.0.0/22,35.191.0.0/16 \
    --layer4-configs tcp:443 \
    --global-firewall-policy

6. Create Apache Web Service

We'll create a simple Apache Web Service that displays "PSC Service."

Create Instance Template

From Cloud Shell

gcloud compute instance-templates create apache-service-template \
    --network producer-vpc \
    --subnet service-subnet \
    --region $region \
    --no-address \
    --metadata startup-script='#! /bin/bash
    sudo apt-get update
    apt-get install apache2 -y
    a2enmod ssl
    sudo a2ensite default-ssl
    echo "PSC Service" | \
    tee /var/www/html/index.html
    systemctl restart apache2'

Create Health Check for MIG

From Cloud Shell

gcloud compute health-checks create https service-mig-healthcheck \
    --port=443 \
    --global

Create Managed Instance Group

From Cloud Shell

gcloud compute instance-groups managed create psc-service-mig \
    --region $region \
    --size=2 \
    --template=apache-service-template \
    --health-check=service-mig-healthcheck

gcloud compute instance-groups managed set-named-ports psc-service-mig \
    --named-ports=https:443 \
    --region=$region

7. Create a Self Signed Certificate

Complete Step 1 of the directions here to create a self signed certificate. You can run all of the commands in Cloud Shell. Return to this place when Step 1 is completed. YOUR COMMON NAME MUST BE CONFIGURED WITH EXAMPLE.COM.

Create a certificate resource to associate with your load balancer. Replace the certificate and private-key parameters with your specific file names.

From Cloud Shell

gcloud compute ssl-certificates create producer-service-cert \
    --certificate=<your-producer-certfile.cert> \
    --private-key=<your-producer-keyfile.pem> \
    --region=$region

8. Create the Internal Regional Application Load Balancer

Next we'll create the load balancer components for the service. We're using the Internal Regional Application Load Balancer, but you have the option of using any Google Cloud internal load balancer. Follow the appropriate load balancer documentation for TLS handling.

Create the internal IP address that will be used for the forwarding rule of your load balancer and make note of the IP to be used later when you make a test call to the service.

From Cloud Shell

gcloud compute addresses create apache-service-ip \
 --region=$region \
 --subnet=service-subnet

gcloud compute addresses describe apache-service-ip \
   --format="get(address)" \
   --region=$region

Create the load balancer health check.

From Cloud Shell

gcloud compute health-checks create https lb-apache-service-hc \
    --region=$region \
    --port-name=https

Create the backend service.

From Cloud Shell

gcloud compute backend-services create apache-bes\
  --load-balancing-scheme=INTERNAL_MANAGED \
  --protocol=HTTPS \
  --port-name=https \
  --health-checks=lb-apache-service-hc \
  --health-checks-region=$region \
  --region=$region


gcloud compute backend-services add-backend apache-bes \
  --balancing-mode=UTILIZATION \
  --instance-group=psc-service-mig \
  --region=$region

Create the URL Map.

From Cloud Shell

gcloud compute url-maps create producer-url-map \
  --default-service=apache-bes \
  --region=$region

Create the target HTTPS proxies.

From Cloud Shell

gcloud compute target-https-proxies create https-proxy \
  --url-map=producer-url-map \
  --region=$region \
  --ssl-certificates=producer-service-cert

Create the Forwarding Rule.

From Cloud Shell

gcloud compute forwarding-rules create apache-fr \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --network=producer-vpc \
  --subnet=service-subnet \
  --address=apache-service-ip \
  --ports=443 \
  --region=$region \
  --target-https-proxy=https-proxy \
  --target-https-proxy-region=$region \
  --allow-global-access

9. Create a Test VM and Test the Service Locally

Before we create the Service Attachment, we'll create a test client vm in a different region to test that the load balancer is configured correctly with Global Access and TLS.

From Cloud Shell

gcloud compute instances create vm-client \
    --zone=us-east4-a \
    --subnet=test-client-subnet \
    --no-address

Wait about a minute for the provisioning to complete and then SSH into the instance.

From Cloud Shell

gcloud compute ssh \
    --zone "us-east4-a" "vm-client" \
    --tunnel-through-iap \
    --project $project

Test the Apache Service by connecting over 443 through the load balancer. The internal IP address is the one you reserved and noted down earlier.

curl https://example.com:443 -k --connect-to example.com:443:<YOUR-INTERNAL-IP>:443

EXPECTED RESULT

PSC Service

Exit from the VM.

From vm-client

exit

10. Create the Service Attachment

For this example, we are configuring our Service Attachment to only allow PSC connections from this project. This can be configured to accept one or more specific projects or networks, but not both. We've set our maximum connection limit to 5 connections. Each project or network must have a limit set.

From Cloud Shell

gcloud compute service-attachments create apache-service-attachment \
    --region=$region \
    --producer-forwarding-rule=apache-fr \
    --connection-preference=ACCEPT_MANUAL \
    --consumer-accept-list=$project=5 \
    --nat-subnets=psc-nat-subnet

You should note down the Service Attachment URI (selfLink) as you will need it in the next step for the PSC Backend configuration. You can obtain it by executing the following in Cloud Shell.

From Cloud Shell

gcloud compute service-attachments describe apache-service-attachment \
    --region $region

Copy the URI starting from projects

Example: projects/$project/regions/$region/serviceAttachments/apache-service-attachment

11. Consumer VPC Setup

Create VPC Network

From Cloud Shell

gcloud compute networks create consumer-vpc --subnet-mode custom

Create Subnet

A subnet is needed on the consumer side where the Private Service Connect Network Endpoint Group (NEG) will be deployed.

From Cloud Shell

gcloud compute networks subnets create consumer-subnet \
    --network=consumer-vpc \
    --region=$region \
    --range=10.0.0.0/28

12. Reserve External IP and Create Consumer Side Self-Signed Certificate

External IP

Create the external static IP address that will be used later for our load balancer forwarding rule and capture the IP address in a Cloud Shell variable.

From Cloud Shell

gcloud compute addresses create external-psc-ip \
    --network-tier=PREMIUM \
    --ip-version=IPV4 \
    --global

export externalip=$(gcloud compute addresses describe external-psc-ip \
    --format="get(address)" \
    --global)

echo $externalip

Consumer Self-Signed Certificate

For a second time, complete Step 1 of the directions here to create a self signed certificate. You can run all of the commands in Cloud Shell. Return to this place when Step 1 is completed. We will be using an open source public wildcard DNS service called nip.io in place of owning our own public DNS zone. The public URL of your PSC service will use the external IP address you just configured. YOUR COMMON NAME MUST BE CONFIGURED WITH <YOUR-EXTERNAL-IP.nip.io>

Create a certificate resource to associate with your external load balancer. Replace the certificate and private-key parameters with your specific file names.

From Cloud Shell

gcloud compute ssl-certificates create consumer-service-cert \
    --certificate=<your-consumer-certfile.cert> \
    --private-key=<your-consumer-keyfile.pem> \
    --global

13. Create the Load Balancer Components

We'll create a Global External Application Load Balancer with a PSC NEG pointing to our newly created Service Attachment as a Backend Service.

Have handy the Service Attachment URI we noted in the last step. Replace the psc-target-service below with your URI.

From Cloud Shell

gcloud compute network-endpoint-groups create apache-psc-neg \
--network-endpoint-type=private-service-connect \
--psc-target-service=projects/$project/regions/$region/serviceAttachments/apache-service-attachment \
--region=$region \
--network=consumer-vpc \
--subnet=consumer-subnet

Create the Backend Service.

From Cloud Shell

gcloud compute backend-services create apache-pscneg-bes \
    --load-balancing-scheme=EXTERNAL_MANAGED \
    --protocol=HTTPS \
    --global

gcloud compute backend-services add-backend apache-pscneg-bes \
    --network-endpoint-group=apache-psc-neg \
    --network-endpoint-group-region=$region \
    --global

Create the URL Map

From Cloud Shell

gcloud compute url-maps create consumer-url-map \
    --default-service=apache-pscneg-bes \
    --global

Create the target HTTPS proxies.

From Cloud Shell

gcloud compute target-https-proxies create psc-https-proxy \
    --url-map=consumer-url-map \
    --ssl-certificates=consumer-service-cert

Create the Forwarding Rule

From Cloud Shell

gcloud compute forwarding-rules create external-fr \
  --load-balancing-scheme=EXTERNAL_MANAGED \
  --network-tier=PREMIUM \
  --address=external-psc-ip \
  --global \
  --target-https-proxy=psc-https-proxy \
  --ports=443

14. Create Public DNS Zone

From Cloud Shell

gcloud dns managed-zones create "psc-service" \
    --dns-name=$externalip.nip.io. \
    --description="public dns for psc service" \
    --visibility=public

From Cloud Shell

gcloud dns record-sets transaction start \
   --zone="psc-service"

gcloud dns record-sets transaction add $externalip \
   --name=$externalip.nip.io \
   --ttl=300 \
   --type=A \
   --zone="psc-service"

gcloud dns record-sets transaction execute \
   --zone="psc-service"

15. Test the Consumer PSC Connection

Wait 7 to 10 minutes before testing to let the public DNS propagate.

From Cloud Shell

curl https://$externalip.nip.io -k

You can also test from your browser by inputting https://<YOUR-EXTERNAL-IP>.nip.io into your browser or desktop terminal.

EXPECTED RESULT

PSC Service

16. Cleanup steps

From a single Cloud Shell terminal delete lab components

gcloud dns record-sets delete $externalip.nip.io --zone="psc-service" --type=A -q

gcloud dns managed-zones delete "psc-service" -q

gcloud compute forwarding-rules delete external-fr --global -q 

gcloud compute target-https-proxies delete psc-https-proxy -q

gcloud compute url-maps delete consumer-url-map --global -q

gcloud compute backend-services delete apache-pscneg-bes --global -q

gcloud compute network-endpoint-groups delete apache-psc-neg --region=$region -q

gcloud compute ssl-certificates delete consumer-service-cert --global -q

gcloud compute addresses delete external-psc-ip --global -q

gcloud compute networks subnets delete consumer-subnet --region $region -q

gcloud compute networks delete consumer-vpc -q

gcloud compute instances delete vm-client --zone=us-east4-a -q

gcloud compute service-attachments delete apache-service-attachment --region $region -q

gcloud compute forwarding-rules delete apache-fr --region $region -q

gcloud compute target-https-proxies delete https-proxy --region $region -q

gcloud compute url-maps delete producer-url-map --region $region -q

gcloud compute backend-services delete apache-bes --region $region -q

gcloud compute health-checks delete lb-apache-service-hc --region $region -q

gcloud compute addresses delete apache-service-ip --region $region -q

gcloud compute ssl-certificates delete producer-service-cert --region $region -q

gcloud compute instance-groups managed delete psc-service-mig --region $region -q

gcloud compute health-checks delete service-mig-healthcheck --global -q

gcloud compute instance-templates delete apache-service-template -q

gcloud compute network-firewall-policies rules delete 2001 --firewall-policy producer-vpc-policy --global-firewall-policy -q

gcloud compute network-firewall-policies rules delete 2000 --firewall-policy producer-vpc-policy --global-firewall-policy -q

gcloud compute network-firewall-policies rules delete 1000 --firewall-policy producer-vpc-policy --global-firewall-policy -q

gcloud compute network-firewall-policies associations delete --firewall-policy=producer-vpc-policy  --name=network-producer-vpc --global-firewall-policy -q

gcloud compute network-firewall-policies delete producer-vpc-policy --global -q

gcloud compute routers nats delete central-nat --router=central-cr --region $region -q

gcloud compute routers delete central-cr --region $region -q

gcloud compute networks subnets delete psc-nat-subnet --region $region -q

gcloud compute networks subnets delete service-subnet --region $region -q

gcloud compute networks subnets delete test-client-subnet --region us-east4 -q 

gcloud compute networks subnets delete central-proxy-subnet --region $region -q

gcloud compute networks delete producer-vpc -q

17. Congratulations!

Congratulations for completing the codelab.

What we've covered

  • Create a configure a PSC Backend associated with the Global External Application Load Balancer
  • Configure an Apache managed web service and expose it as a PSC service through a Service Attachment
  • Create SSL certificates to terminate SSL on Internal and External Application Load Balancers
  • Configure a Cloud DNS public zone to access the PSC service