From ccbf7f338663dce19b4a8fbe9a4e1147e65e9cb4 Mon Sep 17 00:00:00 2001 From: Shingo Omura Date: Fri, 10 Dec 2021 20:58:57 +0900 Subject: [PATCH] Setting just servername to :authority pseudo header in client when using tls. HTTP/2(RFC7540) defines :authority pseudo header includes the authority portion of target URI but it must not include userinfo part (i.e. url.Host). However, when TLS certificate specified, grpc-go requires it must match with its servername specified for certificate validation. Signed-off-by: Shingo Omura --- client/client.go | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/client/client.go b/client/client.go index 0da2a12bd756..a5c14581c578 100644 --- a/client/client.go +++ b/client/client.go @@ -43,6 +43,7 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error } needDialer := true needWithInsecure := true + tlsServerName := "" var unary []grpc.UnaryClientInterceptor var stream []grpc.StreamClientInterceptor @@ -63,6 +64,7 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error } gopts = append(gopts, opt) needWithInsecure = false + tlsServerName = credInfo.ServerName } if wt, ok := o.(*withTracer); ok { customTracer = true @@ -106,14 +108,23 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error address = appdefaults.Address } - // grpc-go uses a slightly different naming scheme: https://github.com/grpc/grpc/blob/master/doc/naming.md - // This will end up setting rfc non-complient :authority header to address string (e.g. tcp://127.0.0.1:1234). - // So, here sets right authority header via WithAuthority DialOption. - addressURL, err := url.Parse(address) - if err != nil { - return nil, err + // Setting :authority pseudo header + // - HTTP/2 (RFC7540) defines :authority pseudo header includes + // the authority portion of target URI but it must not include + // userinfo part (i.e. url.Host). + // ref: https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.3 + // - However, when TLS specified, grpc-go requires it must match + // with its servername specified for certificate validation. + authority := tlsServerName + if authority == "" { + // authority as hostname from target address + uri, err := url.Parse(address) + if err != nil { + return nil, err + } + authority = uri.Host } - gopts = append(gopts, grpc.WithAuthority(addressURL.Host)) + gopts = append(gopts, grpc.WithAuthority(authority)) unary = append(unary, grpcerrors.UnaryClientInterceptor) stream = append(stream, grpcerrors.StreamClientInterceptor)