diff --git a/grpc_client.go b/grpc_client.go index ce32b89..6cd1173 100644 --- a/grpc_client.go +++ b/grpc_client.go @@ -23,6 +23,7 @@ package signaling import ( "context" + "fmt" "log" "net" "strings" @@ -31,6 +32,7 @@ import ( "github.com/dlintw/goconf" "google.golang.org/grpc" codes "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" status "google.golang.org/grpc/status" ) @@ -52,8 +54,8 @@ type GrpcClient struct { impl *grpcClientImpl } -func NewGrpcClient(target string) (*GrpcClient, error) { - conn, err := grpc.Dial(target, grpc.WithTransportCredentials(insecure.NewCredentials())) +func NewGrpcClient(target string, opts ...grpc.DialOption) (*GrpcClient, error) { + conn, err := grpc.Dial(target, opts...) if err != nil { return nil, err } @@ -145,7 +147,19 @@ func (c *GrpcClients) load(config *goconf.ConfigFile) error { c.mu.Lock() defer c.mu.Unlock() - targets, _ := config.GetString("grpc", "targets") + var opts []grpc.DialOption + caFile, _ := config.GetString("grpc", "ca") + if caFile != "" { + creds, err := credentials.NewClientTLSFromFile(caFile, "") + if err != nil { + return fmt.Errorf("invalid GRPC CA in %s: %w", caFile, err) + } + + opts = append(opts, grpc.WithTransportCredentials(creds)) + } else { + log.Printf("WARNING: No GRPC CA configured, expecting unencrypted connections") + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } clientsMap := make(map[string]*GrpcClient) var clients []*GrpcClient @@ -155,6 +169,7 @@ func (c *GrpcClients) load(config *goconf.ConfigFile) error { clientsMap[target] = client } + targets, _ := config.GetString("grpc", "targets") for _, target := range strings.Split(targets, ",") { target = strings.TrimSpace(target) if target == "" { @@ -167,7 +182,7 @@ func (c *GrpcClients) load(config *goconf.ConfigFile) error { continue } - client, err := NewGrpcClient(target) + client, err := NewGrpcClient(target, opts...) if err != nil { for target, client := range clientsMap { if closeerr := client.Close(); closeerr != nil { diff --git a/grpc_server.go b/grpc_server.go index 7d4102f..ec2e454 100644 --- a/grpc_server.go +++ b/grpc_server.go @@ -31,6 +31,7 @@ import ( "github.com/dlintw/goconf" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" status "google.golang.org/grpc/status" ) @@ -50,12 +51,25 @@ func NewGrpcServer(config *goconf.ConfigFile) (*GrpcServer, error) { var err error listener, err = net.Listen("tcp", addr) if err != nil { - return nil, fmt.Errorf("could not create GRPC server: %w", err) + return nil, fmt.Errorf("could not create GRPC listener %s: %w", addr, err) } } - conn := grpc.NewServer() + var opts []grpc.ServerOption + certificateFile, _ := config.GetString("grpc", "certificate") + keyFile, _ := config.GetString("grpc", "key") + if certificateFile != "" && keyFile != "" { + creds, err := credentials.NewServerTLSFromFile(certificateFile, keyFile) + if err != nil { + return nil, fmt.Errorf("invalid GRPC server certificate / key in %s / %s: %w", certificateFile, keyFile, err) + } + opts = append(opts, grpc.Creds(creds)) + } else { + log.Printf("WARNING: No GRPC server certificate and/or key configured, running unencrypted") + } + + conn := grpc.NewServer(opts...) result := &GrpcServer{ conn: conn, listener: listener, diff --git a/server.conf.in b/server.conf.in index acf3bed..d6a88ce 100644 --- a/server.conf.in +++ b/server.conf.in @@ -240,5 +240,14 @@ connectionsperhost = 8 # Comment line to disable the listener. #listen = 0.0.0.0:9090 +# Certificate / private key to use for the GRPC server. +# Omit to use unencrypted connections. +#certificate = /path/to/grpc-server.crt +#key = /path/to/grpc-server.key + +# CA certificate that is allowed to issue certificates of GRPC servers. +# Omit to expect unencrypted connections. +#ca = /path/to/grpc-ca.crt + # Comma-separated list of GRPC targets to connect to for clustering mode. #targets = 192.168.0.1:9090, 192.168.0.1:9091