Automatic HTTPS Certs Using GoDaddy and Gitlab APIs
Before I start, here is some technical information about my website -
- Hosted on Gitlab and usage its CD for automatic deployment, which is triggered on a git commit.
- The domain name registrar is GoDaddy.
- Let's Encrypt as the TLS certificate provider for my domain name.
Let's Encrypt provides certificates for 90 days only, so I was forced to set up
the certbot
certbot
every three months, then generate the certificate and manually
deploy the certificates to GitLab. It was frustrating because in three months,
my shell probably will not remember the command I used last time, and I was too
lazy to document the process somewhere.
Then I came across a project , which was trying to do a similar thing with other domain name registrar. I thought that this is an excellent setup to adapt and modify it to suit my needs. So I decided to write my module for automatic deployment of Let's Encrypt certificates to GitLab.
How does Let's Encrypt work?
Before Let's Encrypt can generate the certificate for the domain, it requires the user to prove domain ownership. Let's Encrypt provides two methods to do this task -
- Updating the DNS records of the domain registrar (DNS-01 challenge)
- Adding an HTTP resource under a well-known URI on the website (HTTP-01 challenge)
Using the second method requires me to add a file on my website, and I did not want to do that. Moreover, if in the future, I decide to host some other service, which does not have a website, then this method will fail.
The first method requires that the domain configuration on the domain registrar is modified. GoDaddy provides a robust API, and it is not difficult to utilize that API to automate specific tasks. The probability of changing the registrar is quite low, at least for the next few years. It will be easier to generate the certificates for any subdomains, as all the subdomains will also be hosted under the same domain registrar.
How does the tool work?
So here are the steps:
- Call
certbot
certbot
with all the domain names - Invoke GoDaddy API to update the DNS records as indicated by Certbot
- Wait for 10 minutes for DNS changes to propagate
- Let
certbot
certbot
verify the DNS changes - Use the GitLab API to deploy the generated certificates to GitLab pages
Invoking certbot
In step 1, we call certbot
certbot
will the preferred method DNS. We also need to
supply an email id (used by Let's Encrypt to notify domain expiration). The
EMAIL_ID
EMAIL_ID
environment variable can be used to store the email id of the user.
Certbot runs in an interactive mode by default. It is not desired in a scripted
environment. Certbot also provides mechanisms to deploy the certificates to a
local server automatically, but as we are hosting our website on Gitlab, we do
not want the automatic deployment facility. So we need to invoke the certbot
certbot
command with --manual
--manual
and certonly
certonly
modes.
certbot --manual \
--preferred-challenges dns \
--agree-tos \
--email "${EMAIL_ID}" \
--no-eff-email \
--expand \
--renew-by-default \
--manual-public-ip-logging-ok \
--noninteractive \
--redirect \
--config-dir ${DIR}/generated/config \
--work-dir ${DIR}/generated/work \
--logs-dir ${DIR}/generated/logs \
--manual-auth-hook ${DIR}/auth_hook.sh \
-d yashagarwal.in \
certonly
certbot --manual \
--preferred-challenges dns \
--agree-tos \
--email "${EMAIL_ID}" \
--no-eff-email \
--expand \
--renew-by-default \
--manual-public-ip-logging-ok \
--noninteractive \
--redirect \
--config-dir ${DIR}/generated/config \
--work-dir ${DIR}/generated/work \
--logs-dir ${DIR}/generated/logs \
--manual-auth-hook ${DIR}/auth_hook.sh \
-d yashagarwal.in \
certonly
The explanation for most of the flags used in the above command can be found by running the following command -
certbot --help
certbot --help
The --manual-auth-hook
--manual-auth-hook
flag is worth looking. This hook provides a mechanism
to specify the executable, which can be used to facilitate domain ownership
validation. In this case, the hook points to a script auth_hook.sh
auth_hook.sh
, which then
calls a Go client, which interacts with GoDaddy API.
Adding DNS entry to GoDaddy DNS manager
Certbot supplies two environment variables CERTBOT_DOMAIN
CERTBOT_DOMAIN
, which contains the
domain name to be verified and CERTBOT_VALIDATION
CERTBOT_VALIDATION
, which includes a random
string corresponding to _acme-challenge TXT
_acme-challenge TXT
entry. What this means is that, if
I have
CERTBOT_DOMAIN=yashagarwal.in
CERTBOT_VALIDATION=6VNg5kDVI_BF1S9N5s74LTBHQnwDpQqKlblKRjIzBwM
CERTBOT_DOMAIN=yashagarwal.in
CERTBOT_VALIDATION=6VNg5kDVI_BF1S9N5s74LTBHQnwDpQqKlblKRjIzBwM
Then the DNS manager should contain a TXT entry _acme-challenge.yashagarwal.in
_acme-challenge.yashagarwal.in
with the value of 6VNg5kDVI_BF1S9N5s74LTBHQnwDpQqKlblKRjIzBwM
6VNg5kDVI_BF1S9N5s74LTBHQnwDpQqKlblKRjIzBwM
.
The auth_hook.sh
auth_hook.sh
file calls the Go client with the abovementioned environment
variables. The relevant code can be found
here .
Once all the DNS entries are added, the auth_hook.sh
auth_hook.sh
script will sleep for 10
minutes. It is to allow DNS changes to propagate throughout the Internet. It is
a random duration as I could not find any GoDaddy support page mentioning the
exact period used by them.
Generation of certificates
Once the auth_hook.sh
auth_hook.sh
script returns successfully, certbot
certbot
will verify the
DNS records. If the verification is successful, certbot
certbot
will generate the
certificates in ./generated/config/live/{CERTBOT_DOMAIN}
./generated/config/live/{CERTBOT_DOMAIN}
directory.
Deploying the certificates to GitLab
I use the following command to deploy the certificates to Gitlab pages where my website is hosted -
curl -vvv \
--request PUT \
--header "Private-Token:${GITLAB_TOKEN}" \
--form "certificate=@${key_dir}/fullchain.pem" \
--form "key=@${key_dir}/privkey.pem" \ "https://gitlab.com/api/v4/projects/yashhere%2Fyashhere.gitlab.io/pages/domains/yashagarwal.in"
curl -vvv \
--request PUT \
--header "Private-Token:${GITLAB_TOKEN}" \
--form "certificate=@${key_dir}/fullchain.pem" \
--form "key=@${key_dir}/privkey.pem" \ "https://gitlab.com/api/v4/projects/yashhere%2Fyashhere.gitlab.io/pages/domains/yashagarwal.in"
where
key_dir="./generated/config/live/yashagarwal.in"
key_dir="./generated/config/live/yashagarwal.in"
Moreover, GITLAB_TOKEN
GITLAB_TOKEN
is an environment variable that contains the API token
generated from the Gitlab settings page.
Automatic Deployment using Travis CI
It is not automation if I have to run this script manually every three months. So I created a Travis CI job to automate this process. The job will run every month and deploy my certificates automatically. It has been four months, and I have not faced any issues with this setup.
The code for this post can be viewed at Github .
Thanks for reading. Cheers 😄