diff options
Diffstat (limited to 'caddyconfig/httpcaddyfile')
-rw-r--r-- | caddyconfig/httpcaddyfile/httptype.go | 56 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/options.go | 21 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/tlsapp.go | 41 |
3 files changed, 98 insertions, 20 deletions
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index 6745969ee..4dacd9058 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -534,8 +534,8 @@ func (st *ServerType) serversFromPairings( if hsp, ok := options["https_port"].(int); ok { httpsPort = strconv.Itoa(hsp) } - autoHTTPS := "on" - if ah, ok := options["auto_https"].(string); ok { + autoHTTPS := []string{} + if ah, ok := options["auto_https"].([]string); ok { autoHTTPS = ah } @@ -594,17 +594,37 @@ func (st *ServerType) serversFromPairings( } // handle the auto_https global option - if autoHTTPS != "on" { - srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig) - switch autoHTTPS { + for _, val := range autoHTTPS { + switch val { case "off": + if srv.AutoHTTPS == nil { + srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig) + } srv.AutoHTTPS.Disabled = true + case "disable_redirects": + if srv.AutoHTTPS == nil { + srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig) + } srv.AutoHTTPS.DisableRedir = true + case "disable_certs": + if srv.AutoHTTPS == nil { + srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig) + } srv.AutoHTTPS.DisableCerts = true + case "ignore_loaded_certs": + if srv.AutoHTTPS == nil { + srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig) + } srv.AutoHTTPS.IgnoreLoadedCerts = true + + case "prefer_wildcard": + if srv.AutoHTTPS == nil { + srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig) + } + srv.AutoHTTPS.PreferWildcard = true } } @@ -673,7 +693,7 @@ func (st *ServerType) serversFromPairings( }) var hasCatchAllTLSConnPolicy, addressQualifiesForTLS bool - autoHTTPSWillAddConnPolicy := autoHTTPS != "off" + autoHTTPSWillAddConnPolicy := srv.AutoHTTPS == nil || !srv.AutoHTTPS.Disabled // if needed, the ServerLogConfig is initialized beforehand so // that all server blocks can populate it with data, even when not @@ -757,6 +777,13 @@ func (st *ServerType) serversFromPairings( } } + wildcardHosts := []string{} + for _, addr := range sblock.parsedKeys { + if strings.HasPrefix(addr.Host, "*.") { + wildcardHosts = append(wildcardHosts, addr.Host[2:]) + } + } + for _, addr := range sblock.parsedKeys { // if server only uses HTTP port, auto-HTTPS will not apply if listenersUseAnyPortOtherThan(srv.Listen, httpPort) { @@ -772,6 +799,18 @@ func (st *ServerType) serversFromPairings( } } + // If prefer wildcard is enabled, then we add hosts that are + // already covered by the wildcard to the skip list + if srv.AutoHTTPS != nil && srv.AutoHTTPS.PreferWildcard && addr.Scheme == "https" { + baseDomain := addr.Host + if idx := strings.Index(baseDomain, "."); idx != -1 { + baseDomain = baseDomain[idx+1:] + } + if !strings.HasPrefix(addr.Host, "*.") && slices.Contains(wildcardHosts, baseDomain) { + srv.AutoHTTPS.Skip = append(srv.AutoHTTPS.Skip, addr.Host) + } + } + // If TLS is specified as directive, it will also result in 1 or more connection policy being created // Thus, catch-all address with non-standard port, e.g. :8443, can have TLS enabled without // specifying prefix "https://" @@ -919,7 +958,10 @@ func (st *ServerType) serversFromPairings( if addressQualifiesForTLS && !hasCatchAllTLSConnPolicy && (len(srv.TLSConnPolicies) > 0 || !autoHTTPSWillAddConnPolicy || defaultSNI != "" || fallbackSNI != "") { - srv.TLSConnPolicies = append(srv.TLSConnPolicies, &caddytls.ConnectionPolicy{DefaultSNI: defaultSNI, FallbackSNI: fallbackSNI}) + srv.TLSConnPolicies = append(srv.TLSConnPolicies, &caddytls.ConnectionPolicy{ + DefaultSNI: defaultSNI, + FallbackSNI: fallbackSNI, + }) } // tidy things up a bit diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go index c14208b61..abbe8f418 100644 --- a/caddyconfig/httpcaddyfile/options.go +++ b/caddyconfig/httpcaddyfile/options.go @@ -452,15 +452,22 @@ func parseOptPersistConfig(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ any) (any, error) { d.Next() // consume option name - if !d.Next() { - return "", d.ArgErr() - } - val := d.Val() - if d.Next() { + val := d.RemainingArgs() + if len(val) == 0 { return "", d.ArgErr() } - if val != "off" && val != "disable_redirects" && val != "disable_certs" && val != "ignore_loaded_certs" { - return "", d.Errf("auto_https must be one of 'off', 'disable_redirects', 'disable_certs', or 'ignore_loaded_certs'") + for _, v := range val { + switch v { + case "off": + case "disable_redirects": + case "disable_certs": + case "ignore_loaded_certs": + case "prefer_wildcard": + break + + default: + return "", d.Errf("auto_https must be one of 'off', 'disable_redirects', 'disable_certs', 'ignore_loaded_certs', or 'prefer_wildcard'") + } } return val, nil } diff --git a/caddyconfig/httpcaddyfile/tlsapp.go b/caddyconfig/httpcaddyfile/tlsapp.go index c6ff81b2b..ed708524d 100644 --- a/caddyconfig/httpcaddyfile/tlsapp.go +++ b/caddyconfig/httpcaddyfile/tlsapp.go @@ -45,8 +45,8 @@ func (st ServerType) buildTLSApp( if hp, ok := options["http_port"].(int); ok { httpPort = strconv.Itoa(hp) } - autoHTTPS := "on" - if ah, ok := options["auto_https"].(string); ok { + autoHTTPS := []string{} + if ah, ok := options["auto_https"].([]string); ok { autoHTTPS = ah } @@ -54,13 +54,14 @@ func (st ServerType) buildTLSApp( // key, so that they don't get forgotten/omitted by auto-HTTPS // (since they won't appear in route matchers) httpsHostsSharedWithHostlessKey := make(map[string]struct{}) - if autoHTTPS != "off" { + if !slices.Contains(autoHTTPS, "off") { for _, pair := range pairings { for _, sb := range pair.serverBlocks { for _, addr := range sb.parsedKeys { if addr.Host != "" { continue } + // this server block has a hostless key, now // go through and add all the hosts to the set for _, otherAddr := range sb.parsedKeys { @@ -350,7 +351,7 @@ func (st ServerType) buildTLSApp( internalAP := &caddytls.AutomationPolicy{ IssuersRaw: []json.RawMessage{json.RawMessage(`{"module":"internal"}`)}, } - if autoHTTPS != "off" && autoHTTPS != "disable_certs" { + if !slices.Contains(autoHTTPS, "off") && !slices.Contains(autoHTTPS, "disable_certs") { for h := range httpsHostsSharedWithHostlessKey { al = append(al, h) if !certmagic.SubjectQualifiesForPublicCert(h) { @@ -417,7 +418,10 @@ func (st ServerType) buildTLSApp( } // consolidate automation policies that are the exact same - tlsApp.Automation.Policies = consolidateAutomationPolicies(tlsApp.Automation.Policies) + tlsApp.Automation.Policies = consolidateAutomationPolicies( + tlsApp.Automation.Policies, + slices.Contains(autoHTTPS, "prefer_wildcard"), + ) // ensure automation policies don't overlap subjects (this should be // an error at provision-time as well, but catch it in the adapt phase @@ -563,7 +567,7 @@ func newBaseAutomationPolicy( // consolidateAutomationPolicies combines automation policies that are the same, // for a cleaner overall output. -func consolidateAutomationPolicies(aps []*caddytls.AutomationPolicy) []*caddytls.AutomationPolicy { +func consolidateAutomationPolicies(aps []*caddytls.AutomationPolicy, preferWildcard bool) []*caddytls.AutomationPolicy { // sort from most specific to least specific; we depend on this ordering sort.SliceStable(aps, func(i, j int) bool { if automationPolicyIsSubset(aps[i], aps[j]) { @@ -648,6 +652,31 @@ outer: j-- } } + + if preferWildcard { + // remove subjects from i if they're covered by a wildcard in j + iSubjs := aps[i].SubjectsRaw + for iSubj := 0; iSubj < len(iSubjs); iSubj++ { + for jSubj := range aps[j].SubjectsRaw { + if !strings.HasPrefix(aps[j].SubjectsRaw[jSubj], "*.") { + continue + } + if certmagic.MatchWildcard(aps[i].SubjectsRaw[iSubj], aps[j].SubjectsRaw[jSubj]) { + iSubjs = slices.Delete(iSubjs, iSubj, iSubj+1) + iSubj-- + break + } + } + } + aps[i].SubjectsRaw = iSubjs + + // remove i if it has no subjects left + if len(aps[i].SubjectsRaw) == 0 { + aps = slices.Delete(aps, i, i+1) + i-- + continue outer + } + } } } |