Google Cloud Run now has support for unary gRPC requests (i.e. non-streaming methods). This guide explains how to authenticate to a private gRPC service running on Cloud Run.
Cloud Run documentation shows you how to authenticate from a service to a
private service: Fetch an id_token
from the metadata service and use it as a
Bearer token in Authorization header in your HTTP requests. gRPC nearly the
same since it uses HTTP/2 as the transport. However, there are a few nuances.
Server: gRPC servers require no change to allow authenticated requests on Cloud Run. The serving infrastructure handles terminating TLS connections and checking authorization tokens. Your server needs to listen on $PORT without TLS.
Client: running a private service on Cloud Run will forcibly add TLS to the gRPC server and therefore your gRPC client app must handle TLS and provide an authentication token:
- Use TLS endpoint to connect
- Verify TLS CA certificate
- Provide authentication token
Using TLS endpoint
Cloud Run now forces HTTPS on any application running on *.run.app
domain.
Therefore you must use port 443
to connect to a gRPC server.
Example in Go:
conn, err := grpc.Dial("routeserver-dpyb4duzqq-uc.a.run.app:443", opts...)
Verifying server TLS certificate
Note that we’re not using TLS to authenticate to the Cloud Run app (i.e. mTLS) but rather to privately communicate.
You need to make sure the TLS certificate presented by the *.run.app
endpoint
is indeed valid and trusted, you need to show gRPC how to validate the
certificate.
For example, here’s Go code to configure gRPC client to validate server
certificate using system root CAs (ca-certificates
package on Linux):
import "crypto/tls"
import "crypto/x509"
...
systemRoots, err := x509.SystemCertPool()
if err != nil {
log.Fatal("failed to load system root CA cert pool")
}
creds := credentials.NewTLS(&tls.Config{
RootCAs: systemRoots,
})
var opts []grpc.DialOption
opts = append(opts, grpc.WithTransportCredentials(creds))
// ...other opts
conn, err := grpc.Dial("addr:port", opts...)
Alternatively, you can ignore the authenticity of the server (not recommended) and skip TLS verification by doing:
creds := credentials.NewTLS(&tls.Config{
InsecureSkipVerify: true,
})
There’s no reason to disable the TLS certificate check on Cloud Run, since
*.run.app
will serve a valid TLS certificate.
Providing authentication token
As explained in the service-to-service authentication documentation for
HTTP services, you need to provide an Authorization
header (called
“metadata” in gRPC) with the identity token for each RPC.
For example, in Go, you need to augment the ctx
object that you use in
the RPC client method to add this header:
import "google.golang.org/grpc/metadata"
ctx := metadata.AppendToOutgoingContext(context.Background(), "authorization", "Bearer " + idToken)
Note that the identity tokens expire every hour. Consider caching the token for a limited time so you don’t burden the instance metadata API to get the token on every RPC, and make sure you refresh it before it expires.
If you apply these three steps in your gRPC client programs, you should be able to authenticate to a gRPC server running on Cloud Run privately.
Leave your thoughts