Managed Identities for Azure Resources

Watch the video to deepen your understanding.
SubscribeComplete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
Module: Design Identity, Governance, and Monitoring Solutions
Section: Design Authentication and Authorization Solutions
Lesson Title: Managed Identities for Azure Resources
Introduction: The Challenge of Credential Management
In modern cloud applications, services often need to communicate with each other. For instance, an Azure Web App might need to retrieve secrets from Azure Key Vault, or an Azure Function might need to write data to an Azure Storage account. Traditionally, this communication required developers to manage credentials such as connection strings, API keys, or service principal client secrets.
This approach presents several challenges:
- Security Risks: Storing credentials in configuration files, environment variables, or source control increases the risk of exposure.
- Credential Rotation: Manual rotation of credentials is a tedious and error-prone process, often leading to service downtime if not handled carefully.
- Complexity: Managing unique credentials for every service-to-service interaction becomes complex as applications scale.
- Auditability: Tracing which application used which credential can be difficult.
Managed Identities for Azure Resources solve these problems by providing an automatically managed identity in Azure Active Directory (Azure AD) for Azure services. This identity can then be used to authenticate to any service that supports Azure AD authentication, without storing any credentials in your code or configuration. Azure takes care of managing the lifecycle and rotation of these credentials.
Simply put, Managed Identities allow your Azure resources to authenticate themselves to other Azure resources securely and seamlessly, leveraging Azure AD.
Detailed Explanation: How Managed Identities Work
When you enable a Managed Identity for an Azure resource, Azure automatically creates a service principal in Azure AD for that resource. This service principal is then used to obtain OAuth 2.0 access tokens from Azure AD. Your application code can then use these tokens to authenticate to other Azure services that support Azure AD authentication.
The key benefit is that you don't manage any secrets. Azure handles the provisioning, rotation, and lifecycle of the underlying service principal's credentials.
There are two types of Managed Identities:
1. System-assigned Managed Identities
- Lifecycle: Tied directly to the lifecycle of the Azure resource. When the resource is deleted, the identity is automatically deleted.
- Scope: Each resource has its own unique identity. It cannot be shared with other resources.
- Creation: Enabled directly on the Azure resource itself.
- Use Case: Ideal for scenarios where a single resource needs its own distinct identity to access other Azure services.
Example: An Azure App Service needs to read secrets from an Azure Key Vault. Enabling a system-assigned identity on the App Service grants it a unique identity to perform this task.
2. User-assigned Managed Identities
- Lifecycle: Created as a standalone Azure resource. It has its own lifecycle, independent of any other resource.
- Scope: Can be assigned to multiple Azure resources (e.g., multiple VMs, App Services, Functions).
- Creation: Created as a separate resource and then assigned to other Azure resources.
- Use Case: Useful for scenarios where multiple resources need to share the same identity, or when you need to pre-provision an identity before the dependent resources are created.
Example: A cluster of Azure Kubernetes Service (AKS) nodes all need to access a specific Azure Container Registry. A single user-assigned identity can be created and assigned to all nodes in the cluster.
Practical Examples and Code Snippets
Let's walk through an example of how an Azure Function can use a system-assigned managed identity to access secrets stored in Azure Key Vault.
Scenario: An Azure Function needs to retrieve a connection string from Azure Key Vault to connect to an Azure SQL Database.
Step 1: Create an Azure Function App and Enable System-assigned Managed Identity
You can do this via the Azure Portal, Azure CLI, or ARM/Bicep.
Azure CLI:
# 1. Create a Resource Group
az group create --name myResourceGroup --location eastus
# 2. Create a Storage Account (required by Function App)
az storage account create --name mystorageaccount12345 --location eastus --resource-group myResourceGroup --sku Standard_LRS
# 3. Create a Function App and enable System-assigned Managed Identity
az functionapp create \
--resource-group myResourceGroup \
--consumption-plan-location eastus \
--name myfunctionapp-mi-demo \
--storage-account mystorageaccount12345 \
--runtime dotnet \
--assign-identity # This flag enables system-assigned managed identity
Azure Portal:
- Navigate to your Function App.
- Under "Settings," select "Identity."
- On the "System assigned" tab, set "Status" to "On" and click "Save."
Step 2: Create an Azure Key Vault and Store a Secret
Azure CLI:
# 1. Create an Azure Key Vault
az keyvault create \
--name mykeyvault-mi-demo \
--resource-group myResourceGroup \
--location eastus \
--enabled-for-template-deployment true # Optional, useful for ARM/Bicep deployments
# 2. Store a secret in the Key Vault
az keyvault secret set \
--vault-name mykeyvault-mi-demo \
--name MyDbConnectionString \
--value "Server=tcp:mydatabase.database.windows.net,1433;Initial Catalog=mydb;Persist Security Info=False;User ID=user;Password=password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
Step 3: Grant the Function App's Managed Identity Access to Key Vault
This is the crucial step where you authorize the Function App (via its Managed Identity) to access the Key Vault. We grant the "Key Vault Secret User" role.
Azure CLI:
First, retrieve the Principal ID (Object ID) of the Function App's system-assigned identity:
# Get the Principal ID of the Function App's Managed Identity
FUNCTION_PRINCIPAL_ID=$(az functionapp identity show --name myfunctionapp-mi-demo --resource-group myResourceGroup --query principalId --output tsv)
echo "Function App Principal ID: $FUNCTION_PRINCIPAL_ID"
# Assign the 'Key Vault Secret User' role to the Function App's identity on the Key Vault
az role assignment create \
--role "Key Vault Secret User" \
--assignee $FUNCTION_PRINCIPAL_ID \
--scope /subscriptions/<YOUR_SUBSCRIPTION_ID>/resourceGroups/myResourceGroup/providers/Microsoft.KeyVault/vaults/mykeyvault-mi-demo
Important: Replace <YOUR_SUBSCRIPTION_ID> with your actual Azure subscription ID.
Azure Portal:
- Navigate to your Key Vault.
- Select "Access control (IAM)."
- Click "Add" -> "Add role assignment."
- Search for and select the "Key Vault Secret User" role.
- Under "Members," select "Managed identity," then click "Select members."
- Choose "Function App" for "Managed identity" type.
- Select your Function App (
myfunctionapp-mi-demo). - Click "Select" and then "Review + assign."
Step 4: Write Function App Code to Retrieve the Secret
Now, your Function App code can use the DefaultAzureCredential to automatically pick up the Managed Identity and authenticate to Key Vault. This works for various SDKs (C#, Python, Java, JavaScript).
C# (.NET) Example:
Add the Azure.Security.KeyVault.Secrets and Azure.Identity NuGet packages to your Function App project.
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Azure.Identity; // For DefaultAzureCredential
using Azure.Security.KeyVault.Secrets; // For SecretClient
public static class GetSecretFunction
{
[FunctionName("GetSecret")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string keyVaultUrl = Environment.GetEnvironmentVariable("KEY_VAULT_URL"); // Set this in Function App config
if (string.IsNullOrEmpty(keyVaultUrl))
{
return new BadRequestObjectResult("KEY_VAULT_URL environment variable is not set.");
}
try
{
// Use DefaultAzureCredential, which automatically tries Managed Identity in Azure environment
var client = new SecretClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
KeyVaultSecret secret = await client.GetSecretAsync("MyDbConnectionString");
log.LogInformation($"Successfully retrieved secret: {secret.Name}");
return new OkObjectResult($"Secret 'MyDbConnectionString' value: {secret.Value}");
}
catch (Exception ex)
{
log.LogError($"Error retrieving secret: {ex.Message}");
return new StatusCodeResult(Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError);
}
}
}
Function App Configuration:
You need to set an application setting for KEY_VAULT_URL in your Function App:
Key: KEY_VAULT_URL
Value: https://mykeyvault-mi-demo.vault.azure.net/ (replace with your Key Vault URL)
Now, when the Function App runs, DefaultAzureCredential will detect that it's running on an Azure resource with a Managed Identity, obtain an Azure AD token, and use it to authenticate to Key Vault to retrieve the secret. No connection strings or secrets are stored in the Function App itself!
User-assigned Managed Identity Example (Creation)
Azure CLI:
# 1. Create a User-assigned Managed Identity
az identity create \
--resource-group myResourceGroup \
--name myUserAssignedIdentity
# Output will include the 'id' and 'principalId' of the new identity
# Example:
# {
# "clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
# "id": "/subscriptions/YOUR_SUB_ID/resourceGroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myUserAssignedIdentity",
# "location": "eastus",
# "name": "myUserAssignedIdentity",
# "principalId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
# "resourceGroup": "myResourceGroup",
# "tenantId": "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz",
# "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
# }
You would then use the principalId for role assignments and the full id (resource ID) when assigning it to an Azure resource. For example, to assign it to a Function App:
# Assign the user-assigned identity to the Function App
az functionapp identity assign \
--resource-group myResourceGroup \
--name myfunctionapp-mi-demo \
--identities /subscriptions/<YOUR_SUBSCRIPTION_ID>/resourceGroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myUserAssignedIdentity
Best Practices and Common Pitfalls
Best Practices
- Least Privilege: Always grant Managed Identities only the minimum necessary permissions (roles) to perform their tasks. Do not grant Contributor or Owner roles unless absolutely required and justified.
- Choose the Right Type:
- Use system-assigned for resources that require a unique identity and whose lifecycle is tied to the host resource. Simpler to manage.
- Use user-assigned when multiple resources need to share the same identity, or when the identity needs to be managed independently of the consuming resources (e.g., pre-provisioning).
- Monitoring: Monitor Azure AD audit logs for activities related to Managed Identities to detect any suspicious usage or unauthorized access attempts.
- Secure Environment Variables: While Managed Identities eliminate the need for most secrets, you might still need to store configuration values like Key Vault URLs. Store these securely in application settings/environment variables.
- Use
DefaultAzureCredential: Leverage theDefaultAzureCredentialclass (or its equivalent in other languages) in the
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons