LetsEncrypt and AWS ELB Load Balancers
This is something that I've struggled to find good information on. You've setup your IIS Web Servers in AWS, get them working nicely behind an ELB Load Balancer, now you want to apply a free LetsEncrypt SSL Certificate. This guide will take you through that process.
Here's he basic run down:
Note that I've changed to manually entering the hostname. I've done this so the binding doesn't require a hostname. This means that the ELB Health Checks work. If you don't have a site running with now hostname IIS returns 404 to the ELB and the health checks fail.
Here's he basic run down:
- Design your Infrastructure to allow for a Central Validation Server
- Setup and IAM identity with access to manage your certificates
- Setup an initial certificate
- Apply the new certificate to a new ELB
- Re-generate the LetsEncrypt Certificate with a script to automatically update the ELB Certificate
Design your Infrastructure to allow for a Central Validation Server
One concept discussed in LetsEncrypt's Integration Guide is a Central Validation Server. To abbreviate this considerably, this is setting up one of the servers to manage the certificates. Fortunately ELB2 presents the certificate to clients and it doesn't matter which certificate is presented by the server. All our servers will be presenting self signed certificates, except for our Central Validation Server.
This is a design decision so I'm not going to go into much detail as your solution will likely differ.
This is a design decision so I'm not going to go into much detail as your solution will likely differ.
- Come up with a DNS name that you can direct straight to one of your WebServers, bypassing the Load Balancer. For me, I used the root of my domain since it can't point to an AWS Load Balancer anyway (A record required, not CNAME).
- Setup two WebServers, one will become the Image for all WebServers, the other will be a WebServer and your Central Validation Server.
- Setup the Web Site on your Web Server with a Self Signed certificate, with a long expiry:
New-SelfSignedCertificate -Subject “RDS.Contoso.local” -DnsName “webserver.contoso.com” -CertStoreLocation “cert:\LocalMachine\My” -KeyAlgorithm RSA -KeyLength 2048 -KeyExportPolicy Exportable -NotAfter (Get-Date).AddYears(5) - Setup URL Re-write on your Web Servers to redirect .well-known to the DNS name you chose in Step 1 above. This is so that any verification requests hit the Central Validation Server instead of any of the other web servers.
- Create and image of your web server. These can be used with Auto Scaling. All the remaining steps below will take place you your Central Validation Server.
Setup and IAM identity with access to manage your certificates
- Open the "IAM Management Console"
- Click on Users
- Click on Add User
- Give the user a meaningful user name, so someone doesn't accidentally disable or delete it
- Select "Programmatic access"
- Click "Next:Permissions"
- At the top of the page select "Attach existing policies directly"
- Search for, and select, the Policy "AWSCertificateManagerFullAccess". I'll admit, it would be more secure to create a new policy and only allow updating the required certificate. (see below)
- Click "Next:Review"
- Click "Create User"
- Record the Access key ID and Secret access key, you'll need these later
- Click Close
Setup an initial certificate
Now, here I'm making a few assumptions:
- You have your web server setup and publicly browseable over HTTP
- You've downloaded and extracted the files for win-acme (more details here). Personally, I've extracted mine into C:\Program Files\ because it's logical and I trust the publisher.
- You've supplied the hostname of your website in the binding (win-acme will use this to update IIS)
If you have all of the setup, follow these steps:
- On your EC2 webserver browse to where you've extracted win-acme (e.g. C:\Program Files\win-acme)
- Open the scripts folders and create a new text file
- Rename the file "ImportAWS.ps1" - make sure you update the file extension too
- Edit your new file and paste this code in:
param(
[Parameter(Position=0,Mandatory=$true)]
[string]$NewCertPFX,
[Parameter(Position=1,Mandatory=$false)]
[string]$AWSCertARN
)
Initialize-AWSDefaultConfiguration -AccessKey xxxxxxxxxx -SecretKey xxxxxxxxxx
# Take the supplied pfx path and remove prepended details - 8 characters to remove -all.pfx
$CertPath = $NewCertPFX.Substring(0,$NewCertPFX.Length-8)
if($AWSCertARN){
Import-ACMCertificate -CertificateArn $AWSCertARN `
-CertificateChain (Get-Content "$($CertPath)-chain.pem" -Encoding Byte) `
-Certificate (Get-Content "$($CertPath)-crt.pem" -Encoding Byte) `
-PrivateKey (Get-Content "$($CertPath)-key.pem" -Encoding Byte)
} else {
Import-ACMCertificate -CertificateChain (Get-Content "$($CertPath)-chain.pem" -Encoding Byte) `
-Certificate (Get-Content "$($CertPath)-crt.pem" -Encoding Byte) `
-PrivateKey (Get-Content "$($CertPath)-key.pem" -Encoding Byte)
}
- Edit the script to insert your access key ID and secret access key from the IAM user you created above.
- Save the script
- Open a command prompt and run letsencrypt.exe
- Type N to select "Create new certificate with advanced options" and press enter
- Type 1 to select "Single binding of an IIS site" and press enter
- From the list of IIS bindings, type the number the corresponds to your site, and press enter.
- letsencrypt.exe will now verify your ownership of the domain, generate a certificate, and update your IIS bindings.
- Type Q and press enter to quit.
Now that the certificate has been generated, we can also upload it to AWS ACM. Just for fun, lets use the script we setup above:
- Open a powershell prompt and browse the the win-acme folder
- Open the scripts folder and run ./ImportAWS.ps1 with a single argument of the path to the pfx file letsencrypt generated. This should be C:\ProgramData\win-acme\httpsacme-v01.api.letsencrypt.org\YOUR FQDN-all.pfx
- This will then run and return a single line. This text is the ARN of the certificate you've just uploaded. Make a note of this, you'll need it later.
Apply the new certificate to a new ELB
- Login to AWS' EC2 Management Console
- On the left, click on "Load Balancers
- Click Create Load Balancer
- Click on Create under "Application Load Balancer"
- Give the load balancer a name and make sure it's Internet Facing
- Select HTTPS (Secure HTTP) as the Load Balancer Protocol
- Select at least two Availability zones, making sure to include the one(s) with your webserver(s)
- Click "Next:Configure Security Settings"
- All going well, the certificate you uploaded above should be in the "Certificate name" dropdown. Select it
- Click "Next:Configure Security Groups"
- Select, or create a Security Group that allows HTTPS
- Create a new Target group and give it a name
- Select HTTPS as the protocol and also in the health checks
- Click "Next:Register Targets"
- Select your Webserver(s) and click "Add to registered"
- Click "Next Review"
- Click Create
Your web server is now running over and ELB load balancer, with a win-acme generated letsencrypt SSL certificate. Don't forget to complete the next step to make sure renewals work.
Re-generate the LetsEncrypt Certificate with a script to automatically update the ELB Certificate
Note that I've changed to manually entering the hostname. I've done this so the binding doesn't require a hostname. This means that the ELB Health Checks work. If you don't have a site running with now hostname IIS returns 404 to the ELB and the health checks fail.
- Jump back on to your EC2 Web Server and re-run letsencrypt.exe from a command prompt
- Type M to select "Create new certificate with advanced options" and press enter
- Type 4 to select "Manually input host names" and press enter
- Type in your hostname(s) and press enter
- Type 4 to select "[http-01] Self-host verification files" and press enter
- Type 2 to select "Create or update https bindings in IIS" and press enter. This tells win-acme to update our IIS bindings as part of the renewal.
- Type y to add another installer step
- Type 2 to select "Run a custom script" and press enter
- Type n and press enter to not add any additional steps
- Type the number corresponding to your IIS Website, so LetsEncrypt can update the binding.
- Enter the path to the script as ./Scripts/PSScript.bat. This is a simple supplied script to launch powershell
- Enter the parameter format string as ./Scripts/ImportAWS.ps1 {2} arn:aws:acm:us-west-2:xxxxxxxxxxxxxxx:certificate/d65xxxxxxxxxxxxxxxxxxxxxx where the last argument is the certificate arn you noted down when you uploaded your initial certificate. Press enter
- All going well, win-acme will again verify your domain, generate a new certificate, update the IIS bindings, and finally, run our script to upload the certificate to AWS ACM, updating the one uploaded earlier.
Congratulations! Now you can configure your auto scaling and target groups so web servers are created as required (don't include the Central Validation Server as we only want one of these).
Comments