Skip to content

Commit

Permalink
Allow domain overrides for challenge delegation (caddy-dns#2)
Browse files Browse the repository at this point in the history
Co-authored-by: Francis Lavoie <[email protected]>
  • Loading branch information
jpeddicord and francislavoie authored Dec 29, 2020
1 parent f09e15f commit c5d221e
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
45 changes: 42 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,31 @@ This package contains a DNS provider module for [Caddy](https://github.com/caddy
dns.providers.duckdns
```

## Caddyfile definition

```
duckdns [<api_token>] {
api_token <api_token>
override_domain <duckdns_domain>
}
```

- `api_token` may be specified as an argument to the `duckdns` directive, or in the body.
- `override_domain` is optional; see [Challenge delegation](#challenge-delegation) below.

## Config examples

To use this module for the ACME DNS challenge, [configure the ACME issuer in your Caddy JSON](https://caddyserver.com/docs/json/apps/tls/automation/policies/issuer/acme/) like so:

```
```json
{
"module": "acme",
"challenges": {
"dns": {
"provider": {
"name": "duckdns",
"api_token": "YOUR_DUCKDNS_API_TOKEN"
"api_token": "YOUR_DUCKDNS_API_TOKEN",
"override_domain": "OPTIONAL_DUCKDNS_DOMAIN"
}
}
}
Expand All @@ -31,7 +44,7 @@ or with the Caddyfile:

```
tls {
dns cloudflare {env.DUCKDNS_API_TOKEN}
dns duckdns {env.DUCKDNS_API_TOKEN}
}
```

Expand All @@ -41,3 +54,29 @@ You can replace `{env.DUCKDNS_API_TOKEN}` with the actual auth token if you pref
## Authenticating

See [the associated README in the libdns package](https://github.com/libdns/duckdns) for important information about credentials. Your token can be found at the top of the page when logged in at https://www.duckdns.org.

## Challenge delegation

To obtain a certificate using ACME DNS challenges, you'd use this module as described above. But, if you have a different domain (say, `my.example.com`) CNAME'd to your Duck DNS domain, you have two options:

1. Not use this module: Use a module matching the DNS provider for `my.example.com`.
2. [Delegate the challenge](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) to Duck DNS.

Delegating the challenge is actually quite easy, and may be useful if the DNS provider for `my.example.com` is difficult to configure or slow:

> Since Let’s Encrypt follows the DNS standards when looking up TXT records for DNS-01 validation, you can use CNAME records or NS records to delegate answering the challenge to other DNS zones. This can be used to delegate the _acme-challenge subdomain to a validation-specific server or zone. It can also be used if your DNS provider is slow to update, and you want to delegate to a quicker-updating server.
Let's say you have `my.example.com` as a CNAME to `example.duckdns.org`. Following the above instructions, you'd want to add a CNAME from `_acme-challenge.my.example.com` to `example.duckdns.org`. Then, in your Caddyfile, instruct this module to override the domain used when communicating with Duck DNS' API:

```
my.example.com {
tls {
dns duckdns <token> {
override_domain example.duckdns.org
}
}
...
}
```

If you do not set `override_domain`, this module will attempt to ask Duck DNS to update `my.example.com`. Duck DNS will return an error, because it does not know about `my.example.com`. Setting this value fixes this up and allows Caddy to ask for a certificate matching `my.example.com`, but by performing DNS challenges on `example.duckdns.org` instead!
15 changes: 15 additions & 0 deletions duckdns.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func (Provider) CaddyModule() caddy.ModuleInfo {
//
// duckdns [<api_token>] {
// api_token <api_token>
// override_domain <duckdns_domain>
// }
//
func (p *Provider) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
Expand All @@ -39,13 +40,27 @@ func (p *Provider) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for nesting := d.Nesting(); d.NextBlock(nesting); {
switch d.Val() {
case "api_token":
if !d.NextArg() {
return d.ArgErr()
}
if p.Provider.APIToken != "" {
return d.Err("API token already set")
}
p.Provider.APIToken = repl.ReplaceAll(d.Val(), "")
if d.NextArg() {
return d.ArgErr()
}
case "override_domain":
if !d.NextArg() {
return d.ArgErr()
}
if p.Provider.OverrideDomain != "" {
return d.Err("Override domain already set")
}
p.Provider.OverrideDomain = repl.ReplaceAll(d.Val(), "")
if d.NextArg() {
return d.ArgErr()
}
default:
return d.Errf("unrecognized subdirective '%s'", d.Val())
}
Expand Down

0 comments on commit c5d221e

Please sign in to comment.