Skip to content

Commit 1bfa111

Browse files
authored
caddytls: Prefer managed wildcard certs over individual subdomain certs (#6959)
* caddytls: Prefer managed wildcard certs over individual subdomain certs * Repurpose force_automate as no_wildcard * Fix a couple bugs * Restore force_automate and use automate loader as wildcard override
1 parent 35c8c2d commit 1bfa111

File tree

13 files changed

+172
-491
lines changed

13 files changed

+172
-491
lines changed

caddyconfig/httpcaddyfile/httptype.go

+39-31
Original file line numberDiff line numberDiff line change
@@ -633,12 +633,6 @@ func (st *ServerType) serversFromPairings(
633633
srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig)
634634
}
635635
srv.AutoHTTPS.IgnoreLoadedCerts = true
636-
637-
case "prefer_wildcard":
638-
if srv.AutoHTTPS == nil {
639-
srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig)
640-
}
641-
srv.AutoHTTPS.PreferWildcard = true
642636
}
643637
}
644638

@@ -706,16 +700,6 @@ func (st *ServerType) serversFromPairings(
706700
return specificity(iLongestHost) > specificity(jLongestHost)
707701
})
708702

709-
// collect all hosts that have a wildcard in them
710-
wildcardHosts := []string{}
711-
for _, sblock := range p.serverBlocks {
712-
for _, addr := range sblock.parsedKeys {
713-
if strings.HasPrefix(addr.Host, "*.") {
714-
wildcardHosts = append(wildcardHosts, addr.Host[2:])
715-
}
716-
}
717-
}
718-
719703
var hasCatchAllTLSConnPolicy, addressQualifiesForTLS bool
720704
autoHTTPSWillAddConnPolicy := srv.AutoHTTPS == nil || !srv.AutoHTTPS.Disabled
721705

@@ -801,7 +785,13 @@ func (st *ServerType) serversFromPairings(
801785
cp.FallbackSNI = fallbackSNI
802786
}
803787

804-
// only append this policy if it actually changes something
788+
// only append this policy if it actually changes something,
789+
// or if the configuration explicitly automates certs for
790+
// these names (this is necessary to hoist a connection policy
791+
// above one that may manually load a wildcard cert that would
792+
// otherwise clobber the automated one; the code that appends
793+
// policies that manually load certs comes later, so they're
794+
// lower in the list)
805795
if !cp.SettingsEmpty() || mapContains(forceAutomatedNames, hosts) {
806796
srv.TLSConnPolicies = append(srv.TLSConnPolicies, cp)
807797
hasCatchAllTLSConnPolicy = len(hosts) == 0
@@ -841,18 +831,6 @@ func (st *ServerType) serversFromPairings(
841831
addressQualifiesForTLS = true
842832
}
843833

844-
// If prefer wildcard is enabled, then we add hosts that are
845-
// already covered by the wildcard to the skip list
846-
if addressQualifiesForTLS && srv.AutoHTTPS != nil && srv.AutoHTTPS.PreferWildcard {
847-
baseDomain := addr.Host
848-
if idx := strings.Index(baseDomain, "."); idx != -1 {
849-
baseDomain = baseDomain[idx+1:]
850-
}
851-
if !strings.HasPrefix(addr.Host, "*.") && slices.Contains(wildcardHosts, baseDomain) {
852-
srv.AutoHTTPS.SkipCerts = append(srv.AutoHTTPS.SkipCerts, addr.Host)
853-
}
854-
}
855-
856834
// predict whether auto-HTTPS will add the conn policy for us; if so, we
857835
// may not need to add one for this server
858836
autoHTTPSWillAddConnPolicy = autoHTTPSWillAddConnPolicy &&
@@ -1083,11 +1061,40 @@ func consolidateConnPolicies(cps caddytls.ConnectionPolicies) (caddytls.Connecti
10831061

10841062
// if they're exactly equal in every way, just keep one of them
10851063
if reflect.DeepEqual(cps[i], cps[j]) {
1086-
cps = append(cps[:j], cps[j+1:]...)
1064+
cps = slices.Delete(cps, j, j+1)
10871065
i--
10881066
break
10891067
}
10901068

1069+
// as a special case, if there are adjacent TLS conn policies that are identical except
1070+
// by their matchers, and the matchers are specifically just ServerName ("sni") matchers
1071+
// (by far the most common), we can combine them into a single policy
1072+
if i == j-1 && len(cps[i].MatchersRaw) == 1 && len(cps[j].MatchersRaw) == 1 {
1073+
if iSNIMatcherJSON, ok := cps[i].MatchersRaw["sni"]; ok {
1074+
if jSNIMatcherJSON, ok := cps[j].MatchersRaw["sni"]; ok {
1075+
// position of policies and the matcher criteria check out; if settings are
1076+
// the same, then we can combine the policies; we have to unmarshal and
1077+
// remarshal the matchers though
1078+
if cps[i].SettingsEqual(*cps[j]) {
1079+
var iSNIMatcher caddytls.MatchServerName
1080+
if err := json.Unmarshal(iSNIMatcherJSON, &iSNIMatcher); err == nil {
1081+
var jSNIMatcher caddytls.MatchServerName
1082+
if err := json.Unmarshal(jSNIMatcherJSON, &jSNIMatcher); err == nil {
1083+
iSNIMatcher = append(iSNIMatcher, jSNIMatcher...)
1084+
cps[i].MatchersRaw["sni"], err = json.Marshal(iSNIMatcher)
1085+
if err != nil {
1086+
return nil, fmt.Errorf("recombining SNI matchers: %v", err)
1087+
}
1088+
cps = slices.Delete(cps, j, j+1)
1089+
i--
1090+
break
1091+
}
1092+
}
1093+
}
1094+
}
1095+
}
1096+
}
1097+
10911098
// if they have the same matcher, try to reconcile each field: either they must
10921099
// be identical, or we have to be able to combine them safely
10931100
if reflect.DeepEqual(cps[i].MatchersRaw, cps[j].MatchersRaw) {
@@ -1189,12 +1196,13 @@ func consolidateConnPolicies(cps caddytls.ConnectionPolicies) (caddytls.Connecti
11891196
}
11901197
}
11911198

1192-
cps = append(cps[:j], cps[j+1:]...)
1199+
cps = slices.Delete(cps, j, j+1)
11931200
i--
11941201
break
11951202
}
11961203
}
11971204
}
1205+
11981206
return cps, nil
11991207
}
12001208

caddyconfig/httpcaddyfile/tlsapp.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,9 @@ func (st ServerType) buildTLSApp(
9292
tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, catchAllAP)
9393
}
9494

95-
// collect all hosts that have a wildcard in them, and arent HTTP
96-
wildcardHosts := []string{}
97-
// hosts that have been explicitly marked to be automated,
98-
// even if covered by another wildcard
99-
forcedAutomatedNames := make(map[string]struct{})
95+
var wildcardHosts []string // collect all hosts that have a wildcard in them, and aren't HTTP
96+
forcedAutomatedNames := make(map[string]struct{}) // explicitly configured to be automated, even if covered by a wildcard
97+
10098
for _, p := range pairings {
10199
var addresses []string
102100
for _, addressWithProtocols := range p.addressesWithProtocols {
@@ -153,7 +151,7 @@ func (st ServerType) buildTLSApp(
153151
ap.OnDemand = true
154152
}
155153

156-
// collect hosts that are forced to be automated
154+
// collect hosts that are forced to have certs automated for their specific name
157155
if _, ok := sblock.pile["tls.force_automate"]; ok {
158156
for _, host := range sblockHosts {
159157
forcedAutomatedNames[host] = struct{}{}
@@ -375,7 +373,9 @@ func (st ServerType) buildTLSApp(
375373
return nil, warnings, err
376374
}
377375
for _, cfg := range ech.Configs {
378-
ap.SubjectsRaw = append(ap.SubjectsRaw, cfg.PublicName)
376+
if cfg.PublicName != "" {
377+
ap.SubjectsRaw = append(ap.SubjectsRaw, cfg.PublicName)
378+
}
379379
}
380380
if tlsApp.Automation == nil {
381381
tlsApp.Automation = new(caddytls.AutomationConfig)

caddytest/integration/caddyfile_adapt/auto_https_prefer_wildcard.caddyfiletest

-109
This file was deleted.

0 commit comments

Comments
 (0)