lnd+rpcserver: refactor TLS configuration

This commit restructures the creation of various tls related object. It
also fixes a bug where wildcard IP addresses where only instantiated for
the main RPC server and not the WalletUnlocker service.
This commit is contained in:
Joost Jager 2019-01-30 09:09:57 +01:00 committed by Wilmer Paulino
parent 3a19afe46d
commit cf42719c45
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
2 changed files with 76 additions and 47 deletions

84
lnd.go
View File

@ -177,29 +177,15 @@ func lndMain() error {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
// Ensure we create TLS key and certificate if they don't exist tlsCfg, restCreds, restProxyDest, err := getTLSConfig(cfg)
if !fileExists(cfg.TLSCertPath) && !fileExists(cfg.TLSKeyPath) { if err != nil {
if err := genCertPair(cfg.TLSCertPath, cfg.TLSKeyPath); err != nil { return err
return err
}
} }
cert, err := tls.LoadX509KeyPair(cfg.TLSCertPath, cfg.TLSKeyPath) serverCreds := credentials.NewTLS(tlsCfg)
if err != nil { serverOpts := []grpc.ServerOption{grpc.Creds(serverCreds)}
return err
} restDialOpts := []grpc.DialOption{grpc.WithTransportCredentials(*restCreds)}
tlsConf := &tls.Config{
Certificates: []tls.Certificate{cert},
CipherSuites: tlsCipherSuites,
MinVersion: tls.VersionTLS12,
}
sCreds := credentials.NewTLS(tlsConf)
serverOpts := []grpc.ServerOption{grpc.Creds(sCreds)}
cCreds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
if err != nil {
return err
}
proxyOpts := []grpc.DialOption{grpc.WithTransportCredentials(cCreds)}
// Before starting the wallet, we'll create and start our Neutrino // Before starting the wallet, we'll create and start our Neutrino
// light client instance, if enabled, in order to allow it to sync // light client instance, if enabled, in order to allow it to sync
@ -237,7 +223,7 @@ func lndMain() error {
if !cfg.NoSeedBackup { if !cfg.NoSeedBackup {
params, err := waitForWalletPassword( params, err := waitForWalletPassword(
cfg.RPCListeners, cfg.RESTListeners, serverOpts, cfg.RPCListeners, cfg.RESTListeners, serverOpts,
proxyOpts, tlsConf, restDialOpts, restProxyDest, tlsCfg,
) )
if err != nil { if err != nil {
return err return err
@ -364,7 +350,8 @@ func lndMain() error {
// exported by the rpcServer. // exported by the rpcServer.
rpcServer, err := newRPCServer( rpcServer, err := newRPCServer(
server, macaroonService, cfg.SubRPCServers, serverOpts, server, macaroonService, cfg.SubRPCServers, serverOpts,
proxyOpts, atplManager, server.invoices, tlsConf, restDialOpts, restProxyDest, atplManager, server.invoices,
tlsCfg,
) )
if err != nil { if err != nil {
srvrLog.Errorf("unable to start RPC server: %v", err) srvrLog.Errorf("unable to start RPC server: %v", err)
@ -439,6 +426,51 @@ func lndMain() error {
return nil return nil
} }
// getTLSConfig returns a TLS configuration for the gRPC server and credentials
// and a proxy destination for the REST reverse proxy.
func getTLSConfig(cfg *config) (*tls.Config, *credentials.TransportCredentials,
string, error) {
// Ensure we create TLS key and certificate if they don't exist
if !fileExists(cfg.TLSCertPath) && !fileExists(cfg.TLSKeyPath) {
err := genCertPair(cfg.TLSCertPath, cfg.TLSKeyPath)
if err != nil {
return nil, nil, "", err
}
}
cert, err := tls.LoadX509KeyPair(cfg.TLSCertPath, cfg.TLSKeyPath)
if err != nil {
return nil, nil, "", err
}
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{cert},
CipherSuites: tlsCipherSuites,
MinVersion: tls.VersionTLS12,
}
restCreds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
if err != nil {
return nil, nil, "", err
}
restProxyDest := cfg.RPCListeners[0].String()
switch {
case strings.Contains(restProxyDest, "0.0.0.0"):
restProxyDest = strings.Replace(
restProxyDest, "0.0.0.0", "127.0.0.1", 1,
)
case strings.Contains(restProxyDest, "[::]"):
restProxyDest = strings.Replace(
restProxyDest, "[::]", "[::1]", 1,
)
}
return tlsCfg, &restCreds, restProxyDest, nil
}
func main() { func main() {
// Call the "real" main in a nested manner so the defers will properly // Call the "real" main in a nested manner so the defers will properly
// be executed in the case of a graceful shutdown. // be executed in the case of a graceful shutdown.
@ -689,8 +721,8 @@ type WalletUnlockParams struct {
// WalletUnlocker server, and block until a password is provided by // WalletUnlocker server, and block until a password is provided by
// the user to this RPC server. // the user to this RPC server.
func waitForWalletPassword(grpcEndpoints, restEndpoints []net.Addr, func waitForWalletPassword(grpcEndpoints, restEndpoints []net.Addr,
serverOpts []grpc.ServerOption, proxyOpts []grpc.DialOption, serverOpts []grpc.ServerOption, restDialOpts []grpc.DialOption,
tlsConf *tls.Config) (*WalletUnlockParams, error) { restProxyDest string, tlsConf *tls.Config) (*WalletUnlockParams, error) {
// Set up a new PasswordService, which will listen for passwords // Set up a new PasswordService, which will listen for passwords
// provided over RPC. // provided over RPC.
@ -750,7 +782,7 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []net.Addr,
mux := proxy.NewServeMux() mux := proxy.NewServeMux()
err := lnrpc.RegisterWalletUnlockerHandlerFromEndpoint( err := lnrpc.RegisterWalletUnlockerHandlerFromEndpoint(
ctx, mux, grpcEndpoints[0].String(), proxyOpts, ctx, mux, restProxyDest, restDialOpts,
) )
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -409,9 +409,12 @@ type rpcServer struct {
// server. // server.
listenerCleanUp []func() listenerCleanUp []func()
// restServerOpts are a set of gRPC dial options that the REST server // restDialOpts are a set of gRPC dial options that the REST server
// proxy will use to connect to the main gRPC server. // proxy will use to connect to the main gRPC server.
restServerOpts []grpc.DialOption restDialOpts []grpc.DialOption
// restProxyDest is the address to forward REST requests to.
restProxyDest string
// tlsCfg is the TLS config that allows the REST server proxy to // tlsCfg is the TLS config that allows the REST server proxy to
// connect to the main gRPC server to proxy all incoming requests. // connect to the main gRPC server to proxy all incoming requests.
@ -435,8 +438,8 @@ var _ lnrpc.LightningServer = (*rpcServer)(nil)
// like requiring TLS, etc. // like requiring TLS, etc.
func newRPCServer(s *server, macService *macaroons.Service, func newRPCServer(s *server, macService *macaroons.Service,
subServerCgs *subRPCServerConfigs, serverOpts []grpc.ServerOption, subServerCgs *subRPCServerConfigs, serverOpts []grpc.ServerOption,
restServerOpts []grpc.DialOption, atpl *autopilot.Manager, restDialOpts []grpc.DialOption, restProxyDest string,
invoiceRegistry *invoices.InvoiceRegistry, atpl *autopilot.Manager, invoiceRegistry *invoices.InvoiceRegistry,
tlsCfg *tls.Config) (*rpcServer, error) { tlsCfg *tls.Config) (*rpcServer, error) {
// Set up router rpc backend. // Set up router rpc backend.
@ -531,13 +534,14 @@ func newRPCServer(s *server, macService *macaroons.Service,
// gRPC server, and register the main lnrpc server along side. // gRPC server, and register the main lnrpc server along side.
grpcServer := grpc.NewServer(serverOpts...) grpcServer := grpc.NewServer(serverOpts...)
rootRPCServer := &rpcServer{ rootRPCServer := &rpcServer{
restServerOpts: restServerOpts, restDialOpts: restDialOpts,
subServers: subServers, restProxyDest: restProxyDest,
tlsCfg: tlsCfg, subServers: subServers,
grpcServer: grpcServer, tlsCfg: tlsCfg,
server: s, grpcServer: grpcServer,
routerBackend: routerBackend, server: s,
quit: make(chan struct{}, 1), routerBackend: routerBackend,
quit: make(chan struct{}, 1),
} }
lnrpc.RegisterLightningServer(grpcServer, rootRPCServer) lnrpc.RegisterLightningServer(grpcServer, rootRPCServer)
@ -604,17 +608,10 @@ func (r *rpcServer) Start() error {
// TODO(roasbeef): eventually also allow the sub-servers to themselves // TODO(roasbeef): eventually also allow the sub-servers to themselves
// have a REST proxy. // have a REST proxy.
mux := proxy.NewServeMux() mux := proxy.NewServeMux()
grpcEndpoint := cfg.RPCListeners[0].String()
switch {
case strings.Contains(grpcEndpoint, "0.0.0.0"):
grpcEndpoint = strings.Replace(
grpcEndpoint, "0.0.0.0", "127.0.0.1", 1,
)
case strings.Contains(grpcEndpoint, "[::]"):
grpcEndpoint = strings.Replace(grpcEndpoint, "[::]", "[::1]", 1)
}
err := lnrpc.RegisterLightningHandlerFromEndpoint( err := lnrpc.RegisterLightningHandlerFromEndpoint(
context.Background(), mux, grpcEndpoint, r.restServerOpts, context.Background(), mux, r.restProxyDest,
r.restDialOpts,
) )
if err != nil { if err != nil {
return err return err