231

Let's Encrypt has announced they have:

Turned on support for the ACME DNS challenge

How do I make ./letsencrypt-auto generate a new certificate using DNS challenge domain validation?

EDIT
I mean: How do I avoid http/https port binding, by using the newly announced feature (2015-01-20) that lets you prove the domain ownership by adding a specific TXT record in the DNS zone of the target domain?

RichVel
  • 3,524
  • 1
  • 17
  • 23
Pierre Prinetti
  • 2,445
  • 3
  • 12
  • 9
  • 4
    Side note: [Certbot](https://certbot.eff.org) (this is the new name for the letsencrypt client) now allows webroot-based authentication by default. – Pierre Prinetti May 22 '16 at 17:04

10 Answers10

310

Currently it is possible to perform DNS validation, also with the certbot LetsEncrypt client in manual mode. Automation is possible as well (see below).

Manual plugin

You can either perform a manual verification - with the manual plugin.

certbot -d bristol3.pki.enigmabridge.com --manual --preferred-challenges dns certonly

Certbot will then provide you instructions to manually update a TXT record for the domain in order to proceed with the validation.

Please deploy a DNS TXT record under the name
_acme-challenge.bristol3.pki.enigmabridge.com with the following value:

667drNmQL3vX6bu8YZlgy0wKNBlCny8yrjF1lSaUndc

Once this is deployed,
Press ENTER to continue

Once you have updated the DNS record, press Enter, certbot will continue and if the LetsEncrypt CA verifies the challenge, the certificate is issued as normally.

You may also use a command with more options to minimize interactivity and answering certbot questions. Note that the manual plugin does not yet support non-interactive mode.

certbot --text --agree-tos --email you@example.com -d bristol3.pki.enigmabridge.com --manual --preferred-challenges dns --expand --renew-by-default  --manual-public-ip-logging-ok certonly

Renewal does not work with the manual plugin as it runs in non-interactive mode. More info in the official certbot documentation.

Update: manual hooks

In the new certbot version you can use hooks, e.g., --manual-auth-hook, --manual-cleanup-hook. The hooks are external scripts executed by certbot to perform the task.

Information is passed in environment variables - e.g., domain to validate, challenge token. Vars: CERTBOT_DOMAIN, CERTBOT_VALIDATION, CERTBOT_TOKEN.

certbot certonly --manual --preferred-challenges=dns --manual-auth-hook /path/to/dns/authenticator.sh --manual-cleanup-hook /path/to/dns/cleanup.sh -d secure.example.com

You can write your own handler or use already existing ones. There are many available, e.g., for Cloudflare DNS.

More info on official certbot hooks documentation.

Automation, Renewal, Scripting

If you would like to automate DNS challenge validation it is not currently possible with vanilla certbot. Update: some automation is possible with the certbot hooks.

We thus created a simple plugin that supports scripting with DNS automation. It's available as certbot-external-auth.

pip install certbot-external-auth

It supports the DNS, HTTP, TLS-SNI validation methods. You can either use it in handler mode or in JSON output mode.

Handler mode

In handler mode, the certbot + plugin calls external hooks (a program, shell script, Python, ...) to perform the validation and installation. In practice you write a simple handler/shell script which gets the input arguments - domain, token and makes the change in DNS. When the handler finishes, certbot proceeds with validation as usual.

This gives you extra flexibility, renewal is also possible.

Handler mode is also compatible with Dehydrated DNS hooks (former letsencrypt.sh). There are already many DNS hooks for common providers (e.g., CloudFlare, GoDaddy, AWS). In the repository there is a README with extensive examples and example handlers.

Example with Dehydrated DNS hook:

certbot \
    --text --agree-tos --email you@example.com \
    --expand --renew-by-default \
    --configurator certbot-external-auth:out \
    --certbot-external-auth:out-public-ip-logging-ok \
    -d "bristol3.pki.enigmabridge.com" \
    --preferred-challenges dns \
    --certbot-external-auth:out-handler ./dehydrated-example.sh \
    --certbot-external-auth:out-dehydrated-dns \
    run 

JSON mode

Another plugin mode is JSON mode. It produces one JSON object per line. This enables a more complicated integration - e.g., when Ansible or some deployment manager is calling certbot. Communication is performed via STDOUT and STDIN. Cerbot produces JSON objects with data to perform the validation, for example:

certbot \
    --text --agree-tos --email you@example.com \
    --expand --renew-by-default \
    --configurator certbot-external-auth:out \
    --certbot-external-auth:out-public-ip-logging-ok \
    -d "bristol3.pki.enigmabridge.com" \
    --preferred-challenges dns \
    certonly 2>/dev/null

{"cmd": "perform_challenge", "type": "dns-01", "domain": "bs3.pki.enigmabridge.com", "token": "3gJ87yANDpmuuKVL2ktfQ0_qURQ3mN0IfqgbTU_AGS4", "validation": "ejEDZXYEeYHUxqBAiX4csh8GKkeVX7utK6BBOBshZ1Y", "txt_domain": "_acme-challenge.bs3.pki.enigmabridge.com", "key_auth": "3gJ87yANDpmuuKVL2ktfQ0_qURQ3mN0IfqgbTU_AGS4.tRQM98JsABZRm5-NiotcgD212RAUPPbyeDP30Ob_7-0"}

Once DNS is updated, the caller sends the new-line character to STDIN of certbot to signal it can continue with validation.

This enables automation and certificate management from the central management server. For installation you can deploy certificates over SSH.

For more info please refer to the readme and examples on certbot-external-auth GitHub.

EDIT: There is also a new blog post describing the DNS validation problem and the plugin usage.

EDIT: We currently work on Ansible 2-step validation, will be soon off.

ph4r05
  • 3,216
  • 1
  • 8
  • 4
  • 4
    When migrating a website to another server you might want a new certificate before switching the A-record. You can use the manual method (`certbot certonly --preferred-challenges dns -d example.com`) for the initial request. After testing and switching the A-record, use the common webroot method (`certbot certonly webroot -d example.com -w /path/to/webroot`) using exactly the same domain name(s) as before. If done correctly, certbot will recognise the existing certificate/config and will update the renewal settings, so the certificate will be automatically renewed in the future. – marcovtwout May 10 '17 at 12:48
  • It works, Beware of AWS Firewall at EC2 level – jruzafa Jul 12 '17 at 15:44
  • 1
    I's sure like to know what --manual-public-ip-logging-ok means.... the documentation is cryptic about it and all the examples out there that use it do not explain... including this one. – Rondo Jun 17 '18 at 23:33
  • 2
    Does the renewal process require a new TXT record each time? – Old Geezer Jul 12 '18 at 05:50
  • @OldGeezer Apparently, it does. I started the process and it asked me to create a TXT record with different contents than the last time. – Dario Fumagalli Jul 22 '18 at 01:07
  • 1
    @Rondo When you request a cert using the manual mode interactively, this prompt is shown "NOTE: The IP of this machine will be publicly logged as having requested this certificate. If you're running certbot in manual mode on a machine that is not your server, please ensure you're okay with that." This option says yes to that prompt. – muru Aug 01 '19 at 09:24
  • Excuse me, is it possible to specify the TXT Record hash to `certbot`? My issue is I pressed Enter before the DNS is renewed, and when I run again the hash changes. Can I do something like `certbot ... -hash=`, or I need to update the TXT record again? It's quite annoying to update the TXT record for our environment. Or do we have a way to wait DNS update other than a very long "press Enter"? – Romulus Urakagi Ts'ai Oct 22 '19 at 08:46
  • @RomulusUrakagiTs'ai you have to update the TXT record again. You can also specify the DNS time to propagate for the test, but if it takes TXT records that long to propagate on your DNS environment it's probably not going to work as you expect. – Thomas Ward Nov 23 '20 at 19:49
  • This answer is worth it's weight in gold. I'll give my upvote and leave! – amateur barista Feb 05 '21 at 17:43
45

I was able to use the dehydrated client to obtain a certificate using DNS validation.

https://github.com/lukas2511/dehydrated

./dehydrated --cron --domain my.domain.example.com --hook ./hook.route53.rb --challenge dns-01

You'll need to use the correct DNS validation hook for your domain, but there are a few options available as examples:

https://github.com/lukas2511/dehydrated/wiki/Examples-for-DNS-01-hooks

lenards
  • 3
  • 2
alexcline
  • 561
  • 3
  • 2
  • This worked really well for me. The only caveat that I would add is that I had to install a few of the gem dependencies defined in the `route53.rb` hook script. – jmreicha Aug 08 '16 at 18:03
  • `dehydrated` seems easier to use, simple, robust and lightweight in comparison with `certbot`, thanks! – Alek_A Jul 14 '20 at 07:12
11

As of today, the official client doesn't support the DNS-01 challenge type (yet).

See https://community.letsencrypt.org/t/status-of-official-letsencrypt-clients-dns-01-challenge-support/9427

I haven't looked at this so I don't really know. My high-level understanding was just "no support in our Python client for the DNS challenge yet".

You can follow the progress at this PR. Alternatively, there are some clients that already support it.

Simone Carletti
  • 1,494
  • 3
  • 15
  • 30
5

I wrote a hook script for the letsencrypt.sh client that allows you to use Lets Encrypt DNS verification for DNS providers that don't provide an api to use (aka, manual entry and verification is required).

You can check it out here: https://github.com/jbjonesjr/letsencrypt-manual-hook

J Jones
  • 151
  • 1
  • 1
3

As mentioned in previous answers, you can easy verify a domain by DNS with this:

  1. install required applications (under Ubuntu): apt-get install -y git ruby letsencrypt git clone https://github.com/lukas2511/dehydrated.git git clone https://github.com/jbjonesjr/letsencrypt-manual-hook.git dehydrated/hooks/manual
  2. generate certificate with manual DNS challenge confirmation for www.example.com (replace with your domain): ./dehydrated/dehydrated -c -t dns-01 -d www.example.com -k ./dehydrated/hooks /manual/manual_hook.rb
panticz
  • 731
  • 7
  • 5
3

After trying different combinations, this is what worked for me using dehydrated and letsencrypt-manual-hook git repositories. If the below steps works for you, don't forget to star these repositories

NOTE: This is in addition to answers of panticz.de and alexcline

~$ git clone https://github.com/lukas2511/dehydrated.git
~$ git clone https://github.com/jbjonesjr/letsencrypt-manual-hook.git dehydrated/hooks/manual
~$ cd dehydrated
~$ ./dehydrated --register --accept-terms
~$ ./dehydrated --cron --challenge dns-01 --domain your.domain.com --hook ./hooks/manual/manual_hook.rb
#
# !! WARNING !! No main config file found, using default config!
#
Processing your.domain.com
 + Signing domains...
 + Creating new directory /Users/vikas/dehydrated/certs/your.domain.com ...
 + Creating chain cache directory /Users/vikas/dehydrated/chains
 + Generating private key...
 + Generating signing request...
 + Requesting authorization for your.domain.com...
 + 1 pending challenge(s)
 + Deploying challenge tokens...
Checking for pre-existing TXT record for the domain: '_acme-challenge.your.domain.com'.
Create TXT record for the domain: '_acme-challenge.your.domain.com'. TXT record:
'gkIxxxxxxxIcAESmjF8pjZGQrrZxxxxxxxxxxx'
Press enter when DNS has been updated...

You will get a hash (after running the above command), create a TXT record in your DNS. Make sure it works by either running the below command or GSuite Toolbox

~$ dig TXT _acme-challenge.your.domain.com. +short @8.8.8.8
"gkIxxxxxxxIcAESmjF8pjZGQrrZxxxxxxxxxxx"
~$

Now, press enter at the prompt. This did not work for me although the TXT record was updated. I had to press Ctrl+C and run the command again.

~$ ./dehydrated --cron --challenge dns-01 --domain your.domain.com --hook ./hooks/manual/manual_hook.rb
#
# !! WARNING !! No main config file found, using default config!
#
Processing your.domain.com
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting authorization for your.domain.com...
 + 1 pending challenge(s)
 + Deploying challenge tokens...
Checking for pre-existing TXT record for the domain: '_acme-challenge.your.domain.com'.
Found gkIxxxxxxxIcAESmjF8pjZGQrrZxxxxxxxxxxx. match.
 + Responding to challenge for your.domain.com authorization...
Challenge complete. Leave TXT record in place to allow easier future refreshes.
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Walking chain...
 + Done!
~$

Now, your public and private certs are present here.

$ ls certs/your.domain.com/privkey.pem certs/your.domain.com/fullchain-1517576424.pem

To renew (minimum wait time is 30 days), just the same command again.

~$ ./dehydrated --cron --challenge dns-01 --domain your.domain.com --hook ./hooks/manual/manual_hook.rb
vikas027
  • 1,149
  • 2
  • 11
  • 14
  • 1
    I also like dehydrated, just wanted to mention that it is usually included in standard repositories of most distros (eg `apt install dehydrated`). – Alek_A Jul 14 '20 at 07:14
2

It is pretty easy to accomplish when using --manual-auth-hook and --manual-cleanup-hook in certbot.

certbot-auto --manual --preferred-challenges dns --manual-auth-hook auth.sh --manual-cleanup-hook cleanup.sh -d your.domain.com -d *.wildcard.domains.com`

where auth.sh would be something like

#!/bin/sh

KEYFILE=tsig_key_file

nsupdate -k $KEYFILE <<EOT
server ns.some-domain.com
update add _acme-challenge.$CERTBOT_DOMAIN 60 txt $CERTBOT_VALIDATION
send
EOT

# wait a few seconds to let the change take effect
sleep 5

and cleanup.sh something like

#!/bin/sh

KEYFILE=/opt/certbot-authenticator/tsig

nsupdate -k $KEYFILE<<EOT
server dns-master
update del _acme-challenge.$CERTBOT_DOMAIN
send
EOT

provided your dns server is properly configured to allow dynamic dns updates (RFC2136). Using a TSIG Key is strongly advisabe but if you choose to make no use of it just cut the -k $KEYFILE option when invoking nsupdate.

karlsebal
  • 273
  • 2
  • 14
1

For macOS

brew install certbot
sudo certbot certonly --manual --preferred-challenges dns -d "domain.com" -d "www.domain.com"
Sam
  • 11
  • 3
1

Hugo Landau wrote an ACME client in Go (https://github.com/hlandau/acme) that supports DNS challenges (with BIND's nsupdate protocol). It's been working flawlessly for me for at least 18 months.

Harald
  • 329
  • 1
  • 8
0

Maybe with one of the DNS plugins of certbot?

This category of plugins automates obtaining a certificate by modifying DNS records to prove you have control over a domain. Doing domain validation in this way is the only way to obtain wildcard certificates from Let’s Encrypt.