Had this happen when testing something in Caddy. A crash at startup left
a lockfile created but empty.
(This was not a production crash, just dev.)
Empty lockfiles have been reported before. I think we should
treat them as stale.
It's not perfect but it's best-effort.
Eliminates a bajillion nil checks and footguns
(except in tests, which bypass exported APIs, but that is expected)
Most recent #207
Logging can still be disabled via zap.NewNop(), if necessary.
(But disabling logging in CertMagic is a really bad idea.)
OnEvent can now control basic program flow for certain events.
For example, it can cancel cert_obtaining or cert_renewing from happening.
Slight API change adds context and changes to map[string]any for data.
This is easier to work with in practice and conforms more with Caddy's
new event system.
Previously, simultaneously solving for example.com and *.example.com
using the DNS challenge (i.e. both SANs on the same cert, which CertMagic
doesn't do; but this is a general-purpose library) would cause a deadlock
because both those names use the same-name TXT record. This caused
problems with previous dependencies like lego and legacy DNS solvers,
but the new acmez library and libdns packages support this.
I've removed the locking around same-name records, which resolves
the deadlock, and improves efficiency as well, since we can now solve
challenges for example.com and *.example.com at the same time.
* Provide more detailed information in certificate events
The `cert_*` events were only providing the domain. This was pretty limited, because not much can be done with it without also knowing the issuer, since that affects where the cert is stored.
Providing both the `issuerKey` and `certKey` makes it possible for the event listener to call `StorageKeys.SiteCert(issuerKey, certKey)` to get the actual location of the cert (and similarly the private key). Particularly useful in situations where the user wants to copy the cert/key to some location for another app to use the cert that is being managed.
A similar change could probably also be done for `cached_managed_cert` and `cached_unmanaged_cert` events to provide more detail, because `cert.Names` string slice doesn't seem that useful, can't do much with that alone. But I'm not sure I understand the usefulness of those events, so meh. Caching seems like pretty much an internal implementation detail of certmagic.
* Adjust struct and field naming
* Mark CertificateEventData as experimental
This is necessary to eliminate confusing naming conventions, since now
we have Manager types, having an issuer called ACMEManager was
confusing.
CertificateManager is a redundant name as this package is called
CertMagic, so that a Manager manages certificates should be obvious.
It's also more succinct. Plus, it's consistent with Issuer which is not
named CertificateIssuer.
Calling checkAuthoritativeNss is wrong as it's not inter-changeable with
checkDNSPropagation.
Though IIUC it's not necessary to follow CNAME when in Wait(), with or
without OverrideDomain, let's wait until the override domain gets some
usage to change this. The reason that following CNAME is not necessary
is that CNAME cannot co-exist with other DNS records, if we succeed in
setting a TXT record on that domain, it cannot have a CNAME record.
@IndeedNotJames
* Fix crash because of a zero value cert in cache
Check a cert is still in cache when trying to update its
ocsp & OCSPStaple fields
Why: Bc in parallel of updateOCSPStaples() loops,
any cert can be removed from a full cache to make some room.
* Update maintain.go
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
* Add context propagation to the Storage interface
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
* Bump to Go 1.17
* Minor cleanup
* filestorage: Honor context cancellation in List()
Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
* Add OverrideDomain option to DNS01Solver
This is to delegate the challenge to a different domain. With this
change, the solver no longer follows CNAME chain when checking for
propagation as well.
* Update solvers.go
* Only check the authoritative NS when OverrideDomain is set
and keep the old code path otherwise.
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
This work made possible by Tailscale: https://tailscale.com - thank you to the Tailscale team!
* Implement custom GetCertificate callback
Useful if another entity is managing certificates and can
provide its own dynamically during handshakes.
* Refactor CustomGetCertificate into OnDemandConfig
* Set certs to managed=true
This is only sorta true, but it allows handshake-time maintenance of the
certificates that are cached from CustomGetCertificate.
Our background maintenance routine skips certs that are OnDemand so it
should be fine.
* Change CustomGetCertificate into interface value
Instead of a function
* Case-insensitive subject name comparison
Hostnames are case-insensitive
Also add context to GetCertificate
* Export a couple of outrageously useful functions
* Allow multiple custom certificate getters
Also minor refactoring and enhancements
* Fix tests
* Rename Getter -> Manager; refactor
And don't cache externally managed certs
* Minor updates to comments
The order of storing the certificates was previously changed so that the
private key would be stored first. For anyone who is creating storage
hooks which push the certificate & key to a 3rd party service (like a
CDN), the certificates are generally refused if uploaded before the
private key.
Loading can trigger the same issue if (for any reason), the certificate
& key have been deleted on the 3rd party service.
I'll admit that this stretches what the storage system should be doing,
but with this trivial change it is really easy to create a reliable
link to a CDN.