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