Security Cloud IAP architecture

This post is part 2 of a series discussing Cloud IAP:

Architecture

Conceptually, you can think of Cloud IAP as a reverse proxy that is deployed in front of your corporate application that intercepts all requests to perform authentication and authorization.

Luckily, that is not exactly how it is actually implemented – instead, Cloud IAP is a actually a feature of the global HTTPS load balancer.

Architecture

Having IAP be a feature of the HTTPS load balancer has a number of nice properties:

  • You do not have to manage any proxy VMs.
  • It is highly available.
  • Because there is no extra hop in the network communication, IAP adds little to no additional overhead.
  • It works for all regions, which is convenient if you have applications deployed across many regions.

OpenID Connect Flow

It is good to know that Cloud IAP is part of the load balancer rather than an extra set of VMs – but that does not explain yet how it actually works.

Cloud IAP uses OpenID Connect to authenticate end users, so let’s revisit how an OpenID Connect flow usually works:

OIDC 1

  • (1) The user uses her browser to access a protected resource - in this case, a web application.
  • (2) The web application finds that the user has not authenticated yet and responds by redurecting the browser to the identity provider (IdP).
  • (3) The user’s browser follows the redirect to the IdP.

OIDC 2

  • (4) The IdP returns a sign-in page to the user (unless there is an ambient single sign-on session in which case the user might not see any page).
  • (5) The user enters her credentials…
  • (6) …and submits them to the IdP.

OIDC 3

  • (7) The IdP verifies the credentials and, assuming success, redirects the browser back to web app. In the redirect URL, the IdP embeds an Authorization Code.
  • (8) The browser again follows the redirect.

OIDC 4

  • (9) The web application takes the Authorization code and sends it to the IdP’s Token endpoint.
  • (10) The IdP verifies the code and returns an Access Token and IdToken to the web application.

Cloud IAP Flow

To see how the Cloud IAP flow works, you can simply take the OpenID Connect flow discussed in the previous section and substitute the web application against Cloud IAP:

OIDC 5

Cloud IAP is, essentially, performing the OpenID Connect flow on the backend application’s behalf.

Having authenticated the user, Cloud IAP verifies whether the user is authorized to access the backend application. It does so by verifying that the user has been assigned the IAP-Secured Web App User role in Cloud IAM.

Once Cloud IAP has authenticated and authorized the user, it passes the request to the backend. Cloud IAP does not pass the access token or IdToken to the backend – however, it does pass 3 special HTTP headers:

X-Goog-Authenticated-User-Id: accounts.google.com:1132692835...
X-Goog-Authenticated-User-Email: accounts.google.com:[email protected] 
X-Goog-Iap-Jwt-Assertion: eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImt...U0rYQ 

The most interesting of these headers is the last one. If you base64-decode its value, you will see that it contains a JSON Web Token (JWT). Looking at this token, it is tempting to assume that Cloud IAP does pass the IdToken it received as part of the OpenID Connect flow – but that is not the case. And as we’ll see later, that’s for good reason too.

Let us compare the IAP JWT assertion and a Google OpenID Connect IdToken side-by-side:

 IAP JWT assertion                             IdToken
 -------------                             --------
 
 { "alg": "ES256",                         { "alg": "RS256",
   "typ": "JWT",                             "kid": "3e187177f9987c19..."
   "kid": "qV5OHQ"                         }
 }                                         
 { "iss": "https://cloud.google.com/iap",  { "iss": "https://accounts.google.com",
   "sub": "accounts.google.com:113269...",   "sub": "11326928...",
   "email": "[email protected]",           "azp": "407408718192.apps.goog...",
   "aud": "/projects/1557147...",            "aud": "407408718192.apps.goog...",
   "exp": 1519405104,                        "at_hash": "QqTcQlSz4...",
   "iat": 1519404504,                        "exp": 1519486531,
   "hd": "example.com"                       "iat": 1519482931
 }                                         } 

As both tokens are JWT-based, there are obviously some commonalities – but there are several significant differences as well:

  • The header specifies a different algorithm, but that’s not too interesting.
  • The issuer is Cloud IAP, not accounts.google.com.
  • The audience specifies the backend application in a path-based encoding.
  • The token always contains the user’s primary email address (which should always be the same as the one in the X-Goog-Authenticated-User-Email header.

Given that the IAP JWT assertion is not an IdToken, what is the purpose of it?

The purpose of the IAP JWT assertion is to enable the backend application to verify that the request has been vetted by Cloud IAP. Why that’s important will be the topic of the next post.

Any opinions expressed on this blog are Johannes' own. Refer to the respective vendor’s product documentation for authoritative information.
« Back to home