github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/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  	tlsConfig *tls.Config
    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  			grpcServer.serverCertificate.Store(cert)
    82  
    83  			//set up our TLS config
    84  			if len(secureConfig.CipherSuites) == 0 {
    85  				secureConfig.CipherSuites = DefaultTLSCipherSuites
    86  			}
    87  			getCert := func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
    88  				cert := grpcServer.serverCertificate.Load().(tls.Certificate)
    89  				return &cert, nil
    90  			}
    91  			//base server certificate
    92  			grpcServer.tlsConfig = &tls.Config{
    93  				VerifyPeerCertificate:  secureConfig.VerifyCertificate,
    94  				GetCertificate:         getCert,
    95  				SessionTicketsDisabled: true,
    96  				CipherSuites:           secureConfig.CipherSuites,
    97  			}
    98  
    99  			if serverConfig.SecOpts.TimeShift > 0 {
   100  				timeShift := serverConfig.SecOpts.TimeShift
   101  				grpcServer.tlsConfig.Time = func() time.Time {
   102  					return time.Now().Add((-1) * timeShift)
   103  				}
   104  			}
   105  			grpcServer.tlsConfig.ClientAuth = tls.RequestClientCert
   106  			//check if client authentication is required
   107  			if secureConfig.RequireClientCert {
   108  				//require TLS client auth
   109  				grpcServer.tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
   110  				//if we have client root CAs, create a certPool
   111  				if len(secureConfig.ClientRootCAs) > 0 {
   112  					grpcServer.clientRootCAs = make(map[string]*x509.Certificate)
   113  					grpcServer.tlsConfig.ClientCAs = x509.NewCertPool()
   114  					for _, clientRootCA := range secureConfig.ClientRootCAs {
   115  						err = grpcServer.appendClientRootCA(clientRootCA)
   116  						if err != nil {
   117  							return nil, err
   118  						}
   119  					}
   120  				}
   121  			}
   122  
   123  			// create credentials and add to server options
   124  			creds := NewServerTransportCredentials(grpcServer.tlsConfig, serverConfig.Logger)
   125  			serverOpts = append(serverOpts, grpc.Creds(creds))
   126  		} else {
   127  			return nil, errors.New("serverConfig.SecOpts must contain both Key and Certificate when UseTLS is true")
   128  		}
   129  	}
   130  	// set max send and recv msg sizes
   131  	serverOpts = append(serverOpts, grpc.MaxSendMsgSize(MaxSendMsgSize))
   132  	serverOpts = append(serverOpts, grpc.MaxRecvMsgSize(MaxRecvMsgSize))
   133  	// set the keepalive options
   134  	serverOpts = append(serverOpts, ServerKeepaliveOptions(serverConfig.KaOpts)...)
   135  	// set connection timeout
   136  	if serverConfig.ConnectionTimeout <= 0 {
   137  		serverConfig.ConnectionTimeout = DefaultConnectionTimeout
   138  	}
   139  	serverOpts = append(
   140  		serverOpts,
   141  		grpc.ConnectionTimeout(serverConfig.ConnectionTimeout))
   142  	// set the interceptors
   143  	if len(serverConfig.StreamInterceptors) > 0 {
   144  		serverOpts = append(
   145  			serverOpts,
   146  			grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(serverConfig.StreamInterceptors...)),
   147  		)
   148  	}
   149  	if len(serverConfig.UnaryInterceptors) > 0 {
   150  		serverOpts = append(
   151  			serverOpts,
   152  			grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(serverConfig.UnaryInterceptors...)),
   153  		)
   154  	}
   155  
   156  	if serverConfig.ServerStatsHandler != nil {
   157  		serverOpts = append(serverOpts, grpc.StatsHandler(serverConfig.ServerStatsHandler))
   158  	}
   159  
   160  	grpcServer.server = grpc.NewServer(serverOpts...)
   161  
   162  	if serverConfig.HealthCheckEnabled {
   163  		grpcServer.healthServer = health.NewServer()
   164  		healthpb.RegisterHealthServer(grpcServer.server, grpcServer.healthServer)
   165  	}
   166  
   167  	return grpcServer, nil
   168  }
   169  
   170  // SetServerCertificate assigns the current TLS certificate to be the peer's server certificate
   171  func (gServer *GRPCServer) SetServerCertificate(cert tls.Certificate) {
   172  	gServer.serverCertificate.Store(cert)
   173  }
   174  
   175  // Address returns the listen address for this GRPCServer instance
   176  func (gServer *GRPCServer) Address() string {
   177  	return gServer.address
   178  }
   179  
   180  // Listener returns the net.Listener for the GRPCServer instance
   181  func (gServer *GRPCServer) Listener() net.Listener {
   182  	return gServer.listener
   183  }
   184  
   185  // Server returns the grpc.Server for the GRPCServer instance
   186  func (gServer *GRPCServer) Server() *grpc.Server {
   187  	return gServer.server
   188  }
   189  
   190  // ServerCertificate returns the tls.Certificate used by the grpc.Server
   191  func (gServer *GRPCServer) ServerCertificate() tls.Certificate {
   192  	return gServer.serverCertificate.Load().(tls.Certificate)
   193  }
   194  
   195  // TLSEnabled is a flag indicating whether or not TLS is enabled for the
   196  // GRPCServer instance
   197  func (gServer *GRPCServer) TLSEnabled() bool {
   198  	return gServer.tlsConfig != nil
   199  }
   200  
   201  // MutualTLSRequired is a flag indicating whether or not client certificates
   202  // are required for this GRPCServer instance
   203  func (gServer *GRPCServer) MutualTLSRequired() bool {
   204  	return gServer.tlsConfig != nil &&
   205  		gServer.tlsConfig.ClientAuth ==
   206  			tls.RequireAndVerifyClientCert
   207  }
   208  
   209  // Start starts the underlying grpc.Server
   210  func (gServer *GRPCServer) Start() error {
   211  	// if health check is enabled, set the health status for all registered services
   212  	if gServer.healthServer != nil {
   213  		for name := range gServer.server.GetServiceInfo() {
   214  			gServer.healthServer.SetServingStatus(
   215  				name,
   216  				healthpb.HealthCheckResponse_SERVING,
   217  			)
   218  		}
   219  		gServer.healthServer.SetServingStatus(
   220  			"",
   221  			healthpb.HealthCheckResponse_SERVING,
   222  		)
   223  	}
   224  	return gServer.server.Serve(gServer.listener)
   225  }
   226  
   227  // Stop stops the underlying grpc.Server
   228  func (gServer *GRPCServer) Stop() {
   229  	gServer.server.Stop()
   230  }
   231  
   232  // AppendClientRootCAs appends PEM-encoded X509 certificate authorities to
   233  // the list of authorities used to verify client certificates
   234  func (gServer *GRPCServer) AppendClientRootCAs(clientRoots [][]byte) error {
   235  	gServer.lock.Lock()
   236  	defer gServer.lock.Unlock()
   237  	for _, clientRoot := range clientRoots {
   238  		err := gServer.appendClientRootCA(clientRoot)
   239  		if err != nil {
   240  			return err
   241  		}
   242  	}
   243  	return nil
   244  }
   245  
   246  // internal function to add a PEM-encoded clientRootCA
   247  func (gServer *GRPCServer) appendClientRootCA(clientRoot []byte) error {
   248  
   249  	certs, subjects, err := pemToX509Certs(clientRoot)
   250  	if err != nil {
   251  		return errors.WithMessage(err, "failed to append client root certificate(s)")
   252  	}
   253  
   254  	if len(certs) < 1 {
   255  		return errors.New("no client root certificates found")
   256  	}
   257  
   258  	for i, cert := range certs {
   259  		//first add to the ClientCAs
   260  		gServer.tlsConfig.ClientCAs.AddCert(cert)
   261  		//add it to our clientRootCAs map using subject as key
   262  		gServer.clientRootCAs[subjects[i]] = cert
   263  	}
   264  	return nil
   265  }
   266  
   267  // SetClientRootCAs sets the list of authorities used to verify client
   268  // certificates based on a list of PEM-encoded X509 certificate authorities
   269  func (gServer *GRPCServer) SetClientRootCAs(clientRoots [][]byte) error {
   270  	gServer.lock.Lock()
   271  	defer gServer.lock.Unlock()
   272  
   273  	//create a new map and CertPool
   274  	clientRootCAs := make(map[string]*x509.Certificate)
   275  	for _, clientRoot := range clientRoots {
   276  		certs, subjects, err := pemToX509Certs(clientRoot)
   277  		if err != nil {
   278  			return errors.WithMessage(err, "failed to set client root certificate(s)")
   279  		}
   280  
   281  		for i, cert := range certs {
   282  			clientRootCAs[subjects[i]] = cert
   283  		}
   284  	}
   285  
   286  	//create a new CertPool and populate with the new clientRootCAs
   287  	certPool := x509.NewCertPool()
   288  	for _, clientRoot := range clientRootCAs {
   289  		certPool.AddCert(clientRoot)
   290  	}
   291  
   292  	gServer.clientRootCAs = clientRootCAs
   293  	gServer.tlsConfig.ClientCAs = certPool
   294  	return nil
   295  }