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