From e3ace5c38f2f54a6c77579a6dc59f19865d99d71 Mon Sep 17 00:00:00 2001 From: Ankur Shrivastava Date: Mon, 10 Jun 2024 15:18:36 +0800 Subject: [PATCH] Adding support for TLS in grpc server --- README.md | 2 +- config/README.md | 15 +++++++++++++-- config/config.go | 7 +++++++ core.go | 39 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 43ac28e..bc2c414 100755 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ type CB interface { ``` -### func [New]() +### func [New]() ```go func New(c config.Config) CB diff --git a/config/README.md b/config/README.md index c5f3655..488bb80 100755 --- a/config/README.md +++ b/config/README.md @@ -16,7 +16,7 @@ import "github.com/go-coldbrew/core/config" -## type [Config]() +## type [Config]() Config is the configuration for the Coldbrew server It is populated from environment variables and has sensible defaults for all fields so that you can just use it as is without any configuration The following environment variables are supported and can be used to override the defaults for the fields @@ -64,8 +64,12 @@ type Config struct { DisableGRPCReflection bool `envconfig:"DISABLE_GRPC_REFLECTION" default:"false"` // Trace header, when this HTTP header is present CB will add the value to log/trace contexts TraceHeaderName string `envconfig:"TRACE_HEADER_NAME" default:"x-trace-id"` - // When we match this HTTP header prefix, we forward append the values to grpc metadata + // [Deprecated] - please use HTTPHeaderPrefixes instead HTTPHeaderPrefix string `envconfig:"HTTP_HEADER_PREFIX" default:""` + // When we match one of the HTTP header prefix configured in this list, + // we forward append the values to grpc metadata. If the deprecated HTTPHeaderPrefix + // is set, it will only be used if this field is not configured + HTTPHeaderPrefixes []string `envconfig:"HTTP_HEADER_PREFIXES" default:""` // Should we log calls to GRPC reflection API, defaults to true DoNotLogGRPCReflection bool `envconfig:"DO_NOT_LOG_GRPC_REFLECTION" default:"true"` // Should we disable signal handler, defaults to false and CB handles all SIG_INT/SIG_TERM @@ -99,6 +103,13 @@ type Config struct { // DisableAutoMaxProcs disables the automatic setting of GOMAXPROCS // This is useful when running in a container where the container runtime sets GOMAXPROCS for you already DisableAutoMaxProcs bool `envconfig:"DISABLE_AUTO_MAX_PROCS" default:"false"` + + // GRPCTLSKeyFile and GRPCTLSCertFile are the paths to the key and cert files for the GRPC server + // If these are set, the server will be started with TLS enabled + GRPCTLSKeyFile string `envconfig:"GRPC_TLS_KEY_FILE"` + // GRPCTLSCertFile an GRPCTLSKeyFile are the paths to the key and cert files for the GRPC server + // If these are set, the server will be started with TLS enabled + GRPCTLSCertFile string `envconfig:"GRPC_TLS_CERT_FILE"` } ``` diff --git a/config/config.go b/config/config.go index 104e918..117102f 100644 --- a/config/config.go +++ b/config/config.go @@ -85,4 +85,11 @@ type Config struct { // DisableAutoMaxProcs disables the automatic setting of GOMAXPROCS // This is useful when running in a container where the container runtime sets GOMAXPROCS for you already DisableAutoMaxProcs bool `envconfig:"DISABLE_AUTO_MAX_PROCS" default:"false"` + + // GRPCTLSKeyFile and GRPCTLSCertFile are the paths to the key and cert files for the GRPC server + // If these are set, the server will be started with TLS enabled + GRPCTLSKeyFile string `envconfig:"GRPC_TLS_KEY_FILE"` + // GRPCTLSCertFile an GRPCTLSKeyFile are the paths to the key and cert files for the GRPC server + // If these are set, the server will be started with TLS enabled + GRPCTLSCertFile string `envconfig:"GRPC_TLS_CERT_FILE"` } diff --git a/core.go b/core.go index 51321a2..e9648e1 100644 --- a/core.go +++ b/core.go @@ -2,6 +2,7 @@ package core import ( "context" + "crypto/tls" "errors" "fmt" "io" @@ -25,6 +26,7 @@ import ( "github.com/opentracing/opentracing-go/ext" "github.com/prometheus/client_golang/prometheus/promhttp" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/reflection" @@ -39,6 +41,7 @@ type cb struct { httpServer *http.Server cancelFunc context.CancelFunc gracefulWait sync.WaitGroup + creds credentials.TransportCredentials } func (c *cb) SetService(svc CBService) error { @@ -170,8 +173,13 @@ func (c *cb) initHTTP(ctx context.Context) (*http.Server, error) { mux := runtime.NewServeMux(muxOpts...) + creds := c.creds + if creds == nil { + creds = insecure.NewCredentials() + } + opts := []grpc.DialOption{ - grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithTransportCredentials(creds), grpc.WithUnaryInterceptor( interceptors.DefaultClientInterceptor( grpc_opentracing.WithTraceHeaderName(c.config.TraceHeaderName), @@ -220,7 +228,7 @@ func (c *cb) initHTTP(ctx context.Context) (*http.Server, error) { return gwServer, nil } -func (c *cb) runHTTP(ctx context.Context, svr *http.Server) error { +func (c *cb) runHTTP(_ context.Context, svr *http.Server) error { return svr.ListenAndServe() } @@ -248,8 +256,33 @@ func (c *cb) getGRPCServerOptions() []grpc.ServerOption { return so } +func loadTLSCredentials(certFile, keyFile string) (credentials.TransportCredentials, error) { + // Load server's certificate and private key + serverCert, err := tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return nil, err + } + + // Create the credentials and return it + config := &tls.Config{ + Certificates: []tls.Certificate{serverCert}, + ClientAuth: tls.NoClientCert, + } + + return credentials.NewTLS(config), nil +} + func (c *cb) initGRPC(ctx context.Context) (*grpc.Server, error) { - grpcServer := grpc.NewServer(c.getGRPCServerOptions()...) + so := c.getGRPCServerOptions() + if c.config.GRPCTLSCertFile != "" && c.config.GRPCTLSKeyFile != "" { + creds, err := loadTLSCredentials(c.config.GRPCTLSCertFile, c.config.GRPCTLSKeyFile) + if err != nil { + return nil, err + } + c.creds = creds + so = append(so, grpc.Creds(creds)) + } + grpcServer := grpc.NewServer(so...) for _, s := range c.svc { if err := s.InitGRPC(ctx, grpcServer); err != nil { return nil, err