Skip to content

Instantly share code, notes, and snippets.

@jvanasco
Created March 18, 2018 07:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jvanasco/3f4cac38d332ebaf03f138354478dd35 to your computer and use it in GitHub Desktop.
Save jvanasco/3f4cac38d332ebaf03f138354478dd35 to your computer and use it in GitHub Desktop.
LetsEncrypt DNS Auth HOWTO

LetsEncrypt DNS Auth HOWTO

This is a quick howto on generating SSL certs via EFF's CertBot using DNS authentication.

This works for domain and wildcard certs.

For security reasons, certbot is run on a local machine.

Wait, Security?

Yes. It's kind of dangerous to automate the DNS authentication because most vendors give the accounts too much control (such as all dns services, or even domain transfers!). Those that do lock-down permissions tend to allow general DNS controls. So if someone were to compromise your keys, they coul switch mailservers, reset your password, and take your domain. It's best to lock down controls as tightly as possible, then only use this locally OR use a custom DNS server like acme-dns (see below).

For more info

The Instructions

To start, install a normal certbot release into a Python virtualenv. Don't use certbot-auto.

Our root for developer tools is going to /devtools/ You can do this anywhere.

cd /devtools/
virtualenv certbot-env
cd certbot-env
source bin/activate
pip install certbot

To handle DNS, we'll use the dns-lexicon library and a technique by Alex Zorin.

Why? The dns-lexicon library handles way more dns clients than the official certbot clients.

pip install dns-lexicon

Now, check out this article by Alex Zorin - https://id-rsa.pub/post/certbot-auto-dns-validation-with-lexicon/ (which he announced here https://community.letsencrypt.org/t/article-certbot-auto-with-dns-based-renewal/52695/5)

It has a tool that will generate the right dns auth shell script for your provider. It's designed for certbot-auto, but we'll adapt it.

I'm just using my registrar namecheap for DNS, so I'll add this to my virtualenv

pip install dns-lexicon[namecheap]

WAIT!

Namecheap's API is too generous and dangerous - it gives full account control. So... I created a second account, gave that account permissions for DNS management (and only that permission), then asked Namecheap to enable API access for that user. That solves some security concerns of having a token on my computer.

unfortunately, the DNS lexicon library isn't compatible with Namecheap accounts like this yet. They ensure API access for a domain by calling a method that only works for 'owned' not 'managed' domains. A proper PR is in the works, but until then you can use my branch that gets around that issue:

https://github.com/jvanasco/lexicon/tree/fix-namecheap_permissions

You can check that out, then call pip install-e .

and to test it...

/devtools/certbot-env/bin/lexicon namecheap --auth-token={{TOKEN}} --auth-username={{USERNAME}} list {{REGISTERED_DOMAIN}} TXT

WEIRD NOTE 1:

In march 2018, the latter works. in feb 2018, the former worked:

--auth-username=john.doe@example.com
or
--auth-username=JohnDoe

Weird Note 2:

Namecheap locks down an API to whitelisted IPs, so make sure you whitelist your ip.

BACK TO WORK

Since this is being done locally, don't use the global /etc datastore.

Create a local datastore:

cd /devtools/certbot-env
mkdir -p /devtools/certbot-env/etc/letsencrypt

Create a DNS hook based on Alex's script above.

Basically I removed the pip commands and am pointing to my local lexicon install

vi  /devtools/certbot-env/hook_namecheap.sh 
~~~~~~~~~~~~~~~~~
#!/usr/bin/env bash
/devtools/certbot-env/bin/lexicon namecheap --auth-token={{TOKEN}} --auth-username={{USERNAME}} \
"$1" "${CERTBOT_DOMAIN}" TXT \
--name "_acme-challenge.${CERTBOT_DOMAIN}" \
--content "${CERTBOT_VALIDATION}" || exit 255

if [ "$1" == "create" ]; then
  sleep 30
fi
~~~~~~~~~~~~~~~~~

set it to execute:

chmod 700 /devtools/certbot-env/hook_namecheap.sh 

Generting a Cert

when certbot is invoked, the following commands need go in to use the custom datastore and not require root access.

* config-dir
* work-dir
* logs-dir

Also the hook file (hook_namecheap.sh) must be passed in for creating the auth and cleaning up:

* manual-auth-hook "/devtools/certbot-env/hook_namecheap.sh create" \
* manual-cleanup-hook "/devtools/certbot-env/hook_namecheap.sh delete" \

Explicitly pass in the DNS

* preferred-challenges dns

And to generate wildcard certs, the v2 endpoint must be explicitly noted:

* server https://acme-v02.api.letsencrypt.org/directory

This is required for now, because the default endpoint hasn't switched in the certbot client yet. It might in v24

So what does that look like?

To generate explicit certificates (up to 100 domains on a cert)

certbot --config-dir /devtools/certbot-env/etc/letsencrypt \
        --work-dir /devtools/certbot-env/-work \
        --logs-dir /devtools/certbot-env/-logs \
        certonly \
        --manual \
        --manual-public-ip-logging-ok \
        --manual-auth-hook "/devtools/certbot-env/hook_namecheap.sh create" \
        --manual-cleanup-hook "/devtools/certbot-env/hook_namecheap.sh delete" \
        --preferred-challenges dns \
        -d domain1.example.com \
        -d domain2.example.com

To generate wildcard certs (only 1 domain on a cert)

certbot --config-dir /devtools/certbot-env/etc/letsencrypt \
        --work-dir /devtools/certbot-env/-work \
        --logs-dir /devtools/certbot-env/-logs \
        certonly \
        --manual \
        --manual-public-ip-logging-ok \
        --manual-auth-hook "/devtools/certbot-env/hook_namecheap.sh create" \
        --manual-cleanup-hook "/devtools/certbot-env/hook_namecheap.sh delete" \
        --preferred-challenges dns \
        --server https://acme-v02.api.letsencrypt.org/directory \
        -d *.example.com

All your certs will appear in /devtools/certbot-env/etc/letsencrypt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment