Although it is possible to purchase an SSL certificate in the Azure Portal, the intention is to apply that Certificate to an App Service and not specifically a VM. But did you know it is actually possible to purchase an Azure App Service certificate, save it to an azure key vault, and then export that certificate from the key vault in PFX format for later utilization with a VM or another resource?  The below steps will lay out this process, whether you have decided that your App Service is not robust enough for your needs and want to move forward with utilizing a full-fledged VM running Apache or Nginx, or just wanted to purchase an SSL certificate through the Azure Portal in the first place but were wondering if you could apply it to a VM.

So, you bought an App Service Certificate, now what? You may have found yourself here because you purchased the certificate and want to apply it to a VM but are confused on how that may work. The good news is that you’re in the right place, and also keep in mind; if you do not utilize the certificate within XXX days it will actually be refunded.

The first step of being able to utilize your certificate is importing it into an Azure Key Vault. This is laid out with additional steps when accessing the certificate and choosing:

Certificate Name > Certificate Configuration:

If you don’t have one already, you will need to create a key vault to store Import your certificate into. Later steps will have you exporting the certificate from the key vault, so this is an important step to both validate/use the certificate as well as necessary to export it later.

During testing we found it easier to create a key vault with “Vault access policy” to avoid the error “The operation is not allowed by RBAC. If role assignments were recently changed, please wait several minutes for role assignments to become effective.” It should be possible to assign proper roles (like Key Vault administrator, etc), however it seems easier if this is a one time use to just use: “Vault access policy”:

Once you have a key vault with appropriate policies, choose Step 1 from the certificate: Import the certificate into a key vault for secure administration.

Step 2 after purchasing the certificate and importing it into a key vault is verifying ownership of the domain – this is easy/straight forward if you are hosting DNS on Azure. Steps there include:

  • To point your registrar to Azure name servers use:
    • ns1-04.azure-dns.com, ns2-04.azure-dns.net, ns3-04.azure-dns.org, ns4-04.azure-dns.info
  • When clicking step 2, you’ll be prompted to create a TXT record to validate ownership:
    • Create that @ TXT record in your DNS Zone with the appropriate value to validate the domain.

After validating the domain, the Certificate is ready to use – you can then proceed to the following documentation for exporting the certificate from PowerShell after connecting with Connect-AzAccount. This function was written in 2017, but at the time of our article all steps were still working flawlessly, and we have added them here for prosperity here as well:
Creating a local PFX copy of App Service Certificate – Azure App Service.

Create the Export-AppServiceCertificate:

Function Export-AppServiceCertificate
{
###########################################################

Param(
[Parameter(Mandatory=$true,Position=1,HelpMessage="ARM Login Url")]
[string]$loginId,

[Parameter(Mandatory=$true,HelpMessage="Subscription Id")]
[string]$subscriptionId,

[Parameter(Mandatory=$true,HelpMessage="Resource Group Name")]
[string]$resourceGroupName,

[Parameter(Mandatory=$true,HelpMessage="Name of the App Service Certificate Resource")]
[string]$name
)

###########################################################

Connect-AzAccount
Set-AzContext -Subscription $subscriptionId

## Get the KeyVault Resource Url and KeyVault Secret Name were the certificate is stored
$ascResource= Get-AzResource -ResourceId "/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.CertificateRegistration/certificateOrders/$name"
$certProps = Get-Member -InputObject $ascResource.Properties.certificates[0] -MemberType NoteProperty
$certificateName = $certProps[0].Name
$keyVaultId = $ascResource.Properties.certificates[0].$certificateName.KeyVaultId
$keyVaultSecretName = $ascResource.Properties.certificates[0].$certificateName.KeyVaultSecretName

## Split the resource URL of KeyVault and get KeyVaultName and KeyVaultResourceGroupName
$keyVaultIdParts = $keyVaultId.Split("/")
$keyVaultName = $keyVaultIdParts[$keyVaultIdParts.Length - 1]
$keyVaultResourceGroupName = $keyVaultIdParts[$keyVaultIdParts.Length - 5]

## --- !! NOTE !! ----
## Only users who can set the access policy and has the the right RBAC permissions can set the access policy on KeyVault, if the command fails contact the owner of the KeyVault
Set-AzKeyVaultAccessPolicy -ResourceGroupName $keyVaultResourceGroupName -VaultName $keyVaultName -UserPrincipalName $loginId -PermissionsToSecrets get
Write-Host "Get Secret Access to account $loginId has been granted from the KeyVault, please check and remove the policy after exporting the certificate"

## Getting the secret from the KeyVault
$secret = Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $keyVaultSecretName -AsPlainText
$pfxCertObject= New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList @([Convert]::FromBase64String($secret),"",[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$pfxPassword = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 50 | % {[char]$_})
$currentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath
[Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath
[io.file]::WriteAllBytes(".\appservicecertificate.pfx",$pfxCertObject.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12,$pfxPassword))

## --- !! NOTE !! ----
## Remove the Access Policy required for exporting the certificate once you have exported the certificate to prevent giving the account prolonged access to the KeyVault
## The account will be completely removed from KeyVault access policy and will prevent to account from accessing any keys/secrets/certificates on the KeyVault, 
## Run the following command if you are sure that the account is not used for any other access on the KeyVault or login to the portal and change the access policy accordingly.
# Remove-AzKeyVaultAccessPolicy -ResourceGroupName $keyVaultResourceGroupName -VaultName $keyVaultName -UserPrincipalName $loginId
# Write-Host "Access to account $loginId has been removed from the KeyVault"

# Print the password for the exported certificate
Write-Host "Created an App Service Certificate copy at: $currentDirectory\appservicecertificate.pfx"
Write-Warning "For security reasons, do not store the PFX password. Use it directly from the console as required."
Write-Host "PFX password: $pfxPassword"

}

Export the Certificate:
Export-AppServiceCertificate -loginId yourarmemail@domain.com -subscriptionId yoursubid -resourceGroupName resourceGroupNameOfYourAppServiceCertificate -name appServiceCertificateName

You can now keep working with the PFX certificate in WSL in Windows or on your favorite Linux Distro in your VM, to extract the cer/crt/key files you will need to utilize within your web server:

openssl pkcs12 -in appservicecertificate.pfx -nocerts -out domain.tld.encrypted.key
(enter a passphrase as prompted)

openssl rsa -in domain.tld.encrypted.key -out domain.tld.key

openssl pkcs12 -in appservicecertificate.pfx -clcerts -nokeys -out domain.tld.crt
This will prompt for the previous password which you received when exporting

openssl pkcs12 -in appservicecertificate.pfx -cacerts -out bundle.crt
This will prompt for the same password and PEM phrase entered in previous steps

To chain your two certs you can perform:
cat domain.tld.crt bundle.crt > domain.tld.chained.crt
You’ll notice if you view/cat the files, that each key will now reside in domain.tld.chained.crt with BEGIN/END sections for each.

From there, you can scp/rsync domain.tld.key and domain.tld.chained.crt to your Apache or Nginx webserver in an appropriate location like: /etc/ssl/private/

Your last step should be to set appropriate configuration within your VM to utilize your certificate. In Apache on Linux, depending on your exact setup this could be:

/etc/apache2/sites-enabled/000-default.conf
Where you would add/change lines:

<VirtualHost *:443>
...
SSLEngine On
SSLCertificateFile       /etc/ssl/private/domain.tld.chained.crt
SSLCertificateKeyFile /etc/ssl/private/domain.tld.key

In Nginx:

SSLEngine on
SSLCertificateFile       /etc/ssl/private/domain.tld.chained.crt
SSLCertficiateKeyFile  /etc/ssl/private/domain.tld.key

Leave a Reply

Your email address will not be published. Required fields are marked *