github.com/true-sqn/fabric@v2.1.1+incompatible/internal/pkg/comm/server.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package comm
     8  
     9  import (
    10  	"crypto/tls"
    11  	"crypto/x509"
    12  	"net"
    13  	"sync"
    14  	"sync/atomic"
    15  	"time"
    16  
    17  	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
    18  	"github.com/pkg/errors"
    19  	"google.golang.org/grpc"
    20  	"google.golang.org/grpc/health"
    21  	healthpb "google.golang.org/grpc/health/grpc_health_v1"
    22  )
    23  
    24  type GRPCServer struct {
    25  	// Listen address for the server specified as hostname:port
    26  	address string
    27  	// Listener for handling network requests
    28  	listener net.Listener
    29  	// GRPC server
    30  	server *grpc.Server
    31  	// Certificate presented by the server for TLS communication
    32  	// stored as an atomic reference
    33  	serverCertificate atomic.Value
    34  	// lock to protect concurrent access to append / remove
    35  	lock *sync.Mutex
    36  	// Set of PEM-encoded X509 certificate authorities used to populate
    37  	// the tlsConfig.ClientCAs indexed by subject
    38  	clientRootCAs map[string]*x509.Certificate
    39  	// TLS configuration used by the grpc server
    40  	tls *TLSConfig
    41  	// Server for gRPC Health Check Protocol.
    42  	healthServer *health.Server
    43  }
    44  
    45  // NewGRPCServer creates a new implementation of a GRPCServer given a
    46  // listen address
    47  func NewGRPCServer(address string, serverConfig ServerConfig) (*GRPCServer, error) {
    48  	if address == "" {
    49  		return nil, errors.New("missing address parameter")
    50  	}
    51  	//create our listener
    52  	lis, err := net.Listen("tcp", address)
    53  
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	return NewGRPCServerFromListener(lis, serverConfig)
    58  }
    59  
    60  // NewGRPCServerFromListener creates a new implementation of a GRPCServer given
    61  // an existing net.Listener instance using default keepalive
    62  func NewGRPCServerFromListener(listener net.Listener, serverConfig ServerConfig) (*GRPCServer, error) {
    63  	grpcServer := &GRPCServer{
    64  		address:  listener.Addr().String(),
    65  		listener: listener,
    66  		lock:     &sync.Mutex{},
    67  	}
    68  
    69  	//set up our server options
    70  	var serverOpts []grpc.ServerOption
    71  
    72  	secureConfig := serverConfig.SecOpts
    73  	if secureConfig.UseTLS {
    74  		//both key and cert are required
    75  		if secureConfig.Key != nil && secureConfig.Certificate != nil {
    76  			//load server public and private keys
    77  			cert, err := tls.X509KeyPair(secureConfig.Certificate, secureConfig.Key)
    78  			if err != nil {
    79  				return nil, err
    80  			}
    81  
    82  			grpcServer.serverCertificate.Store(cert)
    83  
    84  			//set up our TLS config
    85  			if len(secureConfig.CipherSuites) == 0 {
    86  				secureConfig.CipherSuites = DefaultTLSCipherSuites
    87  			}
    88  			getCert := func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
    89  				cert := grpcServer.serverCertificate.Load().(tls.Certificate)
    90  				return &cert, nil
    91  			}
    92  
    93  			grpcServer.tls = NewTLSConfig(&tls.Config{
    94  				VerifyPeerCertificate:  secureConfig.VerifyCertificate,
    95  				GetCertificate:         getCert,
    96  				SessionTicketsDisabled: true,
    97  				CipherSuites:           secureConfig.CipherSuites,
    98  			})
    99  
   100  			if serverConfig.SecOpts.TimeShift > 0 {
   101  				timeShift := serverConfig.SecOpts.TimeShift
   102  				grpcServer.tls.config.Time = func() time.Time {
   103  					return time.Now().Add((-1) * timeShift)
   104  				}
   105  			}
   106  			grpcServer.tls.config.ClientAuth = tls.RequestClientCert
   107  			//check if client authentication is required
   108  			if secureConfig.RequireClientCert {
   109  				//require TLS client auth
   110  				grpcServer.tls.config.ClientAuth = tls.RequireAndVerifyClientCert
   111  				//if we have client root CAs, create a certPool
   112  				if len(secureConfig.ClientRootCAs) > 0 {
   113  					grpcServer.clientRootCAs = make(map[string]*x509.Certificate)
   114  
   115  					grpcServer.tls.config.ClientCAs = x509.NewCertPool()
   116  					for _, clientRootCA := range secureConfig.ClientRootCAs {
   117  						err = grpcServer.appendClientRootCA(clientRootCA)
   118  						if err != nil {
   119  							return nil, err
   120  						}
   121  					}
   122  				}
   123  			}
   124  
   125  			// create credentials and add to server options
   126  			creds := NewServerTransportCredentials(grpcServer.tls, serverConfig.Logger)
   127  			serverOpts = append(serverOpts, grpc.Creds(creds))
   128  		} else {
   129  			return nil, errors.New("serverConfig.SecOpts must contain both Key and Certificate when UseTLS is true")
   130  		}
   131  	}
   132  	// set max send and recv msg sizes
   133  	serverOpts = append(serverOpts, grpc.MaxSendMsgSize(MaxSendMsgSize))
   134  	serverOpts = append(serverOpts, grpc.MaxRecvMsgSize(MaxRecvMsgSize))
   135  	// set the keepalive options
   136  	serverOpts = append(serverOpts, ServerKeepaliveOptions(serverConfig.KaOpts)...)
   137  	// set connection timeout
   138  	if serverConfig.ConnectionTimeout <= 0 {
   139  		serverConfig.ConnectionTimeout = DefaultConnectionTimeout
   140  	}
   141  	serverOpts = append(
   142  		serverOpts,
   143  		grpc.ConnectionTimeout(serverConfig.ConnectionTimeout))
   144  	// set the interceptors
   145  	if len(serverConfig.StreamInterceptors) > 0 {
   146  		serverOpts = append(
   147  			serverOpts,
   148  			grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(serverConfig.StreamInterceptors...)),
   149  		)
   150  	}
   151  
   152  	if len(serverConfig.UnaryInterceptors) > 0 {
   153  		serverOpts = append(
   154  			serverOpts,
   155  			grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(serverConfig.UnaryInterceptors...)),
   156  		)
   157  	}
   158  
   159  	if serverConfig.ServerStatsHandler != nil {
   160  		serverOpts = append(serverOpts, grpc.StatsHandler(serverConfig.ServerStatsHandler))
   161  	}
   162  
   163  	grpcServer.server = grpc.NewServer(serverOpts...)
   164  
   165  	if serverConfig.HealthCheckEnabled {
   166  		grpcServer.healthServer = health.NewServer()
   167  		healthpb.RegisterHealthServer(grpcServer.server, grpcServer.healthServer)
   168  	}
   169  
   170  	return grpcServer, nil
   171  }
   172  
   173  // SetServerCertificate assigns the current TLS certificate to be the peer's server certificate
   174  func (gServer *GRPCServer) SetServerCertificate(cert tls.Certificate) {
   175  	gServer.serverCertificate.Store(cert)
   176  }
   177  
   178  // Address returns the listen address for this GRPCServer instance
   179  func (gServer *GRPCServer) Address() string {
   180  	return gServer.address
   181  }
   182  
   183  // Listener returns the net.Listener for the GRPCServer instance
   184  func (gServer *GRPCServer) Listener() net.Listener {
   185  	return gServer.listener
   186  }
   187  
   188  // Server returns the grpc.Server for the GRPCServer instance
   189  func (gServer *GRPCServer) Server() *grpc.Server {
   190  	return gServer.server
   191  }
   192  
   193  // ServerCertificate returns the tls.Certificate used by the grpc.Server
   194  func (gServer *GRPCServer) ServerCertificate() tls.Certificate {
   195  	return gServer.serverCertificate.Load().(tls.Certificate)
   196  }
   197  
   198  // TLSEnabled is a flag indicating whether or not TLS is enabled for the
   199  // GRPCServer instance
   200  func (gServer *GRPCServer) TLSEnabled() bool {
   201  	return gServer.tls != nil
   202  }
   203  
   204  // MutualTLSRequired is a flag indicating whether or not client certificates
   205  // are required for this GRPCServer instance
   206  func (gServer *GRPCServer) MutualTLSRequired() bool {
   207  	return gServer.TLSEnabled() &&
   208  		gServer.tls.Config().ClientAuth == tls.RequireAndVerifyClientCert
   209  }
   210  
   211  // Start starts the underlying grpc.Server
   212  func (gServer *GRPCServer) Start() error {
   213  	// if health check is enabled, set the health status for all registered services
   214  	if gServer.healthServer != nil {
   215  		for name := range gServer.server.GetServiceInfo() {
   216  			gServer.healthServer.SetServingStatus(
   217  				name,
   218  				healthpb.HealthCheckResponse_SERVING,
   219  			)
   220  		}
   221  
   222  		gServer.healthServer.SetServingStatus(
   223  			"",
   224  			healthpb.HealthCheckResponse_SERVING,
   225  		)
   226  	}
   227  	return gServer.server.Serve(gServer.listener)
   228  }
   229  
   230  // Stop stops the underlying grpc.Server
   231  func (gServer *GRPCServer) Stop() {
   232  	gServer.server.Stop()
   233  }
   234  
   235  // internal function to add a PEM-encoded clientRootCA
   236  func (gServer *GRPCServer) appendClientRootCA(clientRoot []byte) error {
   237  	certs, subjects, err := pemToX509Certs(clientRoot)
   238  	if err != nil {
   239  		return errors.WithMessage(err, "failed to append client root certificate(s)")
   240  	}
   241  
   242  	if len(certs) < 1 {
   243  		return errors.New("no client root certificates found")
   244  	}
   245  
   246  	for i, cert := range certs {
   247  		//first add to the ClientCAs
   248  		gServer.tls.AddClientRootCA(cert)
   249  		//add it to our clientRootCAs map using subject as key
   250  		gServer.clientRootCAs[subjects[i]] = cert
   251  	}
   252  
   253  	return nil
   254  }
   255  
   256  // SetClientRootCAs sets the list of authorities used to verify client
   257  // certificates based on a list of PEM-encoded X509 certificate authorities
   258  func (gServer *GRPCServer) SetClientRootCAs(clientRoots [][]byte) error {
   259  	gServer.lock.Lock()
   260  	defer gServer.lock.Unlock()
   261  
   262  	//create a new map and CertPool
   263  	clientRootCAs := make(map[string]*x509.Certificate)
   264  	for _, clientRoot := range clientRoots {
   265  		certs, subjects, err := pemToX509Certs(clientRoot)
   266  		if err != nil {
   267  			return errors.WithMessage(err, "failed to set client root certificate(s)")
   268  		}
   269  
   270  		for i, cert := range certs {
   271  			clientRootCAs[subjects[i]] = cert
   272  		}
   273  	}
   274  
   275  	//create a new CertPool and populate with the new clientRootCAs
   276  	certPool := x509.NewCertPool()
   277  	for _, clientRoot := range clientRootCAs {
   278  		certPool.AddCert(clientRoot)
   279  	}
   280  
   281  	gServer.clientRootCAs = clientRootCAs
   282  	gServer.tls.SetClientCAs(certPool)
   283  	return nil
   284  }