certcache

package
v0.0.0-...-57974ef Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2022 License: Apache-2.0 Imports: 24 Imported by: 3

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) Init

func (this *CertCache) Init() error

func (*CertCache) IsHealthy

func (this *CertCache) IsHealthy() error

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:

  1. 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?

func (*CertCache) ServeHTTP

func (this *CertCache) ServeHTTP(resp http.ResponseWriter, req *http.Request)

func (*CertCache) Stop

func (this *CertCache) Stop() bool

Stop stops the goroutines spawned in Init, which are automatically updating the certificate and the OCSP response. It returns true if the call actually stops them, false if they have already been stopped.

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).

func (*Chained) Read

func (this *Chained) Read(ctx context.Context, isExpired func([]byte) bool, update func([]byte) []byte) ([]byte, error)

type InMemory

type InMemory struct {
	// contains filtered or unexported fields
}

Represents an in-memory copy of a file.

func (*InMemory) Read

func (this *InMemory) Read(ctx context.Context, isExpired func([]byte) bool, update func([]byte) []byte) ([]byte, error)

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.

func (*LocalFile) Read

func (this *LocalFile) Read(ctx context.Context, isExpired func([]byte) bool, update func([]byte) []byte) ([]byte, error)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL