Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support OverrideDomain is DNS01Solver #160

Merged
merged 3 commits into from Mar 7, 2022
Merged

Conversation

crccw
Copy link
Contributor

@crccw crccw commented Dec 28, 2021

CNAME can be used to delegate answering the chanllenge to another DNS
zone, in order to reduce the exposure of the DNS credential [1]. The
solver already follows CNAME when checking propagation against the
authoritative source, it should follow CNAME when setting the TXT record
as well.

[1] https://letsencrypt.org/docs/challenge-types/#dns-01-challenge

@francislavoie
Copy link
Member

francislavoie commented Dec 28, 2021

This is related to caddyserver/caddy#4071

So from my reading of the code, this would allow DNS records to directly affect where certmagic would attempt to mutate the TXT record.

I'm not sure that's proper. It is kinda cool to make it work dynamically like that, but it also kinda scares me, that it might have some unintended vector for abuse. But maybe I'm being paranoid. I just think we need to be careful.

I'd be more comfortable if there was an explicit domain override configurable instead of following the CNAME record. This is how it's set up in the DuckDNS plugin, so that is explicit at the config level. That config could be in certmagic itself instead, one layer higher (and Caddy would add an option for it).

Maybe if you could enumerate the ways this could be used, to prove it would be infeasible to abuse, it would feel more comfortable.

@crccw
Copy link
Contributor Author

crccw commented Dec 28, 2021

Yes it would allow DNS record to affect where certmagic would attempt to mutate the TXT record.

It certainly makes sense to be paranoid when it comes to security. Though, I'm possibly being naive here, I don't feel it increases the exposure. In the end ACME checks the TXT record, which is independent from how the record is set. If a malicious party is able to put the TXT record there with this commit, they should be able to put it there without this commit too.

Being said, I like the idea of having a domain override configurable. It's simpler than following CNAME, and is more test friendly. If we do this, should we also stop following CNAME when checking propagation for consistency?

@mholt
Copy link
Member

mholt commented Dec 28, 2021

Yeah, I think if it's specified in the config directly it should not be overrideable by any DNS records.

@mholt
Copy link
Member

mholt commented Feb 18, 2022

@crccw Any interest in continuing work/discussion on this PR?

@crccw
Copy link
Contributor Author

crccw commented Feb 20, 2022

Yes! Sorry for the delay, I'll update the PR in a day or two.

This is to delegate the chanllenge to a different domain. With this
change, the solver no longer follows CNAME chain when checking for
propagation as well.
@crccw
Copy link
Contributor Author

crccw commented Feb 23, 2022

Updated. I've tested the change together with caddyserver/caddy#4596. Let me know if there's a way to write a test against. I guess we need to mock a DNS server?

solvers.go Outdated Show resolved Hide resolved
dnsutil.go Outdated Show resolved Hide resolved
@crccw crccw changed the title Query CNAME before setting the TXT record Support OverrideDomain is DNS01Solver Mar 7, 2022
and keep the old code path otherwise.
Copy link
Member

@mholt mholt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks for the update. LGTM now, let's give it a try. Really appreciate your contribution here! I get antsy trying to mess with this kind of code myself.

If there are new issues reported related to this, would you be able to help maintain this change?

@mholt mholt merged commit f60ce01 into caddyserver:master Mar 7, 2022
@crccw
Copy link
Contributor Author

crccw commented Mar 8, 2022

Yeah I'm happy to help.

@emilylange
Copy link
Member

Hi @crccw :)
What was the motivation behind 4be5af5#diff-0d423173eaa496408ee9e7d82ae770feaa3b860783ca6a155f6d7551cb5d4d14R337-R341

checkDNSPropagation and checkAuthoritativeNss don't seem to be actually interchangeable in that case here:

  • dnsName has to be a fqdn in checkAuthoritativeNss but not in checkDNSPropagation

    certmagic/dnsutil.go

    Lines 212 to 215 in 9a56fcd

    func checkDNSPropagation(fqdn, value string, resolvers []string) (bool, error) {
    if !strings.HasSuffix(fqdn, ".") {
    fqdn += "."
    }
  • resolvers don't share a common format: checkAuthoritativeNss takes resolvers without port to add :53 by itself, while checkDNSPropagation assumes the port already set.
  • r, err := dnsQuery(fqdn, dns.TypeTXT, []string{net.JoinHostPort(ns, "53")}, false)
    needs to be recursive=true in my testings. (Though I am not sure what exactly that changes, but wouldn't resolve with false for me)

Using checkDNSPropagation in both cases (so dropping the above if/else again) seems to work just fine on the other hand.

@crccw
Copy link
Contributor Author

crccw commented Mar 21, 2022

Hi @IndeedNotJames ,

The motivation is that if OverrideDomain is set and we succeeded in adding a TXT record on it, that domain should have no CNAME record as CNAME record cannot co-exist with other records. Since it has no CNAME record, there's no need trying to follow the CNAME record.

(Now I feel that this applies to the case without OverrideDomain, but it's good to keep the behavior unchanged for now)

As for the other points I think you're there're some bugs here, let me try to fix it.

@mholt
Copy link
Member

mholt commented Aug 8, 2022

@crccw Was it intentional that the override domain always has to be prefixed with _acme_challenge.? Since that's part of the DNS-01 challenge spec, I am not sure why we would always want to make the user include that in the override domain...

@francislavoie
Copy link
Member

IMO we could adjust it to add that prefix to the configured override if it doesn't have the prefix already.

@mholt
Copy link
Member

mholt commented Aug 8, 2022

Yeah, as long as there's not a legitimate reason to not have that subdomain, I'm good with that. I can make that patch shortly.

@crccw
Copy link
Contributor Author

crccw commented Aug 10, 2022

@mholt My memory has faded a little, but IIRC OverrideDomain can be anything. For the delegation use case, the user needs to create a CNAME record on the _acme_challenge.original.domain that points to the OverrideDomain. In this way they only need to expose the control of _acme_challenge.original.domain to caddy, instead of the original.domain. My understanding is that the CNAME should be, in some means, transparent to the ACME server; they just follow the CNAME chains when checking the TXT record on the _acme_challenge.original.domain.

Have you run into any issues if the override domain doesn't start with _acme_challenge?

@mholt
Copy link
Member

mholt commented Aug 10, 2022

@crccw Thanks for replying! Yeah, we're trying to figure out, from this topic in the forum here: https://caddy.community/t/global-dns-challenge-and-dns-challenge-override-domain/16773

Is our patch (prepend _acme-challenge. if it doesn't exist) correct, do you think?

@crccw
Copy link
Contributor Author

crccw commented Aug 12, 2022

I don't think so. In the post the author has a CNAME record from _acme-challenge.manage.clientsite.com > _acme-challenge.myexamplesite.com, therefore they need to set override_domain to the CNAME target _acme-challenge.myexamplesite.com. The CNAME target can be anything, e.g. _some-random-stuff.myexamplesite.com, in which case override_domain should be _some-random-stuff.myexamplesite.com accordingly.

@mholt
Copy link
Member

mholt commented Aug 12, 2022

Oh I see. So since the original CNAME record has _acme-challenge. subdomain, the configured override domain must also have it.

If they just set it to manage.clientsite.com, then they would not need it in override domain, correct? And that is probably the normal use case.

So their need seems to be a bit of an edge case, in which specifying the _acme-challenge subdomain in the override domain is the correct solution.

I'll look into reverting my patch.

mholt added a commit that referenced this pull request Aug 16, 2022
This reverts commit e022751.

According to discussion in #160, there was a misunderstanding and the previous implementation seems more correct:
#160 (comment)
@mholt
Copy link
Member

mholt commented Aug 16, 2022

Reverted in 9e63f36

@crccw
Copy link
Contributor Author

crccw commented Aug 22, 2022

That's right, if the CNAME points to manage.clientsite.com, then override domain should be set to manage.clientsite.com.

mholt referenced this pull request Aug 29, 2022
This way the user does not need to explicitly configure that
(which is not intuitive).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants