Skip to content

Instantly share code, notes, and snippets.

@mikesparr
Created February 24, 2024 17:56
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/907e1dae7cfd2a2b57b1e4f4da4915c0 to your computer and use it in GitHub Desktop.
Save mikesparr/907e1dae7cfd2a2b57b1e4f4da4915c0 to your computer and use it in GitHub Desktop.
Demo securing a Google Kubernetes Engine (GKE) hosted app using Gateway API, HTTPRoute, and Identity Aware Proxy (IAP)
#!/usr/bin/env bash
#####################################################################
# REFERENCES
# - https://cloud.google.com/iap/docs/concepts-overview
# - https://cloud.google.com/iap/docs/enabling-kubernetes-howto
# - https://cloud.google.com/kubernetes-engine/docs/how-to/configure-gateway-resources#configure_iap
# - https://cloud.google.com/sdk/gcloud/reference/container/clusters/create
# - https://github.com/digitalocean/kubernetes-sample-apps/tree/master/podinfo-example
# - https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing
# - https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-gateways#gateway_ip_addressing
# - https://cloud.google.com/kubernetes-engine/docs/how-to/secure-gateway#secure-using-ssl-certificate
# - https://cloud.google.com/iap/docs/enabling-kubernetes-howto#enabling_iap
# - https://cloud.google.com/iap/docs/managing-access
#####################################################################
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 \
container.googleapis.com \
iap.googleapis.com \
beyondcorp.googleapis.com \
certificatemanager.googleapis.com
# configure gcloud sdk
gcloud config set compute/region $GCP_REGION
gcloud config set compute/zone $GCP_ZONE
# define vars
export EXTERNAL_ADDRESS_NAME="public-ip"
export CLUSTER_NAME="central"
export APP_NAME="podinfo"
export APP_NS=$APP_NAME
export DOMAIN="iapdemo.msparr.com" # CHANGEME: YOUR DOMAIN
export CERT_NAME="iapdemo-msparr-com" # CHANGEME: YOUR DOMAIN
export GATEWAY_NS="gateway-infra"
export GATEWAY_FILE="$APP_NAME-gateway.yaml"
export CLIENT_ID="<YOUR-OAUTH-CLIENT-ID>"
export CLIENT_SECRET="<YOUR-OAUTH-CLIENT-SECRET>" # "<copy client secret from oauth credentials>"
export SECRET_FILE="iap-secret.txt"
export SECRET_NAME="iap-secret"
# create external IP
gcloud compute addresses create $EXTERNAL_ADDRESS_NAME \
--purpose=SHARED_LOADBALANCER_VIP \
--global
export EXTERNAL_IP=$(gcloud compute addresses describe $EXTERNAL_ADDRESS_NAME --global --format="value(address)")
# create cluster
gcloud container clusters create $CLUSTER_NAME \
--location $GCP_REGION \
--gateway-api=standard \
--num-nodes=1
# deploy demo app
git clone https://github.com/digitalocean/kubernetes-sample-apps.git
kubectl apply -k ./kubernetes-sample-apps/podinfo-example/kustomize
# verify
kubectl -n $APP_NS get pods
kubectl -n $APP_NS get svc/$APP_NAME
# create ssl cert
gcloud compute ssl-certificates create $CERT_NAME \
--domains=$DOMAIN \
--global
# create gateway namespace and update ns labels for cross-namespace container-native load balancing
kubectl create ns $GATEWAY_NS
kubectl label namespaces $GATEWAY_NS shared-gateway-access=true --overwrite=true
kubectl label namespaces $APP_NS shared-gateway-access=true --overwrite=true
kubectl annotate --overwrite svc/$APP_NAME -n $APP_NS cloud.google.com/neg='{"ingress": true}'
# create k8s secret for iap oauth credentials
echo -n $CLIENT_SECRET > $SECRET_FILE
kubectl create secret generic $SECRET_NAME --from-file=key=$SECRET_FILE
# create gateway (in infra namespace) and httproute (in app namespace)
cat > $GATEWAY_FILE << EOF | kubectl apply -f -
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: external-http
namespace: $GATEWAY_NS
spec:
gatewayClassName: gke-l7-global-external-managed
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
options:
networking.gke.io/pre-shared-certs: $CERT_NAME
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway-access: "true"
addresses:
- type: NamedAddress
value: $EXTERNAL_ADDRESS_NAME
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: $APP_NAME-external
namespace: $APP_NS
labels:
gateway: external-http
spec:
parentRefs:
- name: external-http
namespace: $GATEWAY_NS
hostnames:
- "$DOMAIN"
rules:
- backendRefs:
- name: $APP_NAME
port: 9898
---
apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
name: backend-policy
namespace: $APP_NS
spec:
default:
iap:
enabled: true
oauth2ClientSecret:
name: $SECRET_NAME
clientID: $CLIENT_ID
targetRef:
group: ""
kind: Service
name: $APP_NAME
EOF
@mikesparr
Copy link
Author

Identity Aware Proxy (IAP) on GKE using Gateway API

This example illustrates how you can configure an application running on GKE to be secured using Google's Identity Aware Proxy (IAP) via Oauth consent flow, leveraging the latest "Ingress" best practice Gateway API and HTTPRoute.

Results

After authentication, the demo app (thanks to Digital Ocean for cute podinfo demo app) should look like this
Screenshot 2024-02-24 at 11 02 32 AM

Prior to authorization, however, the app access will be restricted like this:
Screenshot 2024-02-24 at 11 02 24 AM

Auth flow example

When first visiting the site, it may prompt you to log in with Google's OAuth flow
Screenshot 2024-02-24 at 11 05 59 AM

And if you are wise, you will likely have a 2-factor authentication step
Screenshot 2024-02-24 at 11 06 31 AM

After you authenticated, and your user is added in the IAP admin "Add Principals" (see below), you should be granted access to the site.

Authenticating additional users

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