From dfbb84ef381d9abf554ec60746c08747c7518170 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 10 Mar 2020 14:56:18 +0300 Subject: [PATCH] rpc: support https Allow to start TLS RPC server on a separate port. Closes #702. --- config/config.go | 10 ++++++++++ config/protocol.mainnet.yml | 5 +++++ config/protocol.privnet.yml | 5 +++++ config/protocol.testnet.yml | 5 +++++ pkg/rpc/server/server.go | 39 +++++++++++++++++++++++++++++++++++-- 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index d7b631ca8..177c500ef 100644 --- a/config/config.go +++ b/config/config.go @@ -111,6 +111,16 @@ type ( // MaxGasInvoke is a maximum amount of gas which // can be spent during RPC call. MaxGasInvoke util.Fixed8 `yaml:"MaxGasInvoke"` + TLSConfig TLSConfig `yaml:"TLSConfig"` + } + + // TLSConfig describes SSL/TLS configuration. + TLSConfig struct { + Enabled bool `yaml:"Enabled"` + Address string `yaml:"Address"` + Port uint16 `yaml:"Port"` + CertFile string `yaml:"CertFile"` + KeyFile string `yaml:"KeyFile"` } // NetMode describes the mode the blockchain will operate on. diff --git a/config/protocol.mainnet.yml b/config/protocol.mainnet.yml index b1f354fab..4cae5019c 100644 --- a/config/protocol.mainnet.yml +++ b/config/protocol.mainnet.yml @@ -65,6 +65,11 @@ ApplicationConfiguration: Enabled: true EnableCORSWorkaround: false Port: 10332 + TLSConfig: + Enabled: false + Port: 10331 + CertFile: serv.crt + KeyFile: serv.key Prometheus: Enabled: true Port: 2112 diff --git a/config/protocol.privnet.yml b/config/protocol.privnet.yml index 8e2c092d6..839c47280 100644 --- a/config/protocol.privnet.yml +++ b/config/protocol.privnet.yml @@ -51,6 +51,11 @@ ApplicationConfiguration: Enabled: true EnableCORSWorkaround: false Port: 20331 + TLSConfig: + Enabled: false + Port: 20330 + CertFile: serv.crt + KeyFile: serv.key Prometheus: Enabled: true Port: 2112 diff --git a/config/protocol.testnet.yml b/config/protocol.testnet.yml index 09ea83a23..50d320b2b 100644 --- a/config/protocol.testnet.yml +++ b/config/protocol.testnet.yml @@ -65,6 +65,11 @@ ApplicationConfiguration: Enabled: true EnableCORSWorkaround: false Port: 20332 + TLSConfig: + Enabled: false + Port: 20331 + CertFile: serv.crt + KeyFile: serv.key Prometheus: Enabled: true Port: 2112 diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index c7b3f4040..a8291afcf 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "math" + "net" "net/http" "strconv" @@ -37,6 +38,7 @@ type ( config config.RPCConfig coreServer *network.Server log *zap.Logger + https *http.Server } ) @@ -50,12 +52,20 @@ func New(chain core.Blockchainer, conf config.RPCConfig, coreServer *network.Ser Addr: conf.Address + ":" + strconv.FormatUint(uint64(conf.Port), 10), } + var tlsServer *http.Server + if cfg := conf.TLSConfig; cfg.Enabled { + tlsServer = &http.Server{ + Addr: net.JoinHostPort(cfg.Address, strconv.FormatUint(uint64(cfg.Port), 10)), + } + } + return Server{ Server: httpServer, chain: chain, config: conf, coreServer: coreServer, log: log, + https: tlsServer, } } @@ -69,14 +79,39 @@ func (s *Server) Start(errChan chan error) { s.Handler = http.HandlerFunc(s.requestHandler) s.log.Info("starting rpc-server", zap.String("endpoint", s.Addr)) - errChan <- s.ListenAndServe() + if cfg := s.config.TLSConfig; cfg.Enabled { + s.https.Handler = http.HandlerFunc(s.requestHandler) + s.log.Info("starting rpc-server (https)", zap.String("endpoint", s.https.Addr)) + go func() { + err := s.https.ListenAndServeTLS(cfg.CertFile, cfg.KeyFile) + if err != nil { + s.log.Error("failed to start TLS RPC server", zap.Error(err)) + } + errChan <- err + }() + } + err := s.ListenAndServe() + if err != nil { + s.log.Error("failed to start RPC server", zap.Error(err)) + } + errChan <- err } // Shutdown overrides the http.Server Shutdown // method. func (s *Server) Shutdown() error { + var httpsErr error + if s.config.TLSConfig.Enabled { + s.log.Info("shutting down rpc-server (https)", zap.String("endpoint", s.https.Addr)) + httpsErr = s.https.Shutdown(context.Background()) + } + s.log.Info("shutting down rpc-server", zap.String("endpoint", s.Addr)) - return s.Server.Shutdown(context.Background()) + err := s.Server.Shutdown(context.Background()) + if err == nil { + return httpsErr + } + return err } func (s *Server) requestHandler(w http.ResponseWriter, httpRequest *http.Request) {