caddytls

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Jul 19, 2016 License: Apache-2.0 Imports: 32 Imported by: 0

Documentation

Overview

Package caddytls facilitates the management of TLS assets and integrates Let's Encrypt functionality into Caddy with first-class support for creating and renewing certificates automatically. It also implements the tls directive.

This package is meant to be used by Caddy server types. To use the tls directive, a server type must import this package and call RegisterConfigGetter(). The server type must make and keep track of the caddytls.Config structs that this package produces. It must also add tls to its list of directives. When it comes time to make the server instances, the server type can call MakeTLSConfig() to convert a []caddytls.Config to a single tls.Config for use in tls.NewListener(). It is also recommended to call RotateSessionTicketKeys() when starting a new listener.

Index

Constants

View Source
const (
	// HTTPChallengePort is the officially designated port for
	// the HTTP challenge.
	HTTPChallengePort = "80"

	// TLSSNIChallengePort is the officially designated port for
	// the TLS-SNI challenge.
	TLSSNIChallengePort = "443"

	// DefaultHTTPAlternatePort is the port on which the ACME
	// client will open a listener and solve the HTTP challenge.
	// If this alternate port is used instead of the default
	// port, then whatever is listening on the default port must
	// be capable of proxying or forwarding the request to this
	// alternate port.
	DefaultHTTPAlternatePort = "5033"
)
View Source
const (
	// NumTickets is how many tickets to hold and consider
	// to decrypt TLS sessions.
	NumTickets = 4

	// TicketRotateInterval is how often to generate
	// new ticket for TLS PFS encryption
	TicketRotateInterval = 10 * time.Hour
)
View Source
const (
	// RenewInterval is how often to check certificates for renewal.
	RenewInterval = 12 * time.Hour

	// OCSPInterval is how often to check if OCSP stapling needs updating.
	OCSPInterval = 1 * time.Hour

	// RenewDurationBefore is how long before expiration to renew certificates.
	RenewDurationBefore = (24 * time.Hour) * 30
)

Variables

View Source
var (
	// DefaultEmail represents the Let's Encrypt account email to use if none provided.
	DefaultEmail string

	// Agreed indicates whether user has agreed to the Let's Encrypt SA.
	Agreed bool

	// DefaultCAUrl is the default URL to the CA's ACME directory endpoint.
	// It's very important to set this unless you set it in every Config.
	DefaultCAUrl string

	// DefaultKeyType is used as the type of key for new certificates
	// when no other key type is specified.
	DefaultKeyType = acme.RSA2048
)
View Source
var ErrStorageNotFound = errors.New("data not found")

ErrStorageNotFound is returned by Storage implementations when data is expected to be present but is not.

View Source
var OnDemandIssuedCount = new(int32)

OnDemandIssuedCount is the number of certificates that have been issued on-demand by this process. It is only safe to modify this count atomically. If it reaches onDemandMaxIssue, on-demand issuances will fail.

Functions

func HTTPChallengeHandler

func HTTPChallengeHandler(w http.ResponseWriter, r *http.Request, altPort string) bool

HTTPChallengeHandler proxies challenge requests to ACME client if the request path starts with challengeBasePath. It returns true if it handled the request and no more needs to be done; it returns false if this call was a no-op and the request still needs handling.

func HostQualifies

func HostQualifies(hostname string) bool

HostQualifies returns true if the hostname alone appears eligible for automatic HTTPS. For example, localhost, empty hostname, and IP addresses are not eligible because we cannot obtain certificates for those names.

func MakeTLSConfig

func MakeTLSConfig(configs []*Config) (*tls.Config, error)

MakeTLSConfig reduces configs into a single tls.Config. If TLS is to be disabled, a nil tls.Config will be returned.

func QualifiesForManagedTLS

func QualifiesForManagedTLS(c ConfigHolder) bool

QualifiesForManagedTLS returns true if c qualifies for for managed TLS (but not on-demand TLS specifically). It does NOT check to see if a cert and key already exist for the config. If the return value is true, you should be OK to set c.TLSConfig().Managed to true; then you should check that value in the future instead, because the process of setting up the config may make it look like it doesn't qualify even though it originally did.

func RegisterConfigGetter

func RegisterConfigGetter(serverType string, fn ConfigGetter)

RegisterConfigGetter registers fn as the way to get a Config for server type serverType.

func RegisterDNSProvider

func RegisterDNSProvider(name string, provider DNSProviderConstructor)

RegisterDNSProvider registers provider by name for solving the ACME DNS challenge.

func RenewManagedCertificates

func RenewManagedCertificates(allowPrompts bool) (err error)

RenewManagedCertificates renews managed certificates.

func Revoke

func Revoke(host string) error

Revoke revokes the certificate for host via ACME protocol. It assumes the certificate was obtained from the CA at DefaultCAUrl.

func RotateSessionTicketKeys

func RotateSessionTicketKeys(cfg *tls.Config) chan struct{}

RotateSessionTicketKeys rotates the TLS session ticket keys on cfg every TicketRotateInterval. It spawns a new goroutine so this function does NOT block. It returns a channel you should close when you are ready to stop the key rotation, like when the server using cfg is no longer running.

func SetDefaultTLSParams

func SetDefaultTLSParams(config *Config)

SetDefaultTLSParams sets the default TLS cipher suites, protocol versions, and server preferences of a server.Config if they were not previously set (it does not overwrite; only fills in missing values).

func UpdateOCSPStaples

func UpdateOCSPStaples()

UpdateOCSPStaples updates the OCSP stapling in all eligible, cached certificates.

Types

type ACMEClient

type ACMEClient struct {
	*acme.Client
	AllowPrompts bool
	// contains filtered or unexported fields
}

ACMEClient is an acme.Client with custom state attached.

func (*ACMEClient) Obtain

func (c *ACMEClient) Obtain(names []string) error

Obtain obtains a single certificate for names. It stores the certificate on the disk if successful.

func (*ACMEClient) Renew

func (c *ACMEClient) Renew(name string) error

Renew renews the managed certificate for name. Right now our storage mechanism only supports one name per certificate, so this function only accepts one domain as input. It can be easily modified to support SAN certificates if, one day, they become desperately needed enough that our storage mechanism is upgraded to be more complex to support SAN certs.

Anyway, this function is safe for concurrent use.

func (*ACMEClient) Revoke

func (c *ACMEClient) Revoke(name string) error

Revoke revokes the certificate for name and deltes it from storage.

type Certificate

type Certificate struct {
	tls.Certificate

	// Names is the list of names this certificate is written for.
	// The first is the CommonName (if any), the rest are SAN.
	Names []string

	// NotAfter is when the certificate expires.
	NotAfter time.Time

	// OCSP contains the certificate's parsed OCSP response.
	OCSP *ocsp.Response

	// Config is the configuration with which the certificate was
	// loaded or obtained and with which it should be maintained.
	Config *Config
}

Certificate is a tls.Certificate with associated metadata tacked on. Even if the metadata can be obtained by parsing the certificate, we can be more efficient by extracting the metadata once so it's just there, ready to use.

func CacheManagedCertificate

func CacheManagedCertificate(domain string, cfg *Config) (Certificate, error)

CacheManagedCertificate loads the certificate for domain into the cache, flagging it as Managed and, if onDemand is true, as "OnDemand" (meaning that it was obtained or loaded during a TLS handshake).

This function is safe for concurrent use.

type Config

type Config struct {
	// The hostname or class of hostnames this config is
	// designated for; can contain wildcard characters
	// according to RFC 6125 §6.4.3 - this field MUST
	// be set in order for things to work as expected
	Hostname string

	// Whether TLS is enabled
	Enabled bool

	// Minimum and maximum protocol versions to allow
	ProtocolMinVersion uint16
	ProtocolMaxVersion uint16

	// The list of cipher suites; first should be
	// TLS_FALLBACK_SCSV to prevent degrade attacks
	Ciphers []uint16

	// Whether to prefer server cipher suites
	PreferServerCipherSuites bool

	// Client authentication policy
	ClientAuth tls.ClientAuthType

	// List of client CA certificates to allow, if
	// client authentication is enabled
	ClientCerts []string

	// Manual means user provides own certs and keys
	Manual bool

	// Managed means config qualifies for implicit,
	// automatic, managed TLS; as opposed to the user
	// providing and managing the certificate manually
	Managed bool

	// OnDemand means the class of hostnames this
	// config applies to may obtain and manage
	// certificates at handshake-time (as opposed
	// to pre-loaded at startup); OnDemand certs
	// will be managed the same way as preloaded
	// ones, however, if an OnDemand cert fails to
	// renew, it is removed from the in-memory
	// cache; if this is true, Managed must
	// necessarily be true
	OnDemand bool

	// SelfSigned means that this hostname is
	// served with a self-signed certificate
	// that we generated in memory for convenience
	SelfSigned bool

	// The endpoint of the directory for the ACME
	// CA we are to use
	CAUrl string

	// The host (ONLY the host, not port) to listen
	//on if necessary to start a a listener to solve
	// an ACME challenge
	ListenHost string

	// The alternate port (ONLY port, not host)
	// to use for the ACME HTTP challenge; this
	// port will be used if we proxy challenges
	// coming in on port 80 to this alternate port
	AltHTTPPort string

	// The string identifier of the DNS provider
	// to use when solving the ACME DNS challenge
	DNSProvider string

	// The email address to use when creating or
	// using an ACME account (fun fact: if this
	// is set to "off" then this config will not
	// qualify for managed TLS)
	ACMEEmail string

	// The type of key to use when generating
	// certificates
	KeyType acme.KeyType

	// The explicitly set storage creator or nil; use
	// StorageFor() to get a guaranteed non-nil Storage
	// instance. Note, Caddy may call this frequently so
	// implementors are encouraged to cache any heavy
	// instantiations.
	StorageCreator StorageCreator
}

Config describes how TLS should be configured and used.

func (*Config) ObtainCert

func (c *Config) ObtainCert(allowPrompts bool) error

ObtainCert obtains a certificate for c.Hostname, as long as a certificate does not already exist in storage on disk. It only obtains and stores certificates (and their keys) to disk, it does not load them into memory. If allowPrompts is true, the user may be shown a prompt. If proxyACME is true, the relevant ACME challenges will be proxied to the alternate port.

func (*Config) RenewCert

func (c *Config) RenewCert(allowPrompts bool) error

RenewCert renews the certificate for c.Hostname. If there is already a lock on renewal, this will not perform the renewal and no error will occur.

func (*Config) StorageFor

func (c *Config) StorageFor(caURL string) (Storage, error)

StorageFor obtains a TLS Storage instance for the given CA URL which should be unique for every different ACME CA. If a StorageCreator is set on this Config, it will be used. Otherwise the default file storage implementation is used. When the error is nil, this is guaranteed to return a non-nil Storage instance.

type ConfigGetter

type ConfigGetter func(c *caddy.Controller) *Config

ConfigGetter gets a Config keyed by key.

type ConfigHolder

type ConfigHolder interface {
	TLSConfig() *Config
	Host() string
	Port() string
}

ConfigHolder is any type that has a Config; it presumably is connected to a hostname and port on which it is serving.

type DNSProviderConstructor

type DNSProviderConstructor func(credentials ...string) (acme.ChallengeProvider, error)

DNSProviderConstructor is a function that takes credentials and returns a type that can solve the ACME DNS challenges.

type FileStorage

type FileStorage string

FileStorage is a root directory and facilitates forming file paths derived from it. It is used to get file paths in a consistent, cross- platform way for persisting ACME assets on the file system.

func (FileStorage) DeleteSite

func (s FileStorage) DeleteSite(domain string) error

DeleteSite implements Storage.DeleteSite by deleting just the cert from disk. If it is not present, the ErrStorageNotFound error instance is returned.

func (FileStorage) LoadSite

func (s FileStorage) LoadSite(domain string) (*SiteData, error)

LoadSite implements Storage.LoadSite by loading it from disk. If it is not present, the ErrStorageNotFound error instance is returned.

func (FileStorage) LoadUser

func (s FileStorage) LoadUser(email string) (*UserData, error)

LoadUser implements Storage.LoadUser by loading it from disk. If it is not present, the ErrStorageNotFound error instance is returned.

func (FileStorage) LockRegister

func (s FileStorage) LockRegister(domain string) (bool, error)

LockRegister implements Storage.LockRegister by just returning true because it is not a multi-server storage implementation.

func (FileStorage) MostRecentUserEmail

func (s FileStorage) MostRecentUserEmail() string

MostRecentUserEmail implements Storage.MostRecentUserEmail by finding the most recently written sub directory in the users' directory. It is named after the email address. This corresponds to the most recent call to StoreUser.

func (FileStorage) SiteExists

func (s FileStorage) SiteExists(domain string) bool

SiteExists implements Storage.SiteExists by checking for the presence of cert and key files.

func (FileStorage) StoreSite

func (s FileStorage) StoreSite(domain string, data *SiteData) error

StoreSite implements Storage.StoreSite by writing it to disk. The base directories needed for the file are automatically created as needed.

func (FileStorage) StoreUser

func (s FileStorage) StoreUser(email string, data *UserData) error

StoreUser implements Storage.StoreUser by writing it to disk. The base directories needed for the file are automatically created as needed.

func (FileStorage) UnlockRegister

func (s FileStorage) UnlockRegister(domain string) error

UnlockRegister implements Storage.UnlockRegister as a no-op because it is not a multi-server storage implementation.

type SiteData

type SiteData struct {
	// Cert is the public cert byte array.
	Cert []byte
	// Key is the private key byte array.
	Key []byte
	// Meta is metadata about the site used by Caddy.
	Meta []byte
}

SiteData contains persisted items pertaining to an individual site.

type Storage

type Storage interface {

	// SiteDataExists returns true if this site info exists in storage.
	// Site data is considered present when StoreSite has been called
	// successfully (without DeleteSite having been called of course).
	SiteExists(domain string) bool

	// LoadSite obtains the site data from storage for the given domain and
	// returns. If data for the domain does not exist, the
	// ErrStorageNotFound error instance is returned. For multi-server
	// storage, care should be taken to make this load atomic to prevent
	// race conditions that happen with multiple data loads.
	LoadSite(domain string) (*SiteData, error)

	// StoreSite persists the given site data for the given domain in
	// storage. For multi-server storage, care should be taken to make this
	// call atomic to prevent half-written data on failure of an internal
	// intermediate storage step. Implementers can trust that at runtime
	// this function will only be invoked after LockRegister and before
	// UnlockRegister of the same domain.
	StoreSite(domain string, data *SiteData) error

	// DeleteSite deletes the site for the given domain from storage.
	// Multi-server implementations should attempt to make this atomic. If
	// the site does not exist, the ErrStorageNotFound error instance is
	// returned.
	DeleteSite(domain string) error

	// LockRegister is called before Caddy attempts to obtain or renew a
	// certificate. This function is used as a mutex/semaphore for making
	// sure something else isn't already attempting obtain/renew. It should
	// return true (without error) if the lock is successfully obtained
	// meaning nothing else is attempting renewal. It should return false
	// (without error) if this domain is already locked by something else
	// attempting renewal. As a general rule, if this isn't multi-server
	// shared storage, this should always return true. To prevent deadlocks
	// for multi-server storage, all internal implementations should put a
	// reasonable expiration on this lock in case UnlockRegister is unable to
	// be called due to system crash. Errors should only be returned in
	// exceptional cases. Any error will prevent renewal.
	LockRegister(domain string) (bool, error)

	// UnlockRegister is called after Caddy has attempted to obtain or renew
	// a certificate, regardless of whether it was successful. If
	// LockRegister essentially just returns true because this is not
	// multi-server storage, this can be a no-op. Otherwise this should
	// attempt to unlock the lock obtained in this process by LockRegister.
	// If no lock exists, the implementation should not return an error. An
	// error is only for exceptional cases.
	UnlockRegister(domain string) error

	// LoadUser obtains user data from storage for the given email and
	// returns it. If data for the email does not exist, the
	// ErrStorageNotFound error instance is returned. Multi-server
	// implementations should take care to make this operation atomic for
	// all loaded data items.
	LoadUser(email string) (*UserData, error)

	// StoreUser persists the given user data for the given email in
	// storage. Multi-server implementations should take care to make this
	// operation atomic for all stored data items.
	StoreUser(email string, data *UserData) error

	// MostRecentUserEmail provides the most recently used email parameter
	// in StoreUser. The result is an empty string if there are no
	// persisted users in storage.
	MostRecentUserEmail() string
}

Storage is an interface abstracting all storage used by the Caddy's TLS subsystem. Implementations of this interface store site data along with user data.

func FileStorageCreator

func FileStorageCreator(caURL *url.URL) (Storage, error)

FileStorageCreator creates a new Storage instance backed by the local disk. The resulting Storage instance is guaranteed to be non-nil if there is no error. This can be used by "middleware" implementations that may want to proxy the disk storage.

type StorageCreator

type StorageCreator func(caURL *url.URL) (Storage, error)

StorageCreator is a function type that is used in the Config to instantiate a new Storage instance. This function can return a nil Storage even without an error.

type User

type User struct {
	Email        string
	Registration *acme.RegistrationResource
	// contains filtered or unexported fields
}

User represents a Let's Encrypt user account.

func (User) GetEmail

func (u User) GetEmail() string

GetEmail gets u's email.

func (User) GetPrivateKey

func (u User) GetPrivateKey() crypto.PrivateKey

GetPrivateKey gets u's private key.

func (User) GetRegistration

func (u User) GetRegistration() *acme.RegistrationResource

GetRegistration gets u's registration resource.

type UserData

type UserData struct {
	// Reg is the user registration byte array.
	Reg []byte
	// Key is the user key byte array.
	Key []byte
}

UserData contains persisted items pertaining to a user.

Directories

Path Synopsis
Package storagetest provides utilities to assist in testing caddytls.Storage implementations.
Package storagetest provides utilities to assist in testing caddytls.Storage implementations.

Jump to

Keyboard shortcuts

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