Installing a Let's Encrypt certificate on an Elastic Load Balancer

Have you heard about the new and totally free Certificate Authority Let's Encrypt? If you are using an AWS region where Certificate Manager is supported, then you should probably use that instead. If not, you might be interested in using Let's Encrypt to get your free certificate and installing it on an ELB. This blog post will explain how you can do that without any downtime, when using nginx (for example on Elastic Beanstalk).

In this blog post I will assume that you have already setup HTTP access through an ELB, and the domain name you will be issuing a certificate for is pointing to the ELB. You will also need SSH access to the web server. If you have several web servers, you will need to reattempt issuing the certificate or temporarily detach other instances from the ELB.

Nginx configuration

Add the following location to the nginx site for the domain you will be issuing a certificate for:

location ^~ /.well-known/acme-challenge/ {  
    default_type "text/plain";
    allow all;
}

Reload the nginx configuration:

sudo service nginx reload  
Certbot

How to setup and use Let's Encrypt's Certbot depends on the OS. The following instructions will work for most Linux distributions.

Download and make Certbot executable:

wget https://dl.eff.org/certbot-auto  
chmod a+x certbot-auto  

Request a new certificate:

sudo ./certbot-auto --debug certonly --webroot -w /usr/share/nginx/html/ -d <domain>  

If nginx's web root is some other path than the default /usr/share/nginx/html/, change it accordingly. You can add more domain names by using -d several times, but you will need to set up CNAME or Alias record for each, so they are pointing to the ELB.

When successful, the response should look something like:

 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/<domain>/fullchain.pem. Your cert
   will expire on 2016-10-04.
Upload and install certificate

Add the following inline policy to the instance's IAM profile or IAM user:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:UploadServerCertificate"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:SetLoadBalancerListenerSSLCertificate"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

Then you can upload the certificate:

cd /etc/letsencrypt/live/<domain>

sudo aws iam upload-server-certificate --server-certificate-name <name> --certificate-body file://cert.pem --private-key file://privkey.pem --certificate-chain file://chain.pem  

The reply should look something like:

{
    "ServerCertificateMetadata": {
        "ServerCertificateId": "ASCBJSOPBK7NRDF3HS2MJ", 
        "ServerCertificateName": "<name>", 
        "Expiration": "2016-10-04T13:16:00Z", 
        "Path": "/", 
        "Arn": "<arn>", 
        "UploadDate": "2016-07-07T07:58:47.275Z"
    }
}

And start using it:

 aws elb set-load-balancer-listener-ssl-certificate --region <region> --load-balancer-name <ELB name> --load-balancer-port 443 --ssl-certificate-id <arn>

The <arn> of the certificate is found in the upload command response and <ELB name> can be found by listing your load balancers.

I hope you find this useful for setting up free certificates in your AWS environment!