Secure Serverless Application with Identity Aware Proxy (IAP)

1. Overview

In this lab, you will deploy the employee portal that allows employees to view, update and delete orders from the Cymbal Eats app. You will use Identity Aware Proxy (IAP) to secure portal access without using a Virtual Private Network (VPN). IAP simplifies implementing a zero-trust access model and takes less time than a VPN for remote workers both on-premises and in cloud environments with a single point of control for managing access to your apps.

94b06525c85408ad.png

What is Identity-Aware Proxy?

Identity-Aware Proxy (IAP) is a Google Cloud service that intercepts requests sent to your application, authenticates the user making the request using the Google Identity Service, and only lets the requests through if they come from a user authorized to access the application. In addition, it can modify the request headers to include information about the authenticated user.

What you will learn

  • How to configure a Serverless Network Endpoint Group (NEG)
  • How to configure a load balancer
  • How to enable IAP to restrict access
  • How to restrict access using IAP

2. 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.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.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 update it at any time.
  • 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 the Project ID (it is typically identified as PROJECT_ID). If you don't like the generated ID, you may generate another random one. Alternatively, you can try your own and see if it's available. It cannot be changed after this step and will remain 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 shouldn't cost much, if anything at all. To shut down resources so you don't incur billing beyond this tutorial, you can delete the resources you created or delete the whole project. New users of Google Cloud are eligible for the $300 USD Free Trial program.

Environment Setup

  1. Create project and resource related environment variables
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
export REGION=us-east1
export ORDER_SERVICE_URL=order-service
export INVENTORY_SERVICE_URL=inventory-service
export MENU_SERVICE_URL=menu-service
  1. Enable the IAP and Cloud resource manager service APIs
gcloud services enable \
    iap.googleapis.com \
    cloudresourcemanager.googleapis.com \
    cloudidentity.googleapis.com \
    compute.googleapis.com
  1. Clone the sample app repository and navigate to the directory
git clone https://github.com/GoogleCloudPlatform/cymbal-eats.git && cd cymbal-eats/employee-ui
  1. Deploy the Employee portal using the setup script. Wait for the script to complete before moving to the next step
./setup.sh

Example output

...
Done.
Service [employee-ui-service] revision [employee-ui-service-00001-quw] has been deployed and is serving 100 percent of traffic.
Service URL: https://employee-ui-service-gbtuuy5eda-uk.a.run.app
  1. Click on the Service URL link

86416f68c0b8152a.png

3. Configuring a Serverless Network Endpoint Group (NEG)

You will create a Serverless Network Endpoint Group( Serverless NEG) for the employee UI Cloud Run service. Serverless NEGs allow you to use Google Cloud serverless apps with external HTTP(S) Load Balancing.

2abe669e53c27186.png

  1. Create a network endpoint group for the employee UI service.
gcloud compute network-endpoint-groups create employee-ui-iap-neg \
    --project $PROJECT_ID \
    --region=$REGION \
    --network-endpoint-type=serverless  \
    --cloud-run-service=employee-ui-service

Example Output

Created [https://www.googleapis.com/compute/v1/projects/cymbal-eats-18147-25762/regions/us-east1/networkEndpointGroups/employee-ui-iap-neg].
Created network endpoint group [employee-ui-iap-neg].

Create a backend service and add the serverless NEG

A backend service defines how Cloud Load Balancing distributes traffic. The backend service configuration contains a set of values, such as the protocol used to connect to backends, various distribution and session settings, health checks, and timeouts. These settings provide fine-grained control over how your load balancer behaves.

  1. Create a backend service
gcloud compute backend-services create employee-ui-iap-backend \
        --global 

Example Output

Created [https://www.googleapis.com/compute/v1/projects/cymbal-eats-18147-25762/global/backendServices/employee-ui-iap-backend].
NAME: employee-ui-iap-backend
BACKENDS:
PROTOCOL: HTTP
  1. Add the serverless NEG as a backend to the backend service
gcloud compute backend-services add-backend employee-ui-iap-backend \
    --global \
    --network-endpoint-group=employee-ui-iap-neg \
    --network-endpoint-group-region=$REGION

Example Output

Updated [https://www.googleapis.com/compute/v1/projects/cymbal-eats-18147-25762/global/backendServices/employee-ui-iap-backend].
  1. Create a URL map to route incoming requests to the backend service
gcloud compute url-maps create employee-ui-iap-url-map \
    --default-service employee-ui-iap-backend
Created [https://www.googleapis.com/compute/v1/projects/cymbal-eats-18147-25762/global/urlMaps/employee-ui-iap-url-map].
NAME: employee-ui-iap-url-map
DEFAULT_SERVICE: backendServices/employee-ui-iap-backend

4. Configuring the Load Balancer Components

The following diagram shows the load balancer uses a serverless NEG backend to direct requests to a serverless Cloud Run service.

335f4674737a6514.png

Reserve a static IP address

  1. Reserve an static IPv4 address and store the domain
gcloud compute addresses create employee-ui-iap-ip \
    --network-tier=PREMIUM \
    --ip-version=IPV4 \
    --global

Example Output

Created [https://www.googleapis.com/compute/v1/projects/cymbal-eats-18147-25762/global/addresses/employee-ui-iap-ip].
  1. Store the nip.io domain
export DOMAIN=$(gcloud compute addresses list --filter employee-ui-iap-ip --format='value(ADDRESS)').nip.io

Create a Google-managed SSL certificate resource

  1. Create a Google-managed SSL certificate resource
gcloud compute ssl-certificates create employee-ui-iap-cert \
    --description=employee-ui-iap-cert \
    --domains=$DOMAIN \
    --global

Example Output

Created [https://www.googleapis.com/compute/v1/projects/cymbal-eats-18147-25762/global/sslCertificates/employee-ui-iap-cert].
NAME: employee-ui-iap-cert
TYPE: MANAGED
CREATION_TIMESTAMP: 2022-04-18T06:39:37.474-07:00
EXPIRE_TIME:
MANAGED_STATUS: PROVISIONING

34.102.234.98.nip.io: PROVISIONING

Create a target HTTPS proxy

  1. Create the target HTTPS proxy to route requests to your URL map
gcloud compute target-https-proxies create employee-ui-iap-http-proxy \
    --ssl-certificates employee-ui-iap-cert \
    --url-map employee-ui-iap-url-map

Example Output

Created [https://www.googleapis.com/compute/v1/projects/cymbal-eats-18147-25762/global/targetHttpsProxies/employee-ui-iap-http-proxy].
NAME: employee-ui-iap-http-proxy
SSL_CERTIFICATES: employee-ui-iap-cert
URL_MAP: employee-ui-iap-url-map
CERTIFICATE_MAP:

Configure forwarding rules

  1. Create a forwarding rule to route incoming requests to the proxy
gcloud compute forwarding-rules create employee-ui-iap-forwarding-rule \
    --load-balancing-scheme=EXTERNAL \
    --network-tier=PREMIUM \
    --address=employee-ui-iap-ip \
    --global \
    --ports=443 \
    --target-https-proxy employee-ui-iap-http-proxy

Example output

Created [https://www.googleapis.com/compute/v1/projects/cymbal-eats-18147-25762/global/forwardingRules/employee-ui-iap-forwarding-rule].

Restricting ingress to the Cloud Run service

Restrict the ingress traffic to only accept internal requests and requests coming through HTTP(S) Load Balancing.

26cb0b2a9162e7ab.png

  1. Update the service to only allow ingress traffic from internal requests and requests through HTTP(S) Load Balancer
gcloud run services update employee-ui-service \
    --ingress internal-and-cloud-load-balancing \
    --region $REGION

Example output

OK Deploying... Done.                            
  OK Creating Revision...
  OK Routing traffic...
Done.
Service [employee-ui-service] revision [employee-ui-service-00001-quw] has been deployed and is serving 100 percent of traffic.
Service URL: https://employee-ui-service-gbtuuy5eda-uk.a.run.app
  1. Click on the Service URL link

8505fde7e0784bf1.png

Access to the Cloud Run service URL now shows as forbidden.

5. Enabling Cloud Identity-Aware Proxy (IAP) on the Load Balancer

IAP lets you establish a central authorization layer for applications accessed by HTTPS. You can use an application-level access control model instead of network-level firewalls.

d9740402a74370a8.png

A brand is the OAuth consent screen that contains branding information for users. Brands might be restricted to internal or public users. An internal brand allows the OAuth flow to be accessed by a member of the same Google Workspace organization as the project. A public brand makes the OAuth flow accessible to anyone with access to the internet.

  1. Create a brand
export USER_EMAIL=$(gcloud config list account --format "value(core.account)")

gcloud alpha iap oauth-brands create \
    --application_title="Cymbal Eats" \
    --support_email=$USER_EMAIL

Example Output

Created [462858740426].
applicationTitle: Cymbal Eats
name: projects/462858740426/brands/462858740426
orgInternalOnly: true

Creating an IAP OAuth Client

  1. Create a client using the brand name from the previous step
gcloud alpha iap oauth-clients create \
    projects/$PROJECT_ID/brands/$PROJECT_NUMBER \
    --display_name=cymbal-eats-employee-ui

Example Output

Created [462858740426-tkpv8n03opijg7erd3s9ccued2pfllsd.apps.googleusercontent.com].
displayName: cymbal-eats-employee-ui
name: projects/462858740426/brands/462858740426/identityAwareProxyClients/462858740426-tkpv8n03opijg7erd3s9ccued2pfllsd.apps.googleusercontent.com
secret: [secret-removed]
  1. Store the client name, ID and secret
export CLIENT_NAME=$(gcloud alpha iap oauth-clients list \
    projects/$PROJECT_NUMBER/brands/$PROJECT_NUMBER --format='value(name)' \
    --filter="displayName:cymbal-eats-employee-ui")

export CLIENT_ID=${CLIENT_NAME##*/}

export CLIENT_SECRET=$(gcloud alpha iap oauth-clients describe $CLIENT_NAME --format='value(secret)')
  1. In the Cloud Console, select the project from the drop-down project selection menu
  2. Navigate to the OAuth consent screen in the Cloud Console

bcb460f3ab5241f4.png

  1. Click MAKE EXTERNAL under User Type
  2. Select Testing as the Publishing status

27fd7de6e7b7ef21.png

  1. Click CONFIRM

6. Restricting Access with IAP

Restrict access to the backend service using IAP then verify the application is inaccessible.

  1. Enable IAP on the backend service
gcloud iap web enable --resource-type=backend-services \
    --oauth2-client-id=$CLIENT_ID \
    --oauth2-client-secret=$CLIENT_SECRET \
    --service=employee-ui-iap-backend

Verify IAP configuration

  1. Verify the SSL certificate is ACTIVE
gcloud compute ssl-certificates list --format='value(MANAGED_STATUS)'
  1. Get service URL
echo https://$DOMAIN

Example output

https://34.102.234.98.nip.io
  1. Click on the service URL to open the employee portal.

352b600209c3fb33.png

  1. Login using your lab credentials.

f7e0318388aa0739.png

  1. Close the browser

Grant user access to the employee portal

  1. Add an IAM policy binding for the role of 'roles/iap.httpsResourceAccessor' for the user created in the previous step
gcloud iap web add-iam-policy-binding \
    --resource-type=backend-services \
    --service=employee-ui-iap-backend \
    --member=user:$USER_EMAIL \
    --role='roles/iap.httpsResourceAccessor'

Example output

Updated IAM policy for backend service [projects/462858740426/iap_web/compute/services/employee-ui-iap-backend].

Testing service access

Confirm access to the employee portal has been granted

  1. Get service URL
echo https://$DOMAIN

Example output

https://34.102.234.98.nip.io
  1. Click on the service URL to open the employee portal.

86416f68c0b8152a.png

You should now have access to the employee portal.

(Optional) Deploy all dependencies, deploying these microservices may take ~20 minutes.

unset ORDER_SERVICE_URL
unset INVENTORY_SERVICE_URL
unset MENU_SERVICE_URL

cd ~/cymbal-eats

./setup.sh
./get-site-urls.sh

7. Congratulations!

Congratulations, you finished the codelab!

What's next:

Explore other Cymbal Eats codelabs:

Clean up

To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, either delete the project that contains the resources, or keep the project and delete the individual resources.

Deleting the project

The easiest way to eliminate billing is to delete the project that you created for the tutorial.