Identity-Aware Proxy for On-Prem applications

Edit: Added a note about JWT header validation.

I have a couple internal systems that I run at home, and that I want to be able to access from outside. I want only my partner and myself to be able to access those systems, and I want that access to be as transparent as possible for her. For that, I decided to use Google’s Identity-Aware Proxy (IAP)!

IAP is a Google Cloud feature that allows you to implement Google’s BeyondCorp security model. The goal of BeyondCorp (and of IAP) is to get rid of corporate VPNs: the bane of the existence of office workers all around the world. In this model, corporate applications are accessed through a proxy that deals with authenticating and authorizing the user. That proxy is available directly on the Internet, removing the need for a VPN. When accessing an application behind IAP, the user is authenticated, authorized, and the connection is encrypted (with SSL).

In Google Cloud, IAP is a feature that you enable on an HTTPS Load Balancer. Until now, Google Cloud Load Balancers were only compatible with Google Cloud-hosted resources (virtual machines, Cloud Storage buckets, etc.). That meant that the only way to benefit from IAP for applications hosted on-prem was to setup another reverse proxy within Google Cloud. That’s how the IAP connector does it, using Ambassador.

iap-connector

Note: You don’t have to configure a VPN between your VPC and On-Prem, you can route the traffic from your reverse proxy to On-Prem over the public Internet.

The problem with that architecture is that it’s really not optimized: you need to setup a whole VPC, at least a VM (or even a managed instance group, or a Kubernetes cluster, if you want HA), and optionnally a VPN.

Fortunately, Google Cloud recently released a feature that went a bit under the radar: Internet network endpoint groups (Internet NEGs). This allows Google Load Balancers to have backends outside of Google Cloud! And, best of all, that backend can be a hostname, not only a static IP! That is really convenient for me, since my ISP doesn’t attribute static IPs. You can now simplify greatly the setup:

iap-neg

Note: If you want the traffic between the load balancer and your application to be encrypted, then your application has to listen on HTTPS, and you need to use that as a backend for the load balancer.

Here is how I did it, details will vary for you, of course.

  1. Configure your router to forward incomming traffic on your application’s port to the application.
    • If you can, restrict that forwarding to 34.96.0.0/20 and 34.127.192.0/18 (source). Check the _cloud-eoips.googleusercontent.com DNS TXT record for the current list of IP ranges.
    • If that’s not possible on your router, then setup a firewall rule to restrict incomming traffic to those ranges.
    • See the note about JWT headers for a better solution to secure your endpoint on-prem.
  2. If your ISP gives you a dynamic IP (like me), then setup some kind of dynamic DNS to get a stable hostname.
  3. Reserve a static IP address on GCP.
  4. Point a DNS record that you want to use for your application (myapp.example.com for example) to the newly reserved static IP.
  5. Create an Internet NEG that targets your home IP or home hostname, and the application port, following the documentation.
  6. Create an HTTP(S) Load Balancer:
    • Use the newly created Internet NEG as backend service.
    • Create at least two frontends: one for HTTP and one for HTTPS. Use the static IP you reserved earlier.
    • Create a Google-managed SSL certificate with the hostname myapp.example.com.

After a few minutes, the load balancer will have initialized, and you should be able to access your application through myapp.example.com, without any authentication nor authorization. You can now enable IAP following the documentation on your new load balancer. Grant the IAP-Secured Web App User IAM role to anyone who needs to access the application.

Here you go! An On-Prem application, protected Google-style with Identity-Aware Proxy!


JWT header validation

While whitelisting IPs is easy to setup, there is no guarantee that they will not change. A better, more resilient solution is to validate the X-Goog-Iap-Jwt-Assertion header that IAP injects in the request. You can use something like Envoy for that. See the documentation for more information.