Certificates are often the best way to secure your application (you can use with everything from App Registrations to Web Services). Here’s everything you need to know to integrate certificates stored in your Azure Key Vault into your application.
In an earlier post, Coding Azure 12: Configuring an Azure Key Vault and Adding Secrets, I described how to set up a Key Vault and store a text “secret” in it. This post is about storing and retrieving certificates from your Key Vault.
There are several reasons that your application might need to retrieve a certificate from a Key Vault. In this post (while covering both how to add a certificate to a Key Vault in the Azure Portal and the code to retrieve credentials in a server-side application), I’m going to look at two specific use cases. Those two cases are using a certificate as credentials required to:
Before showing that, however, it’s worth pointing out that you don’t have to use a Key Vault for an application running in an App Service. You can also store certificates in your App Service’s certificates collection.
An App Service’s certificates collection will let you store certificates that have only public keys (i.e. a *.cer file), certificates with public and private keys (*.pfx, *.per files), and Managed Keys (which are certificates that are automatically renewed for you). However, using the App Service’s certificates collection requires a paid App Service Plan and, since I’m using free services as much as possible in my case study, I won’t take advantage of that feature.
Besides, if I used the App Service’s certificates, I wouldn’t have a reason to discuss retrieving certificates from the Key Vault in an ASP.NET Core 8 application.
One last note: The reason you’re storing confidential data in a Key Vault is to restrict its access to only two things—a Key Vault administrator (who adds the confidential data to the vault) and your application (which retrieves the confidential data at run time). I covered how to restrict your vault access to your application in an earlier post.
Your first step is, of course, to create a certificate. For both of my use cases, I’m creating a certificate that will only be used internally: by my application, my App Registration and my Web Service. On that basis, rather than use a certificate from a signing authority (which would be required if I was accessing an external Web Service), I can use a “self-signed certificate” that you can generate.
You can generate a self-signed certificate in two ways: have the Key Vault generate a certificate for you or upload an existing certificate (which is what you’d have to use if you were working with a certificate from a signing authority).
To have your Key Vault generate a certificate:
It may take a few moments for your certificate to finish generating and to be added. During that time, it will appear in the “In progress, pending, or cancelled” section of your certificate’s list with a status of disabled. You can use the Refresh choice in the menu across the top of the page to update your list while you wait for the process to complete.
After your certificate is generated, you may want to have a local copy of it (if you’re going to use this certificate as credentials for claiming an App Registration, you will need a local copy). To create a copy of your certificate in a file:
Choosing your format: If you only need a certificate with a public key (for example, as credentials for an App Service or Web Service), use the CER format. Use the PFX format if you need a certificate with both a public and a private key (a certificate with a private key should never be shared outside of your organization).
You may also want to add your certificate to your local certificate store, rather than keep it on your hard disk. To save your certificate in your certificate store, first open a Windows command window, then enter certmgr and press the Enter key to open the Certificate Manager dialog.
In the treeview on the left of the Certificate Manager dialog, drill down through the Personal node and right-click on the Certificates node. From the All Tasks menu, select Import to start the Certificate Import Wizard. Work your way through the wizard, using the Browse button on the wizard’s second page to surf to your certificate file and add it to your store.
Rather than create a new certificate, you might choose to add an already existing certificate to your vault. That certificate might be in your certificate store or may just be a file on your hard disk.
Note: To demonstrate working with an existing certificate, I generated a self-signed certificate using the following PowerShell command. If decide to create your own, you might want to change the name in the Subject parameter:
New-SelfSignedCertificate -Subject CN=ServerCredentials `
-CertStoreLocation 'Cert:\CurrentUser\My'
If you want to use a certificate from your certificate store, then you’ll first need to export the certificate from your store. Start by opening a Windows command window then entering certmgr and pressing the Enter key to open the Certificate Manager dialog. In the treeview on the left of the dialog, drill down through the Personal node to Certificates to display a list of certificates already in your store in the pane on the right—your newly created certificate will be listed there (in my case, ServerCredentials).
Next right-click on that certificate and, from the popup menu, select All Tasks | Export to start the certificate manager’s Export wizard. Work through the wizard, including:
To upload a certificate file into your vault (in my case, a file called ServerCredentials.pfx), you’ll need both the certificate file and the password that was used when saving the file. With those in hand, the steps to import the file are:
You’ll be returned to the list of certificates in your vault with your new certificate listed under the list’s Completed heading.
Up until this post, I’ve only required my applications to provide a secret text string to claim an App Registration (along with the permissions that the registration grants). A more secure solution is to require an application to provide a certificate as its credentials for claiming an App Registration. Now that I have a certificate securely stored in a Key Vault (and a vault that only my application is able to access), I’m going to switch my App Registration over to requiring that certificate.
To have an App Registration require a certificate as credentials to claim the registration:
While you’re on this tab, if you previously set up this App Registration to use a secret as credentials then you should probably now open the App Registration’s Secrets tab and delete that secret.
You’re now ready to retrieve an App Registration using a certification. First, you need to add a JSON object named AzureAd to your server-side application’s appsettings.json file with these properties:
"https://login.microsoftonline.com/"
)"/signin-oidc",
Each of the JSON objects in the ClientCertificates array must have these three properties (and you only need one):
"KeyVault"
A typical example would look like this:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "warehousemgmtfrontendaspnet.azurewebsites.net",
"TenantId": "e98…-…-…-…-…a461",
"ClientId":"80e…-…-…-…-…f3b",
"CallbackPath": "/signin-oidc",
"ClientCertificates": [
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://warehousemgmtvault.vault.azure.net/",
"KeyVaultCertificateName": "ServerCredentials"
}
]
},
The code that you need to claim your App Registration and get the access tokens it supplies is the same as what you would use if your application was retrieving an App Registration protected with a text secret (see Coding Azure 9a: Authorizing Your Frontend Client-Side App to Access a Web Service). In your Program.cs file, for example, you need this code to retrieve any access tokens from the registration and add them to an internal cache:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration)
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
And you need this code in your application to retrieve the token:
string accessToken = await tokenAcquisition.GetAccessTokenForAppAsync(
"api://abd…-…-…-…-…a0b6/.default",
tenant: config["AzureAd:TenantId"]);
You might also need to retrieve a certificate for other purposes—for example, to use as the credentials for calling a Web Service.
The first step in retrieving your certificate is to install the Azure.Security.KeyVault.Certificates
NuGet package. With that package installed, you can retrieve your certificate by creating a CertificateClient object, passing a Uri object holding the URL for your Key Vault (available from your Key Vault’s Overview page) and a DefaultAzureCredential object.
Once you’ve created a CertificateClient, you can use its DownloadCertificate method to retrieve an Azure.Response object that has a Value property. That property, in turn, has Cer property which you can turn into an X509Certificate2 using the X509CertificateLoader’s static LoadCertificate property.
Typical code to do all that might look like this:
Uri kvu = new Uri("https://warehousemgmtvault.vault.azure.net/");
CertificateClient cc = new CertificateClient(
kvu,
new DefaultAzureCredential());
Azure.Response<KeyVaultCertificateWithPolicy> ar = cc.GetCertificate("FrontendServerRegCredentialsGenerated");
X509Certificate2 cert = X509CertificateLoader.LoadCertificate(ar.Value.Cer);
logger.LogInformation("Certification subject: " + cert.Subject);
How you use that certificate will vary from one use case to another. For my case study, to use it as credentials with an HttpClient to call a Web Service, you need to first create an HttpClientHandler object. Once you’ve done that, you can add your certificate to the handler’s ClientCertificates collection and then pass the handler to your HttpClient object when you create it. Typical code will look like this:
HttpClientHandler chc = new HttpClientHandler();
chc.ClientCertificates.Add(cert);
HttpClient hc = new HttpClient(chc);
HttpResponseMessage resp = await hc.GetAsync("<Web service URL");
Because Key Vaults are Microsoft’s tool for managing certificates in the cloud, there’s a lot more to say about managing certificates over the life of your application (setting a certificate policy to manage rotating your certificate and notifying parties when certificates need to be rotated, for example).
But, because I’m only interested in what’s required to get your application up and running, I’m moving on to my next topic: Accessing a Key Vault from a client-side app.
Peter Vogel is both the author of the Coding Azure series and the instructor for Coding Azure in the Classroom. Peter’s company provides full-stack development from UX design through object modeling to database design. Peter holds multiple certifications in Azure administration, architecture, development and security and is a Microsoft Certified Trainer.