Can gRPC+gRPC Gateway not use certificates?

  gateway, golang, grpc, php

If you have dabbled in gRPC+gRPC Gateway before, you will definitely encounter this problem, namely“Why does TLS have to be turned on in order to realize dual traffic on the same port, can it not be turned on?”Or“I don’t want to use certificates to realize these functions, ok? “. I have been asked these questions by countless people and have convinced many people, but persuasion does not mean giving up. Not the year before last, does not mean not this year, today I want to share the context and specific implementation methods for you.

image

Original address:Can gRPC+gRPC Gateway not use certificates?

In the past

Why not h2

Because ..net/http2Only “h2” identity is supported, while “h2” identity HTTP/2 must use Transport Layer Security (TLS) protocol, which is used for TLS application layer protocol negotiation fields and to identify HTTP/2 over TLS.

In short, it isnet/http2TLS must be used to interact. Generally speaking, certificates are required, so of course, non-TLS cannot be supported.

Looking for h2c

Then this road won’t work. Can we think of another road? That is the “h2c” identifier in the HTTP/2 specification, which identifies the protocol that allows HTTP/2 to run over clear text TCP. This identifier is used in the HTTP/1.1 upgrade header field and identifies HTTP/2 over TCP.

But this road already existed as early as 2015.issueAt that time @bradfitz made it clear that he “does not intend to support h2c, and is very satisfied with supporting TLS only. Please ask me again one year later.” The original reply is as follows:

We do not plan to support h2c. I don’t want to receive bug reports from users who get bitten by transparent proxies messing with h2c. Also, until there’s widespread browser support, it’s not interesting. I am also not interested in being the chicken or the egg to get browser support going. I’m very happy with the TLS-only situation, and things likehttps://LetsEncrypt.org/will make TLS much easier (and automatic) soon.

Ask me again in one year.

Thinking about other ways

Use cmux

Based on multiplexersoheilhy/cmuxThe alternative realization ofStoakes/grpc-gateway-example. If yescmuxI’m interested in the implementation of, you can also see《Golang: Run multiple services on one port》.

Use third-party h2

This kind of logic that belongs to oneself has realized h2c, in order to achieve the effect.

Now

After continuous discussions in the community, in June 2018, the representative of the “h2c” logogolang.org/x/net/http2/h2cThe standard library was formally merged, and since then we can use the official standard library (h2c), which implements the unencrypted mode of HTTP/2, so we can use the standard library to provide both HTTP/1.1 and HTTP/2 functions on the same port.

Using Standard Library h2c

import (
    ...

    "golang.org/x/net/http2"
    "golang.org/x/net/http2/h2c"
    "google.golang.org/grpc"

    "github.com/grpc-ecosystem/grpc-gateway/runtime"

    pb "github.com/EDDYCJY/go-grpc-example/proto"
)

...

func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Handler {
    return h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
            grpcServer.ServeHTTP(w, r)
        } else {
            otherHandler.ServeHTTP(w, r)
        }
    }), &http2.Server{})
}

func main() {
    server := grpc.NewServer()

    pb.RegisterSearchServiceServer(server, &SearchService{})

    mux := http.NewServeMux()
    gwmux := runtime.NewServeMux()
    dopts := []grpc.DialOption{grpc.WithInsecure()}

    err := pb.RegisterSearchServiceHandlerFromEndpoint(context.Background(), gwmux, "localhost:"+PORT, dopts)
    ...
    mux.Handle("/", gwmux)
    http.ListenAndServe(":"+PORT, grpcHandlerFunc(server, mux))
}

We can see that the key is to call theh2c.NewHandlerThe method carries out special treatment,h2c.NewHandlerOne will be returnedhttp.handler, the main internal logic is to intercept allh2cTraffic, and then hijack and redirect it to the corresponding according to different request traffic typesHanderTo deal with.

Verification

HTTP/1.1

$ curl -X GET 'http://127.0.0.1:9005/search?request=EDDYCJY'
{"response":"EDDYCJY"}

HTTP/2(gRPC)

...
func main() {
    conn, err := grpc.Dial(":"+PORT, grpc.WithInsecure())
    ...
    client := pb.NewSearchServiceClient(conn)
    resp, err := client.Search(context.Background(), &pb.SearchRequest{
        Request: "gRPC",
    })
}

Output results:

$ go run main.go
2019/06/21 20:04:09 resp: gRPC h2c Server

Summary

In this article, I introduced the general causes and consequences, and introduced several solutions, I suggest you choose the officialh2cStandard library to achieve this function, is also simple. In the end, I hope this article can help you, whether you have been worried about this problem for a long time or are struggling with it.

References