lnrpc: lets encrypt
This commit enables lnd to request and renew a Let's Encrypt certificate. This certificate is used both for the grpc as well as the rest listeners. It allows clients to connect without having a copy of the (public) server certificate. Co-authored-by: Vegard Engen <vegard@engen.priv.no>
This commit is contained in:
1 parent
999ffffa37
commit
403d72b468
6 files changed
+133
-22
No files matched your search
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/btcsuite/btcwallet/wallet"
|
||||
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/lightninglabs/neutrino"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
@@ -264,13 +265,15 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error {
|
||||
defer cleanUp()
|
||||
|
||||
// Only process macaroons if --no-macaroons isn't set.
|
||||
tlsCfg, restCreds, restProxyDest, err := getTLSConfig(cfg)
|
||||
tlsCfg, restCreds, restProxyDest, cleanUp, err := getTLSConfig(cfg)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("unable to load TLS credentials: %v", err)
|
||||
ltndLog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer cleanUp()
|
||||
|
||||
serverCreds := credentials.NewTLS(tlsCfg)
|
||||
serverOpts := []grpc.ServerOption{grpc.Creds(serverCreds)}
|
||||
|
||||
@@ -748,7 +751,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error {
|
||||
// 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) {
|
||||
string, func(), error) {
|
||||
|
||||
// Ensure we create TLS key and certificate if they don't exist.
|
||||
if !fileExists(cfg.TLSCertPath) && !fileExists(cfg.TLSKeyPath) {
|
||||
@@ -759,7 +762,7 @@ func getTLSConfig(cfg *Config) (*tls.Config, *credentials.TransportCredentials,
|
||||
cfg.TLSDisableAutofill, cert.DefaultAutogenValidity,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
rpcsLog.Infof("Done generating TLS certificates")
|
||||
}
|
||||
@@ -768,7 +771,7 @@ func getTLSConfig(cfg *Config) (*tls.Config, *credentials.TransportCredentials,
|
||||
cfg.TLSCertPath, cfg.TLSKeyPath,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
|
||||
// We check whether the certifcate we have on disk match the IPs and
|
||||
@@ -782,7 +785,7 @@ func getTLSConfig(cfg *Config) (*tls.Config, *credentials.TransportCredentials,
|
||||
cfg.TLSExtraDomains, cfg.TLSDisableAutofill,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,12 +797,12 @@ func getTLSConfig(cfg *Config) (*tls.Config, *credentials.TransportCredentials,
|
||||
|
||||
err := os.Remove(cfg.TLSCertPath)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
|
||||
err = os.Remove(cfg.TLSKeyPath)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
|
||||
rpcsLog.Infof("Renewing TLS certificates...")
|
||||
@@ -809,7 +812,7 @@ func getTLSConfig(cfg *Config) (*tls.Config, *credentials.TransportCredentials,
|
||||
cfg.TLSDisableAutofill, cert.DefaultAutogenValidity,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
rpcsLog.Infof("Done renewing TLS certificates")
|
||||
|
||||
@@ -818,14 +821,15 @@ func getTLSConfig(cfg *Config) (*tls.Config, *credentials.TransportCredentials,
|
||||
cfg.TLSCertPath, cfg.TLSKeyPath,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
tlsCfg := cert.TLSConfFromCert(certData)
|
||||
|
||||
restCreds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
|
||||
restProxyDest := cfg.RPCListeners[0].String()
|
||||
@@ -841,7 +845,65 @@ func getTLSConfig(cfg *Config) (*tls.Config, *credentials.TransportCredentials,
|
||||
)
|
||||
}
|
||||
|
||||
return tlsCfg, &restCreds, restProxyDest, nil
|
||||
// If Let's Encrypt is enabled, instantiate autocert to request/renew
|
||||
// the certificates.
|
||||
cleanUp := func() {}
|
||||
if cfg.LetsEncryptDomain != "" {
|
||||
ltndLog.Infof("Using Let's Encrypt certificate for domain %v",
|
||||
cfg.LetsEncryptDomain)
|
||||
|
||||
manager := autocert.Manager{
|
||||
Cache: autocert.DirCache(cfg.LetsEncryptDir),
|
||||
Prompt: autocert.AcceptTOS,
|
||||
HostPolicy: autocert.HostWhitelist(cfg.LetsEncryptDomain),
|
||||
}
|
||||
|
||||
addr := fmt.Sprintf(":%v", cfg.LetsEncryptPort)
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: manager.HTTPHandler(nil),
|
||||
}
|
||||
shutdownCompleted := make(chan struct{})
|
||||
cleanUp = func() {
|
||||
err := srv.Shutdown(context.Background())
|
||||
if err != nil {
|
||||
ltndLog.Errorf("Autocert listener shutdown "+
|
||||
" error: %v", err)
|
||||
|
||||
return
|
||||
}
|
||||
<-shutdownCompleted
|
||||
ltndLog.Infof("Autocert challenge listener stopped")
|
||||
}
|
||||
|
||||
go func() {
|
||||
ltndLog.Infof("Autocert challenge listener started "+
|
||||
"at %v", addr)
|
||||
|
||||
err := srv.ListenAndServe()
|
||||
if err != http.ErrServerClosed {
|
||||
ltndLog.Errorf("autocert http: %v", err)
|
||||
}
|
||||
close(shutdownCompleted)
|
||||
}()
|
||||
|
||||
getCertificate := func(h *tls.ClientHelloInfo) (
|
||||
*tls.Certificate, error) {
|
||||
|
||||
lecert, err := manager.GetCertificate(h)
|
||||
if err != nil {
|
||||
ltndLog.Errorf("GetCertificate: %v", err)
|
||||
return &certData, nil
|
||||
}
|
||||
|
||||
return lecert, err
|
||||
}
|
||||
|
||||
// The self-signed tls.cert remains available as fallback.
|
||||
tlsCfg.GetCertificate = getCertificate
|
||||
}
|
||||
|
||||
return tlsCfg, &restCreds, restProxyDest, cleanUp, nil
|
||||
}
|
||||
|
||||
// fileExists reports whether the named file or directory exists.
|
||||
|
||||
Reference in new issue
Block a user