gRPC Authentication with Google OpenID Connect tokens

salmaan rashid
Aug 14, 2019 · 5 min read

This is a continuation of an article I wrote about Authenticating using Google OpenID Connect Tokens. That article specifically focused on how to get ID Tokens for HTTP clients while this one focuses on using combination of google-auth-* libraries and applying them them to gRPC clients. The specific advantage of using google auth libraries and Credentials they provide is the legwork of refreshing and applying them to grpc native receivers is a lot easier than manually fiddling with request interceptors.

Figuring out how to use id_tokens with gRPC wasn’t obvious and isn’t well documented so here’s my summary..

gRPC Authentication

A bit of background..gRPC Authentication covers basically two built-in mechanisms:

  • SSL/TLS: This covers basic TLS and mTLS with the gRPC server
  • Token-based authentication with Google: This is oauth2 flows where an access_token is acquired and emitted to a Google Service.

For the token based authentication, an oauth2 access_token gets embedded inside a gRPC header itself similar to HTTP/Rest api calls. You can see an example of how the HTTP2 frame carries the Authorization: Bearer tokencapability here.

Notice the Token based authentication emits an access_token intended to get sent to a Google API or service...what we want to do in this article is to emit an id_token to a service we run on somewhere we can host gRPC. At the moment, that somewhere is really on a GCE or GKE if its limited to Google Cloud Services (Cloud Run, Cloud Functions, App Engine etc do NOT support inbound gRPC currently.). For a primer on access_token vs id_token, review the article cited in the first paragraph.

Anyway, we need an id_token for gRPC and while we can Extending gRPC to support other authentication mechanisms), there's an easier way to acquire and use an id_token within your clients.

The code samples provided here demonstrates how to get and use a Google OIDC token using Google’s own provided authentication library set. Acquiring an ID token is well documented but not how to get one with google’s own auth libraries and then using them with a gRPC Credential object.

So, whats contained here:

  • A) gRPC Server in golang that can optionally revalidate any inbound id_token
  • B) grpc Clients in golang, java, python, nodejs that will acquire Google ID tokens using Google Auth libraries and use that token transparently in making unary calls to A
  • C) Dockerfile for gRPC server in A
  • D) Envoy configuration that will accept validate google-issued id_tokens embedded within gRPC requests.

A as a sample app that demonstrates gRPC app which also does automatic (re)validation of an authorization header. If you are running your gRPC server behind an application that checks the request already (eg, istio), then there is no need to revaliate but thats subject to your paranoia. Essentially that is:

  1. Client → Server

* Any of [go,python,java,node] --> [go]

The second mode is with a proxy:

2. Client → Proxy → Server

* Any of [go,python,java,node] --> [Envoy] --> [go]

The client will first use google credentials to acquire an id_token and then embed that into the gRPC header. THis step is done automatically for you by just specifying the credential type to use. The samples demonstrate ServiceAccountCredentials but you are free to use any credential type except user-based tokens (which cannot proivde id_tokens with named audiences).

The important aspects to note in each call is the client: each language sample here shows how to get an id_token using google apis and then add it into the grpc transport. For example, in golang:

First get an id_token

now that you have the rpcCreds, embed that into the grpc channel credentials as an option grpc.WithPerRPCCredentials():

For reference, see: https://godoc.org/google.golang.org/grpc#WithPerRPCCredentials

A couple of notes about the client bootstrapping credentials. Not all google-auth-* libraries support out of the box id_tokens. That work is in progress so the sample provided here for golang is experimental and sourced from my git repo (not google). You are free to reuse that as necessary in the meantime.

Implemenations

The samples below can be run with or without TLS though certain bindings will only allow credentials over TLS. The snippets are stand alone and uses self-signed certificates with SNI bindings for serverName=grpc.doman.com. Each of the language snippets shows how to specify a self-signed CA as well as how to specify the SNI header.

First step is to download a ServiceAccount JSON file from any google cloud project. Once you have that, run the gRPC server and any client you want

If you want to modify the proto, install protoc and the plugins for the languages you're interested in. You can inspect the steps detailed in golang/Dockerfile for the setp steps for protoc.

Golang

You can run the go sample here in two modes: secure and insecure. If you want to transmit the Authorization Header, its encouraged to run the secure mode.

cd golang
export GOPATH=`pwd`:$GOPATH
go get github.com/golang/protobuf/proto \
github.com/golang/protobuf/protoc-gen-go \
golang.org/x/net/context \
google.golang.org/grpc \
google.golang.org/grpc/credentials \
golang.org/x/oauth2 \
cloud.google.com/go/compute/metadata \
github.com/salrashid123/oauth2/google \
golang.org/x/net/http2

Secure

  • Server
$ go run  src/grpc_server.go --grpcport :8080 --cert ../certs/server_crt.pem --key ../certs/server_key.pem --targetAudience https://foo.bar --usetls=true --validateToken=true
  • Client
$ go run src/grpc_client.go --address localhost:8080 --usetls=true --cacert ..//CA_crt.pem --servername grpc.domain.com --audience  https://foo.bar --serviceAccount=/path/to/yoru/svc_accunt.json

Insecure

  • Server
$ go run src/grpc_server.go --grpcport :8080  --usetls=false
  • Client
$ go run src/grpc_client.go --address localhost:8080 --usetls=false

Python

The provided grpc_client.py already includes the compiled protobuf with grpc support so you can just use what is provided.

Edit the following file an

python grpc_client.py

If needed, you can install the protoc support compiler, first run

python -m pip install grpcio-tools google-authpython -m grpc_tools.protoc -Isrc --python_out=. --grpc_python_out=. echo.proto

References:

Java

The java files provided in this repo ALREADY includes support for id_tokens as will be pull request 330. I’ll remove the built in sources once that code is released into the auth library. NOTE, the api surface may change a bit till there (use the the library once its released; what i’ve got here isn’t officially supported)

to run, just execute mvn clean install exec:java

If you want to regenerate the proto, download the plugin, then execute the compiler

protoc --plugin=protoc-gen-grpc-java=/path/to/protoc-gen-grpc-java --java_out=src/main/java   --grpc-java_out=lite:src/main/java/ --proto_path=echo/ echo/echo.proto

Nodejs

Node already has support for id_tokens so running the sample is pretty easy

npm i
node app.js

Envoy

A sample envoy proxy configuration is proivded here which you can use that proxy to do JWT/id_token validation.

To run, first startup the server in insecure mode on port :8080

  • Server
go run  src/grpc_server.go --grpcport :8080 \
--cert $CERTS/server_crt.pem \
--key ../certs/server_key.pem \
--targetAudience https://foo.bar \
--usetls=false \
--validateToken=false

Now run the envoy proxy which will listen on :18080

  • Envoy
envoy -c envoy_config.yaml

Now run the client to connect to the proxy

  • Client
go run src/grpc_client.go --address localhost:18080 \
--usetls=true \
--cacert ../certs/CA_crt.pem \
--servername grpc.domain.com \
--audience https://foo.bar \
--serviceAccount=/path/to/svc_account.json

Conclusion

Thats it, not much of a conclusion as this is just a concise demonstration on how to easy get an id_token for use against your service hosted anywhere or against google API services that speak gRPC and accept id_tokens.

References

Debug flags for GRPC

export GRPC_VERBOSITY=DEBUG
export GRPC_TRACE=tcp,secure_endpoint,transport_security

Google Cloud - Community

A collection of technical articles published or curated by Google Cloud Developer Advocates. The views expressed are those of the authors and don't necessarily reflect those of Google.

salmaan rashid

Written by

Google Cloud - Community

A collection of technical articles published or curated by Google Cloud Developer Advocates. The views expressed are those of the authors and don't necessarily reflect those of Google.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade