diff --git a/pkg/controller/acmeorders/sync.go b/pkg/controller/acmeorders/sync.go index a6f4f7fac..086834566 100644 --- a/pkg/controller/acmeorders/sync.go +++ b/pkg/controller/acmeorders/sync.go @@ -284,10 +284,6 @@ func (c *Controller) Sync(ctx context.Context, o *cmapi.Order) (err error) { continue } - domainName := spec.DNSName - if spec.Wildcard { - domainName = "*." + domainName - } c.Recorder.Eventf(o, corev1.EventTypeNormal, "Created", "Created Challenge resource %q for domain %q", ch.Name, ch.Spec.DNSName) existingChallenges = append(existingChallenges, ch) @@ -410,88 +406,17 @@ func (c *Controller) challengeSpecForAuthorization(ctx context.Context, cl acmec candidates = append(candidates, cfg) } - challengeForSolver := func(solver *cmapi.ACMEChallengeSolver) *acmeapi.Challenge { - for _, ch := range authz.Challenges { - switch { - case ch.Type == "http-01" && solver.HTTP01 != nil: - return ch - case ch.Type == "dns-01" && solver.DNS01 != nil: - return ch - } - } - return nil - } - // 3. iterate through each solver, finding the most specific match (taking account of dnsNames) + // if a solver config that matches all dns names is found, we'll use the + // one with the most labels, as this is the 'most specific match' for the + // certificate this order is fulfilling. + // the matchAll solver is only used if the domainToFind is not listed in + // any other solver's DNSNames list. domainToFind := authz.Identifier.Value if authz.Wildcard { domainToFind = "*." + domainToFind } - - // if a solver config that matches all dns names is found, we'll use the - // one with the most labels, as this is the 'most specific match' for the - // certificate this order is fulfilling. - // the matchAll solver is only used *iff* the domainToFind is not listed in - // any other solver's DNSNames list. - acmeCh, solverConfigToUse := func() (*acmeapi.Challenge, *cmapi.ACMEChallengeSolver) { - // this variable tracks the number of labels that matched when a solver - // that specifically names the dnsName in the authorization matches. - // This is used to tie-break if two different solver configurations both - // explicitly name a dnsName - numLabelsSpecificMatch := 0 - var specificMatch *cmapi.ACMEChallengeSolver - var specificMatchToSolve *acmeapi.Challenge - - // this variable tracks the number of labels that matched when a solver - // that does NOT specifically list the authorization's dnsName matches. - // If no solver explicitly lists the dnsName then the solver that matches - // the most labels is used. - matchAllDomainsNumLabels := 0 - // matchAll is the most-specific solver that matches the authorization, - // that does not list the authorization's dns name - var matchAll *cmapi.ACMEChallengeSolver - var matchAllToSolve *acmeapi.Challenge - - for _, d := range candidates { - acmech := challengeForSolver(&d) - if acmech == nil { - continue - } - - // empty selector/dnsName list matches all - if d.Selector == nil { - if matchAll == nil { - matchAllDomainsNumLabels = 0 - matchAll = &d - matchAllToSolve = acmech - } - continue - } - if len(d.Selector.DNSNames) == 0 { - if len(d.Selector.MatchLabels) > matchAllDomainsNumLabels || matchAll == nil { - matchAll = &d - matchAllToSolve = acmech - } - } - for _, dom := range d.Selector.DNSNames { - if dom != domainToFind { - continue - } - if len(d.Selector.MatchLabels) > numLabelsSpecificMatch || specificMatch == nil { - specificMatch = &d - specificMatchToSolve = acmech - break - } - } - } - if specificMatch != nil { - return specificMatchToSolve, specificMatch - } - if matchAll != nil { - return matchAllToSolve, matchAll - } - return nil, nil - }() + acmeCh, solverConfigToUse := determineSolverConfigToUse(candidates, authz, domainToFind) if acmeCh == nil || solverConfigToUse == nil { return nil, fmt.Errorf("solver configuration for domain %q not found. Ensure at least one Solver on your Issuer matches the order", domainToFind) } @@ -515,6 +440,83 @@ func (c *Controller) challengeSpecForAuthorization(ctx context.Context, cl acmec }, nil } +// if a solver config that matches all dns names is found, we'll use the +// one with the most labels, as this is the 'most specific match' for the +// certificate this order is fulfilling. +// the matchAll solver is only used if the domainToFind is not listed in +// any other solver's DNSNames list. +func determineSolverConfigToUse(candidates []cmapi.ACMEChallengeSolver, authz *acmeapi.Authorization, domainToFind string) (*acmeapi.Challenge, *cmapi.ACMEChallengeSolver) { + challengeForSolver := func(solver *cmapi.ACMEChallengeSolver) *acmeapi.Challenge { + for _, ch := range authz.Challenges { + switch { + case ch.Type == "http-01" && solver.HTTP01 != nil: + return ch + case ch.Type == "dns-01" && solver.DNS01 != nil: + return ch + } + } + return nil + } + + // this variable tracks the number of labels that matched when a solver + // that specifically names the dnsName in the authorization matches. + // This is used to tie-break if two different solver configurations both + // explicitly name a dnsName + numLabelsSpecificMatch := 0 + var specificMatch *cmapi.ACMEChallengeSolver + var specificMatchToSolve *acmeapi.Challenge + + // this variable tracks the number of labels that matched when a solver + // that does NOT specifically list the authorization's dnsName matches. + // If no solver explicitly lists the dnsName then the solver that matches + // the most labels is used. + matchAllDomainsNumLabels := 0 + // matchAll is the most-specific solver that matches the authorization, + // that does not list the authorization's dns name + var matchAll *cmapi.ACMEChallengeSolver + var matchAllToSolve *acmeapi.Challenge + + for _, d := range candidates { + acmech := challengeForSolver(&d) + if acmech == nil { + continue + } + + // empty selector/dnsName list matches all + if d.Selector == nil { + if matchAll == nil { + matchAllDomainsNumLabels = 0 + matchAll = &d + matchAllToSolve = acmech + } + continue + } + if len(d.Selector.DNSNames) == 0 { + if len(d.Selector.MatchLabels) > matchAllDomainsNumLabels || matchAll == nil { + matchAll = &d + matchAllToSolve = acmech + } + } + for _, dom := range d.Selector.DNSNames { + if dom != domainToFind { + continue + } + if len(d.Selector.MatchLabels) > numLabelsSpecificMatch || specificMatch == nil { + specificMatch = &d + specificMatchToSolve = acmech + break + } + } + } + if specificMatch != nil { + return specificMatchToSolve, specificMatch + } + if matchAll != nil { + return matchAllToSolve, matchAll + } + return nil, nil +} + func resourceMatchesSelector(r metav1.Object, sel map[string]string) bool { labels := r.GetLabels() for k, v := range sel {