Adopt a secure approach to manage your secrets by using Azure KeyVault,Azure Active Directory and Principals based on Certificates

Secure your Secrets with Azure KeyVault and AAD

A customer of mine is in the process of developing a mission critical distributed app; this app will use Azure ServiceFabric as workflow engine, Azure DocumentDB as data repository, Azure Batch to execute long-running tasks, and Azure Media Encoder to store, encode and deliver video assets to its customer. As this will be a mission critical system, security is paramount and we have to make sure that the system is secure.

Developers like the productivity of the Azure Platform, and now with Azure KeyVault and AAD we can easily secure secrets like DocumentDB, Media Services or Azure Batch keys in Azure KeyVault and apply granular policies to define who can access the secrets.

Traditionally, developers will wither just add those secrets in the config files in plain text (yes, I am afraid that this happens quite often) or store them in a central configuration service that in which we apply some secure policies,this could be an OK approach, but it would normally require security experts and significant amounts of time.

The following diagram shows what secrets we have to secure in this scenario :

Without KeyVault

This approach presents two obvious problems :
1-It is difficult (or impossible) to keep those sensitive settings (DocumentDB, AMS, Azure Batch keys) secure. Potentially we can end up with those settings added into our build pipeline, then added them into all the VM or Azure Services etc. All in all, quite quickly we will struggle to manage the secrets.
2 -Rotating the keys will become almost impossible, as it will be difficult to find what applications are using what secrets. Luckily enough, now with Azure KeyVault and Azure Active Directory we can effectively secure those secrets and apply a consistent security model.


The Solution :

Azure Key Vault helps safeguard cryptographic keys and secrets used by cloud applications and services. By using Key Vault, you can encrypt keys and secrets such as authentication keys, storage account keys, data encryption key and passwords. Those secrets are protected by using keys that are protected by hardware security modules (HSMs). For added assurance, you can import or generate keys in HSMs (keys never leave the HSM boundary). The HSMs are FIPS 140-2 Level 2 validated. This post will show you how you can use Powershell to:
Step 1– Create an Azure KeyVault
Step 2– Create test self-signed Certificates that developers can use during Dev & Test.
Step 3– Create an Azure AD Application and Principal for identifying the applications that need access to KeyVault
Step 4– Add secrets to KeyVault
Step 5– Retrieve those secrets from a .NET application Please note that in this example, we won’t encrypt the secrets that we will store in KeyVault. This can be easily done using the test certificates that we will generate, but we will show this in future posts.

After implementing the five steps , all the applications will authenticate into AAD by using certificates. Once authenticated into AAD, the applications will send the AAD credentials to KeyVault when they are requesting a secret. By doing this, we will keep all the sensitive secrets stored in KeyVault and all the applications will authenticate into AAD by using certificates.
The following diagrams shows the process of getting a secret from KeyVault :

Step 1 – The applications authenticate into AAD by using Certificates

Step 2 – The applications request secrets to KeyVault and they send the Bearer token obtained in Step 1 in the requests. Azure KeyVault will use the Bearer token to authenticate and authorize the application.

Get the Code!

You can download all the Powershell scripts and .NET application covered on this post.

STEP 1 : Create Self-signed certificates

The following Powershell function will create self-signed certificates that developers can use during Dev & Test.
It is important to use a Crypto Provider compatible with Azure KeyVault, that is why we specify Microsoft Enhanced RSA and AES Cryptographic Provider.

The following code snippet shows the SetupCertificates function :


function SetupCertificates()
{
    #Makecert if part of Windows SDK
    #     http://msdn.microsoft.com/en-us/windows/desktop/bg162891.aspx
    #     makecert -sv keyvault.pvk -n "cn=AD Test Vault Application" ADTsestVaultApplication.cer -b 03/03/2014 -e 06/05/2018 -r
    #     pvk2pfx -pvk keyvault.pvk -spc ADTestVaultApplication.cer -pfx ADTestVaultApplication.pfx -po test    
    #Makecert Docs : 
    #   https://msdn.microsoft.com/en-us/library/bfsktky3(v=vs.110).aspx

    #New-SelfSignedCertificate  https://technet.microsoft.com/en-us/library/hh848633.aspx    
    #     CSP Providers Info :    
    #     https://msdn.microsoft.com/en-us/library/windows/desktop/bb931357(v=vs.85).aspx    
    #     List of Available CSPs on your Machine  : HKEY_LOCAL_MACHINESOFTWAREMicrosoftCryptographyDefaultsProvider.

    If (-not (Test-Path $certificateFilePath)){
        $newCer = New-SelfSignedCertificate -CertStoreLocation Cert:CurrentUserMy `
                    -Subject $resourceGroupName -DnsName $resourceGroupName `
                    -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" 
        $newCer |Export-PfxCertificate -FilePath $certificateFilePath -Password  $certificatePassword                 
        $newCer |Export-Certificate -FilePath $cerCertificateFilePath -Type CERT 

        ######## Set up the Certs
        #If this is a self signed cert, then add it to the Trusted People Store.Else skip.
        $importedCer = Import-PfxCertificate -Exportable `
                      -CertStoreLocation Cert:CurrentUserTrustedPeople `
                      -FilePath $certificateFilePath -Password $certificatePassword

        #####import the cert into your local store. this is so that you can use the cert to view the secure cluster 
        $importedCer = Import-PfxCertificate -Exportable `
                        -CertStoreLocation Cert:CurrentUserMy `
                       -FilePath $certificateFilePath -Password $certificatePassword

    }    
    $clusterCertificates = new-object System.Security.Cryptography.X509Certificates.X509Certificate2 `
                                        $certificateFilePath, $certificatePassword
    $clusterCertificates
}

STEP 2 : Create or Get an Azure KeyVault

function GetOrCreateKeyVault
{
     
        if (-not (Get-AzureResourceGroup | ? ResourceGroupName -eq $ResourceGroupName))
        {
            $newResourceGroup = New-AzureResourceGroup -Name $ResourceGroupName `
                                                       -Location $Location -Verbose
        } 
        Register-AzureProvider -ProviderNamespace Microsoft.KeyVault -Force 
     
        if((Get-AzureKeyVault -VaultName $VaultName `
                               -ResourceGroupName $ResourceGroupName `
                               -ErrorAction Ignore) -ne $null)
        {
            $keyVault = Get-AzureKeyVault -VaultName $VaultName `
                                          -ResourceGroupName $ResourceGroupName
             
        }
        else
        {
            Write-Host "Creating vault $VaultName in $location (resource group $ResourceGroupName)"   
            $keyVault = New-AzureKeyVault -VaultName $VaultName `
                                          -ResourceGroupName $ResourceGroupName `
                                          -Location $Location `
                                          -EnabledForDeployment -Verbose  -Sku premium                 
        }        
     
    $keyVault
 
}

}

STEP 3 : Create an Azure AD application and Principal

And Add the Certificate to identify the application (the applications that will try to retrieve the secrets from KeyVault will use the Certificate to authenticate into AAD.
With Set-AzureKeyVaultAccessPolicy we create a policy that will allow the AAD Principal to read secrets from KeyVault.

Each application can be represented by an AAD Principal, and the policies can be applied to specific secrets or to all the secrets; this provides very granular control on who can can access the KeyVault secrets.

function SetAADCertificatesAuth()
{

    #Import-Module MSOnline
    #connect-msolservice

    $cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
    $cer.Import($cerCertificateFilePath)    
    $credValue = [System.Convert]::ToBase64String($cer.GetRawCertData())
    $now = [System.DateTime]::Now
    $expirationDate = $now.AddYears(5)

    $newADApplication =  New-AzureADApplication -DisplayName $applicationName  `
                                                -HomePage "http://$applicationName" `
                                                -IdentifierUris "http://$applicationName" `
                                                -KeyValue $credValue -KeyType "AsymmetricX509Cert" `
                                                -KeyUsage "Verify"

    $newAzureAdPrincipal = New-AzureADServicePrincipal -ApplicationId $newADApplication.ApplicationId 

    # New-MsolServicePrincipalCredential -ObjectId $newAzureAdPrincipal.Id `
    # -Type Asymmetric -Value $credValue -Usage verify    

    # Specify Get privileges to the vault for the application
    Set-AzureKeyVaultAccessPolicy -VaultName $VaultName `
	    -ObjectId $newAzureAdPrincipal.Id `
	    -PermissionsToKeys  get `
	    -PermissionsToSecrets get

}

STEP 4 : Add secrets to KeyVault

In this case, we are just adding a secret that will contain the Azure Media Services account name and Key as a json object.

    $mediaServicesAccountName ="YOURACCOUNTNAME"
    $mediaServicesAccountKey ="YOURACCOUNTKEY"
    $mediaServicesSecret = "{'MediaServicesAccountName': '$mediaServicesAccountName','MediaServicesAccountKey': '$mediaServicesAccountName'}"

    # Add KeyVault Secret
    $securedString = ConvertTo-SecureString -String $mediaServicesSecret -AsPlainText -Force 
    Set-AzureKeyVaultSecret -VaultName $VaultName -Name "AMSAccountSettings" -SecretValue $securedString


STEP 5 : Retrieving secrets in your applications with Microsoft.Azure.KeyVault library

After these steps, your application (for instance a ServiceFabric actor or an Azure Batch Job) can use the certificates to get a Bearer token from Azure AD and use it to get access to KeyVault.

The Project KeyVaultAuthorization is a console app that shows how to get a token and request a secret to Azure KeyVault.
As the secret is a Json object, the console apps deserializes the json.

In order to run the application, you only need to change the app.config and specify the settings obtained in the Powershell script.The secrets are :
1- KeyVaultCertificateThumbprint
2- KeyVaultAuthClientId
3- KeyVaultUrl

Next Steps : o authenticate into AAD

This post is the first post of a series in which we will discuss the end-to-end workflow. During the next posts we will discuss how we can use Certificates in Azure Batch to authenticate into AAD and retrieve secrets from KeyVault…..this is only getting more interesting, remember :)

Adopt a secure approach to manage your secrets since Day 0!

Share this Post