Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CertCache ¶
type CertCache struct { // Domains to validate Domains []string CertFile string NewCertFile string // contains filtered or unexported fields }
func New ¶
func New(certs []*x509.Certificate, certFetcher *certfetcher.CertFetcher, domains []string, certFile string, newCertFile string, ocspCache string, generateOCSPResponse OCSPResponder, timeNow func() time.Time) *CertCache
Callers need to call Init() on the returned CertCache before the cache can auto-renew certs. Callers can use the uninitialized CertCache for testing certificates (without doing OCSP or cert refreshes).
TODO(banaag): per gregable@ comments: The long argument list makes the callsites tricky to read and easy to get wrong, especially if several of the arguments have the same type.
An alternative pattern would be to create an IsInitialized() bool or similarly named function that verifies all of the required fields have been set. Then callers can just set fields in the struct by name and assert IsInitialized before doing anything with it.
func PopulateCertCache ¶
func PopulateCertCache(config *util.Config, key crypto.PrivateKey, generateOCSPResponse OCSPResponder, developmentMode bool, autoRenewCert bool) (*CertCache, error)
Creates cert cache by loading certs and keys from disk, doing validation and populating the cert cache with current set of certificate related information. If development mode is true, prints a warning for certs that can't sign HTTP exchanges.
func (*CertCache) GetLatestCert ¶
func (this *CertCache) GetLatestCert() *x509.Certificate
Gets the latest cert. Returns the current cert if the cache has not been initialized or if the certFetcher is not set (good for testing) If cert is invalid, it will attempt to renew. If cert is still valid, returns the current cert.
func (*CertCache) IsHealthy ¶
If we've been unable to fetch a fresh OCSP response before expiry of the old one, or, at server start-up, if we're unable to fetch a valid OCSP request at all (either from disk or network), then return false. This signals to the packager that it should not try to package anything; just proxy the content unsigned. This is per sleevi requirement:
- Some idea of what to do when "things go bad". What happens when it's been 7 days, no new OCSP response can be obtained, and the current response is about to expire?
type CertHandler ¶
type CertHandler interface { GetLatestCert() *x509.Certificate IsHealthy() error }
type Chained ¶
type Chained struct {
// contains filtered or unexported fields
}
Represents a file backed by two updateables. If the first is expired, then the second is consulted, and only if both are expired is update() run (and the contents of both updateables updated).
type InMemory ¶
type InMemory struct {
// contains filtered or unexported fields
}
Represents an in-memory copy of a file.
type LocalFile ¶
type LocalFile struct {
// contains filtered or unexported fields
}
Uses the OS's file locking mechanisms to obtain shared/exclusive locks to ensure update() is only called once. This is probably good enough for a few processes running on one server.
For more processes than that, or for a distributed deployment over NFS, it would require more reading / testing to see if this is OK. I'm not an expert on distributed systems and http://0pointer.de/blog/projects/locking.html and https://gavv.github.io/blog/file-locks/ have lots of warnings, and I haven't found any documentation on how NFS decides on an exclusive lock owner if there's contention. https://tools.ietf.org/html/rfc3530#section-8.1.5 suggests NFSv4 supports some lock sequencing mechanism that I assume won't result in starvation, but I don't know how well that's supported by various clients & servers.
Users interested in scaling this widely may want to implement their own Updateable using some reasonable remote storage / leader election libraries.
type OCSPResponder ¶
type OCSPResponder func(*x509.Certificate) ([]byte, error)
type Updateable ¶
type Updateable interface { // Reads the contents of the file. Calls isExpired(contents); if true, // then it calls update() and writes the returned contents back to the // file. Read(ctx context.Context, isExpired func([]byte) bool, update func([]byte) []byte) ([]byte, error) }
This is an abstraction over a single file on a remote storage mechanism. It is meant for use-cases where there will be mostly reads. The update callback is assumed to be expensive, and thus it should be coordinated among all replicas and only done once.