Azure, C#

Loading a X509 certificate from Azure KeyVault into a .NET Core application

3 min read

In a context where we are now using APIs a lot more than we used to, it becomes important to secure them. One way we can secure them is using the OAUTH/OpenId protocol, which relies on Json Web Tokens (JWTs).  A JWT needs to be generated and digitally signed by the authority (what we call a Security Token Service (STS)) your APIs trust. They require signed JWTs to prevent attackers from altering or counterfeiting such tokens in an attempt to gain unauthorized access to the resources secured by the APIs.

A good open source implementation of such authority is IdentityServer4 which also gives you a lot more features than just being a STS. In development mode, IdentityServer4 provides you with a self-signed token certificate, which is great to get you started very easily.

Once in production, you will want to secure the certificate you use to sign your tokens in a secure place. In Azure, we are fortunate to have Azure KeyVault. In this article, I will show you how you can use Azure KeyVault to retrieve your certificate for token signing so you can use it with IdentityServer4.

As a side note, you can use this technique in another other .NET Core application you wish (and not only ASP.NET Core). Be reminded that managed identity works only when your application is deployed in your Azure cloud.

UPDATE 2021-11-08:
This article uses the old SDKs for Azure. Refer to my post here for the new SDK.

Setup

First, you need to add the following packages to your application

Microsoft.Azure.KeyVault

If you are using Managed Identities (see my post about that here!), add the following package as well

Microsoft.Azure.Services.AppAuthentication
This library makes it easy to fetch access tokens for Service-to-Azure-Service authentication

Uploading your certificate to KeyVault

For this technique to work, you need to upload your certificate. In this example, I will upload a  PKCS #12 (PFX) certificate.

Using the Portal

In your Azure KeyVault resource, under the Certificates blade, click the Generate/Import button. Under Method of Certificate Creation, select import. Select your certificate, give it a name, enter the certificate password and it will be uploaded.
Note: Since we will be using in the SDK the GetSecretAsync method instead of GetCertificateAsync, remember to give your service principal the Get access policy for secrets. If you want to know why we are using GetSecretAsync instead of GetCertificateAsync, in a nutshell, it is because GetCertificateAsync doesn’t return the private key that we need to sign. Refer to the excellent blog post of AzIdentity for a detailed explanation.

Using PowerShell

To upload a certificate in the Certificate portion of the KeyVault, you can use the following PowerShell cmdlet.

Giving your principal the required access policies

As I mentioned above, you need to give your service principal the Get permission for the Secrets.

Wiring it all up

Connecting to your KeyVault

If you are using Managed Identities, you can use the following code to go and fetch your certificate from your KeyVault

This will create a new KeyVault client that will go fetch the access token from your service principal (a.k.a your application) automatically and wire it up all up in the KeyVault client.

If you are using an application (creating an application is out of this scope, but it can be found in the Azure Active Directory resource, under App registrations), you can use the following code to authenticate.

Accessing the certificate

Creating the certificate

If you are using IdentityServer4 you can then add this certificate to the IdentityServerBuilder as such

Things to keep in mind

If you are deploying an ASP.NET Core application to be used with IIS, you will need to make sure to load the user profile otherwise you will get a cryptography exception. If you are using Azure WebApps, you can add the app setting WEBSITE_LOAD_USER_PROFILE  with value 1 to load the user profile. A certificate that has a private key requires user profile and, by default, an Azure WebApp doesn’t create the user profile. This is only supported for Standard App Service plans and above.