DEV Community

Alexey Vasyukov
Alexey Vasyukov

Posted on

How to setup and test TLS in gRPC/gRPC-Web

This article has samples in Node.JS but can be helpful for other languages, so lets start. All working examples you can find here.


How TLS works?

I recommend to read the best comic-article about how TLS works.

gRPC connection types

There are three types for gRPC connections you can use:

  1. Insecure — all data transmitted without encryption.
  2. Server-Side TLS — browser like encryption, where only the server provides TLS certificate to the client.
  3. Mutual TLS — most secure, both the server and the client provides there certificates to each other.

Creating Self-Signed certificates

This is optional step if you don’t have certificate from any CA’s or want to work with TLS on localhost.

Note that in production environment is mostly recommended to choose CA’s certificate for more security, for example you can get free certificate from Let’s Encrypt.


Preparation

Let’s start from implementing our gRPC service.

First, we will define our service Protocol Buffers file.

Second, we need to generate types, service and client definitions.
For TypeScript I prefer to use ts-proto, but you can choose any tool you like depends on your language.

protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_opt=env=node,outputServices=grpc-js --ts_proto_out=./src/generated ./proto/tls_service.proto
Enter fullscreen mode Exit fullscreen mode

Now we can implement our server running on Node.js.


gRPC

We will use an official @grpc/grpc-js package both for server and client side here.


Server-Side TLS

Server-Side TLS requires only the server certificate and it’s private key.

Server

Client

Now we can implement the client side.

Note here that if your TLS certificate signed with CA (not Self-Signed) you don’t need to provide this certificate on the client, it should automatically works.


Mutual TLS

Mutual TLS requires the root certificate, server certificate and it’s private key.
Root certificate would be used here for checking that client certificate is signed and the server can trust to the client.

Server

Like in Server-Side section, changed only getServerCredentials function.

Client

Like in Server-Side section, changed only getChannelCredentials function.


Override SSL target name

@grpc/grpc-js package additionally provides some useful channel options that you can set. You can read about each of them here.

grpc.ssl_target_name_override — would be helpful for us when the actual server behind the proxy and CN don’t match.

To setup channel options you need to pass them into client constructor’s third argument.


gRPC-Web

Read the grpc.io blog post about the state of gRPC-Web.

TL;DR
The things you should know:

  1. Working scheme:
    Client ↔ Proxy [HTTP(S) gRPC-Web] ↔ Server (gRPC)

  2. There are two implementations — official gRPC-Web and @improbable-eng/grpc-web.

  3. Right now gRPC-Web supports only Unary and Server-Streaming requests over HTTP(S).

    Additionally @improbable-eng/grpc-web supports client-side and bi-directional streaming with an experimental websocket transport. This is not part of the gRPC-Web spec, and is not recommended for production use.

  4. There are two proxies — Envoy with gRPC-Web filter from official gRPC-Web and grpcwebproxy from @improbable-eng.

  5. You can use either client with either proxy.

  6. Clients have different communication transports.

    Official gRPC-web supports only XMLHttpRequest.
    @improbable-eng/grpc-web additionally support Fetch (using it if available) and can be extended with custom transport, for example Node.js.

In this example we will use Envoy proxy running in docker.


Server-Side TLS

Server

As you already noticed we need to start our gRPC service behind the proxy. So there is nothing to change, simply start service with Server-Side TLS we discuss earlier.

After that we need to setup envoy and start it.


docker-compose up envoy-server
Enter fullscreen mode Exit fullscreen mode

That’s it. Your gRPC-Web proxy with Server-Side TLS will be available at https://0.0.0.0:8080.

Mutual TLS

Server

The hack here is to start gRPC service with Server-Side TLS but on envoy side check the client certificate signed by trusted CA.


docker-compose up envoy-mutual
Enter fullscreen mode Exit fullscreen mode

Great! Your gRPC-Web proxy with Mutual TLS will be available at https://0.0.0.0:8080.


Testing both gRPC and gRPC-Web requests

Recently I released a multi-platform desktop gRPC / gRPC-Web client called ezy. I’m working with gRPC every day and there is no any fully featured, UI/UX-perfect clients for gRPC testing, so I tried to create one.

This client has fully featured support of gRPC / gRPC-Web. I would be appreciate if you try it.

🙏 If you have any feedback or ideas feel free to open discussion.

Top comments (0)