Secured & Serverless Streamlit App with Google Cloud Run + IAP
This is a step-by-step guide about creating a secured web application on Google Cloud Run using Identity-Aware Proxy (IAP).
This article will not cover Streamlit or network theories.
When we are developing an internet facing application.
The most annoying part is sure to be the authentication.
Which could be a risk, and it need to be aligned with organization’s frequently change policies.
However, GCP provide us an authentication tool called Identity-Aware Proxy (IAP). Which give us a secured application authentication by Google.
To make sure that we know what we are doing.
This how-to article will use the UI method instead of script.
There are 7 steps + 1 optional to activate application authentication using Identity-Aware Proxy (IAP) on Google Cloud Run.
1. Create Simple Streamlit App
First, we need to create a very simple Streamlit application on Google Cloud Run, without authentication. Skip this step if you already have your own Cloud Run application.
I will use a very simple script as show below.
Streamlit Script
import streamlit as st
st.title('Hello')Dockerfile
# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.9-slim
# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True
# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./
# Install Streamlit.
RUN pip install streamlit
# EXPOSE PORT
EXPOSE 8080
# Run the service on container
CMD ["streamlit", "run", "main.py", "--server.port=8080", "--server.address=0.0.0.0"]Build and Deploy with Cloud Run
# Create Place to hold Docker Image in Artifacts Repo
gcloud artifacts repositories create {repo name} \
--repository-format=docker \
--location={region} \
--description="{DESCRIPTION}"
# Build Docker Image
gcloud builds submit \
--tag {region}-docker.pkg.dev/{project name}/{repo name}/{image name}
# Deploy Docker Image to Cloud Run Service
gcloud run deploy {service name} \
--region {region} \
--image {region}-docker.pkg.dev/{project name}/{repo name}/{image name} \
--allow-unauthenticated # Importan!!And we will have our simple Streamlit application on Cloud Run.
2. Reserve IP Address in IP Address
Next, we will need a static IP Address for our application.
On GCP console, go to the IP Address in VPC Network and click on Reserve External Static IP Address.
Fill in required fields and click Reserve, this will bring us back to the IP Address page.
*For naming conversion, I will use {service_name}-{suffix} from now on.
CHECK POIONT:
Try to ping theIP Addressfrom the IP that we just reserved.
3. Register Domain using Cloud Domain
Next, we will need a domain to map theIP address from the 2nd step with a load balancer in the next step.
On GCP console, go to the Cloud Domain in Network Service and click on Register Domain.
Fill in required fields.
- Search domain : Search and select domain name you prefer
- DNS configuration : I suggest using Cloud DNS
- Privacy Protection : I suggest limiting your info
- Contact Details : Your contact details
Wait for a few minutes, then check your mailbox and verify the domain.
4. Mapping name using Cloud DNS
Now, we will create our application domain and map it with the static IP Address from the 2nd step.
On GCP console, go to the Cloud DNS in Network Service and click on your registered domain from the previous section.
Then click Add Standard.
Fill in required information.
- DNS name : Your prefer Application’s domain name
- Resource Record Type :
A - IPv4 Address : The IP that we reserved in the 2nd step
CHECK POINT:
Try to ping the domain name instead of the IP.
It should be redirected into the IP from the 2nd step.
5. Create a load balancer
Now, we will map the Application’s domain to our Cloud Run Application.
On GCP console, go to the Load Balancer in the Network Service and click on Create Load Balancer.
Fill in required information depended on how application will be used.
Next is to configure load balancer’s frontend and backend.
Frontend Configuration
Get Chanon Krittapholchai’s stories in your inbox
Join Medium for free to get updates from this writer.
Fill in required fields, these are what I used.
- Load Balancer’s name :
{Service Name}-lb - Frontend’s name :
{Service Name}-fe - IP version :
IPv4 - IP Address :
IP from the 2nd step - Certificate :
Create A New Certificate-> This will open other window.
For Create A New Certificate , fill in information like these.
- Name :
{Service Name}-fe-cer - Create Mode :
Create Google-manged certificate, or upload if you have. - Domain :
Your Application Domain from the 4th step
Back to the previous window, enable HTTP to HTTPS redirect
Backend Configuration
For backend, click on Create A Backend Service and fill in required fields.
- Name :
{Service Name}-be - Backend Type :
Serverless network endpoint group
Then click on Create A Serverless Network Endpoint Group.
Fill in the required fields.
- Name :
{Service Name}-be-grp - Region : Your application’s region
- Serverless network endpoint group type : Application from the 1st step
And for the rest of load balancer configurations, we can use the default values. After created, we have to wait ~15 minutes for certificate registration.
CHECK POINT :
We should be able to access our Streamlit application from the Application domain from the 4th step.
6. Disable Cloud Run Ingress
Now that we can access our application though the load balancer, we don’t want anyone to access the application though the Cloud Run’s default URL. this step will disable accessibility from the default URL.
On GCP console, go to Cloud Run and click on our Streamlit application from the 1st step.
On Networking tab, Ingress, select Internal and Allow traffic from external Application Load Balancers.
This will make our Streamlit application only accessible though the Load Balancer from the 5th step.
CHECK POINT :
When access though the default URL, it should be anError : Page not Found.
7. Activate IAP
Now, to limit our application accessible only to allowed users, we will set up the Identity-Aware Proxy (IAP).
On GCP console, go to Identity-Aware Proxy in Security. For the first time, GCP will require us to configure the OAuth consent screen.
Click on Configure Consent Screen, fill in required information.
When we come back to the Identity-Aware Proxy, we will see a list of our backend service with IAP turn off.
Turn on the IAP, this will make our application only accessible for users with permission, this process will take ~5 minutes.
CHECK POINT :
Application will require Google’s authentication when access.
And you will get access denied when logged in.
To add permission to the application, on IAP, select the backend service and click on Add Principal, add users with role IAP-secured Web App User, this process also takes ~5 minutes.
And our users will be able to access our Streamlit application!!!
[Optional] Get user’s email
This is an optional step, if we need user’s identification to use for additional logics or logging. We can use IAP’s JWT header to get it.
To get data from IAP’s header, first we need to get the audience from IAP.
On IAP, click on 3 dots and click on Get JWT audience code. This will show an JWT audience code.
Then we will need to modify our Streamlit script and the Dockerfile, don’t forget to put the JWT audience code into the Streamlit script.
Streamlit Script
# Main Streamlit
import streamlit as st
st.title('Hello')
# Get User Info
from google.auth.transport import requests
from google.oauth2 import id_token
from streamlit import context
# Get Header for Streamlit, change this part if you use other framework
def get_header() :
headers= context.headers
return headers.get_all('x-goog-iap-jwt-assertion')[0]
# Get
def validate_iap_jwt(iap_jwt, expected_audience):
try:
decoded_jwt = id_token.verify_token(
iap_jwt,
requests.Request(),
audience=expected_audience,
certs_url="https://www.gstatic.com/iap/verify/public_key",
)
return (decoded_jwt["sub"], decoded_jwt["email"], "")
except Exception as e:
return (None, None, f"**ERROR: JWT validation error {e}**")
expected_audience= 'JWT AUDIENCE from pervious step'
email= validate_iap_jwt(get_header(), expected_audience)[1]
st.title(f"User email : {email}")Dockerfile
# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.9-slim
# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True
# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./
# Install Streamlit and additional lib.
RUN pip install streamlit
RUN pip install google-auth
RUN pip install cryptography
# EXPOSE PORT
EXPOSE 8080
# Run the service on container
CMD ["streamlit", "run", "main.py", "--server.port=8080", "--server.address=0.0.0.0"]After re-build and re-deploy, we will be able to get user’s email.
And that’s how we authenticate our Streamlit application on Google Cloud Run with Identity-Aware Proxy (IAP).
Hope this will help, happy IAP!!!
Reference links :
Cloud IAP :
Identity-Aware Proxy overview | Google Cloud
JWT Audience :
Securing your app with signed headers | Identity-Aware Proxy | Google Cloud










