This is a follow-up to my previous post about getting TLS working on a local Azure Service Fabric cluster. This time I'm aiming for the real goal: running a custom API endpoint (micro-service) on a custom domain name behind https on a cluster running on Azure.
First a short summary of the things we need to do:
- Register a CNAME record with a DNS provider that maps your desired custom domain name to the default domain name of your Service Fabric cluster.
- Obtain a certificate in PFX format from a certificate authority.
- Upload the PFX file to Azure Key Vault.
- Modify the Azure Virtual Machine Scale Set that sits behind your Service Fabric cluster so that the certificate gets installed on all VMs in the scale set.
- Modify the Service Fabric configuration to make sure that our custom API uses the certificate.
Register a DNS CNAME record
This step actually has nothing to do with Service Fabric but is required if you want to run your API micro-service on TLS (or you could try getting a certificate for mysfcluster.westeurope.cloudapp.azure.com
but I don't think Microsoft will allow that ;)
So what you want is a CNAME record that maps your custom domain name, for this article I'll use mysfcluster.nl
, to the domain of your cluster, e.g. mysfcluster.westeurope.cloudapp.azure.com
.
Get a certificate
Again, this has nothing to do with Service Fabric. You need a server authentication certificate in PFX format that includes the private key and the entire certificate chain. And of course the password that protects the private key.
Upload the certificate to Azure Key Vault
Azure Key Vault can be used to securely store a number of different things: passwords, PFX files, storage account keys, etc. Things you store there can be referenced from Azure Resource Manager templates to be used in web sites, VMs, etc. Uploading a PFX file to Azure Key Vault isn't as easy as it should be, so lucky for us Chacko Daniel from Microsoft has written a nice PowerShell module that handles this for us.
So what I did was clone the GitHub repository and import the module (from a PowerShell prompt):
PS c:\projects> git clone https://github.com/ChackDan/Service-Fabric.git
PS c:\projects> Import-Module Service-Fabric\Scripts\ServiceFabricRPHelpers\ServiceFabricRPHelpers.psm1
We can now invoke the PowerShell command Invoke-AddCertToKeyVault
, which you'll find below, including the expected output.
PS C:\projects> Invoke-AddCertToKeyVault `
-SubscriptionId "12345678-aabb-ccdd-eeff-987654321012" `
-ResourceGroupName MySFResourceGroup `
-Location westeurope `
-VaultName "MyKeyVault" `
-CertificateName "MyAPICert" `
-Password "eivhqfBw=AGUsLuJ2Z<r" `
-UseExistingCertificate `
-ExistingPfxFilePath "C:\projects\mysfcluster_nl.pfx"
Switching context to SubscriptionId 12345678-aabb-ccdd-eeff-987654321012
Ensuring ResourceGroup MySFResourceGroup in westeurope
Using existing vault MyKeyVault in westeurope
Reading pfx file from C:\projects\mysfcluster_nl.pfx
Writing secret to MyAPICert in vault MyKeyVault
Name : CertificateThumbprint
Value : C83D60162D7BDC62A41516CD5007E4FDDD196201
Name : SourceVault
Value : /subscriptions/12345678-aabb-ccdd-eeff-987654321012/resourceGroups/MySFResourceGroup/providers/Microsoft.KeyVault/vaults/MyKeyVault
Name : CertificateURL
Value : https://mykeyvault.vault.azure.net:443/secrets/MyAPICert/e72e1834a1ae4be19f249121cc8fc722
I'll walk you through the parameters for Invoke-AddCertToKeyVault
in order of appearance:
SubscriptionId | The id of the Azure subscription that contains your key vault. When the key vault does not yet exist, it will be created. |
ResourceGroupName | Name of the resource group for your key vault. |
Location | Key vault location. If you run the PowerShell cmd Get-AzureRmLocation you'll get a list of location system names. |
VaultName | The name of your key vault. When the script can not find this key vault, it will be created. |
CertificateName | The name of the PFX resource that is created in the key vault. |
Password | The password that you used to protect the private key in the PFX file. |
UseExistingCertificate | Indicates that we are using an existing certificate. Invoke-AddCertToKeyVault can also be used to generate a self-signed certificate and upload that to the key vault. |
ExistingPfxFilePath | The absolute path to your PFX file. |
Install certificate on virtual machines
An Azure Service Fabric cluster is powered by one or more Virtual Machine Scale Sets. A VM Scale Set is a collection of identical VMs that (in the case of Service Fabric) run the micro-services in your Service Fabric applications.
There is very little support for VM Scale Sets in the portal so we use Azure Resource Explorer for this. If you've opened Azure Resource Explorer, you have to browse to the correct resource, which is the VM Scale Set that powers your SF cluster. In my case, it is called Backend.
Once there, you can add a reference to the certificate in the key vault. In the screenshot below, you see a reference to the key vault itself and multiple certificate references.
If I follow my own example:
- the reference to the key vault should be
/subscriptions/12345678-aabb-ccdd-eeff-987654321012/resourceGroups/MySFResourceGroup/providers/Microsoft.KeyVault/vaults/MyKeyVault
- the reference to the certificate should be
https://mykeyvault.vault.azure.net:443/secrets/MyAPICert/e72e1834a1ae4be19f249121cc8fc722
You can copy these values from the output of the Invoke-AddCertToKeyVault
command. If you save (PUT) the updated VM Scale Set resource description, the certificate will be installed to all VMs in the scale set.
Configure Service Fabric to use the certificate
We actually already did this in the previous post so I'll summarize here:
- Extend your
ServiceManifest.xml
with an additional named (https) endpoint. - Extend the
ApplicationManifest.xml
in two places:
- Add an
EndpointBindingPolicy
to theServiceManifestImport
. This links the https endpoint to a certificate. - Add an
EndpointCertificate
to the certificates collection. This is a named reference to the thumbprint of the certificate you uploaded to Azure Key Vault earlier.
- Modify
OwinCommunicationListener
. This class is hard-coded to support onlyhttp
. You can change this to make it supporthttps
as well. - Add a
ServiceInstanceListener
that references the https endpoint.
For more information about service manifests, application manifest and how they are related, check this post.
Conclusion
There are again quite some steps involved, just as in the previous post on how to get this working locally. Each step by itself isn't complicated but the entire process takes some time and effort.
I hope this helps in setting up a protected endpoint in Service Fabric :)