Documentation ¶
Overview ¶
Package https facilitates the management of TLS assets and integrates Let's Encrypt functionality into CoreDNS with first-class support for creating and renewing certificates automatically. It is designed to configure sites for HTTPS by default.
Index ¶
- Constants
- Variables
- func Activate(configs []server.Config) ([]server.Config, error)
- func ConfigQualifies(cfg server.Config) bool
- func Deactivate() (err error)
- func EnableTLS(configs []server.Config, loadCertificates bool) error
- func GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error)
- func GetOrObtainCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error)
- func MarkQualified(configs []server.Config)
- func ObtainCerts(configs []server.Config, allowPrompts, proxyACME bool) error
- func RequestCallback(w http.ResponseWriter, r *http.Request) bool
- func Revoke(host string) error
- func Setup(c *setup.Controller) (middleware.Middleware, error)
- type ACMEClient
- type Certificate
- type Storage
- func (s Storage) Site(domain string) string
- func (s Storage) SiteCertFile(domain string) string
- func (s Storage) SiteKeyFile(domain string) string
- func (s Storage) SiteMetaFile(domain string) string
- func (s Storage) Sites() string
- func (s Storage) User(email string) string
- func (s Storage) UserKeyFile(email string) string
- func (s Storage) UserRegFile(email string) string
- func (s Storage) Users() string
- type User
Constants ¶
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 )
const AlternatePort = "5033"
AlternatePort is the port on which the acme client will open a listener and solve the CA's challenges. If this alternate port is used instead of the default port (80 or 443), then the default port for the challenge must be forwarded to this one.
Variables ¶
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 // CAUrl represents the base URL to the CA's ACME endpoint CAUrl string )
var KeyType = acme.EC384
KeyType is the type to use for new keys. This shouldn't need to change except for in tests; the size can be drastically reduced for speed.
var NewACMEClient = func(email string, allowPrompts bool) (*ACMEClient, error) { leUser, err := getUser(email) if err != nil { return nil, err } client, err := acme.NewClient(CAUrl, &leUser, KeyType) if err != nil { return nil, err } if leUser.Registration == nil { reg, err := client.Register() if err != nil { return nil, errors.New("registration error: " + err.Error()) } leUser.Registration = reg if allowPrompts { if !Agreed && reg.TosURL == "" { Agreed = promptUserAgreement(saURL, false) } if !Agreed && reg.TosURL == "" { return nil, errors.New("user must agree to terms") } } err = client.AgreeToTOS() if err != nil { saveUser(leUser) return nil, errors.New("error agreeing to terms: " + err.Error()) } err = saveUser(leUser) if err != nil { return nil, errors.New("could not save user: " + err.Error()) } } return &ACMEClient{ Client: client, AllowPrompts: allowPrompts, }, nil }
NewACMEClient creates a new ACMEClient given an email and whether prompting the user is allowed. Clients should not be kept and re-used over long periods of time, but immediate re-use is more efficient than re-creating on every iteration.
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 Activate ¶
Activate sets up TLS for each server config in configs as needed; this consists of acquiring and maintaining certificates and keys for qualifying configs and enabling OCSP stapling for all TLS-enabled configs.
This function may prompt the user to provide an email address if none is available through other means. It prefers the email address specified in the config, but if that is not available it will check the command line argument. If absent, it will use the most recent email address from last time. If there isn't one, the user will be prompted and shown SA link.
Also note that calling this function activates asset management automatically, which keeps certificates renewed and OCSP stapling updated.
Activate returns the updated list of configs, since some may have been appended, for example, to redirect plaintext HTTP requests to their HTTPS counterpart. This function only appends; it does not splice.
func ConfigQualifies ¶
ConfigQualifies returns true if cfg qualifies for fully managed TLS (but not on-demand TLS, which is not considered here). It does NOT check to see if a cert and key already exist for the config. If the config does qualify, you should set cfg.TLS.Managed to true and check that instead, because the process of setting up the config may make it look like it doesn't qualify even though it originally did.
func Deactivate ¶
func Deactivate() (err error)
Deactivate cleans up long-term, in-memory resources allocated by calling Activate(). Essentially, it stops the asset maintainer from running, meaning that certificates will not be renewed, OCSP staples will not be updated, etc.
func EnableTLS ¶
EnableTLS configures each config to use TLS according to default settings. It will only change configs that are marked as managed, and assumes that certificates and keys are already on disk. If loadCertificates is true, the certificates will be loaded from disk into the cache for this process to use. If false, TLS will still be enabled and configured with default settings, but no certificates will be parsed loaded into the cache, and the returned error value will always be nil.
func GetCertificate ¶
func GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error)
GetCertificate gets a certificate to satisfy clientHello as long as the certificate is already cached in memory. It will not be loaded from disk or obtained from the CA during the handshake.
This function is safe for use as a tls.Config.GetCertificate callback.
func GetOrObtainCertificate ¶
func GetOrObtainCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error)
GetOrObtainCertificate will get a certificate to satisfy clientHello, even if that means obtaining a new certificate from a CA during the handshake. It first checks the in-memory cache, then accesses disk, then accesses the network if it must. An obtained certificate will be stored on disk and cached in memory.
This function is safe for use as a tls.Config.GetCertificate callback.
func MarkQualified ¶
MarkQualified scans each config and, if it qualifies for managed TLS, it sets the Managed field of the TLSConfig to true.
func ObtainCerts ¶
ObtainCerts obtains certificates for all these configs as long as a certificate does not already exist on disk. It does not modify the configs at all; it only obtains and stores certificates and keys to the disk. If allowPrompts is true, the user may be shown a prompt. If proxyACME is true, the ACME challenges will be proxied to our alt port.
func RequestCallback ¶
func RequestCallback(w http.ResponseWriter, r *http.Request) bool
RequestCallback 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 Setup ¶
func Setup(c *setup.Controller) (middleware.Middleware, error)
Setup sets up the TLS configuration and installs certificates that are specified by the user in the config file. All the automatic HTTPS stuff comes later outside of this function.
Types ¶
type ACMEClient ¶
type ACMEClient struct { *acme.Client AllowPrompts bool // if false, we assume AlternatePort must be used }
ACMEClient is an acme.Client with custom state attached.
func NewACMEClientGetEmail ¶
func NewACMEClientGetEmail(config server.Config, allowPrompts bool) (*ACMEClient, error)
NewACMEClientGetEmail creates a new ACMEClient and gets an email address at the same time (a server config is required, since it may contain an email address in it).
func (*ACMEClient) Configure ¶
func (c *ACMEClient) Configure(bindHost string)
Configure configures c according to bindHost, which is the host (not whole address) to bind the listener to in solving the http and tls-sni challenges.
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.
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 // Managed certificates are certificates that CoreDNS is managing, // as opposed to the user specifying a certificate and key file // or directory and managing the certificate resources themselves. Managed bool // OnDemand certificates are obtained or loaded on-demand during TLS // handshakes (as opposed to preloaded certificates, which are loaded // at startup). If OnDemand is true, Managed must necessarily be true. // OnDemand certificates are maintained in the background just like // preloaded ones, however, if an OnDemand certificate fails to renew, // it is removed from the in-memory cache. OnDemand bool // OCSP contains the certificate's parsed OCSP response. OCSP *ocsp.Response }
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.
type Storage ¶
type Storage string
Storage is a root directory and facilitates forming file paths derived from it.
func (Storage) SiteCertFile ¶
SiteCertFile returns the path to the certificate file for domain.
func (Storage) SiteKeyFile ¶
SiteKeyFile returns the path to domain's private key file.
func (Storage) SiteMetaFile ¶
SiteMetaFile returns the path to the domain's asset metadata file.
func (Storage) UserKeyFile ¶
UserKeyFile gets the path to the private key file for the user with the given email address.
func (Storage) UserRegFile ¶
UserRegFile gets the path to the registration file for the user with the given email address.
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) 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.