Let’s Encrypt Wildcard Certificate | Route53, NGINX, CentOS/RHEL 7
Let's Encrypt Certificates are awesome. It is a great way to upgrade your websites to use https or SSL. If you’re using a fairly common/basic setup it’s fairly straightforward to configure your server to use Let’s Encrypt certificates.
Recently, I was working on a project. Where, it was required to use wildcard certificate. Meaning dynamically created domains like abc.example.com or xyz.example.comcan be made to use https without needing to manually create a new certificate for each subdomain. Though, the setup was pretty common (Route53, Nginx, CentOS7), I wasn't able to find clear documentation of configuring wildcard certificated for mentioned stack.
To archive our goal, we will need Certbot, Python Pip, Certbot Plugin for Route53 and an AWS user with access to Route53 to generate Let's Encrypt Certificate.
I assume that, the root hosted zone for the domain in question already exists in your account. As well as you have your CentOS7/RHEL7 running. And you have your webserver up and running with NGINX. Please note that all the following command are executed as root user.
Install Certbot
Certbot automatically enable HTTPS on your website with Let’s Encrypt certificates. To install certbot you can run the following commands.
# yum install -y epel-release && yum update -y
# yum install -y yum-utils
# yum install -y python2-certbot-nginxInstall pip
Pip is a package manager for the python language. we’ll need this to install the Route 53 plugin we’ll be using with certbot.
# yum install -y python-pipCertbot comes with few dependencies, pyOpenSSL is one of them. It might raise an error like "ImportError: ‘pyOpenSSL’ module missing required functionality. Try upgrading to v0.14 or newer"
This is a well known issue, and we are going to avoid this issue by using virtualenv.
Install and activate virtualenv
virtualenv is a tool to create isolated Python environments. Note: The command virtualenv route53 will create a directory named route53 in current working directory. learn about virtualenv form here.
# pip install virtualenv
# virtualenv route53
# source route53/bin/activateInstall Route53 certbot plugin
Route53 certbot plugin automatically completes the necessary steps
Pass the following command to your terminal to install it.
# pip install certbot_dns_route53==$((certbot --version) 2>&1 | grep -oE "\b([0-9]{1,3}\.){2}[0-9]{1,3}\b")Configure Your AWS User
For the certbot_dns_route53 plugin to work it needs to be able to connect to AWS using an access key with the correct permissions.
To do this securely you’ll want to create a new user that only has the necessary permissions it needs to work.
You can find instructions for creating a user here. The basics of it is you’ll want a user with Programmatic access (not console), add it to a group (I created a new one just for this user and any future certbot users I might need).
The user will need specific permissions that are required to allow the certbot plugin to crease the necessary CNAME records. These can be added by manually selecting them from a very long list or you can use the json view to give it the following permissions.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:GetChange"
],
"Resource": [
"*"
]
},
{
"Effect" : "Allow",
"Action" : [
"route53:ChangeResourceRecordSets"
],
"Resource" : [
"arn:aws:route53:::hostedzone/YOURHOSTEDZONEID"
]
}
]
}Make sure you replace YOURHOSTEDZONEID with the instance ID of your hosted zone.
Once the user is created don’t forget to download and save your access key and secret access key (somewhere secure, these are as sensitive as your passwords).
Setup AWS credentials
We now need to put the AWS credentials on the server so the plugin can use them. I run all my certbot commands out of the default user’s home folder, your setup might be different (or you might have a better idea of where to run certbot).
In the home folder create an .aws folder an dinside that create a text file with the name credentials with the following contents.
[default]
aws_access_key_id=XXXXXX
aws_secret_access_key=XXXX/XXXXXReplace the placeholders with the access key and secret access key that you just saved from AWS and fill them in.
Running Certbot
I like to store all the associated things with letsencrypt like log, config, and work on directory named/etc/letsencrypt. To create the initial certificate I ran the following command.
# certbot certonly -d example.com -d *.example.com --dns-route53 --logs-dir /etc/letsencrypt/log/ --config-dir /etc/letsencrypt/config/ --work-dir /etc/letsencrypt/work/ -m email@example.com --agree-tos --non-interactive --server https://acme-v02.api.letsencrypt.org/directoryA short explanation of the above command
certonly: This means only create the certificate instead of updating the server config and/or restarting the server. I didn’t use this when creating a normal SSL certificate, and I’m not sure if it’s necessary for a wildcard cert or not, but I found it works.-d: This specified what domains you wish to register with the certificate. You can pass more than one of these at a time. Before wildcard certificates you’d have to pass one of these for each subdomain you were using.--dns-route53: this specifies that we want to use the plugin to verify that we control the DNS for the domain. DNS validation is the only way to validate wildcard certificates.--logs-dir,--work-dir,--config-dir: points to a directory, allowing the certbot command to be run withoutsudopermission.-m: set the email address.--agree-tos: agrees to the terms and conditions.--non-interactive: stops it from asking you for stuff. This is intended for using the command in an automated script for example.--server: manually point to the server that allows wildcard certificates. The default server that it uses without this command does not support wildcard certificates at the time of this article being published.
Once you run the command, if it was successful, the new certificate files should be saved in the following folder if your using the same configuration as I did /etc/letsencrypt/config/live/example.com/. There should be two files in the folder, on called fullchain.pem and another called privkey.pem.
Add cert files to your Nginx config
With the files created, we now need to add them to our server configuration.
Open the nginx config file for your website. In that file there should be a server { } block with various settings like listen and location.
Inside the server block for your site add the following lines to it.
ssl_certificate /etc/letsencrypt/config/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/config/live/example.com/privkey.pem;Don’t forget to replace example.com with the domain you created the certificate for. Once you’ve added this to the nginx config file, save the file and close it and then restart the server. For me I use the following command:
# service nginx reloadAfter the server restarts if everything went well, you should now be able to browser your website using the https://example.com version of your website!
Renew Certificate
Now that you’ve created and configured the certificate, you’ll now need to set the certificate to renew as it expires after 90 days.
To renew the certificate you can use the certbot utility. Below is the command I used. Don't forget to activate virtualenv as we did before.
# certbot renew --dns-route53 --logs-dir /etc/letsencrypt/log/ --config-dir /etc/letsencrypt/config/ --work-dir /etc/letsencrypt/work/ --non-interactive --server https://acme-v02.api.letsencrypt.org/directory --post-hook "sudo service nginx reload"This is similar to the first command but instead it will try to renew all the certificates that have been created. The --post-hook lets you specify a command to run after the renew succeeds. We make this part of the command so that this command can be added to the cronjobs to automatically try and renew the certificate every day.
