Quote of the Day

more Quotes

Categories

Get notified of new posts

Buy me coffee

  • Home>
  • security>

Three ways of authenticating a Windows virtual machine against Azure Key Vault.

Published April 13, 2019 in .NET core , ASP.NET core , Azure , security - 2 Comments

In this post, I share three ways of gaining a Windows virtual machine access to a key vault. The machine can be an azure virtual machine or a non-azure machine such as your personal computer or a on premise server.

Use azure managed identity

This approach only works if the VM is an azure VM. Essentially, this approach uses the identity of an azure resource which needs access to the azure key vault. Examples of such resource are azure virtual machines, app services, and azure functions. Developers neither have to store any credentials in the codes nor maintain the identity. Azure manages the identity for us as well as abstract away much of the complexity. It only takes a few clicks to turn on identity for a resource. Once the identity setup is in place, the codes are also fairly straightforward.

There are two types of managed identity: system assigned identity and user assigned identity. The main difference between the two types is that a system assigned identity can only associate with the resource on which it is enabled, whereas a user assigned identity can associate with multiple resources.

For more details on setting up a managed identity using azure portal, checkout this documentation. For an example of using managed identity in an ASP.NET core application, checkout this documentation.

Azure managed identity is the recommended approach for authenticating an azure resource against AAD. The setup is also simple and straightforward. I got it working in just a few steps and few lines of codes. Below are the summary of the steps:

var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(
 new KeyVaultClient.AuthenticationCallback(
  azureServiceTokenProvider.KeyVaultTokenCallback));
builder.AddAzureKeyVault(keyVaultURL, keyVaultClient, new DefaultKeyVaultSecretManager());

Pay attention to the version of the Microsoft.Azure.Services.AppAuthentication library. It costed me several hours of sleep trying to debug the error with connecting to the Managed Service Endpoint (MSI) because of using an out of date version of the library. For more information, checkout this thread.

Azure managed identity is great for authenticating an azure resources. However, it’s not applicable for non-azure resources. For instance, you cannot use managed identity to authenticate your on premise VMs. For non azure resources, the alternative is to authenticate using X.509 certificates.

Use X.509 certificates

This approach authenticates a resource using a X.509 certificate which consists of a public/private key pair. You upload the public key (the certificate’s thumbprint) to azure active directory and keep the private portion accessible to the app. The certificate needs to contain the private key. A self-signed certificate would be sufficient as the only purpose is to identify the server when authenticating against azure active directory. Below I show a sample Powershell script to generate a self-signed .PFX certificate file and install to the Personal certificate store.

$date_now = Get-Date
# Set the number of years before the certificate expires. $extended_date = $date_now.AddYears(20)
# DNS name of the host/machine. Ex: MyTestServer $DnsName = "My test server"
# owner of the certificate. $Subject = "CN=myapp,CN=mycompany,DC=com"
# friendly name of the certificate $FriendlyName = "KeyVaultAccess" $cert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\my -DnsName $DnsName -NotAfter $extended_date -Subject $Subject -FriendlyName $FriendlyName

This sample project from Microsoft shows codes that retrieve the certificate at the root of the source code, but for security, you can and should keep the certificate in the certificate store and let the OS manages the certificate. . You can share a certificate among multiple servers, or use a separate certificate for each server you want to grant access. I find using a different certificate for each server provides better security because I don’t need to export the certificate out of the store, which means I don’t have to set the password to protect the certificate.

If you use different certificates for multiple servers, be sure those certificates have a common value such as same distinguished subject or issuer from which you can base the search.

Below I give a summary of the steps to access azure key vault using certificates:

  • Create and generate a self signed, .PFX certificate file and install to the Personal certificate store. See the above sample PowerShell script
  • Export the public key of the certificate. You can use PowerShell script or Microsoft Management Console.
  • Register the application in Azure Active Directory. For instructions, see the documentation.
  • Upload the certificate to the application’s keys.
    • In azure portal, go to your registered application.
    • Go to Settings -> API Access -> Keys.
    • Click on Upload Public Key and browse to the .CER certificate file.
    • Click Save
  • Gain the application access to the key vault using “Access Policy”.
  • In the codes, use the Nuget libraries to authenticate and access key vault, as shown in the below snippets.
// key vault access using certificate (private/public key) 
                using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
                {
                    store.Open(OpenFlags.ReadOnly);
                    var certs = store.Certificates;
                    var distinguishedName = new X500DistinguishedName(configuration["KeyVault:SubjectDistinguishedName"]);
                    var certFound = certs.Find(X509FindType.FindBySubjectDistinguishedName, distinguishedName.Name, false)
                        .OfType<X509Certificate2>();
                    logger.LogDebug("Certificate found: " + certFound.Count());
                    if (certFound.Count() > 0)
                    {
                        builder.AddAzureKeyVault(
                                                keyVaultURL, appId, certFound.Single());
                        store.Close();
                    }
                    else
                    {
                        logger.LogWarning("Unable to find the certificate for authenticating to key vault.");
                    } 
                }

Use app id/secret

This approach is less secure than using certificate or azure managed identity. For this approach, you just register the application in azure active directory and generate a secret. You should only consider this option for testing, or if you absolutely can’t use certificate and/or managed identity. Even then, you should store the secret outside of the source code, such as in the environment variables. See my post on secure app settings.

References

What is managed identities for Azure resources?

Service-to-service authentication to Azure Key Vault using .NET

Adding a system-assigned identity

Azure Key Vault Configuration Provider

Configure managed identities for Azure resources on a VM using the Azure portal

Export-Certificate PowerShell module

Generating self-signed certificates on Windows

2 comments