@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 1,147 lines 38.1 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package caddytls
16
17 import (
18 "context"
19 "crypto/tls"
20 "encoding/json"
21 "errors"
22 "fmt"
23 "log"
24 "net"
25 "net/http"
26 "runtime/debug"
27 "slices"
28 "strings"
29 "sync"
30 "time"
31
32 "github.com/caddyserver/certmagic"
33 "github.com/libdns/libdns"
34 "go.uber.org/zap"
35 "go.uber.org/zap/zapcore"
36
37 "github.com/caddyserver/caddy/v2"
38 "github.com/caddyserver/caddy/v2/internal"
39 "github.com/caddyserver/caddy/v2/modules/caddyevents"
40 )
41
42 func init() {
43 caddy.RegisterModule(TLS{})
44 caddy.RegisterModule(AutomateLoader{})
45 }
46
47 var (
48 certCache *certmagic.Cache
49 certCacheMu sync.RWMutex
50 )
51
52 // TLS provides TLS facilities including certificate
53 // loading and management, client auth, and more.
54 type TLS struct {
55 // Certificates to load into memory for quick recall during
56 // TLS handshakes. Each key is the name of a certificate
57 // loader module.
58 //
59 // The "automate" certificate loader module can be used to
60 // specify a list of subjects that need certificates to be
61 // managed automatically, including subdomains that may
62 // already be covered by a managed wildcard certificate.
63 // The first matching automation policy will be used
64 // to manage automated certificate(s).
65 //
66 // All loaded certificates get pooled
67 // into the same cache and may be used to complete TLS
68 // handshakes for the relevant server names (SNI).
69 // Certificates loaded manually (anything other than
70 // "automate") are not automatically managed and will
71 // have to be refreshed manually before they expire.
72 CertificatesRaw caddy.ModuleMap `json:"certificates,omitempty" caddy:"namespace=tls.certificates"`
73
74 // Configures certificate automation.
75 Automation *AutomationConfig `json:"automation,omitempty"`
76
77 // Configures session ticket ephemeral keys (STEKs).
78 SessionTickets *SessionTicketService `json:"session_tickets,omitempty"`
79
80 // Configures the in-memory certificate cache.
81 Cache *CertCacheOptions `json:"cache,omitempty"`
82
83 // Disables OCSP stapling for manually-managed certificates only.
84 // To configure OCSP stapling for automated certificates, use an
85 // automation policy instead.
86 //
87 // Disabling OCSP stapling puts clients at greater risk, reduces their
88 // privacy, and usually lowers client performance. It is NOT recommended
89 // to disable this unless you are able to justify the costs.
90 //
91 // EXPERIMENTAL. Subject to change.
92 DisableOCSPStapling bool `json:"disable_ocsp_stapling,omitempty"`
93
94 // Disables checks in certmagic that the configured storage is ready
95 // and able to handle writing new content to it. These checks are
96 // intended to prevent information loss (newly issued certificates), but
97 // can be expensive on the storage.
98 //
99 // Disabling these checks should only be done when the storage
100 // can be trusted to have enough capacity and no other problems.
101 //
102 // EXPERIMENTAL. Subject to change.
103 DisableStorageCheck bool `json:"disable_storage_check,omitempty"`
104
105 // Disables the automatic cleanup of the storage backend.
106 // This is useful when TLS is not being used to store certificates
107 // and the user wants run their server in a read-only mode.
108 //
109 // Storage cleaning creates two files: instance.uuid and last_clean.json.
110 // The instance.uuid file is used to identify the instance of Caddy
111 // in a cluster. The last_clean.json file is used to store the last
112 // time the storage was cleaned.
113 //
114 // EXPERIMENTAL. Subject to change.
115 DisableStorageClean bool `json:"disable_storage_clean,omitempty"`
116
117 // Enable Encrypted ClientHello (ECH). ECH protects the server name
118 // (SNI) and other sensitive parameters of a normally-plaintext TLS
119 // ClientHello during a handshake.
120 //
121 // EXPERIMENTAL: Subject to change.
122 EncryptedClientHello *ECH `json:"encrypted_client_hello,omitempty"`
123
124 // The default DNS provider module to use when a DNS module is needed.
125 //
126 // EXPERIMENTAL: Subject to change.
127 DNSRaw json.RawMessage `json:"dns,omitempty" caddy:"namespace=dns.providers inline_key=name"`
128
129 // The default DNS resolvers to use for TLS-related DNS operations, specifically
130 // for ACME DNS challenges and ACME server DNS validations.
131 // If not specified, the system default resolvers will be used.
132 //
133 // EXPERIMENTAL: Subject to change.
134 Resolvers []string `json:"resolvers,omitempty"`
135
136 dns any // technically, it should be any/all of the libdns interfaces (RecordSetter, RecordAppender, etc.)
137 certificateLoaders []CertificateLoader
138 automateNames map[string]struct{}
139 ctx caddy.Context
140 bgCtx context.Context
141 bgCancel context.CancelFunc
142 bgWg *sync.WaitGroup
143 storageCleanTicker *time.Ticker
144 echRotateInterval time.Duration
145 logger *zap.Logger
146 events *caddyevents.App
147
148 serverNames map[string]serverNameRegistration
149 serverNamesMu *sync.Mutex
150
151 // set of subjects with managed certificates,
152 // and hashes of manually-loaded certificates
153 // (managing's value is an optional issuer key, for distinction)
154 managing, loaded map[string]string
155 }
156
157 // CaddyModule returns the Caddy module information.
158 func (TLS) CaddyModule() caddy.ModuleInfo {
159 return caddy.ModuleInfo{
160 ID: "tls",
161 New: func() caddy.Module { return new(TLS) },
162 }
163 }
164
165 // Provision sets up the configuration for the TLS app.
166 func (t *TLS) Provision(ctx caddy.Context) error {
167 eventsAppIface, err := ctx.App("events")
168 if err != nil {
169 return fmt.Errorf("getting events app: %v", err)
170 }
171 t.events = eventsAppIface.(*caddyevents.App)
172 t.ctx = ctx
173 t.logger = ctx.Logger()
174 repl := caddy.NewReplacer()
175 t.managing, t.loaded = make(map[string]string), make(map[string]string)
176 t.serverNames = make(map[string]serverNameRegistration)
177 t.serverNamesMu = new(sync.Mutex)
178
179 // set up default DNS module, if any, and make sure it implements all the
180 // common libdns interfaces, since it could be used for a variety of things
181 // (do this before provisioning other modules, since they may rely on this)
182 if len(t.DNSRaw) > 0 {
183 dnsMod, err := ctx.LoadModule(t, "DNSRaw")
184 if err != nil {
185 return fmt.Errorf("loading overall DNS provider module: %v", err)
186 }
187 switch dnsMod.(type) {
188 case interface {
189 libdns.RecordAppender
190 libdns.RecordDeleter
191 libdns.RecordGetter
192 libdns.RecordSetter
193 }:
194 default:
195 return fmt.Errorf("DNS module does not implement the most common libdns interfaces: %T", dnsMod)
196 }
197 t.dns = dnsMod
198 }
199
200 // set up a new certificate cache; this (re)loads all certificates
201 cacheOpts := certmagic.CacheOptions{
202 GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {
203 return t.getConfigForName(cert.Names[0]), nil
204 },
205 Logger: t.logger.Named("cache"),
206 }
207 if t.Automation != nil {
208 cacheOpts.OCSPCheckInterval = time.Duration(t.Automation.OCSPCheckInterval)
209 cacheOpts.RenewCheckInterval = time.Duration(t.Automation.RenewCheckInterval)
210 }
211 if t.Cache != nil {
212 cacheOpts.Capacity = t.Cache.Capacity
213 }
214 if cacheOpts.Capacity <= 0 {
215 cacheOpts.Capacity = 10000
216 }
217
218 certCacheMu.Lock()
219 if certCache == nil {
220 certCache = certmagic.NewCache(cacheOpts)
221 } else {
222 certCache.SetOptions(cacheOpts)
223 }
224 certCacheMu.Unlock()
225
226 // certificate loaders
227 val, err := ctx.LoadModule(t, "CertificatesRaw")
228 if err != nil {
229 return fmt.Errorf("loading certificate loader modules: %s", err)
230 }
231 for modName, modIface := range val.(map[string]any) {
232 if modName == "automate" {
233 // special case; these will be loaded in later using our automation facilities,
234 // which we want to avoid doing during provisioning
235 if automateNames, ok := modIface.(*AutomateLoader); ok && automateNames != nil {
236 if t.automateNames == nil {
237 t.automateNames = make(map[string]struct{})
238 }
239 repl := caddy.NewReplacer()
240 for _, sub := range *automateNames {
241 t.automateNames[repl.ReplaceAll(sub, "")] = struct{}{}
242 }
243 } else {
244 return fmt.Errorf("loading certificates with 'automate' requires array of strings, got: %T", modIface)
245 }
246 continue
247 }
248 t.certificateLoaders = append(t.certificateLoaders, modIface.(CertificateLoader))
249 }
250
251 // using the certificate loaders we just initialized, load
252 // manual/static (unmanaged) certificates - we do this in
253 // provision so that other apps (such as http) can know which
254 // certificates have been manually loaded, and also so that
255 // commands like validate can be a better test
256 certCacheMu.RLock()
257 magic := certmagic.New(certCache, certmagic.Config{
258 Storage: ctx.Storage(),
259 Logger: t.logger,
260 OnEvent: t.onEvent,
261 ShouldEmitFunc: t.events.ShouldEmit,
262 OCSP: certmagic.OCSPConfig{
263 DisableStapling: t.DisableOCSPStapling,
264 },
265 DisableStorageCheck: t.DisableStorageCheck,
266 })
267 certCacheMu.RUnlock()
268 for _, loader := range t.certificateLoaders {
269 certs, err := loader.LoadCertificates()
270 if err != nil {
271 return fmt.Errorf("loading certificates: %v", err)
272 }
273 for _, cert := range certs {
274 hash, err := magic.CacheUnmanagedTLSCertificate(ctx, cert.Certificate, cert.Tags)
275 if err != nil {
276 return fmt.Errorf("caching unmanaged certificate: %v", err)
277 }
278 t.loaded[hash] = ""
279 }
280 }
281
282 // on-demand permission module
283 if t.Automation != nil && t.Automation.OnDemand != nil && t.Automation.OnDemand.PermissionRaw != nil {
284 if t.Automation.OnDemand.Ask != "" {
285 return fmt.Errorf("on-demand TLS config conflict: both 'ask' endpoint and a 'permission' module are specified; 'ask' is deprecated, so use only the permission module")
286 }
287 val, err := ctx.LoadModule(t.Automation.OnDemand, "PermissionRaw")
288 if err != nil {
289 return fmt.Errorf("loading on-demand TLS permission module: %v", err)
290 }
291 t.Automation.OnDemand.permission = val.(OnDemandPermission)
292 }
293
294 // automation/management policies
295 if t.Automation == nil {
296 t.Automation = new(AutomationConfig)
297 }
298 t.Automation.defaultPublicAutomationPolicy = new(AutomationPolicy)
299 err = t.Automation.defaultPublicAutomationPolicy.Provision(t)
300 if err != nil {
301 return fmt.Errorf("provisioning default public automation policy: %v", err)
302 }
303 for n := range t.automateNames {
304 // if any names specified by the "automate" loader do not qualify for a public
305 // certificate, we should initialize a default internal automation policy
306 // (but we don't want to do this unnecessarily, since it may prompt for password!)
307 if certmagic.SubjectQualifiesForPublicCert(n) {
308 continue
309 }
310 t.Automation.defaultInternalAutomationPolicy = &AutomationPolicy{
311 IssuersRaw: []json.RawMessage{json.RawMessage(`{"module":"internal"}`)},
312 }
313 err = t.Automation.defaultInternalAutomationPolicy.Provision(t)
314 if err != nil {
315 return fmt.Errorf("provisioning default internal automation policy: %v", err)
316 }
317 break
318 }
319 for i, ap := range t.Automation.Policies {
320 err := ap.Provision(t)
321 if err != nil {
322 return fmt.Errorf("provisioning automation policy %d: %v", i, err)
323 }
324 }
325
326 // run replacer on ask URL (for environment variables) -- return errors to prevent surprises (#5036)
327 if t.Automation != nil && t.Automation.OnDemand != nil && t.Automation.OnDemand.Ask != "" {
328 t.Automation.OnDemand.Ask, err = repl.ReplaceOrErr(t.Automation.OnDemand.Ask, true, true)
329 if err != nil {
330 return fmt.Errorf("preparing 'ask' endpoint: %v", err)
331 }
332 perm := PermissionByHTTP{
333 Endpoint: t.Automation.OnDemand.Ask,
334 }
335 if err := perm.Provision(ctx); err != nil {
336 return fmt.Errorf("provisioning 'ask' module: %v", err)
337 }
338 t.Automation.OnDemand.permission = perm
339 }
340
341 // session ticket ephemeral keys (STEK) service and provider
342 if t.SessionTickets != nil {
343 err := t.SessionTickets.provision(ctx)
344 if err != nil {
345 return fmt.Errorf("provisioning session tickets configuration: %v", err)
346 }
347 }
348
349 // ECH (Encrypted ClientHello) initialization
350 if t.EncryptedClientHello != nil {
351 outerNames, err := t.EncryptedClientHello.Provision(ctx)
352 if err != nil {
353 return fmt.Errorf("provisioning Encrypted ClientHello components: %v", err)
354 }
355
356 // outer names should have certificates to reduce client brittleness
357 for _, outerName := range outerNames {
358 if outerName == "" {
359 continue
360 }
361 if !t.HasCertificateForSubject(outerName) {
362 if t.automateNames == nil {
363 t.automateNames = make(map[string]struct{})
364 }
365 t.automateNames[outerName] = struct{}{}
366 }
367 }
368 }
369
370 return nil
371 }
372
373 // Validate validates t's configuration.
374 func (t *TLS) Validate() error {
375 if t.Automation != nil {
376 // ensure that host aren't repeated; since only the first
377 // automation policy is used, repeating a host in the lists
378 // isn't useful and is probably a mistake; same for two
379 // catch-all/default policies
380 var hasDefault bool
381 hostSet := make(map[string]int)
382 for i, ap := range t.Automation.Policies {
383 if len(ap.subjects) == 0 {
384 if hasDefault {
385 return fmt.Errorf("automation policy %d is the second policy that acts as default/catch-all, but will never be used", i)
386 }
387 hasDefault = true
388 }
389 for _, h := range ap.subjects {
390 if first, ok := hostSet[h]; ok {
391 return fmt.Errorf("automation policy %d: cannot apply more than one automation policy to host: %s (first match in policy %d)", i, h, first)
392 }
393 hostSet[h] = i
394 }
395 }
396 }
397 if t.Cache != nil {
398 if t.Cache.Capacity < 0 {
399 return fmt.Errorf("cache capacity must be >= 0")
400 }
401 }
402 return nil
403 }
404
405 // Start activates the TLS module.
406 func (t *TLS) Start() error {
407 // warn if on-demand TLS is enabled but no restrictions are in place
408 if t.Automation.OnDemand == nil || (t.Automation.OnDemand.Ask == "" && t.Automation.OnDemand.permission == nil) {
409 for _, ap := range t.Automation.Policies {
410 if ap.OnDemand && ap.isWildcardOrDefault() {
411 if c := t.logger.Check(zapcore.WarnLevel, "YOUR SERVER MAY BE VULNERABLE TO ABUSE: on-demand TLS is enabled, but no protections are in place"); c != nil {
412 c.Write(zap.String("docs", "https://caddyserver.com/docs/automatic-https#on-demand-tls"))
413 }
414 break
415 }
416 }
417 }
418
419 if t.bgCtx == nil {
420 parentCtx := t.ctx.Context
421 if parentCtx == nil {
422 parentCtx = context.Background()
423 }
424 t.bgCtx, t.bgCancel = context.WithCancel(parentCtx)
425 }
426 if t.bgWg == nil {
427 t.bgWg = new(sync.WaitGroup)
428 }
429
430 // now that we are running, and all manual certificates have
431 // been loaded, time to load the automated/managed certificates
432 err := t.Manage(t.automateNames)
433 if err != nil {
434 return fmt.Errorf("automate: managing %v: %v", t.automateNames, err)
435 }
436
437 if t.EncryptedClientHello != nil {
438 echLogger := t.logger.Named("ech")
439
440 // publish ECH configs in the background; does not need to block
441 // server startup, as it could take a while; then keep keys rotated
442 t.bgWg.Add(1)
443 go func(ctx context.Context) {
444 defer t.bgWg.Done()
445 defer func() {
446 if err := recover(); err != nil {
447 log.Printf("[PANIC] tls ech publisher: %v\n%s", err, debug.Stack())
448 }
449 }()
450
451 // publish immediately first
452 if err := t.publishECHConfigs(ctx, echLogger); err != nil {
453 if !errors.Is(err, context.Canceled) && ctx.Err() == nil {
454 echLogger.Error("publication(s) failed", zap.Error(err))
455 }
456 }
457
458 ticker := time.NewTicker(t.echRotationInterval())
459 defer ticker.Stop()
460
461 // then every so often, rotate and publish if needed
462 // (both of these functions only do something if needed)
463 for {
464 select {
465 case <-ticker.C:
466 // ensure old keys are rotated out
467 t.EncryptedClientHello.configsMu.Lock()
468 err := t.EncryptedClientHello.rotateECHKeys(t.caddyContext(ctx), echLogger, false)
469 t.EncryptedClientHello.configsMu.Unlock()
470 if err != nil {
471 if !errors.Is(err, context.Canceled) && ctx.Err() == nil {
472 echLogger.Error("rotating ECH configs failed", zap.Error(err))
473 }
474 if ctx.Err() != nil {
475 return
476 }
477 continue
478 }
479 if ctx.Err() != nil {
480 return
481 }
482 err = t.publishECHConfigs(ctx, echLogger)
483 if err != nil {
484 if !errors.Is(err, context.Canceled) && ctx.Err() == nil {
485 echLogger.Error("publication(s) failed", zap.Error(err))
486 }
487 }
488 case <-ctx.Done():
489 return
490 }
491 }
492 }(t.bgCtx)
493 }
494
495 if !t.DisableStorageClean {
496 // start the storage cleaner goroutine and ticker,
497 // which cleans out expired certificates and more
498 t.keepStorageClean()
499 }
500
501 return nil
502 }
503
504 // Stop stops the TLS module and cleans up any allocations.
505 func (t *TLS) Stop() error {
506 // cancel all background goroutines (storage cleaner, ECH rotation/publication, etc.)
507 if t.bgCancel != nil {
508 t.bgCancel()
509 }
510 if t.storageCleanTicker != nil {
511 t.storageCleanTicker.Stop()
512 }
513 // wait for all background goroutines to finish before returning,
514 // ensuring no background storage users are active when module Cleanup() runs
515 if t.bgWg != nil {
516 t.bgWg.Wait()
517 }
518 return nil
519 }
520
521 // Cleanup frees up resources allocated during Provision.
522 func (t *TLS) Cleanup() error {
523 // stop the session ticket rotation goroutine
524 if t.SessionTickets != nil {
525 t.SessionTickets.stop()
526 }
527
528 // if a new TLS app was loaded, remove certificates from the cache that are no longer
529 // being managed or loaded by the new config; if there is no more TLS app running,
530 // then stop cert maintenance and let the cert cache be GC'ed
531 if nextTLS, err := caddy.ActiveContext().AppIfConfigured("tls"); err == nil && nextTLS != nil {
532 nextTLSApp := nextTLS.(*TLS)
533
534 // compute which certificates were managed or loaded into the cert cache by this
535 // app instance (which is being stopped) that are not managed or loaded by the
536 // new app instance (which just started), and remove them from the cache
537 var noLongerManaged []certmagic.SubjectIssuer
538 var noLongerLoaded []string
539 reManage := make(map[string]struct{})
540 for subj, currentIssuerKey := range t.managing {
541 // It's a bit nuanced: managed certs can sometimes be different enough that we have to
542 // swap them out for a different one, even if they are for the same subject/domain.
543 // We consider "private" certs (internal CA/locally-trusted/etc) to be significantly
544 // distinct from "public" certs (production CAs/globally-trusted/etc) because of the
545 // implications when it comes to actual deployments: switching between an internal CA
546 // and a production CA, for example, is quite significant. Switching from one public CA
547 // to another, however, is not, and for our purposes we consider those to be the same.
548 // Anyway, if the next TLS app does not manage a cert for this name at all, definitely
549 // remove it from the cache. But if it does, and it's not the same kind of issuer/CA
550 // as we have, also remove it, so that it can swap it out for the right one.
551 if nextIssuerKey, ok := nextTLSApp.managing[subj]; !ok || nextIssuerKey != currentIssuerKey {
552 // next app is not managing a cert for this domain at all or is using a different issuer, so remove it
553 noLongerManaged = append(noLongerManaged, certmagic.SubjectIssuer{Subject: subj, IssuerKey: currentIssuerKey})
554
555 // then, if the next app is managing a cert for this name, but with a different issuer, re-manage it
556 if ok && nextIssuerKey != currentIssuerKey {
557 reManage[subj] = struct{}{}
558 }
559 }
560 }
561 for hash := range t.loaded {
562 if _, ok := nextTLSApp.loaded[hash]; !ok {
563 noLongerLoaded = append(noLongerLoaded, hash)
564 }
565 }
566
567 // remove the certs
568 certCacheMu.RLock()
569 certCache.RemoveManaged(noLongerManaged)
570 certCache.Remove(noLongerLoaded)
571 certCacheMu.RUnlock()
572
573 // give the new TLS app a "kick" to manage certs that it is configured for
574 // with its own configuration instead of the one we just evicted
575 if err := nextTLSApp.Manage(reManage); err != nil {
576 if c := t.logger.Check(zapcore.ErrorLevel, "re-managing unloaded certificates with new config"); c != nil {
577 c.Write(
578 zap.Strings("subjects", internal.MaxSizeSubjectsListForLog(reManage, 1000)),
579 zap.Error(err),
580 )
581 }
582 }
583 } else {
584 // no more TLS app running, so delete in-memory cert cache, if it was created yet
585 certCacheMu.RLock()
586 hasCache := certCache != nil
587 certCacheMu.RUnlock()
588 if hasCache {
589 certCache.Stop()
590 certCacheMu.Lock()
591 certCache = nil
592 certCacheMu.Unlock()
593 }
594 }
595
596 return nil
597 }
598
599 // Manage immediately begins managing subjects according to the
600 // matching automation policy. The subjects are given in a map
601 // to prevent duplication and also because quick lookups are
602 // needed to assess wildcard coverage, if any, depending on
603 // certain config parameters (with lots of subjects, computing
604 // wildcard coverage over a slice can be highly inefficient).
605 func (t *TLS) Manage(subjects map[string]struct{}) error {
606 // for a large number of names, we can be more memory-efficient
607 // by making only one certmagic.Config for all the names that
608 // use that config, rather than calling ManageAsync once for
609 // every name; so first, bin names by AutomationPolicy
610 policyToNames := make(map[*AutomationPolicy][]string)
611 for subj := range subjects {
612 ap := t.getAutomationPolicyForName(subj)
613 // by default, if a wildcard that covers the subj is also being
614 // managed, either by a previous call to Manage or by this one,
615 // prefer using that over individual certs for its subdomains;
616 // but users can disable this and force getting a certificate for
617 // subdomains by adding the name to the 'automate' cert loader
618 if t.managingWildcardFor(subj, subjects) {
619 if _, ok := t.automateNames[subj]; !ok {
620 continue
621 }
622 }
623 policyToNames[ap] = append(policyToNames[ap], subj)
624 }
625
626 // now that names are grouped by policy, we can simply make one
627 // certmagic.Config for each (potentially large) group of names
628 // and call ManageAsync just once for the whole batch
629 for ap, names := range policyToNames {
630 err := ap.magic.ManageAsync(t.ctx.Context, names)
631 if err != nil {
632 const maxNamesToDisplay = 100
633 if len(names) > maxNamesToDisplay {
634 names = append(names[:maxNamesToDisplay], fmt.Sprintf("(and %d more...)", len(names)-maxNamesToDisplay))
635 }
636 return fmt.Errorf("automate: manage %v: %v", names, err)
637 }
638 for _, name := range names {
639 // certs that are issued solely by our internal issuer are a little bit of
640 // a special case: if you have an initial config that manages example.com
641 // using internal CA, then after testing it you switch to a production CA,
642 // you wouldn't want to keep using the same self-signed cert, obviously;
643 // so we differentiate these by associating the subject with its issuer key;
644 // we do this because CertMagic has no notion of "InternalIssuer" like we
645 // do, so we have to do this logic ourselves
646 var issuerKey string
647 if len(ap.Issuers) == 1 {
648 if intIss, ok := ap.Issuers[0].(*InternalIssuer); ok && intIss != nil {
649 issuerKey = intIss.IssuerKey()
650 }
651 }
652 t.managing[name] = issuerKey
653 }
654 }
655
656 return nil
657 }
658
659 // managingWildcardFor returns true if the app is managing a certificate that covers that
660 // subject name (including consideration of wildcards), either from its internal list of
661 // names that it IS managing certs for, from the otherSubjsToManage which includes names
662 // that WILL be managed, or from names configured in the 'automate' loader.
663 func (t *TLS) managingWildcardFor(subj string, otherSubjsToManage map[string]struct{}) bool {
664 // TODO: we could also consider manually-loaded certs using t.HasCertificateForSubject(),
665 // but that does not account for how manually-loaded certs may be restricted as to which
666 // hostnames or ClientHellos they can be used with by tags, etc; I don't *think* anyone
667 // necessarily wants this anyway, but I thought I'd note this here for now (if we did
668 // consider manually-loaded certs, we'd probably want to rename the method since it
669 // wouldn't be just about managed certs anymore)
670
671 // IP addresses must match exactly
672 if ip := net.ParseIP(subj); ip != nil {
673 _, managing := t.managing[subj]
674 return managing
675 }
676
677 // replace labels of the domain with wildcards until we get a match from names
678 // already being managed, those about to be managed in this batch, or those
679 // configured for automation
680 labels := strings.Split(subj, ".")
681 for i := range labels {
682 if labels[i] == "*" {
683 continue
684 }
685 labels[i] = "*"
686 candidate := strings.Join(labels, ".")
687 if _, ok := t.managing[candidate]; ok {
688 return true
689 }
690 if _, ok := otherSubjsToManage[candidate]; ok {
691 return true
692 }
693 if _, ok := t.automateNames[candidate]; ok {
694 return true
695 }
696 }
697
698 return false
699 }
700
701 // RegisterServerNames registers the provided DNS names with the TLS app and
702 // associates them with the given HTTPS RR ALPN values, if any. This is
703 // currently used to auto-publish Encrypted ClientHello (ECH) configurations,
704 // if enabled. Use of this function by apps using the TLS app removes the need
705 // for the user to redundantly specify domain names in their configuration.
706 // This function separates hostname and port, keeping only the hostname, and
707 // filters IP addresses which can't be used with ECH.
708 //
709 // EXPERIMENTAL: This function and its semantics/behavior are subject to change.
710 func (t *TLS) RegisterServerNames(dnsNames, alpnValues []string) {
711 t.serverNamesMu.Lock()
712 defer t.serverNamesMu.Unlock()
713
714 for _, name := range dnsNames {
715 host, _, err := net.SplitHostPort(name)
716 if err != nil {
717 host = name
718 }
719 host = strings.ToLower(strings.TrimSpace(host))
720 if host == "" || certmagic.SubjectIsIP(host) {
721 continue
722 }
723
724 registration := t.serverNames[host]
725
726 if len(alpnValues) == 0 {
727 t.serverNames[host] = registration
728 continue
729 }
730
731 if registration.alpnValues == nil {
732 registration.alpnValues = make(map[string]struct{}, len(alpnValues))
733 }
734 for _, alpn := range alpnValues {
735 if alpn == "" {
736 continue
737 }
738 registration.alpnValues[alpn] = struct{}{}
739 }
740 t.serverNames[host] = registration
741 }
742 }
743
744 func (t *TLS) alpnValuesForServerNames(dnsNames []string) map[string][]string {
745 t.serverNamesMu.Lock()
746 defer t.serverNamesMu.Unlock()
747
748 result := make(map[string][]string, len(dnsNames))
749 for _, name := range dnsNames {
750 host, _, err := net.SplitHostPort(name)
751 if err != nil {
752 host = name
753 }
754 host = strings.ToLower(strings.TrimSpace(host))
755 if host == "" {
756 continue
757 }
758
759 registration, ok := t.serverNames[host]
760 if !ok || len(registration.alpnValues) == 0 {
761 continue
762 }
763 result[host] = OrderedHTTPSRRALPN(registration.alpnValues)
764 }
765
766 return result
767 }
768
769 // OrderedHTTPSRRALPN returns the HTTPS RR ALPN values in preferred order.
770 func OrderedHTTPSRRALPN(alpnSet map[string]struct{}) []string {
771 if len(alpnSet) == 0 {
772 return nil
773 }
774
775 knownOrder := append([]string{"h3"}, defaultALPN...)
776 ordered := make([]string, 0, len(alpnSet))
777 seen := make(map[string]struct{}, len(alpnSet))
778
779 for _, alpn := range knownOrder {
780 if _, ok := alpnSet[alpn]; ok {
781 ordered = append(ordered, alpn)
782 seen[alpn] = struct{}{}
783 }
784 }
785
786 if len(ordered) == len(alpnSet) {
787 return ordered
788 }
789
790 var remaining []string
791 for alpn := range alpnSet {
792 if _, ok := seen[alpn]; ok {
793 continue
794 }
795 remaining = append(remaining, alpn)
796 }
797 slices.Sort(remaining)
798
799 return append(ordered, remaining...)
800 }
801
802 type serverNameRegistration struct {
803 alpnValues map[string]struct{}
804 }
805
806 // HandleHTTPChallenge ensures that the ACME HTTP challenge or ZeroSSL HTTP
807 // validation request is handled for the certificate named by r.Host, if it
808 // is an HTTP challenge request. It requires that the automation policy for
809 // r.Host has an issuer that implements GetACMEIssuer() or is a *ZeroSSLIssuer.
810 func (t *TLS) HandleHTTPChallenge(w http.ResponseWriter, r *http.Request) bool {
811 acmeChallenge := certmagic.LooksLikeHTTPChallenge(r)
812 zerosslValidation := certmagic.LooksLikeZeroSSLHTTPValidation(r)
813
814 // no-op if it's not an ACME challenge request
815 if !acmeChallenge && !zerosslValidation {
816 return false
817 }
818
819 // try all the issuers until we find the one that initiated the challenge
820 ap := t.getAutomationPolicyForName(r.Host)
821
822 if acmeChallenge {
823 type acmeCapable interface{ GetACMEIssuer() *ACMEIssuer }
824
825 for _, iss := range ap.magic.Issuers {
826 if acmeIssuer, ok := iss.(acmeCapable); ok {
827 if acmeIssuer.GetACMEIssuer().issuer.HandleHTTPChallenge(w, r) {
828 return true
829 }
830 }
831 }
832
833 // it's possible another server in this process initiated the challenge;
834 // users have requested that Caddy only handle HTTP challenges it initiated,
835 // so that users can proxy the others through to their backends; but we
836 // might not have an automation policy for all identifiers that are trying
837 // to get certificates (e.g. the admin endpoint), so we do this manual check
838 if challenge, ok := certmagic.GetACMEChallenge(r.Host); ok {
839 return certmagic.SolveHTTPChallenge(t.logger, w, r, challenge.Challenge)
840 }
841 } else if zerosslValidation {
842 for _, iss := range ap.magic.Issuers {
843 if ziss, ok := iss.(*ZeroSSLIssuer); ok {
844 if ziss.issuer.HandleZeroSSLHTTPValidation(w, r) {
845 return true
846 }
847 }
848 }
849 }
850
851 return false
852 }
853
854 // AddAutomationPolicy provisions and adds ap to the list of the app's
855 // automation policies. If an existing automation policy exists that has
856 // fewer hosts in its list than ap does, ap will be inserted before that
857 // other policy (this helps ensure that ap will be prioritized/chosen
858 // over, say, a catch-all policy).
859 func (t *TLS) AddAutomationPolicy(ap *AutomationPolicy) error {
860 if t.Automation == nil {
861 t.Automation = new(AutomationConfig)
862 }
863 err := ap.Provision(t)
864 if err != nil {
865 return err
866 }
867 // sort new automation policies just before any other which is a superset
868 // of this one; if we find an existing policy that covers every subject in
869 // ap but less specifically (e.g. a catch-all policy, or one with wildcards
870 // or with fewer subjects), insert ap just before it, otherwise ap would
871 // never be used because the first matching policy is more general
872 for i, existing := range t.Automation.Policies {
873 // first see if existing is superset of ap for all names
874 var otherIsSuperset bool
875 outer:
876 for _, thisSubj := range ap.subjects {
877 for _, otherSubj := range existing.subjects {
878 if certmagic.MatchWildcard(thisSubj, otherSubj) {
879 otherIsSuperset = true
880 break outer
881 }
882 }
883 }
884 // if existing AP is a superset or if it contains fewer names (i.e. is
885 // more general), then new AP is more specific, so insert before it
886 if otherIsSuperset || len(existing.SubjectsRaw) < len(ap.SubjectsRaw) {
887 t.Automation.Policies = append(t.Automation.Policies[:i],
888 append([]*AutomationPolicy{ap}, t.Automation.Policies[i:]...)...)
889 return nil
890 }
891 }
892 // otherwise just append the new one
893 t.Automation.Policies = append(t.Automation.Policies, ap)
894 return nil
895 }
896
897 func (t *TLS) getConfigForName(name string) *certmagic.Config {
898 ap := t.getAutomationPolicyForName(name)
899 return ap.magic
900 }
901
902 // getAutomationPolicyForName returns the first matching automation policy
903 // for the given subject name. If no matching policy can be found, the
904 // default policy is used, depending on whether the name qualifies for a
905 // public certificate or not.
906 func (t *TLS) getAutomationPolicyForName(name string) *AutomationPolicy {
907 for _, ap := range t.Automation.Policies {
908 if len(ap.subjects) == 0 {
909 return ap // no host filter is an automatic match
910 }
911 for _, h := range ap.subjects {
912 if certmagic.MatchWildcard(name, h) {
913 return ap
914 }
915 }
916 }
917 if certmagic.SubjectQualifiesForPublicCert(name) || t.Automation.defaultInternalAutomationPolicy == nil {
918 return t.Automation.defaultPublicAutomationPolicy
919 }
920 return t.Automation.defaultInternalAutomationPolicy
921 }
922
923 // AllMatchingCertificates returns the list of all certificates in
924 // the cache which could be used to satisfy the given SAN.
925 func AllMatchingCertificates(san string) []certmagic.Certificate {
926 certCacheMu.RLock()
927 defer certCacheMu.RUnlock()
928 return certCache.AllMatchingCertificates(san)
929 }
930
931 func (t *TLS) HasCertificateForSubject(subject string) bool {
932 certCacheMu.RLock()
933 allMatchingCerts := certCache.AllMatchingCertificates(subject)
934 certCacheMu.RUnlock()
935 for _, cert := range allMatchingCerts {
936 // check if the cert is manually loaded by this config
937 if _, ok := t.loaded[cert.Hash()]; ok {
938 return true
939 }
940 // check if the cert is automatically managed by this config
941 for _, name := range cert.Names {
942 if _, ok := t.managing[name]; ok {
943 return true
944 }
945 }
946 }
947 return false
948 }
949
950 // keepStorageClean starts a goroutine that immediately cleans up all
951 // known storage units if it was not recently done, and then runs the
952 // operation at every tick from t.storageCleanTicker.
953 func (t *TLS) keepStorageClean() {
954 if t.bgCtx == nil {
955 parentCtx := t.ctx.Context
956 if parentCtx == nil {
957 parentCtx = context.Background()
958 }
959 t.bgCtx, t.bgCancel = context.WithCancel(parentCtx)
960 }
961 if t.bgWg == nil {
962 t.bgWg = new(sync.WaitGroup)
963 }
964 t.storageCleanTicker = time.NewTicker(t.storageCleanInterval())
965 t.bgWg.Add(1)
966 go func(ctx context.Context) {
967 defer t.bgWg.Done()
968 defer func() {
969 if err := recover(); err != nil {
970 log.Printf("[PANIC] storage cleaner: %v\n%s", err, debug.Stack())
971 }
972 }()
973 t.cleanStorageUnits(ctx)
974 for {
975 select {
976 case <-ctx.Done():
977 return
978 case <-t.storageCleanTicker.C:
979 t.cleanStorageUnits(ctx)
980 }
981 }
982 }(t.bgCtx)
983 }
984
985 func (t *TLS) cleanStorageUnits(ctx context.Context) {
986 storageCleanMu.Lock()
987 defer storageCleanMu.Unlock()
988
989 if err := ctx.Err(); err != nil {
990 return
991 }
992
993 // TODO: This check might not be needed anymore now that CertMagic syncs
994 // and throttles storage cleaning globally across the cluster.
995 // The original comment below might be outdated:
996 //
997 // If storage was cleaned recently, don't do it again for now. Although the ticker
998 // calling this function drops missed ticks for us, config reloads discard the old
999 // ticker and replace it with a new one, possibly invoking a cleaning to happen again
1000 // too soon. (We divide the interval by 2 because the actual cleaning takes non-zero
1001 // time, and we don't want to skip cleanings if we don't have to; whereas if a cleaning
1002 // took most of the interval, we'd probably want to skip the next one so we aren't
1003 // constantly cleaning. This allows cleanings to take up to half the interval's
1004 // duration before we decide to skip the next one.)
1005 if !storageClean.IsZero() && time.Since(storageClean) < t.storageCleanInterval()/2 {
1006 return
1007 }
1008
1009 id, err := caddy.InstanceID()
1010 if err != nil {
1011 if c := t.logger.Check(zapcore.WarnLevel, "unable to get instance ID; storage clean stamps will be incomplete"); c != nil {
1012 c.Write(zap.Error(err))
1013 }
1014 }
1015 options := certmagic.CleanStorageOptions{
1016 Logger: t.logger,
1017 InstanceID: id.String(),
1018 Interval: t.storageCleanInterval(),
1019 OCSPStaples: true,
1020 ExpiredCerts: true,
1021 ExpiredCertGracePeriod: 24 * time.Hour * 14,
1022 }
1023
1024 // start with the default/global storage
1025 if storage := t.ctx.Storage(); storage != nil {
1026 err = certmagic.CleanStorage(ctx, storage, options)
1027 if err != nil {
1028 if errors.Is(err, context.Canceled) || ctx.Err() != nil {
1029 return
1030 }
1031 // probably don't want to return early, since we should still
1032 // see if any other storages can get cleaned up
1033 if c := t.logger.Check(zapcore.ErrorLevel, "could not clean default/global storage"); c != nil {
1034 c.Write(zap.Error(err))
1035 }
1036 }
1037 }
1038
1039 // then clean each storage defined in ACME automation policies
1040 if t.Automation != nil {
1041 for _, ap := range t.Automation.Policies {
1042 if ap.storage == nil {
1043 continue
1044 }
1045 if err := certmagic.CleanStorage(ctx, ap.storage, options); err != nil {
1046 if errors.Is(err, context.Canceled) || ctx.Err() != nil {
1047 return
1048 }
1049 if c := t.logger.Check(zapcore.ErrorLevel, "could not clean storage configured in automation policy"); c != nil {
1050 c.Write(zap.Error(err))
1051 }
1052 }
1053 }
1054 }
1055
1056 if err := ctx.Err(); err != nil {
1057 return
1058 }
1059
1060 // remember last time storage was finished cleaning
1061 storageClean = time.Now()
1062
1063 t.logger.Info("finished cleaning storage units")
1064 }
1065
1066 func (t *TLS) storageCleanInterval() time.Duration {
1067 if t.Automation != nil && t.Automation.StorageCleanInterval > 0 {
1068 return time.Duration(t.Automation.StorageCleanInterval)
1069 }
1070 return defaultStorageCleanInterval
1071 }
1072
1073 func (t *TLS) echRotationInterval() time.Duration {
1074 if t.echRotateInterval > 0 {
1075 return t.echRotateInterval
1076 }
1077 return 1 * time.Hour
1078 }
1079
1080 func (t *TLS) caddyContext(ctx context.Context) caddy.Context {
1081 caddyCtx := t.ctx
1082 caddyCtx.Context = ctx
1083 return caddyCtx
1084 }
1085
1086 // onEvent translates CertMagic events into Caddy events then dispatches them.
1087 func (t *TLS) onEvent(ctx context.Context, eventName string, data map[string]any) error {
1088 evt := t.events.Emit(t.ctx, eventName, data)
1089 return evt.Aborted
1090 }
1091
1092 // CertificateLoader is a type that can load certificates.
1093 // Certificates can optionally be associated with tags.
1094 type CertificateLoader interface {
1095 LoadCertificates() ([]Certificate, error)
1096 }
1097
1098 // Certificate is a TLS certificate, optionally
1099 // associated with arbitrary tags.
1100 type Certificate struct {
1101 tls.Certificate
1102 Tags []string
1103 }
1104
1105 // AutomateLoader will automatically manage certificates for the names in the
1106 // list, including obtaining and renewing certificates. Automated certificates
1107 // are managed according to their matching automation policy, configured
1108 // elsewhere in this app.
1109 //
1110 // Technically, this is a no-op certificate loader module that is treated as
1111 // a special case: it uses this app's automation features to load certificates
1112 // for the list of hostnames, rather than loading certificates manually. But
1113 // the end result is the same: certificates for these subject names will be
1114 // loaded into the in-memory cache and may then be used.
1115 type AutomateLoader []string
1116
1117 // CaddyModule returns the Caddy module information.
1118 func (AutomateLoader) CaddyModule() caddy.ModuleInfo {
1119 return caddy.ModuleInfo{
1120 ID: "tls.certificates.automate",
1121 New: func() caddy.Module { return new(AutomateLoader) },
1122 }
1123 }
1124
1125 // CertCacheOptions configures the certificate cache.
1126 type CertCacheOptions struct {
1127 // Maximum number of certificates to allow in the
1128 // cache. If reached, certificates will be randomly
1129 // evicted to make room for new ones. Default: 10,000
1130 Capacity int `json:"capacity,omitempty"`
1131 }
1132
1133 // Variables related to storage cleaning.
1134 var (
1135 defaultStorageCleanInterval = 24 * time.Hour
1136
1137 storageClean time.Time
1138 storageCleanMu sync.Mutex
1139 )
1140
1141 // Interface guards
1142 var (
1143 _ caddy.App = (*TLS)(nil)
1144 _ caddy.Provisioner = (*TLS)(nil)
1145 _ caddy.Validator = (*TLS)(nil)
1146 _ caddy.CleanerUpper = (*TLS)(nil)
1147 )