Acme-dns on CentOS 7

Setting up acme-dns on CentOS 7 and configuring a client

In this post an acme-dns server will be set up and a client will acquire a Let’s Encrypt certificate using the DNS-01 challenge.

Acme-dns provides a simple API exclusively for TXT record updates and should be used with ACME magic “_acme-challenge” - subdomain CNAME records. This way, in the unfortunate exposure of API keys, the effects are limited to the subdomain TXT record in question.

https://github.com/joohoi/acme-dns

Network topology

In this post the following is assumed:

The future acme-dns server has an IP address of 192.0.2.100. The following DNS records have been created:

acme-dns.example.com. A 192.0.2.100
a.acme-dns.example.com. NS acme-dns.example.com.

If you manage your own DNS or your provider supports it, you can just use acme-dns.example.com. NS acme-dns.example.com.. Cloudflare does not support records for a host if a different nameserver was set, so I will use the subdomain a. for the acme-dns-managed DNS entries.

Prerequisites

To install acme-dns we need git, gcc and go.

sudo yum install git gcc -y
# install go:
wget https://dl.google.com/go/go1.11.4.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.11.4.linux-amd64.tar.gz
sudo ln -s /usr/local/go/bin/* /usr/local/bin

Install acme-dns as a service

The following will build and install the acme-dns binary.

go get github.com/joohoi/acme-dns/...
sudo mv ~/go/bin/acme-dns /usr/local/bin/acme-dns

Now we need to add a user for the acme-dns service and set up the service itself

sudo adduser --system --home /var/lib/acme-dns acme-dns
sudo mkdir /var/lib/acme-dns
sudo chown acme-dns: /var/lib/acme-dns
sudo wget -O /etc/systemd/system/acme-dns.service https://raw.githubusercontent.com/joohoi/acme-dns/master/acme-dns.service
sudo systemctl daemon-reload

As I was getting errors trying to set the capabilities (allow binding to a port <1000) in the service configuration, I removed that part from the configuration and gave the executable the required permissions directly:

sudo sed -i 's/AmbientCapabilities/#AmbientCapabilities/g' /etc/systemd/system/acme-dns.service
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/acme-dns
sudo systemctl daemon-reload

Configure acme-dns

We can use the example configuration file with our own dns-name and ip address.

sudo mkdir /etc/acme-dns
sudo wget -O /etc/acme-dns/config.cfg https://raw.githubusercontent.com/joohoi/acme-dns/master/config.cfg
sudo sed -i 's/^listen = .*/listen = ":53"/g' /etc/acme-dns/config.cfg
sudo sed -i 's/auth.example.org/a.acme-dns.example.com/g' /etc/acme-dns/config.cfg
sudo sed -i 's/198.51.100.1/192.0.2.100/g' /etc/acme-dns/config.cfg
sudo sed -i 's/^connection = .*/connection = "\/var\/lib\/acme-dns\/acme-dns.db"/g' /etc/acme-dns/config.cfg

Acme-dns supports acquiring it’s own SSL certificate via Let’s Encrypt and serving it’s API on https.

sudo sed -i 's/^tls = .*/tls = "letsencrypt"/g' /etc/acme-dns/config.cfg
sudo sed -i 's/^port = .*/port = "443"/g' /etc/acme-dns/config.cfg
sudo sed -i 's/^api_domain = .*/api_domain = "acme-dns.example.com"/g' /etc/acme-dns/config.cfg
sudo sed -i 's/^acme_cache_dir = .*/acme_cache_dir = "/var/lib/acme-dns/cert"/g' /etc/acme-dns/config.cfg

Starting the service

sudo systemctl enable acme-dns.service
sudo systemctl start acme-dns.service

Client-side

Now we can switch to the client that is supposed to get it’s own certificate issued. First we need to register a new subdomain on the acme-dns server. The response will contain the details needed for the next steps.

curl -X POST https://acme-dns.example.com/register
	{
		"username":		"eabcdb41-d89f-4580-826f-3e62e9755ef2",
		"password":		"pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0",
		"fulldomain":	"d420c923-bbd7-4056-ab64-c3ca54c9b3cf.a.acme-dns.example.com",
		"subdomain":	"d420c923-bbd7-4056-ab64-c3ca54c9b3cf",
		"allowfrom":	[]
	}

We can now set up DNS accordingly. In this example, the response contains the subdomain d420c923-bbd7-4056-ab64-c3ca54c9b3cf and we want to set up the domain server01.example.com so that a certificate can be issued using acme-dns.

_acme-challenge.server01.example.com. CNAME d420c923-bbd7-4056-ab64-c3ca54c9b3cf.a.acme-dns.example.com.

When the entries finished propagating we can install acme.sh and issue a certificate using the acme-dns method. All settings will be saved and the certificate will be renewed automatically.

curl https://get.acme.sh | sh

export ACMEDNS_UPDATE_URL="https://acme-dns.example.com/update"
export ACMEDNS_USERNAME="eabcdb41-d89f-4580-826f-3e62e9755ef2"
export ACMEDNS_PASSWORD="pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0"
export ACMEDNS_SUBDOMAIN="d420c923-bbd7-4056-ab64-c3ca54c9b3cf"

~/.acme.sh/acme.sh --issue --dns dns_acmedns -d server01.example.com

On success, the newly issued certificate will be located in ~/.acme.sh/server01.example.com/ which can be changed using the parameters --cert-file, --key-file, --ca-file and --fullchain-file. Using the parameter --reloadcmd we can issue a command on every future successful renewal.