diff --git a/main_test.go b/main_test.go index d8afc9c..3c559c1 100644 --- a/main_test.go +++ b/main_test.go @@ -414,10 +414,20 @@ func runOtelCli(t *testing.T, fixture Fixture) (string, Results) { return results.SpanCount >= fixture.Expect.SpanCount } + // prepare TLS configuration if needed + var tlsConf *tls.Config + if fixture.Config.ServerTLSEnabled { + tlsConf = fixture.TlsData.serverTLSConf.Clone() + if fixture.Config.ServerTLSAuthEnabled { + tlsConf.ClientAuth = tls.RequireAndVerifyClientCert + } + } + + // create server with TLS config if needed (gRPC requires it, HTTP uses TLS listener) var cs otlpserver.OtlpServer switch fixture.Config.ServerProtocol { case grpcProtocol: - cs = otlpserver.NewServer("grpc", cb, func(otlpserver.OtlpServer) {}) + cs = otlpserver.NewServer("grpc", cb, func(otlpserver.OtlpServer) {}, tlsConf) case httpProtocol: cs = otlpserver.NewServer("http", cb, func(otlpserver.OtlpServer) {}) } @@ -443,11 +453,8 @@ func runOtelCli(t *testing.T, fixture Fixture) (string, Results) { // port :0 means randomly assigned port, which we copy into {{endpoint}} var listener net.Listener var err error - if fixture.Config.ServerTLSEnabled { - tlsConf := fixture.TlsData.serverTLSConf.Clone() - if fixture.Config.ServerTLSAuthEnabled { - tlsConf.ClientAuth = tls.RequireAndVerifyClientCert - } + if fixture.Config.ServerTLSEnabled && fixture.Config.ServerProtocol == httpProtocol { + // HTTP needs a TLS listener; gRPC uses credentials passed to server listener, err = tls.Listen("tcp", "localhost:0", tlsConf) } else { listener, err = net.Listen("tcp", "localhost:0") diff --git a/otlpserver/grpcserver.go b/otlpserver/grpcserver.go index 4e32b9b..9847585 100644 --- a/otlpserver/grpcserver.go +++ b/otlpserver/grpcserver.go @@ -26,10 +26,11 @@ type GrpcServer struct { } // NewGrpcServer takes a callback and stop function and returns a Server ready -// to run with .Serve(). -func NewGrpcServer(cb Callback, stop Stopper) *GrpcServer { +// to run with .Serve(). Optional grpc.ServerOption arguments can be provided +// for TLS configuration and other server options. +func NewGrpcServer(cb Callback, stop Stopper, opts ...grpc.ServerOption) *GrpcServer { s := GrpcServer{ - server: grpc.NewServer(), + server: grpc.NewServer(opts...), callback: cb, stopper: make(chan struct{}), stopdone: make(chan struct{}, 1), diff --git a/otlpserver/server.go b/otlpserver/server.go index 683c4f6..9537e99 100644 --- a/otlpserver/server.go +++ b/otlpserver/server.go @@ -6,10 +6,13 @@ package otlpserver import ( "context" + "crypto/tls" "net" colv1 "go.opentelemetry.io/proto/otlp/collector/trace/v1" tracepb "go.opentelemetry.io/proto/otlp/trace/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" ) // Callback is a type for the function passed to newServer that is @@ -30,11 +33,17 @@ type OtlpServer interface { } // NewServer will start the requested server protocol, one of grpc, http/protobuf, -// and http/json. -func NewServer(protocol string, cb Callback, stop Stopper) OtlpServer { +// and http/json. Optional TLS configuration can be provided for gRPC servers. +func NewServer(protocol string, cb Callback, stop Stopper, tlsConf ...*tls.Config) OtlpServer { switch protocol { case "grpc": - return NewGrpcServer(cb, stop) + // if TLS config is provided, convert to gRPC credentials + var opts []grpc.ServerOption + if len(tlsConf) > 0 && tlsConf[0] != nil { + creds := credentials.NewTLS(tlsConf[0]) + opts = append(opts, grpc.Creds(creds)) + } + return NewGrpcServer(cb, stop, opts...) case "http": return NewHttpServer(cb, stop) }