-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Re-create TLS files if IPs or domains changed #3932
Conversation
2a60d00
to
0700680
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solid fix! No major comments on my end after a first pass review. Have reproduced a live scenario to test this fix to ensure that the upgrade to 0.9 will be seamless for any existing mobile apps that package the current form of lnd
on mobile?
cert/selfsigned.go
Outdated
@@ -100,6 +100,52 @@ func dnsNames(tlsExtraDomains []string) (string, []string) { | |||
return host, dnsNames | |||
} | |||
|
|||
// Outdated returns whether the given certificate is outdated wrt the IPs and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming suggestion: IsOutdated
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrt -> w.r.t
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
godoc
comment could also use further elaboration on what "outdated" means in this context (IPs or domains aren't a sub-set of what's currently in the cert), as a few of our related packages use this cert
package to handle routine cert operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
cert/selfsigned.go
Outdated
|
||
// If the certificate has a different number of IP addresses, it is | ||
// definitely out of date. | ||
if len(ips) != len(cert.IPAddresses) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, should we relax this to allow more IPs in the cert than are specified in our config? A sample case being a cert that a user has generated themselves, and synced with the existing configuration options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem then is that even though the user removes an IP from the config, the cert will still allow it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will return a false positive if the user accidentally includes a duplicate IP, when in fact we don't need to change the cert. imo it'd be better to convert both to sets, then compare length.
one possible downside of this is that certs generated before this may not have checked for duplicates, so it would cause those to be refreshed. perhaps we should start checking for duplicate entries before creating new certs as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, fixed: 7aba914
@@ -744,6 +744,12 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs, | |||
return nil, nil, "", err | |||
} | |||
rpcsLog.Infof("Done renewing TLS certificates") | |||
|
|||
// Reload the certificate data. | |||
certData, _, err = cert.LoadCert(tlsCertPath, tlsKeyPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depending on where we go with this PR, we may want to consider splitting off this commit (either into a new PR or to be cherry-picked onto the next release branch).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we know why our unit tests didn't catch this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we have any lnd.go
level unit tests?
Gate behind cmd line flag |
ef5bd29
to
5010ad6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, nice and clean pr, only nits
cert/selfsigned_test.go
Outdated
} | ||
|
||
// We expect it to be considered outdated if the IPs or | ||
// domains don't match exaactly what we created. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: exactly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
cert/selfsigned_test.go
Outdated
|
||
// We'll attempt to check up-to-date status for all variants of 1-3 | ||
// number of IPs and domains. | ||
for numIPs := 1; numIPs <= 3; numIPs++ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could use len(extraIPs)
and len(extraDomains)
instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is much better indeed!
cert/selfsigned_test.go
Outdated
expected := numIPs != 2 || numDomains != 2 | ||
if outdated != expected { | ||
t.Fatalf("expected certificate to be "+ | ||
"outdated=%v", expected) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: i'd add "got=%v" to be more informative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
5010ad6
to
2e6ee95
Compare
cert/selfsigned.go
Outdated
|
||
// If the certificate has a different number of IP addresses, it is | ||
// definitely out of date. | ||
if len(ips) != len(cert.IPAddresses) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will return a false positive if the user accidentally includes a duplicate IP, when in fact we don't need to change the cert. imo it'd be better to convert both to sets, then compare length.
one possible downside of this is that certs generated before this may not have checked for duplicates, so it would cause those to be refreshed. perhaps we should start checking for duplicate entries before creating new certs as well?
cert/selfsigned.go
Outdated
// the order to match exactly, as we assume the same tlsExtraIPs were | ||
// used when the certificate was first created. | ||
for i := range ips { | ||
if !ips[i].Equal(cert.IPAddresses[i]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
related to above, imo order shouldn't matter here. plus we can reuse the sets created above to check. i think it'd be less obvious to users that reordering ip/dns/domains would cause their certs to be renewed
cert/selfsigned.go
Outdated
_, dnsNames := dnsNames(tlsExtraDomains) | ||
|
||
// If the number of domains are different, it is out of date. | ||
if len(cert.DNSNames) != len(dnsNames) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar comment here wrt to duplicates/set matching
@@ -744,6 +744,12 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs, | |||
return nil, nil, "", err | |||
} | |||
rpcsLog.Infof("Done renewing TLS certificates") | |||
|
|||
// Reload the certificate data. | |||
certData, _, err = cert.LoadCert(tlsCertPath, tlsKeyPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we know why our unit tests didn't catch this?
LogDir string `long:"logdir" description:"Directory to log output."` | ||
MaxLogFiles int `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation)"` | ||
MaxLogFileSize int `long:"maxlogfilesize" description:"Maximum logfile size in MB"` | ||
TLSAutoRefresh bool `long:"tlsautorefresh" description:"Re-generate TLS certificate and key if the IPs or domains are changed"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: recently i think we've been preferring the hyphenated config options, but i see that it would deviate from our other --tls*
options :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, would be nice to move all tls options into its own category, but maybe not for a minor release like this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed!
This commit creates a new utility method IsOutdated that can be used to check whether a TLS certificate mathces the extra IPs and domains given in the lnd config.
This commit makes lnd recreate its TLS certificate if the config's tlsextradomains or tlsextraips changed. This is useful, since earlier user would have to manually delete the files to trigger lnd to recreate them. To ensure users don't accidentally have their TLS certificate recreated, we gate it behind a flag --tlsautorefresh that defaults to false.
After renewing the certificate, the new certificate wasn't actually loaded and used, causing the old one to be used until lnd was restarted. This fixes that by reloading it after it has been written.
d964be6
to
ba38bda
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-blocking comment, otherwise LGTM! 🔥
LogDir string `long:"logdir" description:"Directory to log output."` | ||
MaxLogFiles int `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation)"` | ||
MaxLogFileSize int `long:"maxlogfilesize" description:"Maximum logfile size in MB"` | ||
TLSAutoRefresh bool `long:"tlsautorefresh" description:"Re-generate TLS certificate and key if the IPs or domains are changed"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed!
|
||
// And that the IPs are considered equal. | ||
if !ip1.Equal(ip2) { | ||
return true, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this reachable? is it possible for two IPs to have the same string representation, but be unequal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No idea 😂
This commit makes lnd recreate its TLS certificate if the config's
tlsextradomains or tlsextraips changed. This is useful, since earlier
user would have to manually delete the files to trigger lnd to recreate
them.
The new bahavior is gated behind a new flag
--tlsautorefresh