Azure Managed Identity Best Practices: Production Patterns for .NET 2025
Azure Managed Identity eliminates the need to manage credentials in your code by providing Azure services with automatically managed identities. For .NET applications, using Managed Identity for service-to-service authentication, Key Vault access, and secure credential management is essential for production deployments.
This comprehensive guide covers Azure Managed Identity best practices for .NET applications, including system-assigned and user-assigned identities, Key Vault integration, service-to-service authentication, and production deployment patterns. You'll learn how to implement Managed Identity, handle identity lifecycle, secure access to resources, and monitor identity usage.
Understanding Managed Identity
What is Managed Identity?
Managed Identity provides:
- No Credentials in Code: Eliminates secrets from application code
- Automatic Rotation: Azure manages credential lifecycle
- Secure by Default: Integrated with Azure RBAC
- Easy Integration: Works with Azure services seamlessly
Types of Managed Identity
1. System-Assigned Identity
- Tied to specific Azure resource
- Created and deleted with resource
- Unique per resource instance
2. User-Assigned Identity
- Standalone Azure resource
- Can be assigned to multiple resources
- Independent lifecycle
Enabling Managed Identity
System-Assigned Identity
Enable for Azure resources:
// Azure Portal:
// App Service > Identity > System assigned > On
// Or via Azure CLI:
az webapp identity assign --name <app-name> --resource-group <rg-name>
// Or via ARM template:
{
"type": "Microsoft.Web/sites",
"identity": {
"type": "SystemAssigned"
}
}
User-Assigned Identity
Create and assign user-assigned identity:
// Create identity
az identity create --name my-identity --resource-group my-rg
// Assign to App Service
az webapp identity assign --name <app-name> --resource-group <rg-name> --identities <identity-resource-id>
Using Managed Identity in .NET
DefaultAzureCredential
Use DefaultAzureCredential for automatic credential chain:
public class ManagedIdentityService
{
private readonly DefaultAzureCredential _credential;
public ManagedIdentityService()
{
_credential = new DefaultAzureCredential(
new DefaultAzureCredentialOptions
{
ExcludeEnvironmentCredential = false,
ExcludeManagedIdentityCredential = false,
ExcludeSharedTokenCacheCredential = true,
ExcludeVisualStudioCredential = false,
ExcludeVisualStudioCodeCredential = true,
ExcludeAzureCliCredential = false,
ExcludeAzurePowerShellCredential = false,
ExcludeInteractiveBrowserCredential = true
});
}
public async Task<string> GetAccessTokenAsync(string resource)
{
var tokenRequestContext = new TokenRequestContext(
new[] { $"{resource}/.default" });
var token = await _credential.GetTokenAsync(tokenRequestContext);
return token.Token;
}
}
Key Vault Integration
Access Key Vault with Managed Identity:
public class KeyVaultService
{
private readonly SecretClient _secretClient;
private readonly DefaultAzureCredential _credential;
public KeyVaultService(string keyVaultUrl)
{
_credential = new DefaultAzureCredential();
_secretClient = new SecretClient(
new Uri(keyVaultUrl),
_credential);
}
public async Task<string> GetSecretAsync(string secretName)
{
try
{
var secret = await _secretClient.GetSecretAsync(secretName);
return secret.Value.Value;
}
catch (RequestFailedException ex) when (ex.Status == 403)
{
throw new UnauthorizedAccessException(
"Managed Identity does not have access to Key Vault", ex);
}
}
public async Task SetSecretAsync(string secretName, string secretValue)
{
await _secretClient.SetSecretAsync(secretName, secretValue);
}
}
Service-to-Service Authentication
Authenticate to other Azure services:
public class ServiceToServiceAuth
{
private readonly DefaultAzureCredential _credential;
public async Task<HttpClient> CreateAuthenticatedClientAsync(string resource)
{
var token = await GetAccessTokenAsync(resource);
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
return client;
}
private async Task<string> GetAccessTokenAsync(string resource)
{
var tokenRequestContext = new TokenRequestContext(
new[] { $"{resource}/.default" });
var token = await _credential.GetTokenAsync(tokenRequestContext);
return token.Token;
}
}
Key Vault Best Practices
Access Policies
Configure Key Vault access:
// Grant Managed Identity access to Key Vault
az keyvault set-policy \
--name <key-vault-name> \
--object-id <managed-identity-object-id> \
--secret-permissions get list
// Or use RBAC
az role assignment create \
--role "Key Vault Secrets User" \
--assignee <managed-identity-object-id> \
--scope /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<kv-name>
Secret Caching
Cache secrets to reduce Key Vault calls:
public class CachedKeyVaultService
{
private readonly SecretClient _secretClient;
private readonly IMemoryCache _cache;
private readonly ILogger<CachedKeyVaultService> _logger;
public async Task<string> GetSecretAsync(
string secretName,
TimeSpan? cacheDuration = null)
{
var cacheKey = $"secret:{secretName}";
if (_cache.TryGetValue(cacheKey, out string cachedSecret))
{
return cachedSecret;
}
var secret = await _secretClient.GetSecretAsync(secretName);
var duration = cacheDuration ?? TimeSpan.FromMinutes(15);
_cache.Set(cacheKey, secret.Value.Value, duration);
return secret.Value.Value;
}
}
Secret Rotation
Handle secret rotation:
public class RotatingSecretService
{
private readonly SecretClient _secretClient;
private readonly IMemoryCache _cache;
public async Task<string> GetSecretWithRotationAsync(string secretName)
{
// Try current version
try
{
var secret = await _secretClient.GetSecretAsync(secretName);
return secret.Value.Value;
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
// Secret rotated, try new version
_cache.Remove($"secret:{secretName}");
var newSecret = await _secretClient.GetSecretAsync(secretName);
return newSecret.Value.Value;
}
}
}
Production Patterns
Identity Lifecycle
Handle identity lifecycle:
public class ManagedIdentityLifecycle
{
public async Task ValidateIdentityAsync()
{
try
{
var credential = new DefaultAzureCredential();
var tokenRequestContext = new TokenRequestContext(
new[] { "https://management.azure.com/.default" });
var token = await credential.GetTokenAsync(tokenRequestContext);
// Identity is valid if we can get a token
return true;
}
catch (CredentialUnavailableException)
{
// Managed Identity not available
return false;
}
}
}
Fallback Strategies
Implement fallback for local development:
public class CredentialProvider
{
public TokenCredential GetCredential()
{
// Try Managed Identity first
try
{
return new DefaultAzureCredential(
new DefaultAzureCredentialOptions
{
ExcludeManagedIdentityCredential = false
});
}
catch
{
// Fallback to local development credentials
return new DefaultAzureCredential(
new DefaultAzureCredentialOptions
{
ExcludeManagedIdentityCredential = true,
ExcludeAzureCliCredential = false,
ExcludeVisualStudioCredential = false
});
}
}
}
Monitoring
Monitor Managed Identity usage:
public class ManagedIdentityMonitor
{
private readonly ILogger<ManagedIdentityMonitor> _logger;
private readonly IMetricsCollector _metrics;
public async Task LogIdentityUsageAsync(
string resource,
bool success,
TimeSpan duration)
{
_metrics.RecordMetric("managed_identity.requests", new Dictionary<string, string>
{
["resource"] = resource,
["success"] = success.ToString()
}, duration.TotalMilliseconds);
if (!success)
{
_logger.LogWarning(
"Managed Identity authentication failed for {Resource}",
resource);
}
}
}
Best Practices
1. Use Managed Identity for All Azure Services
- Key Vault
- Storage Accounts
- Service Bus
- SQL Database
- App Configuration
2. Implement Proper RBAC
Grant minimum required permissions:
# Key Vault Secrets User (read only)
az role assignment create \
--role "Key Vault Secrets User" \
--assignee <identity-id>
# Storage Blob Data Reader
az role assignment create \
--role "Storage Blob Data Reader" \
--assignee <identity-id>
3. Cache Secrets Appropriately
- Cache non-sensitive configuration
- Don't cache highly sensitive secrets
- Use appropriate TTL
- Invalidate on rotation
4. Handle Errors Gracefully
public async Task<string> GetSecretSafelyAsync(string secretName)
{
try
{
return await _keyVaultService.GetSecretAsync(secretName);
}
catch (RequestFailedException ex) when (ex.Status == 403)
{
_logger.LogError("Access denied to Key Vault secret: {SecretName}", secretName);
throw new UnauthorizedAccessException("Key Vault access denied", ex);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
_logger.LogWarning("Secret not found: {SecretName}", secretName);
throw new KeyNotFoundException($"Secret {secretName} not found", ex);
}
}
5. Test Locally
Use Azure CLI or Visual Studio credentials for local testing:
// appsettings.Development.json
{
"Azure": {
"UseManagedIdentity": false,
"UseAzureCli": true
}
}
Advanced Managed Identity Patterns
Multi-Identity Support
Use multiple identities for different purposes:
public class MultiIdentityService
{
private readonly DefaultAzureCredential _defaultCredential;
private readonly ManagedIdentityCredential _specificIdentity;
public MultiIdentityService()
{
_defaultCredential = new DefaultAzureCredential();
_specificIdentity = new ManagedIdentityCredential(
clientId: "specific-identity-client-id");
}
public async Task<string> GetSecretAsync(string vaultName, string secretName)
{
// Use specific identity for Key Vault
var keyVaultClient = new SecretClient(
new Uri($"https://{vaultName}.vault.azure.net/"),
_specificIdentity);
return (await keyVaultClient.GetSecretAsync(secretName)).Value.Value;
}
public async Task<BlobClient> GetBlobClientAsync(string connectionString)
{
// Use default credential chain for Blob Storage
return new BlobClient(
new Uri(connectionString),
_defaultCredential);
}
}
Identity Rotation
Handle identity rotation gracefully:
public class IdentityRotationHandler
{
public async Task RotateIdentityAsync(string resourceId)
{
// Create new user-assigned identity
var newIdentity = await CreateUserAssignedIdentityAsync();
// Assign to resource
await AssignIdentityToResourceAsync(resourceId, newIdentity);
// Wait for propagation
await Task.Delay(TimeSpan.FromMinutes(5));
// Verify new identity works
if (await VerifyIdentityAsync(newIdentity))
{
// Remove old identity
await RemoveOldIdentityAsync(resourceId);
}
}
}
Real-World Scenarios
Scenario 1: Multi-Tenant Application
Handle identities for multiple tenants:
public class MultiTenantIdentityService
{
private readonly Dictionary<string, ManagedIdentityCredential> _tenantIdentities;
public async Task<string> GetTenantSecretAsync(
string tenantId,
string secretName)
{
if (!_tenantIdentities.TryGetValue(tenantId, out var credential))
{
credential = new ManagedIdentityCredential(
clientId: await GetTenantIdentityIdAsync(tenantId));
_tenantIdentities[tenantId] = credential;
}
var keyVaultClient = new SecretClient(
new Uri($"https://{tenantId}-vault.vault.azure.net/"),
credential);
return (await keyVaultClient.GetSecretAsync(secretName)).Value.Value;
}
}
Scenario 2: Cross-Subscription Access
Access resources across subscriptions:
public class CrossSubscriptionIdentityService
{
public async Task AccessCrossSubscriptionResourceAsync(
string subscriptionId,
string resourceGroup,
string resourceName)
{
// Use managed identity with explicit subscription
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
TenantId = await GetTenantIdForSubscriptionAsync(subscriptionId)
});
var resourceClient = new ResourceManagementClient(
new Uri($"https://management.azure.com/"),
credential);
var resource = await resourceClient.Resources.GetAsync(
subscriptionId,
resourceGroup,
resourceName);
return resource;
}
}
Troubleshooting Managed Identity
Common Issues
Issue 1: Identity Not Found
Symptoms:
- 401 Unauthorized errors
- Identity not available
Solution:
public class IdentityTroubleshooter
{
public async Task<IdentityStatus> CheckIdentityStatusAsync(string resourceId)
{
var resource = await GetResourceAsync(resourceId);
return new IdentityStatus
{
HasSystemIdentity = resource.Identity?.PrincipalId != null,
HasUserIdentity = resource.Identity?.UserAssignedIdentities?.Any() == true,
IdentityType = resource.Identity?.Type,
PrincipalId = resource.Identity?.PrincipalId
};
}
public async Task EnableIdentityIfNeededAsync(string resourceId)
{
var status = await CheckIdentityStatusAsync(resourceId);
if (!status.HasSystemIdentity && !status.HasUserIdentity)
{
await EnableSystemIdentityAsync(resourceId);
}
}
}
Issue 2: Insufficient Permissions
Symptoms:
- 403 Forbidden errors
- Access denied
Solution:
public class PermissionValidator
{
public async Task<bool> ValidatePermissionsAsync(
string identityId,
string resourceId,
string permission)
{
var assignments = await GetRoleAssignmentsAsync(identityId);
return assignments.Any(a =>
a.Scope == resourceId &&
a.RoleDefinitionName == permission);
}
public async Task GrantPermissionAsync(
string identityId,
string resourceId,
string roleName)
{
if (!await ValidatePermissionsAsync(identityId, resourceId, roleName))
{
await AssignRoleAsync(identityId, resourceId, roleName);
}
}
}
Performance Optimization
Credential Caching
Cache credentials to reduce calls:
public class CachedCredentialProvider
{
private readonly IMemoryCache _cache;
private readonly DefaultAzureCredential _credential;
public async Task<string> GetAccessTokenAsync(string scope)
{
var cacheKey = $"token:{scope}";
if (_cache.TryGetValue(cacheKey, out string cachedToken))
{
return cachedToken;
}
var token = await _credential.GetTokenAsync(
new TokenRequestContext(new[] { scope }));
_cache.Set(cacheKey, token.Token,
TimeSpan.FromSeconds(token.ExpiresOn.ToUnixTimeSeconds() -
DateTimeOffset.UtcNow.ToUnixTimeSeconds() - 300)); // 5 min buffer
return token.Token;
}
}
Batch Operations
Process multiple identity operations:
public class BatchIdentityOperations
{
public async Task<List<IdentityResult>> EnableIdentitiesBatchAsync(
List<string> resourceIds)
{
var tasks = resourceIds.Select(id => EnableIdentityAsync(id));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
private async Task<IdentityResult> EnableIdentityAsync(string resourceId)
{
try
{
await EnableSystemIdentityAsync(resourceId);
return new IdentityResult
{
ResourceId = resourceId,
Success = true
};
}
catch (Exception ex)
{
return new IdentityResult
{
ResourceId = resourceId,
Success = false,
Error = ex.Message
};
}
}
}
Extended FAQ
Q: How do I test managed identity locally?
A: Use Azure CLI or Visual Studio:
// Azure CLI automatically provides credentials
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
ExcludeVisualStudioCodeCredential = false,
ExcludeVisualStudioCredential = false,
ExcludeAzureCliCredential = false
});
Q: Can I use managed identity with on-premises resources?
A: Yes, use Azure Arc:
// Enable Azure Arc on on-premises server
// Then use managed identity as normal
var credential = new DefaultAzureCredential();
Q: How do I rotate managed identity credentials?
A: Azure handles rotation automatically, but you can force refresh:
public async Task RefreshIdentityTokenAsync()
{
var credential = new DefaultAzureCredential();
// Force new token
var token = await credential.GetTokenAsync(
new TokenRequestContext(new[] { "https://management.azure.com/.default" }),
CancellationToken.None);
}
Case Studies
Case Study 1: Enterprise Key Vault Integration
Challenge: A large enterprise needed to access 50+ Key Vaults from 100+ applications.
Solution: Implemented centralized identity management:
public class EnterpriseKeyVaultService
{
private readonly Dictionary<string, SecretClient> _vaultClients;
private readonly IMemoryCache _cache;
public async Task<string> GetSecretAsync(
string vaultName,
string secretName)
{
var cacheKey = $"secret:{vaultName}:{secretName}";
if (_cache.TryGetValue(cacheKey, out string cached))
{
return cached;
}
var client = await GetVaultClientAsync(vaultName);
var secret = await client.GetSecretAsync(secretName);
_cache.Set(cacheKey, secret.Value.Value, TimeSpan.FromHours(1));
return secret.Value.Value;
}
private async Task<SecretClient> GetVaultClientAsync(string vaultName)
{
if (!_vaultClients.TryGetValue(vaultName, out var client))
{
var credential = new DefaultAzureCredential();
client = new SecretClient(
new Uri($"https://{vaultName}.vault.azure.net/"),
credential);
_vaultClients[vaultName] = client;
}
return client;
}
}
Results:
- 100% credential-free applications
- 90% reduction in credential management overhead
- Zero credential-related security incidents
Migration Guide
Migrating from Connection Strings
Step 1: Identify connection strings:
public class ConnectionStringAuditor
{
public async Task<List<ConnectionStringUsage>> AuditConnectionStringsAsync()
{
var usages = new List<ConnectionStringUsage>();
// Scan codebase for connection strings
var connectionStrings = await ScanForConnectionStringsAsync();
foreach (var connStr in connectionStrings)
{
usages.Add(new ConnectionStringUsage
{
Location = connStr.Location,
Service = DetermineService(connStr.Value),
CanMigrate = CanMigrateToManagedIdentity(connStr.Value)
});
}
return usages;
}
}
Step 2: Migrate to managed identity:
public async Task MigrateToManagedIdentityAsync(ConnectionStringUsage usage)
{
// Enable managed identity
await EnableManagedIdentityAsync(usage.ResourceId);
// Update code to use DefaultAzureCredential
await UpdateCodeAsync(usage.Location, usage.Service);
// Remove connection string from configuration
await RemoveConnectionStringAsync(usage.Location);
// Test migration
await TestMigrationAsync(usage);
}
Conclusion
Azure Managed Identity provides secure, credential-free authentication for .NET applications. By following best practices for Key Vault integration, service-to-service authentication, and production deployment, you can eliminate credential management overhead while maintaining security.
Key Takeaways:
- Use Managed Identity for all Azure service authentication
- Integrate with Key Vault for secret management
- Implement caching to reduce Key Vault calls
- Handle errors gracefully with proper fallbacks
- Monitor identity usage for security and performance
- Test locally with Azure CLI credentials
- Multi-identity support for complex scenarios
- Identity rotation for security
- Performance optimization with caching
- Migration planning from connection strings
Next Steps:
- Enable Managed Identity on your resources
- Configure Key Vault access
- Implement credential providers
- Set up monitoring
- Test in production
- Plan migration from connection strings
- Optimize performance
Managed Identity Best Practices
Implementation Checklist
- Enable managed identity on resources
- Configure Key Vault access policies
- Implement credential providers
- Set up credential caching
- Configure error handling
- Enable monitoring
- Test locally with Azure CLI
- Document identity usage
- Review permissions regularly
- Plan for identity rotation
Production Readiness
Before deploying with managed identity:
- Verify all identities are enabled
- Test Key Vault access
- Verify credential providers work
- Test fallback mechanisms
- Set up monitoring and alerting
- Document identity procedures
- Review security settings
- Conduct security audit
Additional Resources
Managed Identity Documentation
- Azure Managed Identity overview
- System-assigned identity guide
- User-assigned identity guide
- Key Vault integration
Related Topics
- Azure Key Vault
- Service-to-service authentication
- Azure RBAC
- DefaultAzureCredential
Managed Identity Implementation Guide
Step-by-Step Setup
-
Enable Managed Identity
- Enable on App Service
- Enable on Function App
- Enable on VM
- Enable on Container Instance
-
Configure Key Vault Access
- Grant Key Vault access
- Set access policies
- Configure secrets
- Test access
-
Implement Credential Providers
- Use DefaultAzureCredential
- Configure credential chain
- Handle credential errors
- Test locally
-
Set Up Monitoring
- Track identity usage
- Monitor Key Vault calls
- Alert on failures
- Generate reports
-
Test and Deploy
- Test in staging
- Verify all scenarios
- Deploy to production
- Monitor continuously
Managed Identity Patterns
Key Vault Integration
Integrate with Key Vault:
public class KeyVaultService
{
private readonly SecretClient _client;
public KeyVaultService()
{
var credential = new DefaultAzureCredential();
_client = new SecretClient(
new Uri("https://myvault.vault.azure.net/"),
credential);
}
public async Task<string> GetSecretAsync(string secretName)
{
var secret = await _client.GetSecretAsync(secretName);
return secret.Value.Value;
}
}
Service-to-Service Authentication
Authenticate to Azure services:
public class AzureServiceClient
{
private readonly DefaultAzureCredential _credential;
public AzureServiceClient()
{
_credential = new DefaultAzureCredential();
}
public async Task<BlobClient> GetBlobClientAsync(string connectionString)
{
return new BlobClient(
new Uri(connectionString),
_credential);
}
}
Managed Identity Advanced Patterns
Credential Chain Configuration
Configure credential chain:
public class CredentialChainConfig
{
public static DefaultAzureCredential CreateCredentialChain()
{
return new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
ExcludeEnvironmentCredential = false,
ExcludeManagedIdentityCredential = false,
ExcludeVisualStudioCodeCredential = true,
ExcludeVisualStudioCredential = true,
ExcludeAzureCliCredential = false,
ExcludeAzurePowerShellCredential = false,
ExcludeInteractiveBrowserCredential = true
});
}
}
Identity Lifecycle Management
Manage identity lifecycle:
public class IdentityLifecycleManager
{
public async Task ManageIdentityLifecycleAsync(string resourceId)
{
// Check identity status
var status = await CheckIdentityStatusAsync(resourceId);
// Enable if needed
if (!status.HasIdentity)
{
await EnableIdentityAsync(resourceId);
}
// Rotate if needed
if (ShouldRotateIdentity(status))
{
await RotateIdentityAsync(resourceId);
}
// Monitor usage
await MonitorIdentityUsageAsync(resourceId);
}
}
Managed Identity Monitoring
Identity Usage Monitoring
Monitor identity usage:
public class IdentityUsageMonitor
{
public async Task<UsageReport> GetUsageReportAsync(string identityId, TimeSpan period)
{
var usage = await GetIdentityUsageAsync(identityId, period);
return new UsageReport
{
IdentityId = identityId,
TotalRequests = usage.Count,
SuccessfulRequests = usage.Count(u => u.Success),
FailedRequests = usage.Count(u => !u.Success),
AverageLatency = usage.Average(u => u.Latency),
TopResources = GetTopResources(usage)
};
}
}
Identity Health Monitoring
Monitor identity health:
public class IdentityHealthMonitor
{
public async Task<HealthStatus> CheckIdentityHealthAsync(string identityId)
{
var recentUsage = await GetRecentUsageAsync(identityId, TimeSpan.FromMinutes(5));
var health = new HealthStatus
{
IdentityId = identityId,
IsHealthy = recentUsage.All(u => u.Success),
ErrorRate = (double)recentUsage.Count(u => !u.Success) / recentUsage.Count,
LastSuccessfulRequest = recentUsage.LastOrDefault(u => u.Success)?.Timestamp,
LastFailedRequest = recentUsage.LastOrDefault(u => !u.Success)?.Timestamp
};
if (!health.IsHealthy)
{
await AlertOnHealthIssueAsync(health);
}
return health;
}
}
Managed Identity Troubleshooting
Common Issues and Solutions
Troubleshoot common identity issues:
public class IdentityTroubleshooter
{
public async Task<TroubleshootingResult> TroubleshootAsync(string resourceId)
{
var issues = new List<Issue>();
// Check if identity is enabled
var identityStatus = await CheckIdentityStatusAsync(resourceId);
if (!identityStatus.HasIdentity)
{
issues.Add(new Issue
{
Type = IssueType.IdentityNotEnabled,
Severity = Severity.High,
Solution = "Enable managed identity on the resource"
});
}
// Check permissions
var permissions = await CheckPermissionsAsync(resourceId);
if (!permissions.HasRequiredPermissions)
{
issues.Add(new Issue
{
Type = IssueType.InsufficientPermissions,
Severity = Severity.High,
Solution = "Grant required permissions to the identity"
});
}
// Check Key Vault access
var keyVaultAccess = await CheckKeyVaultAccessAsync(resourceId);
if (!keyVaultAccess.HasAccess)
{
issues.Add(new Issue
{
Type = IssueType.KeyVaultAccessDenied,
Severity = Severity.Medium,
Solution = "Configure Key Vault access policy for the identity"
});
}
return new TroubleshootingResult
{
ResourceId = resourceId,
Issues = issues,
Recommendations = GenerateRecommendations(issues)
};
}
}
Managed Identity Best Practices Summary
Implementation Checklist
- Enable managed identity on resources
- Configure Key Vault access policies
- Implement credential providers
- Set up credential caching
- Configure error handling
- Enable monitoring
- Test locally with Azure CLI
- Document identity usage
- Review permissions regularly
- Plan for identity rotation
Production Deployment
Before deploying with managed identity:
- Verify all identities are enabled
- Test Key Vault access
- Verify credential providers work
- Test fallback mechanisms
- Set up monitoring and alerting
- Document identity procedures
- Review security settings
- Conduct security audit
Managed Identity Troubleshooting Summary
Common Issues and Solutions
Issue 1: Identity Not Enabled
- Solution: Enable managed identity on the resource
- Verification: Check identity status via Azure portal or API
Issue 2: Insufficient Permissions
- Solution: Grant required permissions to the identity
- Verification: Check role assignments
Issue 3: Key Vault Access Denied
- Solution: Configure Key Vault access policy
- Verification: Test Key Vault access
Issue 4: Credential Chain Failure
- Solution: Check credential chain configuration
- Verification: Test each credential source
Managed Identity Advanced Scenarios
Cross-Subscription Access
Access resources across subscriptions:
public class CrossSubscriptionAccess
{
public async Task AccessCrossSubscriptionAsync(
string subscriptionId,
string resourceId)
{
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
TenantId = await GetTenantIdForSubscriptionAsync(subscriptionId)
});
var resourceClient = new ResourceManagementClient(credential);
var resource = await resourceClient.Resources.GetAsync(
subscriptionId,
resourceId);
return resource;
}
}
Multi-Resource Identity
Use single identity for multiple resources:
public class MultiResourceIdentity
{
private readonly DefaultAzureCredential _credential;
public MultiResourceIdentity()
{
_credential = new DefaultAzureCredential();
}
public async Task<string> GetKeyVaultSecretAsync(string vaultName, string secretName)
{
var keyVaultClient = new SecretClient(
new Uri($"https://{vaultName}.vault.azure.net/"),
_credential);
return (await keyVaultClient.GetSecretAsync(secretName)).Value.Value;
}
public async Task<BlobClient> GetBlobClientAsync(string connectionString)
{
return new BlobClient(
new Uri(connectionString),
_credential);
}
}
Managed Identity Monitoring
Identity Usage Monitoring
Monitor identity usage:
public class IdentityUsageMonitor
{
public async Task<IdentityUsageReport> GetIdentityUsageAsync(
string identityId,
TimeSpan period)
{
var usage = await GetIdentityUsageDataAsync(identityId, period);
return new IdentityUsageReport
{
IdentityId = identityId,
Period = period,
TotalRequests = usage.Sum(u => u.RequestCount),
SuccessfulRequests = usage.Count(u => u.Success),
FailedRequests = usage.Count(u => !u.Success),
ResourcesAccessed = usage.Select(u => u.ResourceId).Distinct().Count()
};
}
}
Identity Health Monitoring
Monitor identity health:
public class IdentityHealthMonitor
{
public async Task<HealthStatus> GetIdentityHealthAsync(string identityId)
{
var health = new HealthStatus
{
IdentityId = identityId,
Status = HealthStatus.Healthy
};
// Check credential validity
var credentialHealth = await CheckCredentialValidityAsync(identityId);
if (!credentialHealth.IsValid)
{
health.Status = HealthStatus.Unhealthy;
health.Issues.Add("Invalid credentials");
}
// Check permissions
var permissionHealth = await CheckPermissionsAsync(identityId);
if (!permissionHealth.IsValid)
{
health.Status = HealthStatus.Degraded;
health.Warnings.Add("Permission issues");
}
return health;
}
}
Managed Identity Best Practices Summary
Key Takeaways
- Use Managed Identity When Possible: Eliminates credential management overhead
- Follow Least Privilege: Grant only necessary permissions
- Monitor Identity Usage: Track identity access patterns and usage
- Implement Proper Error Handling: Handle credential acquisition failures gracefully
- Test Identity Access: Verify identity permissions before production deployment
Security Best Practices
- Use managed identity instead of connection strings
- Implement least privilege access model
- Monitor identity usage for anomalies
- Rotate credentials when necessary
- Document identity permissions and usage
Common Pitfalls to Avoid
- Not using managed identity when available
- Over-provisioning identity permissions
- Not monitoring identity usage
- Failing to handle credential acquisition errors
- Not testing identity access before deployment
Managed Identity Implementation Checklist
Pre-Implementation
- Identify resources that need managed identity
- Plan identity permissions
- Design credential acquisition strategy
- Plan error handling
- Design monitoring and logging
Implementation
- Enable managed identity on resources
- Grant necessary permissions
- Implement credential acquisition
- Add error handling
- Add monitoring and logging
Post-Implementation
- Monitor identity usage
- Review and audit permissions
- Optimize credential caching
- Update documentation
- Train team on managed identity
For more Azure guidance, explore our Azure Service Bus patterns or Enterprise Service Bus Patterns.