Make the DNS-Over-HTTPS Json endpoint configurable

Signed-off-by: Florian Liebhart <flo.liebhart@gmail.com>
This commit is contained in:
Florian Liebhart 2022-04-05 00:56:02 +02:00
parent 6383a08a79
commit a934bbf462
5 changed files with 44 additions and 12 deletions

View File

@ -91,6 +91,8 @@ type ControllerOptions struct {
ACMEDNS01CheckMethod string
DnsOverHttpsJsonEndpoint string
ClusterIssuerAmbientCredentials bool
IssuerAmbientCredentials bool
@ -148,6 +150,8 @@ const (
defaultACMEDNS01CheckMethod = dnsutil.ACMEDNS01CheckViaDNSLookup
defaultDnsOverHttpsJsonEndpoint = "https://8.8.8.8/resolve"
defaultClusterResourceNamespace = "kube-system"
defaultNamespace = ""
@ -338,6 +342,11 @@ func (s *ControllerOptions) AddFlags(fs *pflag.FlagSet) {
"than the rest of the world (aka DNS split horizon).",
dnsutil.ACMEDNS01CheckViaDNSLookup, dnsutil.ACMEDNS01CheckViaHTTPS))
fs.StringVar(&s.DnsOverHttpsJsonEndpoint, "dns-over-https-json-endpoint", defaultDnsOverHttpsJsonEndpoint, fmt.Sprintf(
"[%s, %s] Only used when specifying \"dns-over-https\" for the \"acme-dns01-check-method\" option. "+
"This allows specifying what JSON endpoint to use for doing the DNS-over-HTTPS verification."+
"Examples: 'https://1.1.1.1/dns-query', 'https://8.8.8.8/resolve', ''https://8.8.4.4/resolve'. or 'https://9.9.9.9:5053/dns-query'"))
fs.StringVar(&s.ACMEHTTP01SolverResourceRequestCPU, "acme-http01-solver-resource-request-cpu", defaultACMEHTTP01SolverResourceRequestCPU, ""+
"Defines the resource request CPU size when spawning new ACME HTTP01 challenge solver pods.")

View File

@ -170,6 +170,14 @@ type ACMEOptions struct {
// ACMEDNS01CheckMethod specifies how to check for DNS propagation for DNS01 challenges
ACMEDNS01CheckMethod string
// DnsOverHttpsJsonEndpoint allows specifying what Json endpoint to use for doing the DNS-over-HTTPS verification.
// Examples:
// - "https://1.1.1.1/dns-query"
// - "https://8.8.8.8/resolve"
// - "https://8.8.4.4/resolve"
// - "https://9.9.9.9:5053/dns-query"
DnsOverHttpsJsonEndpoint string
// ACMEHTTP01SolverImage is the image to use for solving ACME HTTP01
// challenges
HTTP01SolverImage string

View File

@ -116,7 +116,7 @@ func (s *Solver) Check(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.
log.V(logf.DebugLevel).Info("checking DNS propagation", "nameservers", s.Context.DNS01Nameservers)
ok, err := util.PreCheckDNS(fqdn, ch.Spec.Key, s.Context.DNS01Nameservers,
s.Context.DNS01CheckAuthoritative, s.Context.ACMEDNS01CheckMethod)
s.Context.DNS01CheckAuthoritative, s.Context.ACMEDNS01CheckMethod, s.Context.DnsOverHttpsJsonEndpoint)
if err != nil {
return err
}

View File

@ -23,7 +23,7 @@ import (
)
type preCheckDNSFunc func(fqdn, value string, nameservers []string,
useAuthoritative bool, acmeDNS01CheckMethod string) (bool, error)
useAuthoritative bool, acmeDNS01CheckMethod string, dnsOverHttpsJsonEndpoint string) (bool, error)
type dnsQueryFunc func(fqdn string, rtype uint16, nameservers []string, recursive bool) (in *dns.Msg, err error)
var (
@ -48,6 +48,8 @@ const (
ACMEDNS01CheckViaHTTPS = "dns-over-https"
)
const DefaultDnsOverHttpsJsonEndpoint = "https://8.8.8.8/resolve"
var defaultNameservers = []string{
"8.8.8.8:53",
"8.8.4.4:53",
@ -132,14 +134,27 @@ func checkDNSPropagationWithDNSLookup(fqdn, value string, nameservers []string,
return checkAuthoritativeNss(fqdn, value, authoritativeNss)
}
func checkDNSPropagationWithHTTPS(fqdn, value string, nameservers []string, useAuthoritative bool) (bool, error) {
// The dnsOverHttpsJsonEndpoint has to be a JSON GET endpoint and NOT an RFC 8484 GET endpoint.
// This decision was taken because the JSON format is much easier to parse, test and debug, and is a standard
// for the big DNS-over-HTTPS DNS providers such as Google, Cloudflare, or Quad9.
// Examples:
// - "https://1.1.1.1/dns-query"
// - "https://8.8.8.8/resolve"
// - "https://8.8.4.4/resolve"
// - "https://9.9.9.9:5053/dns-query"
func checkDNSPropagationWithHTTPS(fqdn, value string, dnsOverHttpsJsonEndpoint string) (bool, error) {
logf.V(logf.InfoLevel).Infof("Checking DNS propagation for FQDN %s using Google's API for DNS over HTTPS", fqdn)
req, err := http.NewRequest("GET", "https://8.8.8.8/resolve?name="+fqdn+"&type=TXT", nil)
if dnsOverHttpsJsonEndpoint == "" {
dnsOverHttpsJsonEndpoint = DefaultDnsOverHttpsJsonEndpoint
}
req, err := http.NewRequest("GET", dnsOverHttpsJsonEndpoint+"?name="+fqdn+"&type=TXT", nil)
if err != nil {
return false, err
}
req.Header.Add("Cache-Control", "no-cache")
req.Header.Add("accept", "application/dns-json")
r, err := http.DefaultClient.Do(req)
if err != nil {
return false, fmt.Errorf("Unable to lookup DNS via HTTPS: %s", err)
@ -158,7 +173,7 @@ func checkDNSPropagationWithHTTPS(fqdn, value string, nameservers []string, useA
if resp.Status == 0 && len(resp.Answer) >= 1 {
for _, answer := range resp.Answer {
if txt := strings.Trim(answer.Data, "\""); txt == value {
logf.V(logf.DebugLevel).Infof("Selfchecking using the DNS-over-HTTPS Lookup method was successful")
logf.V(logf.DebugLevel).Infof("Self-checking using the DNS-over-HTTPS Lookup method was successful")
return true, nil
}
}
@ -169,14 +184,14 @@ func checkDNSPropagationWithHTTPS(fqdn, value string, nameservers []string, useA
}
func checkDNSPropagation(fqdn, value string, nameservers []string,
useAuthoritative bool, acmeDNS01CheckMethod string) (bool, error) {
useAuthoritative bool, acmeDNS01CheckMethod string, dnsOverHttpsJsonEndpoint string) (bool, error) {
switch acmeDNS01CheckMethod {
case ACMEDNS01CheckViaDNSLookup:
logf.V(logf.DebugLevel).Infof("Selfchecking using the DNS Lookup method")
logf.V(logf.DebugLevel).Infof("Self-checking using the DNS Lookup method")
return checkDNSPropagationWithDNSLookup(fqdn, value, nameservers, useAuthoritative)
case ACMEDNS01CheckViaHTTPS:
logf.V(logf.DebugLevel).Infof("Selfchecking using the DNS over HTTPS Lookup method")
return checkDNSPropagationWithHTTPS(fqdn, value, nameservers, useAuthoritative)
logf.V(logf.DebugLevel).Infof("Self-checking using the DNS-over-HTTPS Lookup method")
return checkDNSPropagationWithHTTPS(fqdn, value, dnsOverHttpsJsonEndpoint)
default:
return false, fmt.Errorf("Unknown DNS propagation method")
}

View File

@ -166,7 +166,7 @@ func TestMatchCAA(t *testing.T) {
}
func TestPreCheckDNSOverHTTPS(t *testing.T) {
ok, err := PreCheckDNS("google.com.", "v=spf1 include:_spf.google.com ~all", []string{"8.8.8.8:53"}, true, "dns-over-https")
ok, err := PreCheckDNS("google.com.", "v=spf1 include:_spf.google.com ~all", []string{"8.8.8.8:53"}, true, "dns-over-https", "https://8.8.8.8/resolve")
if err != nil || !ok {
t.Errorf("preCheckDNS failed for acme-staging.api.letsencrypt.org: %s", err.Error())
}
@ -174,7 +174,7 @@ func TestPreCheckDNSOverHTTPS(t *testing.T) {
func TestPreCheckDNS(t *testing.T) {
// TODO: find a better TXT record to use in tests
ok, err := PreCheckDNS("google.com.", "v=spf1 include:_spf.google.com ~all", []string{"8.8.8.8:53"}, true, "dnslookup")
ok, err := PreCheckDNS("google.com.", "v=spf1 include:_spf.google.com ~all", []string{"8.8.8.8:53"}, true, "dnslookup", "")
if err != nil || !ok {
t.Errorf("preCheckDNS failed for acme-staging.api.letsencrypt.org: %s", err.Error())
}
@ -182,7 +182,7 @@ func TestPreCheckDNS(t *testing.T) {
func TestPreCheckDNSNonAuthoritative(t *testing.T) {
// TODO: find a better TXT record to use in tests
ok, err := PreCheckDNS("google.com.", "v=spf1 include:_spf.google.com ~all", []string{"1.1.1.1:53"}, false, "dnslookup")
ok, err := PreCheckDNS("google.com.", "v=spf1 include:_spf.google.com ~all", []string{"1.1.1.1:53"}, false, "dnslookup", "")
if err != nil || !ok {
t.Errorf("preCheckDNS failed for acme-staging.api.letsencrypt.org: %s", err.Error())
}