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 }