LetsEncrypt Terraform (OLD-with DNSimple)

by Nicki Watt
May 28, 2024
by Nicki Watt
May 28, 2024

This blog aims to provide an end to end example of how you can automagically request, generate and install a free HTTPS/TLS/SSL certificate from Let’s Encrypt using Terraform. Let’s Encrypt is a free, automated, and open certificate authority (CA) aiming to make it super easy (and free – did I say free!) for people to obtain HTTPS (SSL/TLS) certificates for their websites and infrastructure. Under the hood, Let’s Encrypt implements and leverages an innovative protocol called ACME to make all this magic happen, and it is this ACME protocol that powers the Terraform provider we will be using. For more information on how Let’s Encrypt and the ACME protocol actually work, please see how Let’s Encrypt works.At present, Terraform does not have a native ACME provider as part of its core offering, although this has been requested. In the meanwhile, a standalone provider (https://github.com/paybyphone/terraform-provider-acme) has already sprung up which provides us with a great first pass at exploring what a terraform ACME integration may look like. Getting certain aspects of the ACME protocol and Terraform to play nicely together can be somewhat challenging as discussed here and here, plus the ACME spec itself is still in draft and evolving. I expect this standalone provider will more than likely be merged into the core Terraform codebase at some point. However I also think it will undergo a few (potentially fundamental) changes along the way as well. So in short, you have been warned – things may change, this is not set in stone! Nevertheless, lets crack on and see how far we can get with what we currently have and know!

Overview

To practically demonstrate this working, we will spin up a basic Amazon Web Services (AWS) environment with a website needing an HTTPS certificate. This basic environment will comprise of a VPC housing two EC2 instances with NGINX installed on them. These instances will be fronted by a classic Elastic Load Balancer (ELB) terminating HTTPS. In other words, it is against the classic ELB that our freshly generated certificate from Let’s Encrypt will need to be uploaded.As Let’s Encrypt can only work with publicly accessible domain names (DNS), we will need to a have a site with a domain accessible on the public internet, as well as an API driven DNS provider. Route53 is a perfectly valid option to use for a DNS provider, however to spice things up a bit (and also demonstrate Terraforms ability to work well across providers) this blog will use DNSimple. Throughout this blog, you will see the letsencrypt-terraform.ocdemo.net domain referenced in all example code. By the time you actually read this however, that domain, as well as any infrastructure backing it, will no longer exist. If you therefore want to run this example for yourself, you will first need to get your own domain name, and make the appropriate changes to the Terraform configuration.

Running the example

On Your Marks …

Get the binaries

Download the core Terraform as well as the standalone ACME Terraform provider binaries and ensure they are available on your path. Example instructions are based on a MacOS environment, using Terraform v0.8.4 and ACME Terraform provider v0.2.1.mkdir ~/demobin

wget https://releases.hashicorp.com/terraform/0.8.4/terraform_0.8.4_darwin_amd64.zip

unzip terraform_0.8.4_darwin_amd64.zip -d ~/demobin

wget https://github.com/paybyphone/terraform-provider-acme/releases/download/v0.2.1/terraform-provider-acme_v0.2.1_darwin_amd64.zip

unzip terraform-provider-acme_v0.2.1_darwin_amd64.zip -d ~/demobin

sudo chmod +x demobin/terraform*

export PATH=$PATH:~/demobin

Get the code

Clone the GitHub repo https://github.com/opencredo/letsencrypt-terraform.git, change into the consolidated demo directory where we will run Terraform from.git clone https://github.com/opencredo/letsencrypt-terraform.git

cd demos/acme-consolidated

Get set …

Configure base variables

Configure the domain name details and target Let’s Encrypt server to use. Let’s Encrypt advise on using their staging server first to ensure you get things right, and to prevent hitting production rate limits until you are genuinely ready. When you are happy, this can be changed to use the production server. The staging server works in pretty much the same way as the production server. It will however generate certificates signed by the Let’s Encrypt Test CA which will NOT automatically be trusted by the browser.https://gist.github.com/nickithewatt/d8d3e93ea003c9b2af053c5880d2e012

Configure core Terraform provider credentials

Using environment variables, configure the AWS and DNSimple credentials required by the core Terraform providers to create the main infrastructure resources. Please note the DNSIMPLE_TOKEN needs to be a v1 token, which is not always that obvious and can be found here on your dashboard.export DNSIMPLE_EMAIL=yourname@youremail.com

export DNSIMPLE_TOKEN=xxxxxxxxxxx

export AWS_ACCESS_KEY_ID=yyyyyyyy

export AWS_SECRET_ACCESS_KEY=zzzzzzzz

export AWS_DEFAULT_REGION=eu-west-1

Configure ACME Terraform provider credentials

There are separate processes for registering an account with an ACME provider, and managing certificates via it. In this blog, we will be doing both the initial registration and certificate request as part of a single consolidated process. So, unlike many other providers where account registration, and thus gaining access to credentials MUST be done before hand, out of band, for ease of demonstration we will do it as part of our consolidated process.In addition to the basic account creation however, our Terraform ACME provider has been configured to do a DNS challenge (dns-01) for our domain. This will involve creating some new DNS records against the domain (in DNSimple) to prove control. Under the covers this responsibility is delegated to an underlying library called lego. Lego is a Let’s Encrypt client and ACME library written in Go. Credentials will need to passed through for this phase. Lego can use environment variables, however although some of these environment variable names align with those used by Terraform, some do not. This has caused great confusion, especially for me. So for this example, the variables are required to be explicitly defined and passed in.This can be done by adding them into a terraform.tfvars file, or, as shown here, set as the special TF_VAR environment variables. This allows them to be picked up as bona fide Terraform variables at runtime. This should now take care of providing values for the variables we ignored a bit earlier on.# These will be the same as those specified for the core

# DNSimple terraform credentials

export TF_VAR_demo_acme_challenge_dnsimple_email=yourname@youremail.com

export TF_VAR_demo_acme_challenge_dnsimple_api_key=xxxxxxxxxxx

Go …

Execute terraform

We should now be in a place where we can actually run Terraform. As is best practice, your should first you do a Terraform plan in order to verify that your basic setup and configuration is correct, saving this plan to a file. Then, provided all is well, this specific plan can be applied via the Terraform apply and all the infrastructure will be stood up.terraform get

terraform plan -out letf-demo.plan

terraform apply -input letf-demo.plan

Verify

Once Terraform completes, and assuming that the DNS entries have propagated (I found that sometimes the AWS ELB DNS name was taking up to a minute to propagate out), you should now be able to go and visit your domain, served securely over HTTPS. You should see the default NGINX page, with a slight modified title to indicate whether it is hitting EC2 instance 1 or 2.When running with the Let’s Encrypt staging server configured, your browser (Chrome used for example) will look something like that shown below. Recall that the staging server creates certificates signed by the Let’s Encrypt test CA, which is not automatically trusted by browsers. It is still however very useful for testing!

letsencrypt terraform domain with staging signed certificate

Domain with a Let’s Encrypt staging signed certificate

When changed to use the Let’s Encrypt production server however, your site should be loaded with a perfectly formed, validated and trusted HTTPS certificate.
letsencrypt terraform domain with a production signed certificate

Domain with a Let’s Encrypt production signed certificate

Running this domain through the online Qualys SSL Server Test utility results in an A rating! All of this done with one Terraform invocation, and all for free – did I say free!

letsencrypt terraform - Qualys SSL Server Test results

Qualys SSL Server Test results

What just happened?

Let’s start by looking at a diagram depicting the logical Terraform process flow taking place.

logical letsencrypt terraform integration flow

logical LetsEncrypt Terraform integration flow