diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 22b2f01f..56802838 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -90,6 +90,7 @@ func parseBind(h Helper) ([]ConfigValue, error) { // dns_ttl // dns_challenge_override_domain // on_demand +// reuse_private_keys // eab // issuer [...] // get_certificate [...] @@ -106,6 +107,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) { var issuers []certmagic.Issuer var certManagers []certmagic.Manager var onDemand bool + var reusePrivateKeys bool for h.Next() { // file certificate loader @@ -483,6 +485,12 @@ func parseTLS(h Helper) ([]ConfigValue, error) { } onDemand = true + case "reuse_private_keys": + if h.NextArg() { + return nil, h.ArgErr() + } + reusePrivateKeys = true + case "insecure_secrets_log": if !h.NextArg() { return nil, h.ArgErr() @@ -589,6 +597,14 @@ func parseTLS(h Helper) ([]ConfigValue, error) { }) } + // reuse private keys TLS + if reusePrivateKeys { + configVals = append(configVals, ConfigValue{ + Class: "tls.reuse_private_keys", + Value: true, + }) + } + // custom certificate selection if len(certSelector.AnyTag) > 0 { cp.CertSelection = &certSelector diff --git a/caddyconfig/httpcaddyfile/tlsapp.go b/caddyconfig/httpcaddyfile/tlsapp.go index cb947a6e..1adb2b6e 100644 --- a/caddyconfig/httpcaddyfile/tlsapp.go +++ b/caddyconfig/httpcaddyfile/tlsapp.go @@ -118,6 +118,11 @@ func (st ServerType) buildTLSApp( ap.OnDemand = true } + // reuse private keys tls + if _, ok := sblock.pile["tls.reuse_private_keys"]; ok { + ap.ReusePrivateKeys = true + } + if keyTypeVals, ok := sblock.pile["tls.key_type"]; ok { ap.KeyType = keyTypeVals[0].Value.(string) } @@ -587,6 +592,7 @@ outer: aps[i].MustStaple == aps[j].MustStaple && aps[i].KeyType == aps[j].KeyType && aps[i].OnDemand == aps[j].OnDemand && + aps[i].ReusePrivateKeys == aps[j].ReusePrivateKeys && aps[i].RenewalWindowRatio == aps[j].RenewalWindowRatio { if len(aps[i].SubjectsRaw) > 0 && len(aps[j].SubjectsRaw) == 0 { // later policy (at j) has no subjects ("catch-all"), so we can diff --git a/modules/caddytls/automation.go b/modules/caddytls/automation.go index 6d085ee3..72eeae76 100644 --- a/modules/caddytls/automation.go +++ b/modules/caddytls/automation.go @@ -138,6 +138,15 @@ type AutomationPolicy struct { // load. This enables On-Demand TLS for this policy. OnDemand bool `json:"on_demand,omitempty"` + // If true, private keys already existing in storage + // will be reused. Otherwise, a new key will be + // created for every new certificate to mitigate + // pinning and reduce the scope of key compromise. + // TEMPORARY: Key pinning is against industry best practices. + // This property will likely be removed in the future. + // Do not rely on it forever; watch the release notes. + ReusePrivateKeys bool `json:"reuse_private_keys,omitempty"` + // Disables OCSP stapling. Disabling OCSP stapling puts clients at // greater risk, reduces their privacy, and usually lowers client // performance. It is NOT recommended to disable this unless you @@ -288,6 +297,7 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error { KeySource: keySource, OnEvent: tlsApp.onEvent, OnDemand: ond, + ReusePrivateKeys: ap.ReusePrivateKeys, OCSP: certmagic.OCSPConfig{ DisableStapling: ap.DisableOCSPStapling, ResponderOverrides: ap.OCSPOverrides,