diff options
Diffstat (limited to 'modules/caddytls')
| -rw-r--r-- | modules/caddytls/acmemanager.go | 68 | ||||
| -rw-r--r-- | modules/caddytls/certselection.go | 4 | ||||
| -rw-r--r-- | modules/caddytls/connpolicy.go | 51 | ||||
| -rw-r--r-- | modules/caddytls/distributedstek/distributedstek.go | 17 | ||||
| -rw-r--r-- | modules/caddytls/fileloader.go | 21 | ||||
| -rw-r--r-- | modules/caddytls/folderloader.go | 4 | ||||
| -rw-r--r-- | modules/caddytls/matchers.go | 4 | ||||
| -rw-r--r-- | modules/caddytls/pemloader.go | 17 | ||||
| -rw-r--r-- | modules/caddytls/sessiontickets.go | 24 | ||||
| -rw-r--r-- | modules/caddytls/standardstek/stek.go | 4 | ||||
| -rw-r--r-- | modules/caddytls/tls.go | 201 | 
11 files changed, 302 insertions, 113 deletions
diff --git a/modules/caddytls/acmemanager.go b/modules/caddytls/acmemanager.go index 9f31215..31c954f 100644 --- a/modules/caddytls/acmemanager.go +++ b/modules/caddytls/acmemanager.go @@ -40,16 +40,50 @@ func init() {  // after you have configured this struct  // to your liking.  type ACMEManagerMaker struct { -	CA                   string            `json:"ca,omitempty"` -	Email                string            `json:"email,omitempty"` -	RenewAhead           caddy.Duration    `json:"renew_ahead,omitempty"` -	KeyType              string            `json:"key_type,omitempty"` -	ACMETimeout          caddy.Duration    `json:"acme_timeout,omitempty"` -	MustStaple           bool              `json:"must_staple,omitempty"` -	Challenges           *ChallengesConfig `json:"challenges,omitempty"` -	OnDemand             bool              `json:"on_demand,omitempty"` -	Storage              json.RawMessage   `json:"storage,omitempty"` -	TrustedRootsPEMFiles []string          `json:"trusted_roots_pem_files,omitempty"` +	// The URL to the CA's ACME directory endpoint. +	CA string `json:"ca,omitempty"` + +	// Your email address, so the CA can contact you if necessary. +	// Not required, but strongly recommended to provide one so +	// you can be reached if there is a problem. Your email is +	// not sent to any Caddy mothership or used for any purpose +	// other than ACME transactions. +	Email string `json:"email,omitempty"` + +	// How long before a certificate's expiration to try renewing it. +	// Should usually be about 1/3 of certificate lifetime, but long +	// enough to give yourself time to troubleshoot problems before +	// expiration. Default: 30d +	RenewAhead caddy.Duration `json:"renew_ahead,omitempty"` + +	// The type of key to generate for the certificate. +	// Supported values: `rsa2048`, `rsa4096`, `p256`, `p384`. +	KeyType string `json:"key_type,omitempty"` + +	// Time to wait before timing out an ACME operation. +	ACMETimeout caddy.Duration `json:"acme_timeout,omitempty"` + +	// If true, certificates will be requested with MustStaple. Not all +	// CAs support this, and there are potentially serious consequences +	// of enabling this feature without proper threat modeling. +	MustStaple bool `json:"must_staple,omitempty"` + +	// Configures the various ACME challenge types. +	Challenges *ChallengesConfig `json:"challenges,omitempty"` + +	// If true, certificates will be managed "on demand", that is, during +	// TLS handshakes or when needed, as opposed to at startup or config +	// load. +	OnDemand bool `json:"on_demand,omitempty"` + +	// Optionally configure a separate storage module associated with this +	// manager, instead of using Caddy's global/default-configured storage. +	Storage json.RawMessage `json:"storage,omitempty"` + +	// An array of files of CA certificates to accept when connecting to the +	// ACME CA. Generally, you should only use this if the ACME CA endpoint +	// is internal or for development/testing purposes. +	TrustedRootsPEMFiles []string `json:"trusted_roots_pem_files,omitempty"`  	storage  certmagic.Storage  	rootPool *x509.CertPool @@ -58,8 +92,8 @@ type ACMEManagerMaker struct {  // CaddyModule returns the Caddy module information.  func (ACMEManagerMaker) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls.management.acme", -		New:  func() caddy.Module { return new(ACMEManagerMaker) }, +		ID:  "tls.management.acme", +		New: func() caddy.Module { return new(ACMEManagerMaker) },  	}  } @@ -73,26 +107,24 @@ func (m ACMEManagerMaker) NewManager(interactive bool) (certmagic.Manager, error  func (m *ACMEManagerMaker) Provision(ctx caddy.Context) error {  	// DNS providers  	if m.Challenges != nil && m.Challenges.DNSRaw != nil { -		val, err := ctx.LoadModuleInline("provider", "tls.dns", m.Challenges.DNSRaw) +		val, err := ctx.LoadModule(m.Challenges, "DNSRaw")  		if err != nil { -			return fmt.Errorf("loading DNS provider module: %s", err) +			return fmt.Errorf("loading DNS provider module: %v", err)  		}  		m.Challenges.DNS = val.(challenge.Provider) -		m.Challenges.DNSRaw = nil // allow GC to deallocate  	}  	// policy-specific storage implementation  	if m.Storage != nil { -		val, err := ctx.LoadModuleInline("module", "caddy.storage", m.Storage) +		val, err := ctx.LoadModule(m, "Storage")  		if err != nil { -			return fmt.Errorf("loading TLS storage module: %s", err) +			return fmt.Errorf("loading TLS storage module: %v", err)  		}  		cmStorage, err := val.(caddy.StorageConverter).CertMagicStorage()  		if err != nil {  			return fmt.Errorf("creating TLS storage configuration: %v", err)  		}  		m.storage = cmStorage -		m.Storage = nil // allow GC to deallocate  	}  	// add any custom CAs to trust store diff --git a/modules/caddytls/certselection.go b/modules/caddytls/certselection.go index b56185a..eb01605 100644 --- a/modules/caddytls/certselection.go +++ b/modules/caddytls/certselection.go @@ -28,8 +28,8 @@ type Policy struct {  // CaddyModule returns the Caddy module information.  func (Policy) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls.certificate_selection.custom", -		New:  func() caddy.Module { return new(Policy) }, +		ID:  "tls.certificate_selection.custom", +		New: func() caddy.Module { return new(Policy) },  	}  } diff --git a/modules/caddytls/connpolicy.go b/modules/caddytls/connpolicy.go index c82337d..6ce6b9e 100644 --- a/modules/caddytls/connpolicy.go +++ b/modules/caddytls/connpolicy.go @@ -39,23 +39,21 @@ func (cp ConnectionPolicies) TLSConfig(ctx caddy.Context) (*tls.Config, error) {  	// set up each of the connection policies  	for i, pol := range cp {  		// matchers -		for modName, rawMsg := range pol.Matchers { -			val, err := ctx.LoadModule("tls.handshake_match."+modName, rawMsg) -			if err != nil { -				return nil, fmt.Errorf("loading handshake matcher module '%s': %s", modName, err) -			} -			cp[i].matchers = append(cp[i].matchers, val.(ConnectionMatcher)) +		mods, err := ctx.LoadModule(pol, "MatchersRaw") +		if err != nil { +			return nil, fmt.Errorf("loading handshake matchers: %v", err) +		} +		for _, modIface := range mods.(map[string]interface{}) { +			cp[i].matchers = append(cp[i].matchers, modIface.(ConnectionMatcher))  		} -		cp[i].Matchers = nil // allow GC to deallocate  		// certificate selector  		if pol.CertSelection != nil { -			val, err := ctx.LoadModuleInline("policy", "tls.certificate_selection", pol.CertSelection) +			val, err := ctx.LoadModule(pol, "CertSelection")  			if err != nil {  				return nil, fmt.Errorf("loading certificate selection module: %s", err)  			}  			cp[i].certSelector = val.(certmagic.CertificateSelector) -			cp[i].CertSelection = nil // allow GC to deallocate  		}  	} @@ -109,14 +107,33 @@ func (cp ConnectionPolicies) TLSConfig(ctx caddy.Context) (*tls.Config, error) {  // ConnectionPolicy specifies the logic for handling a TLS handshake.  type ConnectionPolicy struct { -	Matchers      map[string]json.RawMessage `json:"match,omitempty"` -	CertSelection json.RawMessage            `json:"certificate_selection,omitempty"` - -	CipherSuites         []string              `json:"cipher_suites,omitempty"` -	Curves               []string              `json:"curves,omitempty"` -	ALPN                 []string              `json:"alpn,omitempty"` -	ProtocolMin          string                `json:"protocol_min,omitempty"` -	ProtocolMax          string                `json:"protocol_max,omitempty"` +	// How to match this policy with a TLS ClientHello. If +	// this policy is the first to match, it will be used. +	MatchersRaw caddy.ModuleMap `json:"match,omitempty" caddy:"namespace=tls.handshake_match"` + +	// How to choose a certificate if more than one matched +	// the given ServerName (SNI) value. +	CertSelection json.RawMessage `json:"certificate_selection,omitempty" caddy:"namespace=tls.certificate_selection inline_key=policy"` + +	// The list of cipher suites to support. Caddy's +	// defaults are modern and secure. +	CipherSuites []string `json:"cipher_suites,omitempty"` + +	// The list of elliptic curves to support. Caddy's +	// defaults are modern and secure. +	Curves []string `json:"curves,omitempty"` + +	// Protocols to use for Application-Layer Protocol +	// Negotiation (ALPN) during the handshake. +	ALPN []string `json:"alpn,omitempty"` + +	// Minimum TLS protocol version to allow. Default: `tls1.2` +	ProtocolMin string `json:"protocol_min,omitempty"` + +	// Maximum TLS protocol version to allow. Default: `tls1.3` +	ProtocolMax string `json:"protocol_max,omitempty"` + +	// Enables and configures TLS client authentication.  	ClientAuthentication *ClientAuthentication `json:"client_authentication,omitempty"`  	matchers     []ConnectionMatcher diff --git a/modules/caddytls/distributedstek/distributedstek.go b/modules/caddytls/distributedstek/distributedstek.go index a0c4cd2..cef3733 100644 --- a/modules/caddytls/distributedstek/distributedstek.go +++ b/modules/caddytls/distributedstek/distributedstek.go @@ -39,9 +39,15 @@ func init() {  	caddy.RegisterModule(Provider{})  } -// Provider implements a distributed STEK provider. +// Provider implements a distributed STEK provider. This +// module will obtain STEKs from a storage module instead +// of generating STEKs internally. This allows STEKs to be +// coordinated, improving TLS session resumption in a cluster.  type Provider struct { -	Storage json.RawMessage `json:"storage,omitempty"` +	// The storage module wherein to store and obtain session +	// ticket keys. If unset, Caddy's default/global-configured +	// storage module will be used. +	Storage json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`  	storage    certmagic.Storage  	stekConfig *caddytls.SessionTicketService @@ -51,8 +57,8 @@ type Provider struct {  // CaddyModule returns the Caddy module information.  func (Provider) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls.stek.distributed", -		New:  func() caddy.Module { return new(Provider) }, +		ID:  "tls.stek.distributed", +		New: func() caddy.Module { return new(Provider) },  	}  } @@ -60,7 +66,7 @@ func (Provider) CaddyModule() caddy.ModuleInfo {  func (s *Provider) Provision(ctx caddy.Context) error {  	// unpack the storage module to use, if different from the default  	if s.Storage != nil { -		val, err := ctx.LoadModuleInline("module", "caddy.storage", s.Storage) +		val, err := ctx.LoadModule(s, "Storage")  		if err != nil {  			return fmt.Errorf("loading TLS storage module: %s", err)  		} @@ -69,7 +75,6 @@ func (s *Provider) Provision(ctx caddy.Context) error {  			return fmt.Errorf("creating TLS storage configuration: %v", err)  		}  		s.storage = cmStorage -		s.Storage = nil // allow GC to deallocate  	}  	// otherwise, use default storage diff --git a/modules/caddytls/fileloader.go b/modules/caddytls/fileloader.go index b2cc132..6d6ff99 100644 --- a/modules/caddytls/fileloader.go +++ b/modules/caddytls/fileloader.go @@ -32,18 +32,27 @@ type FileLoader []CertKeyFilePair  // CaddyModule returns the Caddy module information.  func (FileLoader) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls.certificates.load_files", -		New:  func() caddy.Module { return new(FileLoader) }, +		ID:  "tls.certificates.load_files", +		New: func() caddy.Module { return new(FileLoader) },  	}  }  // CertKeyFilePair pairs certificate and key file names along with their  // encoding format so that they can be loaded from disk.  type CertKeyFilePair struct { -	Certificate string   `json:"certificate"` -	Key         string   `json:"key"` -	Format      string   `json:"format,omitempty"` // "pem" is default -	Tags        []string `json:"tags,omitempty"` +	// Path to the certificate (public key) file. +	Certificate string `json:"certificate"` + +	// Path to the private key file. +	Key string `json:"key"` + +	// The format of the cert and key. Can be "pem". Default: "pem" +	Format string `json:"format,omitempty"` + +	// Arbitrary values to associate with this certificate. +	// Can be useful when you want to select a particular +	// certificate when there may be multiple valid candidates. +	Tags []string `json:"tags,omitempty"`  }  // LoadCertificates returns the certificates to be loaded by fl. diff --git a/modules/caddytls/folderloader.go b/modules/caddytls/folderloader.go index da1dff0..f1a742d 100644 --- a/modules/caddytls/folderloader.go +++ b/modules/caddytls/folderloader.go @@ -39,8 +39,8 @@ type FolderLoader []string  // CaddyModule returns the Caddy module information.  func (FolderLoader) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls.certificates.load_folders", -		New:  func() caddy.Module { return new(FolderLoader) }, +		ID:  "tls.certificates.load_folders", +		New: func() caddy.Module { return new(FolderLoader) },  	}  } diff --git a/modules/caddytls/matchers.go b/modules/caddytls/matchers.go index 47fb296..9e2dfc5 100644 --- a/modules/caddytls/matchers.go +++ b/modules/caddytls/matchers.go @@ -30,8 +30,8 @@ type MatchServerName []string  // CaddyModule returns the Caddy module information.  func (MatchServerName) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls.handshake_match.sni", -		New:  func() caddy.Module { return new(MatchServerName) }, +		ID:  "tls.handshake_match.sni", +		New: func() caddy.Module { return new(MatchServerName) },  	}  } diff --git a/modules/caddytls/pemloader.go b/modules/caddytls/pemloader.go index 30a491c..46d06a8 100644 --- a/modules/caddytls/pemloader.go +++ b/modules/caddytls/pemloader.go @@ -33,16 +33,23 @@ type PEMLoader []CertKeyPEMPair  // CaddyModule returns the Caddy module information.  func (PEMLoader) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls.certificates.load_pem", -		New:  func() caddy.Module { return PEMLoader{} }, +		ID:  "tls.certificates.load_pem", +		New: func() caddy.Module { return PEMLoader{} },  	}  }  // CertKeyPEMPair pairs certificate and key PEM blocks.  type CertKeyPEMPair struct { -	CertificatePEM string   `json:"certificate"` -	KeyPEM         string   `json:"key"` -	Tags           []string `json:"tags,omitempty"` +	// The certificate (public key) in PEM format. +	CertificatePEM string `json:"certificate"` + +	// The private key in PEM format. +	KeyPEM string `json:"key"` + +	// Arbitrary values to associate with this certificate. +	// Can be useful when you want to select a particular +	// certificate when there may be multiple valid candidates. +	Tags []string `json:"tags,omitempty"`  }  // LoadCertificates returns the certificates contained in pl. diff --git a/modules/caddytls/sessiontickets.go b/modules/caddytls/sessiontickets.go index 6ca921d..258c135 100644 --- a/modules/caddytls/sessiontickets.go +++ b/modules/caddytls/sessiontickets.go @@ -28,11 +28,22 @@ import (  // SessionTicketService configures and manages TLS session tickets.  type SessionTicketService struct { -	KeySource        json.RawMessage `json:"key_source,omitempty"` -	RotationInterval caddy.Duration  `json:"rotation_interval,omitempty"` -	MaxKeys          int             `json:"max_keys,omitempty"` -	DisableRotation  bool            `json:"disable_rotation,omitempty"` -	Disabled         bool            `json:"disabled,omitempty"` +	// KeySource is the method by which Caddy produces or obtains +	// TLS session ticket keys (STEKs). By default, Caddy generates +	// them internally using a secure pseudorandom source. +	KeySource json.RawMessage `json:"key_source,omitempty" caddy:"namespace=tls.stek inline_key=provider"` + +	// How often Caddy rotates STEKs. Default: 12h. +	RotationInterval caddy.Duration `json:"rotation_interval,omitempty"` + +	// The maximum number of keys to keep in rotation. Default: 4. +	MaxKeys int `json:"max_keys,omitempty"` + +	// Disables STEK rotation. +	DisableRotation bool `json:"disable_rotation,omitempty"` + +	// Disables TLS session resumption by tickets. +	Disabled bool `json:"disabled,omitempty"`  	keySource   STEKProvider  	configs     map[*tls.Config]struct{} @@ -57,12 +68,11 @@ func (s *SessionTicketService) provision(ctx caddy.Context) error {  	}  	// load the STEK module, which will provide keys -	val, err := ctx.LoadModuleInline("provider", "tls.stek", s.KeySource) +	val, err := ctx.LoadModule(s, "KeySource")  	if err != nil {  		return fmt.Errorf("loading TLS session ticket ephemeral keys provider module: %s", err)  	}  	s.keySource = val.(STEKProvider) -	s.KeySource = nil // allow GC to deallocate  	// if session tickets or just rotation are  	// disabled, no need to start service diff --git a/modules/caddytls/standardstek/stek.go b/modules/caddytls/standardstek/stek.go index 6d10c76..eb609ca 100644 --- a/modules/caddytls/standardstek/stek.go +++ b/modules/caddytls/standardstek/stek.go @@ -35,8 +35,8 @@ type standardSTEKProvider struct {  // CaddyModule returns the Caddy module information.  func (standardSTEKProvider) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls.stek.standard", -		New:  func() caddy.Module { return new(standardSTEKProvider) }, +		ID:  "tls.stek.standard", +		New: func() caddy.Module { return new(standardSTEKProvider) },  	}  } diff --git a/modules/caddytls/tls.go b/modules/caddytls/tls.go index 5dfe063..1b155b0 100644 --- a/modules/caddytls/tls.go +++ b/modules/caddytls/tls.go @@ -30,15 +30,30 @@ import (  func init() {  	caddy.RegisterModule(TLS{}) +	caddy.RegisterModule(AutomateLoader{})  } -// TLS represents a process-wide TLS configuration. +// TLS provides TLS facilities including certificate +// loading and management, client auth, and more.  type TLS struct { -	Certificates   map[string]json.RawMessage `json:"certificates,omitempty"` -	Automation     *AutomationConfig          `json:"automation,omitempty"` -	SessionTickets *SessionTicketService      `json:"session_tickets,omitempty"` +	// Caches certificates in memory for quick use during +	// TLS handshakes. Each key is the name of a certificate +	// loader module. All loaded certificates get pooled +	// into the same cache and may be used to complete TLS +	// handshakes for the relevant server names (SNI). +	// Certificates loaded manually (anything other than +	// "automate") are not automatically managed and will +	// have to be refreshed manually before they expire. +	CertificatesRaw caddy.ModuleMap `json:"certificates,omitempty" caddy:"namespace=tls.certificates"` + +	// Configures the automation of certificate management. +	Automation *AutomationConfig `json:"automation,omitempty"` + +	// Configures session ticket ephemeral keys (STEKs). +	SessionTickets *SessionTicketService `json:"session_tickets,omitempty"`  	certificateLoaders []CertificateLoader +	automateNames      []string  	certCache          *certmagic.Cache  	ctx                caddy.Context  	storageCleanTicker *time.Ticker @@ -49,8 +64,8 @@ type TLS struct {  // CaddyModule returns the Caddy module information.  func (TLS) CaddyModule() caddy.ModuleInfo {  	return caddy.ModuleInfo{ -		Name: "tls", -		New:  func() caddy.Module { return new(TLS) }, +		ID:  "tls", +		New: func() caddy.Module { return new(TLS) },  	}  } @@ -74,25 +89,32 @@ func (t *TLS) Provision(ctx caddy.Context) error {  	// automation/management policies  	if t.Automation != nil {  		for i, ap := range t.Automation.Policies { -			val, err := ctx.LoadModuleInline("module", "tls.management", ap.ManagementRaw) +			val, err := ctx.LoadModule(&ap, "ManagementRaw")  			if err != nil {  				return fmt.Errorf("loading TLS automation management module: %s", err)  			}  			t.Automation.Policies[i].Management = val.(ManagerMaker) -			t.Automation.Policies[i].ManagementRaw = nil // allow GC to deallocate  		}  	}  	// certificate loaders -	for modName, rawMsg := range t.Certificates { -		if modName == automateKey { -			continue // special case; these will be loaded in later -		} -		val, err := ctx.LoadModule("tls.certificates."+modName, rawMsg) -		if err != nil { -			return fmt.Errorf("loading certificate module '%s': %s", modName, err) +	val, err := ctx.LoadModule(t, "CertificatesRaw") +	if err != nil { +		return fmt.Errorf("loading TLS automation management module: %s", err) +	} +	for modName, modIface := range val.(map[string]interface{}) { +		if modName == "automate" { +			// special case; these will be loaded in later +			// using our automation facilities, which we +			// want to avoid during provisioning +			var ok bool +			t.automateNames, ok = modIface.([]string) +			if !ok { +				return fmt.Errorf("loading certificates with 'automate' requires []string, got: %#v", modIface) +			} +			continue  		} -		t.certificateLoaders = append(t.certificateLoaders, val.(CertificateLoader)) +		t.certificateLoaders = append(t.certificateLoaders, modIface.(CertificateLoader))  	}  	// session ticket ephemeral keys (STEK) service and provider @@ -115,7 +137,8 @@ func (t *TLS) Provision(ctx caddy.Context) error {  	// load manual/static (unmanaged) certificates - we do this in  	// provision so that other apps (such as http) can know which -	// certificates have been manually loaded +	// certificates have been manually loaded, and also so that +	// commands like validate can be a better test  	magic := certmagic.New(t.certCache, certmagic.Config{  		Storage: ctx.Storage(),  	}) @@ -137,19 +160,12 @@ func (t *TLS) Provision(ctx caddy.Context) error {  // Start activates the TLS module.  func (t *TLS) Start() error { -	// load automated (managed) certificates -	if automatedRawMsg, ok := t.Certificates[automateKey]; ok { -		var names []string -		err := json.Unmarshal(automatedRawMsg, &names) -		if err != nil { -			return fmt.Errorf("automate: decoding names: %v", err) -		} -		err = t.Manage(names) -		if err != nil { -			return fmt.Errorf("automate: managing %v: %v", names, err) -		} +	// now that we are running, and all manual certificates have +	// been loaded, time to load the automated/managed certificates +	err := t.Manage(t.automateNames) +	if err != nil { +		return fmt.Errorf("automate: managing %v: %v", t.automateNames, err)  	} -	t.Certificates = nil // allow GC to deallocate  	t.keepStorageClean() @@ -311,18 +327,48 @@ type Certificate struct {  // AutomationConfig designates configuration for the  // construction and use of ACME clients.  type AutomationConfig struct { -	Policies           []AutomationPolicy `json:"policies,omitempty"` -	OnDemand           *OnDemandConfig    `json:"on_demand,omitempty"` -	OCSPCheckInterval  caddy.Duration     `json:"ocsp_interval,omitempty"` -	RenewCheckInterval caddy.Duration     `json:"renew_interval,omitempty"` +	// The list of automation policies. The first matching +	// policy will be applied for a given certificate/name. +	Policies []AutomationPolicy `json:"policies,omitempty"` + +	// On-Demand TLS defers certificate operations to the +	// moment they are needed, e.g. during a TLS handshake. +	// Useful when you don't know all the hostnames up front. +	// Caddy was the first web server to deploy this technology. +	OnDemand *OnDemandConfig `json:"on_demand,omitempty"` + +	// Caddy staples OCSP (and caches the response) for all +	// qualifying certificates by default. This setting +	// changes how often it scans responses for freshness, +	// and updates them if they are getting stale. +	OCSPCheckInterval caddy.Duration `json:"ocsp_interval,omitempty"` + +	// Every so often, Caddy will scan all loaded, managed +	// certificates for expiration. Certificates which are +	// about 2/3 into their valid lifetime are due for +	// renewal. This setting changes how frequently the scan +	// is performed. If your certificate lifetimes are very +	// short (less than ~1 week), you should customize this. +	RenewCheckInterval caddy.Duration `json:"renew_interval,omitempty"`  }  // AutomationPolicy designates the policy for automating the -// management of managed TLS certificates. +// management (obtaining, renewal, and revocation) of managed +// TLS certificates.  type AutomationPolicy struct { -	Hosts         []string        `json:"hosts,omitempty"` -	ManagementRaw json.RawMessage `json:"management,omitempty"` -	ManageSync    bool            `json:"manage_sync,omitempty"` +	// Which hostnames this policy applies to. +	Hosts []string `json:"hosts,omitempty"` + +	// How to manage certificates. +	ManagementRaw json.RawMessage `json:"management,omitempty" caddy:"namespace=tls.management inline_key=module"` + +	// If true, certificate management will be conducted +	// in the foreground; this will block config reloads +	// and return errors if there were problems with +	// obtaining or renewing certificates. This is often +	// not desirable, especially when serving sites out +	// of your control. Default: false +	ManageSync bool `json:"manage_sync,omitempty"`  	Management ManagerMaker `json:"-"`  } @@ -345,36 +391,84 @@ func (ap AutomationPolicy) makeCertMagicConfig(ctx caddy.Context) certmagic.Conf  // ChallengesConfig configures the ACME challenges.  type ChallengesConfig struct { -	HTTP    *HTTPChallengeConfig    `json:"http,omitempty"` +	// HTTP configures the ACME HTTP challenge. This +	// challenge is enabled and used automatically +	// and by default. +	HTTP *HTTPChallengeConfig `json:"http,omitempty"` + +	// TLSALPN configures the ACME TLS-ALPN challenge. +	// This challenge is enabled and used automatically +	// and by default.  	TLSALPN *TLSALPNChallengeConfig `json:"tls-alpn,omitempty"` -	DNSRaw  json.RawMessage         `json:"dns,omitempty"` + +	// Configures the ACME DNS challenge. Because this +	// challenge typically requires credentials for +	// interfacing with a DNS provider, this challenge is +	// not enabled by default. This is the only challenge +	// type which does not require a direct connection +	// to Caddy from an external server. +	DNSRaw json.RawMessage `json:"dns,omitempty" caddy:"namespace=tls.dns inline_key=provider"`  	DNS challenge.Provider `json:"-"`  }  // HTTPChallengeConfig configures the ACME HTTP challenge.  type HTTPChallengeConfig struct { -	Disabled      bool `json:"disabled,omitempty"` -	AlternatePort int  `json:"alternate_port,omitempty"` +	// If true, the HTTP challenge will be disabled. +	Disabled bool `json:"disabled,omitempty"` + +	// An alternate port on which to service this +	// challenge. Note that the HTTP challenge port is +	// hard-coded into the spec and cannot be changed, +	// so you would have to forward packets from the +	// standard HTTP challenge port to this one. +	AlternatePort int `json:"alternate_port,omitempty"`  }  // TLSALPNChallengeConfig configures the ACME TLS-ALPN challenge.  type TLSALPNChallengeConfig struct { -	Disabled      bool `json:"disabled,omitempty"` -	AlternatePort int  `json:"alternate_port,omitempty"` +	// If true, the TLS-ALPN challenge will be disabled. +	Disabled bool `json:"disabled,omitempty"` + +	// An alternate port on which to service this +	// challenge. Note that the TLS-ALPN challenge port +	// is hard-coded into the spec and cannot be changed, +	// so you would have to forward packets from the +	// standard TLS-ALPN challenge port to this one. +	AlternatePort int `json:"alternate_port,omitempty"`  }  // OnDemandConfig configures on-demand TLS, for obtaining -// needed certificates at handshake-time. +// needed certificates at handshake-time. Because this +// feature can easily be abused, you should set up rate +// limits and/or an internal endpoint that Caddy can +// "ask" if it should be allowed to manage certificates +// for a given hostname.  type OnDemandConfig struct { +	// An optional rate limit to throttle the +	// issuance of certificates from handshakes.  	RateLimit *RateLimit `json:"rate_limit,omitempty"` -	Ask       string     `json:"ask,omitempty"` + +	// If Caddy needs to obtain or renew a certificate +	// during a TLS handshake, it will perform a quick +	// HTTP request to this URL to check if it should be +	// allowed to try to get a certificate for the name +	// in the "domain" query string parameter, like so: +	// `?domain=example.com`. The endpoint must return a +	// 200 OK status if a certificate is allowed; +	// anything else will cause it to be denied. +	// Redirects are not followed. +	Ask string `json:"ask,omitempty"`  }  // RateLimit specifies an interval with optional burst size.  type RateLimit struct { +	// A duration value. A certificate may be obtained 'burst' +	// times during this interval.  	Interval caddy.Duration `json:"interval,omitempty"` -	Burst    int            `json:"burst,omitempty"` + +	// How many times during an interval a certificate can be obtained. +	Burst int `json:"burst,omitempty"`  }  // ManagerMaker makes a certificate manager. @@ -382,6 +476,21 @@ type ManagerMaker interface {  	NewManager(interactive bool) (certmagic.Manager, error)  } +// AutomateLoader is a no-op certificate loader module +// that is treated as a special case: it uses this app's +// automation features to load certificates for the +// list of hostnames, rather than loading certificates +// manually. +type AutomateLoader []string + +// CaddyModule returns the Caddy module information. +func (AutomateLoader) CaddyModule() caddy.ModuleInfo { +	return caddy.ModuleInfo{ +		ID:  "tls.certificates.automate", +		New: func() caddy.Module { return new(AutomateLoader) }, +	} +} +  // These perpetual values are used for on-demand TLS.  var (  	onDemandRateLimiter = certmagic.NewRateLimiter(0, 0)  | 
