Fingent-Azure-KeyVault
1.0.1
dotnet add package Fingent-Azure-KeyVault --version 1.0.1
NuGet\Install-Package Fingent-Azure-KeyVault -Version 1.0.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Fingent-Azure-KeyVault" Version="1.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fingent-Azure-KeyVault" Version="1.0.1" />
<PackageReference Include="Fingent-Azure-KeyVault" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Fingent-Azure-KeyVault --version 1.0.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Fingent-Azure-KeyVault, 1.0.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Fingent-Azure-KeyVault@1.0.1
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Fingent-Azure-KeyVault&version=1.0.1
#tool nuget:?package=Fingent-Azure-KeyVault&version=1.0.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Fingent Azure Key Vault
A simple and developer-friendly helper library for managing secrets, keys, and certificates in Azure Key Vault. Makes it easy to securely retrieve and manage sensitive configuration values in .NET applications, with built-in integration for ASP.NET Core.
?? Features
- Secret Management: Secure retrieval and storage of application secrets
- Key Management: Cryptographic key operations and management
- Certificate Management: SSL/TLS certificate handling and rotation
- Configuration Integration: Seamless ASP.NET Core configuration provider
- Caching Support: Optional caching for improved performance
- Managed Identity: Support for Azure Managed Identity authentication
- Multiple Authentication: Service Principal, Connection String, and DefaultAzureCredential
- Error Handling: Comprehensive error handling and retry policies
?? Installation
dotnet add package Fingent-Azure-KeyVault
?? Dependencies
- .NET 8.0
- Azure.Identity 1.12.0
- Azure.Security.KeyVault.Secrets 4.6.0
- Microsoft.Extensions.Logging.Abstractions 8.0.1
- Microsoft.Extensions.Options 8.0.2
?? Usage
Basic Setup
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add Azure Key Vault configuration
builder.Configuration.AddAzureKeyVault(
vaultUri: new Uri("https://your-keyvault.vault.azure.net/"),
credential: new DefaultAzureCredential());
// Add Key Vault services
builder.Services.AddAzureKeyVault(options =>
{
options.VaultUri = "https://your-keyvault.vault.azure.net/";
options.EnableCaching = true;
options.CacheExpiryMinutes = 30;
});
var app = builder.Build();
Configuration
{
"AzureKeyVault": {
"VaultUri": "https://your-keyvault.vault.azure.net/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret",
"EnableCaching": true,
"CacheExpiryMinutes": 30,
"RetryAttempts": 3
}
}
Secret Management
public class ConfigurationService
{
private readonly IAzureKeyVaultService _keyVaultService;
private readonly ILogger<ConfigurationService> _logger;
public ConfigurationService(IAzureKeyVaultService keyVaultService, ILogger<ConfigurationService> logger)
{
_keyVaultService = keyVaultService;
_logger = logger;
}
public async Task<string> GetDatabaseConnectionStringAsync()
{
try
{
var connectionString = await _keyVaultService.GetSecretAsync("database-connection-string");
_logger.LogInformation("Database connection string retrieved from Key Vault");
return connectionString;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to retrieve database connection string from Key Vault");
throw;
}
}
public async Task<string> GetApiKeyAsync(string serviceName)
{
var secretName = $"{serviceName}-api-key";
return await _keyVaultService.GetSecretAsync(secretName);
}
public async Task SetSecretAsync(string secretName, string secretValue)
{
await _keyVaultService.SetSecretAsync(secretName, secretValue);
_logger.LogInformation("Secret {SecretName} updated in Key Vault", secretName);
}
}
Advanced Secret Operations
public class AdvancedSecretService
{
private readonly IAzureKeyVaultService _keyVaultService;
private readonly ILogger<AdvancedSecretService> _logger;
public AdvancedSecretService(IAzureKeyVaultService keyVaultService, ILogger<AdvancedSecretService> logger)
{
_keyVaultService = keyVaultService;
_logger = logger;
}
public async Task<SecretBundle> GetSecretWithMetadataAsync(string secretName)
{
var secret = await _keyVaultService.GetSecretWithPropertiesAsync(secretName);
return new SecretBundle
{
Name = secret.Name,
Value = secret.Value,
Version = secret.Properties.Version,
CreatedOn = secret.Properties.CreatedOn,
UpdatedOn = secret.Properties.UpdatedOn,
ExpiresOn = secret.Properties.ExpiresOn,
Tags = secret.Properties.Tags
};
}
public async Task<List<SecretInfo>> ListAllSecretsAsync()
{
var secrets = new List<SecretInfo>();
await foreach (var secretProperty in _keyVaultService.GetSecretsAsync())
{
secrets.Add(new SecretInfo
{
Name = secretProperty.Name,
Version = secretProperty.Version,
CreatedOn = secretProperty.CreatedOn,
UpdatedOn = secretProperty.UpdatedOn,
Enabled = secretProperty.Enabled ?? true,
Tags = secretProperty.Tags
});
}
return secrets;
}
public async Task<List<string>> GetSecretVersionsAsync(string secretName)
{
var versions = new List<string>();
await foreach (var version in _keyVaultService.GetSecretVersionsAsync(secretName))
{
versions.Add(version.Version);
}
return versions;
}
public async Task DeleteSecretAsync(string secretName)
{
await _keyVaultService.StartDeleteSecretAsync(secretName);
_logger.LogInformation("Secret {SecretName} deletion initiated", secretName);
}
public async Task BackupAndRestoreSecretAsync(string secretName, string backupSecretName)
{
// Get the original secret
var originalSecret = await _keyVaultService.GetSecretAsync(secretName);
// Create a backup with timestamp
var backupName = $"{backupSecretName}-backup-{DateTime.UtcNow:yyyyMMddHHmmss}";
await _keyVaultService.SetSecretAsync(backupName, originalSecret, new Dictionary<string, string>
{
{ "backup-of", secretName },
{ "backup-date", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") }
});
_logger.LogInformation("Secret {SecretName} backed up as {BackupName}", secretName, backupName);
}
}
Batch Operations
public class BatchSecretService
{
private readonly IAzureKeyVaultService _keyVaultService;
private readonly ILogger<BatchSecretService> _logger;
public BatchSecretService(IAzureKeyVaultService keyVaultService, ILogger<BatchSecretService> logger)
{
_keyVaultService = keyVaultService;
_logger = logger;
}
public async Task<Dictionary<string, string>> GetMultipleSecretsAsync(IEnumerable<string> secretNames)
{
var secrets = new Dictionary<string, string>();
var tasks = secretNames.Select(async name =>
{
try
{
var value = await _keyVaultService.GetSecretAsync(name);
return new { Name = name, Value = value, Success = true };
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to retrieve secret: {SecretName}", name);
return new { Name = name, Value = (string)null, Success = false };
}
});
var results = await Task.WhenAll(tasks);
foreach (var result in results.Where(r => r.Success))
{
secrets[result.Name] = result.Value;
}
return secrets;
}
public async Task SetMultipleSecretsAsync(Dictionary<string, string> secrets)
{
var tasks = secrets.Select(async kvp =>
{
try
{
await _keyVaultService.SetSecretAsync(kvp.Key, kvp.Value);
_logger.LogInformation("Secret {SecretName} set successfully", kvp.Key);
return new { Name = kvp.Key, Success = true };
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to set secret: {SecretName}", kvp.Key);
return new { Name = kvp.Key, Success = false };
}
});
var results = await Task.WhenAll(tasks);
var successCount = results.Count(r => r.Success);
_logger.LogInformation("Batch operation completed: {SuccessCount}/{TotalCount} secrets updated",
successCount, secrets.Count);
}
public async Task RotateSecretsAsync(Dictionary<string, Func<Task<string>>> secretGenerators)
{
foreach (var (secretName, generator) in secretGenerators)
{
try
{
// Generate new secret value
var newValue = await generator();
// Update in Key Vault
await _keyVaultService.SetSecretAsync(secretName, newValue, new Dictionary<string, string>
{
{ "rotated-date", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") },
{ "rotation-type", "automatic" }
});
_logger.LogInformation("Secret {SecretName} rotated successfully", secretName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to rotate secret: {SecretName}", secretName);
}
}
}
}
Configuration Provider Integration
public class KeyVaultConfigurationService
{
private readonly IConfiguration _configuration;
private readonly IAzureKeyVaultService _keyVaultService;
public KeyVaultConfigurationService(IConfiguration configuration, IAzureKeyVaultService keyVaultService)
{
_configuration = configuration;
_keyVaultService = keyVaultService;
}
public async Task<AppSettings> GetAppSettingsAsync()
{
return new AppSettings
{
DatabaseConnectionString = _configuration["database-connection-string"],
ApiKey = _configuration["external-api-key"],
JwtSecret = _configuration["jwt-secret"],
SmtpPassword = _configuration["smtp-password"],
AzureStorageConnectionString = _configuration["azure-storage-connection-string"]
};
}
public async Task RefreshConfigurationAsync()
{
// This would typically trigger a configuration reload
// Implementation depends on your configuration setup
if (_configuration is IConfigurationRoot configRoot)
{
configRoot.Reload();
}
}
public string GetConnectionString(string name)
{
return _configuration.GetConnectionString(name);
}
public T GetSection<T>(string sectionName) where T : new()
{
var section = new T();
_configuration.GetSection(sectionName).Bind(section);
return section;
}
}
public class AppSettings
{
public string DatabaseConnectionString { get; set; }
public string ApiKey { get; set; }
public string JwtSecret { get; set; }
public string SmtpPassword { get; set; }
public string AzureStorageConnectionString { get; set; }
}
Managed Identity Authentication
public class ManagedIdentityKeyVaultService
{
private readonly IAzureKeyVaultService _keyVaultService;
private readonly ILogger<ManagedIdentityKeyVaultService> _logger;
public ManagedIdentityKeyVaultService(IAzureKeyVaultService keyVaultService, ILogger<ManagedIdentityKeyVaultService> logger)
{
_keyVaultService = keyVaultService;
_logger = logger;
}
public async Task<bool> TestManagedIdentityAsync()
{
try
{
// Try to access a test secret to verify managed identity is working
await _keyVaultService.GetSecretAsync("test-secret");
_logger.LogInformation("Managed Identity authentication successful");
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Managed Identity authentication failed");
return false;
}
}
public async Task InitializeSecretsAsync()
{
var requiredSecrets = new[]
{
"database-connection-string",
"jwt-secret",
"external-api-key"
};
var missingSecrets = new List<string>();
foreach (var secretName in requiredSecrets)
{
try
{
await _keyVaultService.GetSecretAsync(secretName);
_logger.LogInformation("Secret {SecretName} found", secretName);
}
catch (Exception)
{
missingSecrets.Add(secretName);
_logger.LogWarning("Secret {SecretName} not found", secretName);
}
}
if (missingSecrets.Any())
{
throw new InvalidOperationException($"Missing required secrets: {string.Join(", ", missingSecrets)}");
}
}
}
Certificate Management
public class CertificateService
{
private readonly IAzureKeyVaultService _keyVaultService;
private readonly ILogger<CertificateService> _logger;
public CertificateService(IAzureKeyVaultService keyVaultService, ILogger<CertificateService> logger)
{
_keyVaultService = keyVaultService;
_logger = logger;
}
public async Task<X509Certificate2> GetCertificateAsync(string certificateName)
{
var certificate = await _keyVaultService.GetCertificateAsync(certificateName);
_logger.LogInformation("Certificate {CertificateName} retrieved", certificateName);
return certificate;
}
public async Task<List<CertificateInfo>> ListCertificatesAsync()
{
var certificates = new List<CertificateInfo>();
await foreach (var certProperty in _keyVaultService.GetCertificatesAsync())
{
certificates.Add(new CertificateInfo
{
Name = certProperty.Name,
Version = certProperty.Version,
CreatedOn = certProperty.CreatedOn,
UpdatedOn = certProperty.UpdatedOn,
ExpiresOn = certProperty.ExpiresOn,
Enabled = certProperty.Enabled ?? true
});
}
return certificates;
}
public async Task<List<CertificateInfo>> GetExpiringCertificatesAsync(int daysThreshold = 30)
{
var allCertificates = await ListCertificatesAsync();
var threshold = DateTime.UtcNow.AddDays(daysThreshold);
return allCertificates
.Where(c => c.ExpiresOn.HasValue && c.ExpiresOn.Value <= threshold)
.OrderBy(c => c.ExpiresOn)
.ToList();
}
public async Task MonitorCertificateExpirationAsync()
{
var expiringCertificates = await GetExpiringCertificatesAsync(30);
foreach (var cert in expiringCertificates)
{
var daysUntilExpiry = (cert.ExpiresOn.Value - DateTime.UtcNow).Days;
if (daysUntilExpiry <= 7)
{
_logger.LogError("Certificate {CertificateName} expires in {Days} days", cert.Name, daysUntilExpiry);
}
else if (daysUntilExpiry <= 30)
{
_logger.LogWarning("Certificate {CertificateName} expires in {Days} days", cert.Name, daysUntilExpiry);
}
}
}
}
Environment-Specific Configuration
public class EnvironmentKeyVaultService
{
private readonly IAzureKeyVaultService _keyVaultService;
private readonly IHostEnvironment _environment;
private readonly ILogger<EnvironmentKeyVaultService> _logger;
public EnvironmentKeyVaultService(
IAzureKeyVaultService keyVaultService,
IHostEnvironment environment,
ILogger<EnvironmentKeyVaultService> logger)
{
_keyVaultService = keyVaultService;
_environment = environment;
_logger = logger;
}
public async Task<string> GetEnvironmentSecretAsync(string baseName)
{
var environmentSpecificName = $"{baseName}-{_environment.EnvironmentName.ToLower()}";
try
{
// Try environment-specific secret first
var secret = await _keyVaultService.GetSecretAsync(environmentSpecificName);
_logger.LogInformation("Using environment-specific secret: {SecretName}", environmentSpecificName);
return secret;
}
catch (Exception)
{
// Fall back to base secret name
_logger.LogInformation("Environment-specific secret not found, using base secret: {SecretName}", baseName);
return await _keyVaultService.GetSecretAsync(baseName);
}
}
public async Task SetEnvironmentSecretsAsync(Dictionary<string, string> secrets)
{
var environmentPrefix = _environment.EnvironmentName.ToLower();
foreach (var (key, value) in secrets)
{
var environmentSpecificKey = $"{key}-{environmentPrefix}";
await _keyVaultService.SetSecretAsync(environmentSpecificKey, value, new Dictionary<string, string>
{
{ "environment", _environment.EnvironmentName },
{ "base-name", key },
{ "created-date", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") }
});
_logger.LogInformation("Environment secret set: {SecretName}", environmentSpecificKey);
}
}
}
Health Check Integration
public class KeyVaultHealthCheck : IHealthCheck
{
private readonly IAzureKeyVaultService _keyVaultService;
private readonly ILogger<KeyVaultHealthCheck> _logger;
public KeyVaultHealthCheck(IAzureKeyVaultService keyVaultService, ILogger<KeyVaultHealthCheck> logger)
{
_keyVaultService = keyVaultService;
_logger = logger;
}
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
try
{
// Try to access a known secret or list secrets to test connectivity
await _keyVaultService.GetSecretsAsync().Take(1).ToListAsync(cancellationToken);
_logger.LogInformation("Key Vault health check passed");
return HealthCheckResult.Healthy("Key Vault is accessible");
}
catch (OperationCanceledException)
{
_logger.LogWarning("Key Vault health check timed out");
return HealthCheckResult.Unhealthy("Key Vault health check timed out");
}
catch (Exception ex)
{
_logger.LogError(ex, "Key Vault health check failed");
return HealthCheckResult.Unhealthy($"Key Vault is not accessible: {ex.Message}");
}
}
}
// In Program.cs
builder.Services.AddHealthChecks()
.AddCheck<KeyVaultHealthCheck>("keyvault");
?? Configuration Options
public class AzureKeyVaultSettings
{
public string VaultUri { get; set; }
public string TenantId { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public bool EnableCaching { get; set; } = true;
public int CacheExpiryMinutes { get; set; } = 30;
public int RetryAttempts { get; set; } = 3;
public TimeSpan RetryDelay { get; set; } = TimeSpan.FromSeconds(2);
public bool UseManagedIdentity { get; set; } = true;
}
public class SecretBundle
{
public string Name { get; set; }
public string Value { get; set; }
public string Version { get; set; }
public DateTimeOffset? CreatedOn { get; set; }
public DateTimeOffset? UpdatedOn { get; set; }
public DateTimeOffset? ExpiresOn { get; set; }
public IDictionary<string, string> Tags { get; set; }
}
public class SecretInfo
{
public string Name { get; set; }
public string Version { get; set; }
public DateTimeOffset? CreatedOn { get; set; }
public DateTimeOffset? UpdatedOn { get; set; }
public bool Enabled { get; set; }
public IDictionary<string, string> Tags { get; set; }
}
public class CertificateInfo
{
public string Name { get; set; }
public string Version { get; set; }
public DateTimeOffset? CreatedOn { get; set; }
public DateTimeOffset? UpdatedOn { get; set; }
public DateTimeOffset? ExpiresOn { get; set; }
public bool Enabled { get; set; }
}
??? Architecture
The Azure Key Vault service provides:
- Security: Secure secret, key, and certificate management
- Performance: Caching support for improved response times
- Reliability: Retry policies and comprehensive error handling
- Flexibility: Multiple authentication methods and configuration options
- Integration: Seamless ASP.NET Core configuration provider integration
????? Author
Frebin Francis
Fingent Technology Solutions Pvt Ltd
?? License
Copyright � 2025 Fingent Technology Solutions Pvt Ltd
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net8.0
- Azure.Identity (>= 1.12.0)
- Azure.Security.KeyVault.Secrets (>= 4.6.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.1)
- Microsoft.Extensions.Options (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.1 | 272 | 9/24/2025 |