Seemingly every project I work on gets bogged down at some point on authentication. Why must it take so much time! Why must I solve the same problems so many times now! I found myself nodding furiously while reading Google's BeyondCorp papers, "we should solve it in the proxy layer!". Let's stop wasting time with Oauth2 language clients, much like we did with TLS a while ago. Solve it well once, and reuse it for everything henceforth.
Why? Because Identity Aware Proxies are awesome for security, they allow you to take insecure binaries and wrap them with a pre-audited secure implementation. They can be deployed outside of VPNs safely, so your employees can access internal functionality from anywhere, and it's less effort to setup than VPN. So I decided to do security right and use an Identity Aware Proxy to secure my Serverless Camunda backend.
I hit a snag though, Google's official Identity Aware Proxy is only available for Google App Engine and Compute Engine, and not my favorite Serverless hosting technology Cloud Run! As the project I was working on needed authentication, I decided to try and solve it a bit like Google would, but in a serverless container.
- If called without a Bearer or Cookie access token, the proxy redirects to Google sign-in
- 3rd party apps like Zapier can negotiate refresh tokens nicely by going straight to
- A valid access token is exchanged for a backend token using the proxy service account.
- No secrets are required, it validates tokens using GCP platform features (/tokeninfo).
- Nginx caching is exploited to reuse token creation and validation.
- Small image size and scales-to-zero when not in use.
To get a working Zapier integration the authorization URL should be customized with scopes and offline access
The only manual part involved is creating the Oauth2 credentials in the GCP console. In some sense the manual process is a blessing, as this step involves secrets and having it done outside of Terraform avoids secret management headaches. Google requires public Oauth 2 applications to be verified, however, I was able to get an internal-only app working with Zapier without verification.
I am very pleased with the results. A ton of powerful features got to be reused to create a very concise and high performance implementation. The OpenResty config is only 140 lines of code! And it plays nicely with Zapier. Neat, I hope I never have to do that again, but if I do, at least I will have this recipe as a reference for a minimal Oauth 2 gateway!
Update: This recipe has been expended with deeper Slack and Zapier integration, a local development environment and a Write Ahead Log. Read about the latest version here.