This post is part of a series, for the series contents see: Azure MFA
I’m a cheap guy so I don’t want to spend any money on this lab. My Azure stuff is covered by the hours I get as part of my MSDN subscription and my test domain is free from freenom, so there’s no way that I want to fork out and pay for an SSL certificate.
Enter, Let’s Encrypt: the free, automated, and open certificate authority.
I first read about Let’s Encrypt over a year ago when a teammate at work put forward the idea that we might want to use it as a cost saving measure for securing some of our internal management interfaces which we’ve always tended to use public CA certs for as they’re relatively cheap and it saves us the hassle of managing an internal PKI infrastructure. At the time I had a look and Let’s Encrypt wasn’t yet inherently trusted by the common browsers (it was going through the Mozilla process but there wasn’t much on the site about IE or Chrome), so I thought it wasn’t quite ready.
Fast forward to now and those problems have all gone, it seems that all the major browsers now trust the CA by default, so I thought I’d give it a go for this ADFS lab.
How It Works…
This took me a few minutes to get my head around at first because I’m very much used to the traditional method for getting an SSL certificate:
That’s all far too manual for the Let’s Encrypt model, which is designed for an automated DevOps kind of world. In fact, each Let’s Encrypt cert only lasts 90 days so, generally, if you’re not running a build and burn DevOps style deployment method then you might want to question if it’s the right solution for you.
The Let’s Encrypt method uses tooling and the “Automated Certificate Management Environment (ACME)” protocol as follows:
All pretty simple and logical when you think about it – Let’s Encrypt do a much better job of explaining the process than me here.
Putting it into Action
Most of the ACME tools out there are for Linux but I wanted to get it up an running on Windows for no better reason than it would make my life easier for exporting the cert to use on my ADFS and proxy servers. I can never remember my OpenSSL command line switches so I always end up having to Google things…
This is how you do it, the high-level steps are:
- Create a new Windows Server VM being sure to give it a public IP
- Install IIS and create a basic site with the host header you want for your cert. In my case: sts.irankon.tk
- Create a DNS entry pointing sts.irankon.tk to the VM’s public IP
- Install and run the Windows ACME agent on the VM (you can download it here)
Step 1 – Create the Windows VM with a Public IP
First up, create a certificate VM in the DMZ with a public IP.
#Login to Azure resource manager Login-AzureRmAccount #Just in case you have multiple subscriptions check which one you're working in Get-AzureSubscription #If you need to select your test subscription use: #Set-AzureSubscription -SubscriptionName ########################################### # Setup Windows Cert VM for Let's Encrypt # ########################################### #This is needed to use Let's Encrypt to get a free SSL cert for ADFS usage #Specify the resource group and location $RGName = "dmz-rg" $Location = "North Europe" #First setup default credentials to use in provisioning by retrieving and decrypting our Key Vault password $Username = "adminuser" $SecurePwd = Get-AzureKeyVaultSecret -VaultName 'lab-vault' -Name 'ProvisionPassword' $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePwd.SecretValue #Define VM basics $VMName = "cert-vm" $VMSize = "Standard_A1" $OSDiskName = $VMName + "OSDisk" $StorageAccount = Get-AzureRmStorageAccount -ResourceGroupName $RGName -Name dmzvmstr $vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name dmz-vnet #Create a public IP New-AzureRmPublicIpAddress -Name cert-vm-pip -ResourceGroupName $RGName ` -AllocationMethod Static -Location $Location #Define VM network details #Private IP $NIC1 = New-AzureRmNetworkInterface -Name "cert-vm-eth0" -ResourceGroupName $RGName -Location $Location -SubnetId $vnet.Subnets.Id -PrivateIpAddress 192.168.1.6 #Public IP $pip = Get-AzureRMPublicIPAddress -ResourceGroupName $RGName -Name cert-vm-pip $NIC1.IPConfigurations.PublicIPAddress = $pip #Confirm the details Set-AzureRmNetworkInterface -NetworkInterface $NIC1 #Define the VM config $VirtualMachine = New-AzureRmVMConfig -VMName $VMName -VMSize $VMSize $VirtualMachine = Set-AzureRmVMOperatingSystem -VM $VirtualMachine -ComputerName $VMName -Windows -Credential $Credential $VirtualMachine = Set-AzureRmVMSourceImage -VM $VirtualMachine -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Skus "2016-Datacenter" -Version "latest" $VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $NIC1.Id $OSDiskUri = $StorageAccount.PrimaryEndpoints.Blob.ToString() + "vhds/" + $OSDiskName + ".vhd" $VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -Name $OSDiskName -VhdUri $OSDiskUri -CreateOption FromImage #Create the VM New-AzureRmVM -ResourceGroupName $RGName -Location $Location -VM $VirtualMachine
Step 2 – Install IIS and Setup a Basic Site
There’s nothing big or clever here, just simply using Add Roles & Features to install IIS. Or you could do it with PowerShell using the following:
Install-WindowsFeature -Name Web-Server, Web-Mgmt-Tools
The whole point of this step is to have a website where the ACME tool can create a publicly available file that Let’s Encrypt can then use as verification that I do indeed own my domain.
Once IIS is installed, fire up the management console and create a site with the host header and bindings for “sts.irankon.tk”
Then in the site’s root directory add a noddy index.htm file:
I don’t think this is necessary for the whole Let’s Encrypt thing but it does give you some content to use to verify that the site is up and running (see the next step for details).
Step 3 – Setup a DNS Record
If you’ve got your zone setup and hosted in Azure DNS, like I have for irankon.tk, then create a record for sts.<domain>.<tld> with a quick bit of PowerShell:
#Specify the resource group and location $RGName = "dmz-rg" $Location = "North Europe" #Public IP $pip = Get-AzureRMPublicIPAddress -ResourceGroupName $RGName -Name cert-vm-pip #Setup DNS $RGName = "hub-rg" New-AzureRmDnsRecordSet ` -Name "sts"` -RecordType A ` -ZoneName "irankon.tk" ` -ResourceGroupName "$RGName" ` -Ttl 3600 ` -DnsRecords (New-AzureRmDnsRecordConfig -IPv4Address $pip.IpAddress)
With that all in place, you should then be able to verify that the web server is indeed working by simply browsing to it:
Step 4 – Use the Windows ACME Tool to Get an SSL Cert
With all the prep done, all that is left to do is to use the Windows ACME tool and get an SSL cert.
After a quick Google the Windows ACME agent I settled on was “Let’s Encrypt Win Simple”. It’s very easy to use, first up download it from the GitHub page and extract the zip file locally on your VM. Then open up a command prompt, browse to the directory, and just run: letsencrypt.exe
The tool will search IIS for sites and their bindings, at which point just enter the number for the site you want to create an SSL cert for (“1” in my example below).
At this point the tool will kick in and sort out the verification stage before installing a brand new Let’s Encrypt cert for the chosen site.
With that done, the final step for will be to export that cert for use on your ADFS servers later on.