summaryrefslogtreecommitdiff
path: root/modules/caddytls
diff options
context:
space:
mode:
Diffstat (limited to 'modules/caddytls')
-rw-r--r--modules/caddytls/acmemanager.go68
-rw-r--r--modules/caddytls/certselection.go4
-rw-r--r--modules/caddytls/connpolicy.go51
-rw-r--r--modules/caddytls/distributedstek/distributedstek.go17
-rw-r--r--modules/caddytls/fileloader.go21
-rw-r--r--modules/caddytls/folderloader.go4
-rw-r--r--modules/caddytls/matchers.go4
-rw-r--r--modules/caddytls/pemloader.go17
-rw-r--r--modules/caddytls/sessiontickets.go24
-rw-r--r--modules/caddytls/standardstek/stek.go4
-rw-r--r--modules/caddytls/tls.go201
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)