AZ-204: Developing Solutions for Microsoft Azure
Implementing Azure Key Vault
Authenticating to Azure Key Vault
In this guide, we explore multiple methods to authenticate your application with Azure Key Vault. Azure Key Vault securely stores secrets and keys, making proper authentication essential for managing access. We discuss two primary authentication techniques—managed identities and service principals—and provide detailed code examples utilizing the Azure SDK.
Managed Identities for Azure Resources
The most secure and recommended option for Azure Key Vault authentication is using managed identities. When deploying your application on an Azure service (such as a virtual machine) that supports managed identities, Azure handles the authentication automatically. This approach eliminates the need for storing secrets or credentials in your code, substantially enhancing security.
Managed identities are not limited to Key Vault; they are also compatible with other Azure services that support Microsoft Entra ID.
Service Principal with Certificate or Secret
Another approach is using a service principal. Creating an app registration in Azure Active Directory offers two credential options: certificate or secret.
- Service Principal with Certificate: Create and register a service principal, then generate a certificate for your application to authenticate with Azure Key Vault.
- Service Principal with Secret: Traditionally, a secret is stored in the application for authentication. While this method is common, it is generally less secure compared to managed identities due to the challenges of securely managing secrets in your code.
Authenticating with Code Libraries and APIs
Azure offers SDKs for various programming languages, including .NET, Python, Java, and JavaScript, so you can securely connect to Azure Key Vault using the language of your choice. This flexibility ensures compatibility regardless of your development platform.
For frameworks not covered by these SDKs, the REST API is also available. You can, for example, send a PUT request to the keys endpoint with the required API version and access token to perform operations such as creating or retrieving keys.
PUT /keys/MYKEY?api-version=<api_version> HTTP/1.1
Authorization: Bearer <access_token>
Authenticating from an Azure Function
This section demonstrates how to authenticate to Azure Key Vault from an Azure Function using a service principal with a secret. While using secrets in applications is not best practice, this approach is useful for comparison until transitioning to managed identities.
Before you begin, ensure an app registration is created and the corresponding secret is generated. Additionally, verify that your service principal has the necessary permissions (e.g., the "secret user" role) in the Key Vault.
Below is an example C# Azure Function that retrieves essential environment variables—such as tenant ID, client ID, client secret, Key Vault URL, and secret name—and uses these values to connect to Key Vault, securely retrieving a secret.
using System;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
public static class GetSecretFromKeyVault
{
[FunctionName("GetSecretFromKeyVault")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("# HTTP trigger function processed a request.");
// Retrieve environment variables
string tenantId = Environment.GetEnvironmentVariable("AZURE_TENANT_ID");
string clientId = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID");
string clientSecret = Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET");
string keyVaultUrl = Environment.GetEnvironmentVariable("KEY_VAULT_URL");
string secretName = Environment.GetEnvironmentVariable("SECRET_NAME");
if (string.IsNullOrEmpty(tenantId) || string.IsNullOrEmpty(clientId) ||
string.IsNullOrEmpty(clientSecret) || string.IsNullOrEmpty(keyVaultUrl) ||
string.IsNullOrEmpty(secretName))
{
return new BadRequestObjectResult("Missing one or more environment variables: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, KEY_VAULT_URL, SECRET_NAME");
}
try
{
// Create a client secret credential
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
// Create a Key Vault client
var secretClient = new SecretClient(new Uri(keyVaultUrl), clientSecretCredential);
// Retrieve the secret from the Key Vault
KeyVaultSecret secret = await secretClient.GetSecretAsync(secretName);
// Return the secret value
return new OkObjectResult($"The value of the secret '{secretName}' is: {secret.Value}");
}
catch (Exception ex)
{
log.LogError($"Error retrieving secret: {ex.Message}");
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
}
This function performs the following steps:
- Reads configuration values from environment variables.
- Validates the presence of all necessary variables.
- Creates a client secret credential and a Key Vault client.
- Retrieves the secret using the
GetSecretAsync
method. - Returns the secret value on success or logs an error and returns an HTTP 500 error if something goes wrong.
After deploying the function via Visual Studio Code, test it by accessing the function URL. The output might resemble the following JSON response:
{
"value": [
{
"businessPhones": [],
"displayName": "Audrey Adams",
"givenName": null,
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "[email protected]",
"id": "bd95babe-8bde-4c1a-9cfa-dcceceba495c"
}
]
}
Verifying the secret value stored in Key Vault confirms the successful retrieval:
The value of the secret 'sql-conn-string' is: Data Source=airports;Database=airportcodes;Application Name=app;Integrated Security=false;User ID=sqldadmin;Password=M43djurgb1
Important
Storing sensitive configuration details, such as client secrets and tenant IDs, directly in environment variables is a common practice but not ideal for long-term security. Consider transitioning to managed identities for enhanced security and simplified credential management.
Watch Video
Watch video content