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:

  1. Use TLS endpoint to connect
  2. Verify TLS CA certificate
  3. 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.