Scope TLS max_certs to site config instead of global

This commit is contained in:
Matthew Holt 2016-07-28 11:08:18 -06:00
parent 1e1e69b90f
commit af48bbd234
No known key found for this signature in database
GPG Key ID: 0D97CC73664F4D03
3 changed files with 25 additions and 22 deletions

View File

@ -75,7 +75,7 @@ type Config struct {
CAUrl string
// The host (ONLY the host, not port) to listen
//on if necessary to start a a listener to solve
// on if necessary to start a listener to solve
// an ACME challenge
ListenHost string
@ -105,6 +105,22 @@ type Config struct {
// implementors are encouraged to cache any heavy
// instantiations.
StorageCreator StorageCreator
// The state needed to operate on-demand TLS
OnDemandState OnDemandState
}
// OnDemandState contains some state relevant for providing
// on-demand TLS.
type OnDemandState struct {
// The number of certificates that have been issued on-demand
// by this config. It is only safe to modify this count atomically.
// If it reaches MaxObtain, on-demand issuances must fail.
ObtainedCount int32
// Based on max_certs in tls config, it specifies the
// maximum number of certificates that can be issued.
MaxObtain int32
}
// ObtainCert obtains a certificate for c.Hostname, as long as a certificate

View File

@ -100,7 +100,7 @@ func (cg configGroup) getCertDuringHandshake(name string, loadIfNecessary, obtai
name = strings.ToLower(name)
// Make sure aren't over any applicable limits
err := cg.checkLimitsForObtainingNewCerts(name)
err := cg.checkLimitsForObtainingNewCerts(name, cfg)
if err != nil {
return Certificate{}, err
}
@ -127,10 +127,11 @@ func (cg configGroup) getCertDuringHandshake(name string, loadIfNecessary, obtai
// now according to mitigating factors we keep track of and preferences the
// user has set. If a non-nil error is returned, do not issue a new certificate
// for name.
func (cg configGroup) checkLimitsForObtainingNewCerts(name string) error {
func (cg configGroup) checkLimitsForObtainingNewCerts(name string, cfg *Config) error {
// User can set hard limit for number of certs for the process to issue
if onDemandMaxIssue > 0 && atomic.LoadInt32(OnDemandIssuedCount) >= onDemandMaxIssue {
return fmt.Errorf("%s: maximum certificates issued (%d)", name, onDemandMaxIssue)
if cfg.OnDemandState.MaxObtain > 0 &&
atomic.LoadInt32(&cfg.OnDemandState.ObtainedCount) >= cfg.OnDemandState.MaxObtain {
return fmt.Errorf("%s: maximum certificates issued (%d)", name, cfg.OnDemandState.MaxObtain)
}
// Make sure name hasn't failed a challenge recently
@ -146,7 +147,7 @@ func (cg configGroup) checkLimitsForObtainingNewCerts(name string) error {
lastIssueTimeMu.Lock()
since := time.Since(lastIssueTime)
lastIssueTimeMu.Unlock()
if atomic.LoadInt32(OnDemandIssuedCount) >= 10 && since < 10*time.Minute {
if atomic.LoadInt32(&cfg.OnDemandState.ObtainedCount) >= 10 && since < 10*time.Minute {
return fmt.Errorf("%s: throttled; last certificate was obtained %v ago", name, since)
}
@ -202,7 +203,7 @@ func (cg configGroup) obtainOnDemandCertificate(name string, cfg *Config) (Certi
}
// Success - update counters and stuff
atomic.AddInt32(OnDemandIssuedCount, 1)
atomic.AddInt32(&cfg.OnDemandState.ObtainedCount, 1)
lastIssueTimeMu.Lock()
lastIssueTime = time.Now()
lastIssueTimeMu.Unlock()
@ -286,18 +287,6 @@ func (cg configGroup) renewDynamicCertificate(name string, cfg *Config) (Certifi
var obtainCertWaitChans = make(map[string]chan struct{})
var obtainCertWaitChansMu sync.Mutex
// OnDemandIssuedCount is the number of certificates that have been issued
// on-demand by this process. It is only safe to modify this count atomically.
// If it reaches onDemandMaxIssue, on-demand issuances will fail.
var OnDemandIssuedCount = new(int32)
// onDemandMaxIssue is set based on max_certs in tls config. It specifies the
// maximum number of certificates that can be issued.
// TODO: This applies globally, but we should probably make a server-specific
// way to keep track of these limits and counts, since it's specified in the
// Caddyfile...
var onDemandMaxIssue int32
// failedIssuance is a set of names that we recently failed to get a
// certificate for from the ACME CA. They are removed after some time.
// When a name is in this map, do not issue a certificate for it on-demand.

View File

@ -156,9 +156,7 @@ func setupTLS(c *caddy.Controller) error {
if err != nil || maxCertsNum < 1 {
return c.Err("max_certs must be a positive integer")
}
if onDemandMaxIssue == 0 || int32(maxCertsNum) < onDemandMaxIssue { // keep the minimum; TODO: We have to do this because it is global; should be per-server or per-vhost...
onDemandMaxIssue = int32(maxCertsNum)
}
config.OnDemandState.MaxObtain = int32(maxCertsNum)
}
// don't try to load certificates unless we're supposed to