Certifier is a library designed to make it easy to obtain ACME TLS certificates using the DNS-01 Challenge. Certifier is not designed to work as a standalone-CLI, but instead it is designed to be embedded within other Golang applications.
This library requires Go1.17 or later.
This repository generally follows Semantic Versioning. However, this library is currently in Beta and is still considered experimental. Breaking changes of the library will not trigger a new major release. The same is true for selected other new features explicitly marked as EXPERIMENTAL in CHANGELOG.md.
There are two parts to certifier - the DNS Server and the ACME manager.
The DNS Server is quite simple - it only responds to TXT Record queries for subdomains of a single given root domain.
This means that if the certifier is configured with the root domain acme.mydomain.com
, it will only respond to TXT queries
for the domains matching *.*.acme.mydomain.com
. It will also respond to NS Record queries and SOA Record Queries for the root domain
and all of its subdomains.
The ACME manager makes use of the Lego ACME Library to begin and complete DNS-01
challenges.
In order to use certifier to obtain a TLS Certificate using an ACME provider like Let's Encrypt, you must first configure and run Certifier somewhere that is accessible from the public internet.
Let's say you configure certifier for the domain acme.mydomain.com
. The first thing you'll need to do is create the proper A and NS Records
to point DNS requests to certifier. We want to forward NS Queries of the form *.*.acme.mydomain.com
to your certifier instance, so you first need to create an A record
for certifier.mydomain.com
that points to the IP of your certifier instance.
Something like certifier.mydomain.com A <certifier IP>
should work great.
Next you need to create an NS record for acme.mydomain.com
setting your certifier instance as the authoritive name server. A record like acme.mydomain.com NS certifier.mydomain.com
should work perfectly.
Next, you'll need to register a user with Certifier. You will need to do this for every new user that wants to use certifier to obtain certificates.
To do this, you must provide a unique ID for the user, and it is your responsibility to guarantee that the correct user is requesting certificates using their own ID.
Once you have a unique ID for your user, you can register them with Certifier by doing certifier.RegisterCID
. This will map a certifier identifier (the CID
)
to your user's ID.
Your user should then create a CNAME record of the form _acme-challenge.testdomain.com
pointing to testdomain-com.<CID>.acme.mydomain.com
. You must replace
the periods in your root domain (testdomain.com
) with hyphens (-
), and create a CNAME record that points to <root domain with periods replaced>.<cid returned by certifier>.acme.mydomain.com
.
Remember that acme.mydomain.com
is the domain who's name server is your certifier instance.
During an actual Certificate Request Flow, the following happens:
- Create the CNAME record of the form
_acme-challenge.testdomain.com
(if your chosen domain istestdomain.com
), and point it attestdomain-com.<CID>.acme.mydomain.com
, replacing all the periods with hyphens (-
). - Start the renewer using the
certifier.Renew
function, passing in your Lego ACME configuration, your private key, an authorized user ID, and the domain you'd like to obtain a certificate for. - Certifier begin the Certificate Request flow and will receive a Challenge Response. It will then begin to serve a TXT record containing the Challenge Response at the domain
testdomain-com.<CID>.acme.mydomain.com
. - Certifier will manually verify that the TXT record exists and is valid before proceeding with the certificate request flow.
- Let's Encrypt will then look up the TXT Record at
_acme-challenge.testdomain.com
and will be told via the CNAME record you created to instead query the TXT Record attestdomain-com.<CID>.acme.mydomain.com
. - Let's Encrypt will then query the NS Record of
testdomain-com.<CID>.acme.mydomain.com
and receive the IP address of your Certifier instance. It will then query the TXT Record attestdomain-com.<CID>.acme.mydomain.com
where your Certifier will respond with the ACME Challenge Response password that was stored during step 3. - Let's Encrypt will then return a valid certificate, and Certifier will clean up the TXT Record at
testdomain-com.<CID>.acme.mydomain.com
- but you should leave the CNAME Record for_acme-challenge.testdomain.com
pointing to your certifier instance for future renewals.
There is a very simple demo application in this repo that will demonstrate end-to-end how to use Certifier + Lego ACME to receive an SSL Certificate from Let's Encrypt.
It must be run on a server that is routable from the internet (a simple Digital Ocean VPS should work nicely), and it will get a valid SSL Certificate for a given domain.
You must first pick 3 separate domains:
- The domain that will point to your certifier instance (the server that certifier is running on, which is routable from the public internet) - as an example, we will use
certifier.loopholelabs.com
- A certifier root domain - this will be used to tell let's encrypt which DNS Server it should query for a valid DNS-01 Challenge (in our case, that DNS Server is certifier) - as an example, we will use
acme.loopholelabs.com
- The domain what you will obtain an SSL Certificate for - as an example, we will use
testdomain.loopholelabs.com
.
To set up the demo command, begin by spinning up a VPS or any sort of server that is routable from the public internet. You'll want to make sure port 53
is open for UDP
traffic. Note the public IP for this server - in this example, we will use 10.0.0.50
.
- Start by creating an
A
record for the first domain you picked that points to the public IP of your server - we pickedcertifier.loopholelabs.com
so we'll create anA
record that looks something likecertifier.loopholelabs.com A 10.0.0.50
- Next, create the
NS
record that instructs let's encrypt to use your certifier instance as the DNS Server for DNS-01 Challenges - we pickedacme.loopholelabs.com
as our root domain, so we'll create anNS
record that looks something likeacme.loopholelabs.com NS certifier.loopholelabs.com
- Replace all the periods in the domain you'll be obtaining an SSL certificate for with hyphens (
-
) - we will call this the normalized domain - we pickedtestdomain.loopholelabs.com
so our normalized domain would betestdomain-loopholelabs-com
. - For this demo application, the
CID
will always betestcid
- however during real use of Certifier this will be an autogenerated UUID that will map to a user ID. - Finally, create a
CNAME
record that points to the root domain you chose. The CNAME record should be of the form<normalized domain>.<CID>.<root domain>
- we pickedtestdomain-loopholelabs-com
andacme.loopholelabs.com
, so we'll create aCNAME
record that looks something liketestdomain-loopholelabs-com.testcid.acme.loopholelabs.com
.
Once you've completed the setup for running the Demo Command, you can run it like so:
go run cmd/demo/main.go --listen <listen address> --root <root domain> --public <certifier domain> --email <your email> --domain <the domain you want to obtain an SSL certificate for> --directory <acme directory URL>
For this example, a working command would be
go run cmd/demo/main.go --listen 0.0.0.0:53 --root acme.loopholelabs.com --public certifier.loopholelabs.com --email testemail@loopholelabs.io --domain testdomain.loopholelabs.com --directory https://acme-staging-v02.api.letsencrypt.org/directory
We recommend testing with the Let's Encrypt Staging Directory First. It may take up to 24 hours for your DNS Records to propagate before you can run the Demo Command.
Bug reports and pull requests are welcome on GitHub at https://github.com/loopholelabs/certifier. For more contribution information check out the contribution guide.
The Certifier project is available as open source under the terms of the Apache License, Version 2.0.
Everyone interacting in the Certifier project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the CNCF Code of Conduct.