Guide: Setup Key Vault using Azure AD Application and Certificates

In a previous post we have discussed options for setting up an Azure Key Vault. Let’s move to next logical topic, how to access Azure Key Vault securely from client applications.

To access Azure Key Vault securely, you can opt for either of the following options.

There are some advantages that I see for using Certificate over Client Secret. I would do a detail blog post in future regarding the subject. However, these are some key points,

  • Client Secret is like a strong password and application would require employing adequate measures to store it safely for first-time use. While Certificates can be persisted securely in Local or Server Certificate Store, engineering efforts would be less with Certificate and it would be more secure.
  • It is easy to revoke X509 Certificate in the event of security breach or compromise, and existing Security Orchestration configuration with CA or Certificate Provider could beneficial. Client Secret would require additional configuration and efforts to achieve a similar level of orchestration.
  • Certificate reduce Attack Surface Area than Client Secret due to limited redundancy if implemented correctly.
  • Certificates simplify DevOps requirement, where CD/CI pipeline can generate or renew and delegate grunt job to Certificate Authority or Certificate Management would propagate the change throughout a cluster of machines.
  • In a Hybrid Network or Multi-Tenant System scenario, certificates can be associated with Local AD and Groups. This would allow to localise Security Orchestration and minimise the scope. This is the very useful solution for B2C and B2B integrations.

Authenticate with Certificate to Azure Key Vault

Azure AD Application authenticates to Key Vault by using a Client Id and an X509 Certificate instead of Client Secret.

  1. Create or Get a Certificate
  2. Configure Azure AD and Associate the Certificate
  3. Access Azure Key Vault from .NET Client using X509 Certificate

Create or Get a Certificate

Here are couple of options available to you,

  • Create self-signed X509 Certificate.
  • Obtain X509 Certificate from CA or Certification Management.
  • Obtain Certificate from Managed PKI.
    • Microsoft Azure Key Vault supports DigiCert, GlobalSign and WoSign.
    • You can still use other Managed PKI but they would require additional engineering and security efforts.
    • The scenario has limited impact in this context.

Referance 

Azure Key Vault and Managed PKI

Azure Key Vault supports enrollment of certificates from Public CA such as DigiCert, GlobalSign and WoSign. Azure Key Vault goes on behalf of the user to enroll for certificates from one of the above issuers.

I would simply demonstrate, how to create a self-signed .pfx certificate.

/* use developer command prompt if you see `command not found` errors */

makecert -sv nilayblogkey.pvk -n "cn=NPBlogKVApp" nilayblogkey.cer -b 02/04/2017 -e 02/04/2018 -r
pvk2pfx -pvk nilayblogkey.pvk -spc nilayblogkey.cer -pfx nilayblogkey.pfx -po password123

Or alternatively, you can use trustico self-signed online tool  or getaCert’s free service  to create self-signed certificate.

There are various certificate types,

  • .cer contains the Public Key and usually distributed outside.
  • .pvk contains the Private key and securely stored.
  • .pfx contains the All Keys and certificate chains and it should always be passphrase(password) protected.

Configure Azure AD and Associate the Certificate

I have used PowerShell and Azure PowerShell cmdlets to configure and associate the certificate with Azure AD Application. If you are not familiarised with PowerShell cmdlets, then I would recommend you Get started with Azure PowerShell cmdlets  .

The below command would create an X509Certificate2 instance and import newly created key.

Note: Azure Key Vault REST API interface would require Base64 encoding.

$x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$x509Cert.Import("D:\nilayblogkey.cer")
$credValue = [System.Convert]::ToBase64String($x509Cert.GetRawCertData())

Assign correct certificate date to PowerShell variable to use in future. $startYear and $endYear should match the X508Certificate dates.

$startDate = [Datetime]"02/04/2017"
$endDate = [Datetime]"02/04/2018"

Login to your Azure Subscription first, replace 00000000-0000-0000-0000-000000000000 with your Azure SubscriptionId.

Login-AzureRmAccount -SubscriptionId 00000000-0000-0000-0000-000000000000

After importing the certificate and casting Certificate Data to Base64, you are ready to create your Azure Resource Manager AD Application (AzureRMAdApplication) and Service Principal (AzureRmADServicePrincipal).

$azureRmADApplication = New-AzureRmADApplication -DisplayName "KeyVault Reader - Cert" -HomePage "<a href="http://npblogkvapp/">http://NPBlogKVApp</a>" -IdentifierUris "<a href="http://npblogkvapp/">http://NPBlogKVApp</a>" -CertValue $credValue -StartDate $startDate -EndDate $endDate
$azureRmADServicePrincipal = New-AzureRmADServicePrincipal -ApplicationId $azureRmADApplication.ApplicationId

Now, you can associate Azure Resource Manager Service Principal to Key Vault instance. Replace the values for -ValutName and -ResourceGroupName. For demonstration, I have assigned -PermissionsToSecrets to all, you should assign access as needed.

Set-AzureRmKeyVaultAccessPolicy -VaultName '***********' -ServicePrincipalName $azureRmADServicePrincipal.ServicePrincipalName -PermissionsToSecrets all -ResourceGroupName '***********'

That is it; you have successfully configured Azure Resource Manager Application and Service Principal for an Azure Key Vault. You can verify in Azure Portal.

Access Azure Key Vault from .NET Client using X509 Certificate

You can use Authenticate by assertion X509 Certificate, the code is lift and shift from SimplifiedAzure.KeyVault, you can find source at Github/SimplifiedAzure.KeyVault  or install from NuGet. To keep track of the progress, please follow or subscribe to my Github repository or profile.

https://github.com/nilayparikh/SimplifiedAzure

Note: The library is not matured yet for production use. Work in progress with Documentation and Key Vault Patterns & Practices. I would release soon to public domain.

#region copyright
/*
Copyright (c) 2017 Nilay Parikh
Modifications Copyright (c) 2017 Nilay Parikh
B: <a href="https://blog.nilayparikh.com/">https://blog.nilayparikh.com</a> E: [email protected] G: <a href="https://github.com/nilayparikh/">https://github.com/nilayparikh/</a>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.  If not, see <<a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.
*/
#endregion

/// <summary>
/// Constructor
/// </summary>
/// <param name="clientId">Client Id</param>
/// <param name="certificate">X509Certificate Certificate to Authenticate</param>
public Client(string clientId, X509Certificate2 certificate)
{
    var assertionCert = new ClientAssertionCertificate(clientId, certificate);
    KeyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(
           (authority, resource, scope) => GetAccessToken(authority, resource, scope, assertionCert)),
           new HttpMessageHandler());
}

/// <summary>
/// Gets the access token
/// </summary>
/// <param name="authority"> Authority </param>
/// <param name="resource"> Resource </param>
/// <param name="scope"> scope </param>
/// <param name="assertionCert"></param>
/// <returns> token </returns>
private async Task<string> GetAccessToken(string authority, string resource, string scope, ClientAssertionCertificate assertionCert)
{
    var context = new AuthenticationContext(authority, TokenCache.DefaultShared);
    var result = await context.AcquireTokenAsync(resource, assertionCert).ConfigureAwait(false);

    return result.AccessToken;
}

You can use Local or Current User certificate store to persist your X509 Certificate securely. Using certificate thumbprint, you can search and retrieve the X509 Certificate on demand from a local store. I would recommend Local Machine and Current User Certificate Stores  reading.

Disclaimer

The views expressed on this site are personal opinions only and have no affiliation. See full disclaimerterms & conditions, and privacy policy. No obligations assumed.