Authentication using GCP Identity-Aware Proxy

Authentication using GCP Identity-Aware Proxy.

Introduction

In my previous blog post, Some GCP IAM Observations (with Terraform), I wrote that I’m currently between customer projects and spending my time implementing one internal financial application. I’m using Google Cloud Platform (GCP) to create the cloud infrastructure. The actual infrastructure code is implemented using Terraform. In that previous blog post, I explained some GCP IAM observations. I have now finalized the cloud infrastructure and will explain the authentication using GCP Identity-Aware Proxy (IAP) in this new blog post.

The High-Level User-Story

The high-level user story is depicted in the diagram above. The user writes the domain url of the application in his/her browser. The DNS service provides the IP address of the GCP load balancer.

The load balancer then forwards the user to GCP Identity-Aware Proxy (IAP). IAP then checks the authentication information in the browser session. If IAP doesn’t find the authentication information, it forwards the user to authenticate; in our diagram using the G Suite authentication. IAP then uses the authenticated identity to check the user’s IAM role and if the user is authorized to access the application.

Identity-Aware Proxy

It is a good practice not to implement authentication inside the application. Instead, implement the authentication in the infrastructure using the cloud provider’s best practice mechanisms for authentication. GCP provides GCP Identity-Aware Proxy (IAP) to implement authentication outside your application. I used IAP for the first time in this project, and there were quite a lot of various GCP resources and procedures involved. I’ll next explain some of the most important key players shortly.

Pre-Configurations - OAuth Client ID and Secret

There is some manual work before you can create the GCP resources using Terraform - you need to create the OAuth client id and secret. Go to https://console.cloud.google.com/apis/credentials?project=YOUR_INFRA_PROJECT_ID and click the + CREATE CREDENTIALS button. You get the OAuth client id and secret; I inserted them into my environment variables file so that I can use them in my infrastructure code later:

export TF_VAR_OAUTH_CLIENT_ID=TODO
export TF_VAR_OAUTH_CLIENT_SECRET=TODO

I created the OAuth Consent using Terraform as part of my infrastructure GCP project creation:

# Needed to consent the project for IAP (Identity-Aware Proxy).
# See: https://cloud.google.com/iap/docs/enabling-compute-howto
resource "google_iap_brand" "project_brand" {
  support_email     = "terraform@${var.ADMIN_PROJ_ID}.iam.gserviceaccount.com"
  application_title = "${local.res_prefix}-${local.module_name}"
  project           = google_project_service.project_service["iap.googleapis.com"].project
}

Note: You cannot create IAP Brand for an external user type using Terraform (see iap_brand) - therefore, you have to go to GCP Console and manually change the user type to external.

GCP Authentication Key Players

Cloud Run

Let’s assume you already have the Cloud Run application up and running, as I explained in my previous blog post Some GCP IAM Observations (with Terraform). Next, you want to restrict access to your Cloud Run application only through your load balancer as explained in the GCP documentation Restricting ingress for Cloud Run:

  # Required by IAP (identity-aware proxy)
  metadata {
    annotations = {
      "run.googleapis.com/ingress" = "internal-and-cloud-load-balancing"
    }
  }

IP, Certificate, and A Record

You need a GCP address. For some reason I couldn’t get a regional Cloud Run Backend working and therefore I used a global address:

resource "google_compute_global_address" "cloud_run_lb_address" {
  project  = data.terraform_remote_state.project.outputs.project_id
  name = "${local.res_prefix}-cloudrun-lb-address"
}

resource "google_compute_managed_ssl_certificate" "cloud_run_lb_managed_ssl_cert" {
  provider = google-beta
  name     = "${local.res_prefix}-cloudrun-lb-cert"
  project  = data.terraform_remote_state.project.outputs.project_id
  managed {
    domains = [local.domain]
  }
}

Next, create a DNS A record and assign your domain the IP you got when you created the google_compute_global_address resource above. The A record configuration depends on which DNS service provider you use; in the diagram I have added Cloud DNS for illustration.

Network Endpoint Group and Backend Service

Next, you need to create a network endpoint group (neg) and backend service. I’m not going to list all Terraform code here but let’s highlight that with the backend, you need the OAuth client id and the secret that we created earlier:

resource "google_compute_backend_service" "cloud_run_backend_service" {
...
  iap {
    oauth2_client_id = var.OAUTH_CLIENT_ID
    oauth2_client_secret = var.OAUTH_CLIENT_SECRET
  }
...

Next create the IAM policy for your users, e.g.:

data "google_iam_policy" "iap_iam_policy" {
  binding {
    role = "roles/iap.httpsResourceAccessor"
    members = [
      # provide your domain or individual G suite users here.
...

Url Map, Http Proxy and Forwarding Rule

Finally, you need the actual load balancer. This is configured using url map, http proxy, and forwarding rule. These are just a few lines of code; see Terraform documentation on how to create these resources.

The connection between the GCP load balancer and your cloud-run application can be traced using this path: forwarding rule -> target http proxy -> url map -> backend service -> cloud-run.

Post-Configurations - Redirect Url

I did one post-configuration step manually (I’m not sure if you can even automate this): Navigate to: https://console.cloud.google.com/apis/credentials?project=YOUR_INFRA_PROJECT_ID and click the OAuth Client ID you created earlier. On this page in Authorised redirect URIs -> + ADD URI, copy-paste the authorized-redirect-uri of your infrastructure environment; I have it in my terraform outputs:

output "authorized-redirect-uri" {
  value = "https://iap.googleapis.com/v1/oauth/clientIds/${var.OAUTH_CLIENT_ID}:handleRedirect"
}

Conclusions

GCP Identity-Aware Proxy is an excellent way to outsource the authentication from your application to be managed by your GCP infrastructure.

The writer is working at Metosin using Clojure in cloud projects. If you are interested to start a cloud or Clojure project in Finland or you are interested getting cloud or Clojure training in Finland you can contact me by sending an email to my Metosin email address or contact me via LinkedIn.

Kari Marttila