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

Base the server's own name on "nsname", not "domain" #225

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

blkeller
Copy link
Contributor

Summary:

When nsname and domain in the config are not identical, and the API is set to use Let's Encrypt for its own HTTPS needs, the API is unusable because it gets a cert for the name given in domain, but the API is accessed at nsname. All connections to the API then fail because the API cannot locate its own cert in the filesystem, though the cert would be invalid even if it could be located. Setting the api_domain config variable has no effect because this setting has been deprecated.

This bug is masked whenever nsname == domain, so the problem would not be noticeable in this very common case.

This PR fixes the problem by using nsname instead of domain for the API's Let's Encrypt cert's CN and SAN.

Examples:

Where the config file includes these entries:

[general]
# domain name to serve the requests off of
domain = "certs.mydomain.com"
# zone name server
nsname = "ns1.certs.mydomain.com"

[api]
# possible values: "letsencrypt", "letsencryptstaging", "cert", "none"
tls = "letsencrypt"

Without this patch:

$ sudo ls /var/lib/acme-dns/api-certs/acme/acme-v02.api.letsencrypt.org/sites
certs.mydomain.com

$ sudo openssl x509 -in /var/lib/acme-dns/api-certs/acme/acme-v02.api.letsencrypt.org/sites/certs.mydomain.com/certs.mydomain.com.crt -nocert -subject -ext subjectAltName
subject=CN = certs.mydomain.com
X509v3 Subject Alternative Name:
    DNS:certs.mydomain.com

With this patch:

$ sudo ls /var/lib/acme-dns/api-certs/acme/acme-v02.api.letsencrypt.org/sites
ns1.certs.mydomain.com

$ sudo openssl x509 -in /var/lib/acme-dns/api-certs/acme/acme-v02.api.letsencrypt.org/sites/ns1.certs.mydomain.com/ns1.certs.mydomain.com.crt -nocert -subject -ext subjectAltName
subject=CN = ns1.certs.mydomain.com
X509v3 Subject Alternative Name:
    DNS:ns1.certs.mydomain.com

@coveralls
Copy link

coveralls commented Apr 28, 2020

Coverage Status

Coverage increased (+0.1%) to 73.233% when pulling 51788ce on blkeller:nsname-is-own-name into 68bb6ab on joohoi:master.

@johnbartholomew
Copy link

johnbartholomew commented Oct 5, 2020

It doesn't seem strictly necessary for the API to be accessed at nsname; it could be exposed through any name within the zone that has been delegated to acme-dns. You might want to use a different name for it because then you could do this:

Static records (external):

ns1.magicauth.mydomain.com. A 123.1.1.1  # Public IP for acme-dns. Glue record.
magicauth.mydomain.com. NS ns1.magicauth.mydomain.com.
_acme-challenge.mydomain.com. CNAME __SOME_UUID__.magicauth.mydomain.com. # delegate acme-challenge to within the acme-dns managed zone

Static records (in acme-dns):

ns1.magicauth.mydomain.com. A 123.1.1.1  # Public IP for acme-dns.
magicauth.mydomain.com. NS ns1.magicauth.mydomain.com.
api.magicauth.mydomain.com. A 192.168.100.1  # IP to access the acme-dns HTTP API; not publicly routable (routable within your VPN or whatever)

Dynamic records (challenge responses):

_acme-challenge.api.magicauth.mydomain.com. TXT "... response key for acme-dns's own cert request..."
__SOME_UUID__.magicauth.mydomain.com. TXT "... response key for mydomain.com cert request..."

Edit:
If you don't want to expose the private IP of api.magicauth.mydomain.com and if you're running your own DNS resolver within your private network then you could leave it out of the acme-dns static record set and just include it in your private resolver's config somehow. But acme-dns still needs to know at what domain you want to access it, and be able to run DNS-01 challenge-response to get a certificate for itself (which is simplest if the domain you're using to access the API is within the zone that acme-dns is authoritative for, otherwise you need to set up another CNAME record etc).

@blkeller
Copy link
Contributor Author

@joohoi I merged in the latest master, resolved the merge conflicts, and all of the new GitHub Actions tests are passing. When you have a moment, could you please review?

@candlerb
Copy link

candlerb commented Mar 2, 2022

This PR fixes the problem by using nsname instead of domain for the API's Let's Encrypt cert's CN and SAN.

I think this is a reasonable request, and indeed it confused me why I wasn't able to do this initially. It would also remove the need to put static A/AAAA records inside the acme zone, and for glue records outside the acme zone.

However, I just wanted to point out that it adds another setup requirement: for acme-dns to be able to fetch a certificate for itself, the user will need to add something to the DNS to allow it to answer its own dns-01 challenge. Either:

_acme-challenge.<nsname>. NS <nsname>.

or for consistency with how acme-dns handles other domains:

_acme-challenge.<nsname>. CNAME something.<domain>.

Then 'something' needs to be defined which doesn't clash with any user domains. It could be empty for this special case.

@Ajedi32
Copy link
Contributor

Ajedi32 commented Mar 3, 2022

FYI this appears to be related to #295

@maddes-b
Copy link

maddes-b commented Apr 11, 2024

Sorry for being late to the party, just answering for others finding this PR.

This PR should not be needed if used as intended (see "DNS records" in README): the NS and the DOMAIN have the IP addresses of acme-dns, and are therefore identical. Configuration at DNS provider and in acme-dns config.cfg must match.
Design decision was to use DOMAIN for HTTP API.

If NS and DOMAIN are the same (e.g. my-auth.example.com) then glue records are needed via the DNS provider..
But not every DNS provider allows glue records for subdomains, then an "external" NS server is needed: names for NS and DOMAIN have to differ and NS must not be part of DOMAIN.

nsname = "my-ns.example.com" (via DNS provider with IPs of acme-dns)
domain = "my-auth.example.com" (via acme-dns with IPs of acme-dns maintained in config.cfg below)

records = [
    "my-auth.example.com. A a.b.c.d",
    "my-auth.example.com. AAAA aaaa:bbbb::cccc:dddd",
    "my-auth.example.com. NS my-ns.example.com.",
]

Still NS and DOMAIN must have the same IP addresses, so using DOMAIN (my-auth.example.com) for the API always work.

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.

6 participants