Feedemy.KeyManagement.Providers.Npgsql
2.5.2
See the version list below for details.
dotnet add package Feedemy.KeyManagement.Providers.Npgsql --version 2.5.2
NuGet\Install-Package Feedemy.KeyManagement.Providers.Npgsql -Version 2.5.2
<PackageReference Include="Feedemy.KeyManagement.Providers.Npgsql" Version="2.5.2" />
<PackageVersion Include="Feedemy.KeyManagement.Providers.Npgsql" Version="2.5.2" />
<PackageReference Include="Feedemy.KeyManagement.Providers.Npgsql" />
paket add Feedemy.KeyManagement.Providers.Npgsql --version 2.5.2
#r "nuget: Feedemy.KeyManagement.Providers.Npgsql, 2.5.2"
#:package Feedemy.KeyManagement.Providers.Npgsql@2.5.2
#addin nuget:?package=Feedemy.KeyManagement.Providers.Npgsql&version=2.5.2
#tool nuget:?package=Feedemy.KeyManagement.Providers.Npgsql&version=2.5.2
Feedemy.KeyManagement
Enterprise-grade key management library for .NET applications with versioned encryption, automatic rotation, distributed caching, and comprehensive audit logging.
Overview
Feedemy.KeyManagement provides a production-ready solution for managing cryptographic keys and sensitive configuration in .NET applications. It combines platform-specific secure storage with advanced features like automatic key rotation, version management, distributed caching, health monitoring, and full audit trails.
Key Features
- Versioned Encryption Format (v2.3.0+): Auto-decryption with version detection, backward compatibility
- Generic String-Based Keys: No hardcoded key names - fully application-agnostic
- Automatic Key Rotation: Background service with configurable intervals and health monitoring
- Asymmetric Key Support: RSA (2048/3072/4096-bit) and ECDSA (P-256/P-384/P-521) for signing and encryption
- Multi-Platform Secure Storage: Windows DPAPI, Linux AES-256-GCM, Azure Key Vault, InMemory
- High-Performance Caching: Redis/Memory cache with multi-layer strategy (< 1ms cache hits)
- Distributed Cache Invalidation: Pub/sub pattern for multi-server synchronization
- Database Persistence: SQL Server and PostgreSQL support with automatic migrations
- Master Key Encryption: Envelope encryption for sensitive keys
- Health Monitoring: Built-in ASP.NET Core health checks
- Fallback Storage: Multi-provider redundancy with automatic synchronization
- Audit Trail: Complete audit logging for compliance
- Roslyn Analyzers: 48 compile-time rules for security and best practices
- OpenTelemetry Integration: Metrics, traces, and structured logging
Production-Ready
- 100% Test Coverage: 450+ unit tests, 120+ integration tests
- Benchmark Tested: < 1ms cached retrieval, < 100ms rotation operations
- Battle-Tested: Used in production environments
- .NET 10.0: Latest framework support
Quick Start
Installation
# Core library
dotnet add package Feedemy.KeyManagement
# Persistence providers (choose one)
dotnet add package Feedemy.KeyManagement.Providers.EntityFramework # SQL Server
dotnet add package Feedemy.KeyManagement.Providers.Npgsql # PostgreSQL
# Optional: Analyzers for compile-time checks
dotnet add package Feedemy.KeyManagement.Analyzers
Initial Setup (First Time)
Step 1: Create keys.json (Key Definitions)
Create a keys.json file to define which keys should be auto-generated on first run:
{
"Keys": [
{
"KeyName": "EncryptionKey",
"KeyType": "Symmetric",
"KeySize": 256,
"RotationIntervalDays": 90,
"Category": "MasterKey",
"Description": "Master encryption key for envelope encryption",
"AutoRotationEnabled": true,
"RequiresMasterKeyEncryption": false
},
{
"KeyName": "JwtSigningKey",
"KeyType": "RSA",
"KeySize": 2048,
"RotationIntervalDays": 180,
"Category": "Signing",
"Description": "RSA key for JWT RS256 tokens",
"AutoRotationEnabled": true,
"RequiresMasterKeyEncryption": true
},
{
"KeyName": "ApiEncryptionKey",
"KeyType": "Symmetric",
"KeySize": 256,
"RotationIntervalDays": 90,
"Category": "Encryption",
"Description": "AES-256 key for API payload encryption",
"AutoRotationEnabled": true,
"RequiresMasterKeyEncryption": true
},
{
"KeyName": "DocumentSigningKey",
"KeyType": "ECDSA",
"KeySize": 256,
"RotationIntervalDays": 365,
"Category": "Signing",
"Description": "ECDSA P-256 key for document signatures",
"AutoRotationEnabled": false,
"RequiresMasterKeyEncryption": true
}
]
}
Key Definition Fields:
| Field | Type | Description |
|---|---|---|
KeyName |
string | Unique key identifier |
KeyType |
string | Symmetric, RSA, or ECDSA |
KeySize |
int | 256 (AES), 2048/3072/4096 (RSA), 256/384/521 (ECDSA) |
RotationIntervalDays |
int | Days between automatic rotations |
Category |
string | Encryption, Signing, ApiKey, Secret, MasterKey |
SourceType |
string | Generated (auto), External (provide content) |
InitialContent |
string | For external keys: plain text, hex, or base64:... |
RequiresMasterKeyEncryption |
bool | Encrypt with master key (recommended for sensitive keys) |
Step 2: Create azure-credentials.json (Azure Key Vault)
For Azure Key Vault storage, create azure-credentials.json:
{
"TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ClientSecret": "your-client-secret-here"
}
How to get these values:
- Go to Azure Portal → Azure Active Directory → App registrations
- Create new registration or use existing
- Copy Application (client) ID →
ClientId - Copy Directory (tenant) ID →
TenantId - Go to Certificates & secrets → New client secret → Copy value →
ClientSecret - Go to your Key Vault → Access policies → Add access policy for this app
Security Note: On first run, credentials are imported to platform-secure storage:
- Windows: Credential Manager (DPAPI protected)
- Linux: Secret Service / Keyring
After successful import, delete azure-credentials.json for security.
Step 3: Configure appsettings.json
{
"KeyManagement": {
"EnableAutoRotation": true,
"RotationCheckInterval": "06:00:00",
"DefaultRotationDays": 90,
"MasterEncryptionKeyName": "EncryptionKey",
"Storage": {
"ProviderType": "AzureKeyVault",
"AzureKeyVaultUrl": "https://your-vault.vault.azure.net/",
"AzureCredentialsJsonPath": "azure-credentials.json"
},
"Cache": {
"ProviderType": "Redis",
"RedisConnectionString": "localhost:6379"
},
"Initialization": {
"EnableAutoInitialization": true,
"ExternalKeysJsonPath": "keys.json"
}
},
"ConnectionStrings": {
"KeyManagement": "Server=localhost;Database=MyApp;Trusted_Connection=true;"
}
}
Basic Setup (Development)
using Feedemy.KeyManagement.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add KeyManagement with in-memory providers (development only)
builder.Services.AddKeyManagement(options =>
{
options.EnableAutoRotation = true;
options.RotationCheckInterval = TimeSpan.FromHours(6);
options.DefaultRotationDays = 90;
});
var app = builder.Build();
app.Run();
Production Setup (SQL Server + Redis + Azure Key Vault)
using Feedemy.KeyManagement.Extensions;
using StackExchange.Redis;
var builder = WebApplication.CreateBuilder(args);
// Configure Redis
builder.Services.AddSingleton<IConnectionMultiplexer>(
ConnectionMultiplexer.Connect("localhost:6379"));
// Add KeyManagement with production providers
builder.Services.AddKeyManagement(options =>
{
options.EnableAutoRotation = true;
options.RotationCheckInterval = TimeSpan.FromHours(6);
options.DefaultRotationDays = 90;
// Storage: Azure Key Vault
options.Storage.ProviderType = StorageProviderType.AzureKeyVault;
options.Storage.AzureKeyVaultUrl = "https://your-vault.vault.azure.net/";
// Cache: Redis with distributed invalidation
options.Cache.ProviderType = CacheProviderType.Redis;
options.Cache.RedisConnectionString = "localhost:6379";
})
.UseEntityFramework() // SQL Server persistence
.AddHealthChecks(); // ASP.NET Core health checks
// Add health check endpoint
builder.Services.AddHealthChecks()
.AddKeyManagementHealthCheck(
name: "key_management",
failureStatus: HealthStatus.Unhealthy,
tags: new[] { "security", "keys" });
var app = builder.Build();
app.MapHealthChecks("/health");
app.Run();
Basic Usage
public class MyService
{
private readonly IKeyManagementService _keyService;
private readonly IKeyManagementAdminService _adminService;
public MyService(
IKeyManagementService keyService,
IKeyManagementAdminService adminService)
{
_keyService = keyService;
_adminService = adminService;
}
// Create a new encryption key (admin operation)
public async Task CreateEncryptionKeyAsync()
{
var result = await _adminService.CreateKeyAsync(new CreateKeyRequest
{
KeyName = "MyEncryptionKey",
Description = "AES-256 encryption key for sensitive data",
AutoGenerate = true,
KeySize = 32, // 256 bits
RotationIntervalDays = 90,
AutoRotationEnabled = true,
MaxVersionsToRetain = 5,
Category = KeyCategory.Encryption,
SourceType = KeySourceType.Generated,
CreatedBy = "Admin"
});
if (result.Success)
{
Console.WriteLine($"Key created: {result.Data.KeyName} v{result.Data.CurrentVersion}");
}
}
// Retrieve key (cache-first, extremely fast)
public async Task<byte[]> GetEncryptionKeyAsync()
{
return await _keyService.RetrieveKeyAsync("MyEncryptionKey");
}
// Get key metadata
public async Task<KeyMetadata> GetKeyInfoAsync()
{
var metadata = await _keyService.GetKeyMetadataAsync("MyEncryptionKey");
Console.WriteLine($"Current Version: {metadata.CurrentVersion}");
Console.WriteLine($"Next Rotation: {metadata.NextRotationDue}");
Console.WriteLine($"Auto Rotation: {metadata.AutoRotationEnabled}");
return metadata;
}
// Check key health
public async Task MonitorKeyHealthAsync()
{
var health = await _keyService.GetKeyHealthAsync("MyEncryptionKey");
if (health.Status == KeyHealthStatus.NeedsRotation)
{
Console.WriteLine("WARNING: Key needs immediate rotation!");
}
else if (health.Status == KeyHealthStatus.Warning)
{
Console.WriteLine($"Key approaching rotation: {health.DaysUntilRotation} days remaining");
}
}
}
Core Features
1. Generic String-Based Keys (v3.0+)
The library is fully generic - no hardcoded key names. Applications define their own key names as strings.
// Create any key with any name
await adminService.CreateKeyAsync(new CreateKeyRequest
{
KeyName = "MyCustomKey", // Any string you want
Description = "Application-specific key",
AutoGenerate = true,
KeySize = 32,
RotationIntervalDays = 90,
CreatedBy = "Admin"
});
// Retrieve by name
var key = await keyService.RetrieveKeyAsync("MyCustomKey");
Migration from v2.x: If you used hardcoded KeyName enums, replace them with strings:
KeyName.EncryptionKey→"EncryptionKey"keyName.ToKeyString()→ Direct string usage
2. Versioned Encryption Format
Auto-decryption with version detection for backward compatibility.
// Encrypt data (automatically adds version header)
var encryptedData = await encryptionService.EncryptAsync(plaintext, "MyKey");
// Decrypt (auto-detects version and decrypts accordingly)
var decryptedData = await encryptionService.DecryptAsync(encryptedData, "MyKey");
// Works even if key has been rotated - automatically uses correct version
Format: [VERSION_BYTE][ENCRYPTED_CONTENT]
- Version 1 (legacy): No version byte
- Version 2 (v2.3.0+):
0x01prefix + versioned encryption
3. Asymmetric Key Support (RSA & ECDSA)
Full support for digital signatures, JWT signing, and public key encryption.
Creating Asymmetric Keys
// RSA key for JWT signing
var rsaResult = await adminService.CreateKeyAsync(new CreateKeyRequest
{
KeyName = "JwtSigningKey",
KeyType = KeyType.AsymmetricRSA,
RsaKeySize = RsaKeySize.Rsa2048,
Category = KeyCategory.Signing,
Description = "RSA key for JWT RS256 tokens",
AutoRotationEnabled = true,
RotationIntervalDays = 180,
CreatedBy = "System"
});
// ECDSA key for document signing
var ecdsaResult = await adminService.CreateKeyAsync(new CreateKeyRequest
{
KeyName = "DocumentSigningKey",
KeyType = KeyType.AsymmetricECDSA,
EcdsaCurve = EcdsaCurve.P256,
Category = KeyCategory.Signing,
Description = "ECDSA key for document signatures",
CreatedBy = "Admin"
});
Using Asymmetric Keys
public class JwtService
{
private readonly IAsymmetricKeyOperations _asymmetricOps;
public JwtService(IAsymmetricKeyOperations asymmetricOps)
{
_asymmetricOps = asymmetricOps;
}
// Sign JWT token
public async Task<string> CreateJwtTokenAsync(Dictionary<string, object> claims)
{
var payload = JsonSerializer.SerializeToUtf8Bytes(claims);
// Sign with RS256
var signature = await _asymmetricOps.SignAsync(
"JwtSigningKey",
payload,
HashAlgorithmName.SHA256);
return EncodeJwt(payload, signature);
}
// Verify JWT token
public async Task<bool> VerifyJwtTokenAsync(string token)
{
var (payload, signature) = DecodeJwt(token);
// Verify using cached public key (very fast - ~0.15ms)
return await _asymmetricOps.VerifyAsync(
"JwtSigningKey",
payload,
signature,
HashAlgorithmName.SHA256);
}
// Export public key for clients
public async Task<string> GetPublicKeyPemAsync()
{
// Safe to expose publicly
return await _asymmetricOps.GetPublicKeyPemAsync("JwtSigningKey");
}
}
Supported Algorithms:
| Algorithm | Key Sizes | Use Case | Performance |
|---|---|---|---|
| RSA | 2048, 3072, 4096-bit | Signing, Encryption | Sign: ~1.2ms, Verify: ~0.15ms |
| ECDSA | P-256, P-384, P-521 | Signing (compact) | Sign: ~0.35ms, Verify: ~0.12ms |
4. Automatic Key Rotation
Background service automatically rotates keys based on configured intervals.
// Enable in configuration
builder.Services.AddKeyManagement(options =>
{
options.EnableAutoRotation = true;
options.RotationCheckInterval = TimeSpan.FromHours(6);
options.DefaultRotationDays = 90;
});
// Per-key configuration
await adminService.CreateKeyAsync(new CreateKeyRequest
{
KeyName = "ApiKey",
RotationIntervalDays = 90, // Rotate every 90 days
AutoRotationEnabled = true, // Enable auto-rotation
MaxVersionsToRetain = 5, // Keep last 5 versions
// ...
});
// Monitor rotation status
var status = await adminService.GetRotationServiceStatusAsync();
Console.WriteLine($"Keys Pending Rotation: {status.KeysPendingRotation.Count}");
Rotation Flow:
- Background service checks every
RotationCheckInterval - Identifies keys where
NextRotationDue <= Now - Generates new key content
- Saves to storage and database
- Invalidates all cache layers
- Triggers cache warming
- Logs audit entry
5. Health Monitoring
Built-in ASP.NET Core health checks for monitoring system health.
// Add health checks
builder.Services.AddHealthChecks()
.AddKeyManagementHealthCheck(
name: "key_management",
failureStatus: HealthStatus.Unhealthy,
tags: new[] { "security", "keys" });
// Map endpoint
app.MapHealthChecks("/health");
Health Status Levels:
- Healthy: All keys operational, > 30 days until rotation
- Degraded: Warning keys detected (7-30 days until rotation)
- Unhealthy: Critical keys (rotation overdue) or system failure
Response Example:
{
"status": "Healthy",
"totalKeys": 15,
"healthyKeys": 13,
"warningKeys": 2,
"criticalKeys": 0,
"storageProvider": "Azure Key Vault",
"storageAvailable": true,
"checks": {
"key_management": {
"status": "Healthy",
"description": "Key management system is healthy"
}
}
}
6. Distributed Caching with Redis
Multi-layer caching with distributed invalidation for multi-server deployments.
// Configure Redis
builder.Services.AddSingleton<IConnectionMultiplexer>(
ConnectionMultiplexer.Connect("localhost:6379"));
builder.Services.AddKeyManagement(options =>
{
options.Cache.ProviderType = CacheProviderType.Redis;
options.Cache.RedisConnectionString = "localhost:6379";
});
// Configure cache invalidation options
builder.Services.Configure<KeyManagementCacheOptions>(options =>
{
options.EnableDistributedInvalidation = true;
options.InvalidationChannel = "keymanagement:invalidation";
options.EnableCacheWarming = true;
options.MaxConcurrentWarmingTasks = 5;
});
Cache Layers:
- Content Cache:
key:{KeyName}:content:v{Version}(1-hour TTL) - Metadata Cache:
key:{KeyName}:metadata(5-min TTL) - Version Cache:
key:{KeyName}:versions(5-min TTL)
Invalidation Flow:
- Server 1 rotates key
- Publishes invalidation message to Redis pub/sub
- All servers receive notification
- Each server clears local cache
- Cache warming preloads critical keys
7. Database Persistence
SQL Server and PostgreSQL support with automatic migrations.
SQL Server (EntityFramework)
builder.Services.AddKeyManagement(options => { /* ... */ })
.UseEntityFramework();
// Migrations are applied automatically on startup
// Tables created: KeyMetadata, KeyVersions, KeyAuditLogs, SchemaVersion
PostgreSQL (Npgsql)
builder.Services.AddKeyManagement(options => { /* ... */ })
.UseNpgsql("Host=localhost;Database=mydb;Username=user;Password=pass");
// Automatic migrations for PostgreSQL
Database Tables:
KeyManagement.KeyMetadata: Key configuration and current versionKeyManagement.KeyVersions: Version history with content hashesKeyManagement.KeyAuditLogs: Complete audit trailKeyManagement.SchemaVersion: Migration tracking
8. Platform-Specific Storage
Automatic selection of the best storage provider for your platform.
Windows DPAPI
builder.Services.AddKeyManagement(options =>
{
options.Storage.ProviderType = StorageProviderType.WindowsCredentialManager;
});
- Location:
%LOCALAPPDATA%\Feedemy\Keys - Encryption: Windows Data Protection API (DPAPI)
- Scope: CurrentUser
- Security: Protected by Windows ACLs + DPAPI encryption
Linux AES-256-GCM
builder.Services.AddKeyManagement(options =>
{
options.Storage.ProviderType = StorageProviderType.LinuxKeyring;
});
- Location:
~/.feedemy-keys/ - Encryption: AES-256-GCM with machine-specific key
- Key Derivation: PBKDF2-SHA256 (100,000 iterations) from
/etc/machine-id - File Permissions: 600 (owner read/write only)
Azure Key Vault
builder.Services.AddKeyManagement(options =>
{
options.Storage.ProviderType = StorageProviderType.AzureKeyVault;
options.Storage.AzureKeyVaultUrl = "https://your-vault.vault.azure.net/";
});
- Authentication: DefaultAzureCredential (Managed Identity or Client Secret)
- Retry Policy: 3 attempts with exponential backoff
- Security: Managed by Azure, hardware security modules (HSM) optional
Auto-Detection
builder.Services.AddKeyManagement(options =>
{
options.Storage.ProviderType = StorageProviderType.Auto; // Default
});
Automatically selects Windows DPAPI on Windows, Linux AES-GCM on Linux.
9. Fallback Storage
Multi-provider redundancy with automatic synchronization.
builder.Services.AddKeyManagement(options =>
{
options.Storage.ProviderType = StorageProviderType.Fallback;
options.Storage.Fallback.PrimaryProvider = StorageProviderType.AzureKeyVault;
options.Storage.Fallback.FallbackProvider = StorageProviderType.WindowsCredentialManager;
options.Storage.Fallback.EnableAutoSync = true;
options.Storage.Fallback.SyncOnStartup = true;
});
Benefits:
- Automatic failover if primary storage fails
- Background synchronization between providers
- Zero-downtime migrations
10. Master Key Encryption
Envelope encryption for sensitive keys.
// Create master encryption key
await adminService.CreateKeyAsync(new CreateKeyRequest
{
KeyName = "EncryptionKey", // Master key
AutoGenerate = true,
KeySize = 32,
RotationIntervalDays = 90,
CreatedBy = "System"
});
// Create encrypted key
await adminService.CreateKeyAsync(new CreateKeyRequest
{
KeyName = "DatabaseEncryptionKey",
RequiresMasterKeyEncryption = true, // Encrypted with master key
AutoGenerate = true,
KeySize = 32,
CreatedBy = "System"
});
Re-encryption after master key rotation:
// Detect version mismatches
var mismatches = await adminService.GetEnvKeysWithVersionMismatchAsync();
// Re-encrypt automatically handled by rotation service
Advanced Features
Version Management
// Get all versions
var versions = await keyService.GetKeyVersionsAsync("ApiKey");
foreach (var version in versions)
{
Console.WriteLine($"Version {version.Version}: {version.Status}");
}
// Retrieve specific version
var oldKey = await keyService.RetrieveKeyByVersionAsync("ApiKey", version: 3);
// Rollback to previous version
var rollbackResult = await adminService.RollbackToVersionAsync(
keyName: "ApiKey",
targetVersion: 3,
reason: "Revert after incident",
performedBy: "Admin");
Audit Logging
// Get audit history
var logs = await adminService.GetAuditLogsAsync(
keyName: "ApiKey",
fromDate: DateTime.UtcNow.AddMonths(-1));
foreach (var log in logs)
{
Console.WriteLine($"{log.Timestamp}: {log.Action} by {log.PerformedBy}");
Console.WriteLine($" Reason: {log.Reason}");
}
Audit Operations Tracked:
- KeyCreated
- KeyUpdated
- KeyRotated
- KeyDeactivated
- KeyReactivated
- VersionDeactivated
- VersionReactivated
- RollbackPerformed
- ConfigurationUpdated
Cache Warming
// Configure cache warming
builder.Services.Configure<KeyManagementCacheOptions>(options =>
{
options.EnableCacheWarming = true;
options.MaxConcurrentWarmingTasks = 5;
});
// Manually warm cache for specific keys
await keyService.WarmCacheAsync(new[] { "ApiKey", "JwtSigningKey" });
Roslyn Analyzers
48 compile-time rules for security and best practices.
dotnet add package Feedemy.KeyManagement.Analyzers
Example Rules:
- KM0001: Empty key name (Error)
- KM0002: Invalid rotation interval (Warning)
- KM0101: Hardcoded key content (Warning)
- KM0103: Key exposure in logs (Warning)
- KM0104: Insecure storage in production (Warning)
- KM0203: Key retrieval in loop (Warning)
Disable specific rules:
#pragma warning disable KM0101
var key = new byte[] { ... };
#pragma warning restore KM0101
See ANALYZER_RULES.md for complete list.
Configuration
KeyManagementOptions
builder.Services.AddKeyManagement(options =>
{
// Auto-rotation
options.EnableAutoRotation = true;
options.RotationCheckInterval = TimeSpan.FromHours(6);
options.DefaultRotationDays = 90;
// Master key name (default: "EncryptionKey")
options.MasterEncryptionKeyName = "EncryptionKey";
// Storage
options.Storage.ProviderType = StorageProviderType.Auto;
options.Storage.AzureKeyVaultUrl = "https://your-vault.vault.azure.net/";
// Cache
options.Cache.ProviderType = CacheProviderType.Redis;
options.Cache.RedisConnectionString = "localhost:6379";
// Persistence
options.Persistence.ProviderType = PersistenceProviderType.EntityFramework;
// Initialization
options.Initialization.EnableAutoInitialization = true;
options.Initialization.ExternalKeysJsonPath = "keys.json";
});
KeyManagementCacheOptions
builder.Services.Configure<KeyManagementCacheOptions>(options =>
{
// Distributed invalidation
options.EnableDistributedInvalidation = true;
options.InvalidationChannel = "keymanagement:invalidation";
options.PubSubTimeoutSeconds = 5;
// Cache warming
options.EnableCacheWarming = true;
options.MaxConcurrentWarmingTasks = 5;
// Retry
options.MaxInvalidationRetries = 3;
options.RetryDelayMilliseconds = 100;
});
Environment Variables
# Core settings
KeyManagement__EnableAutoRotation=true
KeyManagement__RotationCheckInterval=06:00:00
KeyManagement__DefaultRotationDays=90
# Storage
KeyManagement__Storage__ProviderType=AzureKeyVault
KeyManagement__Storage__AzureKeyVaultUrl=https://your-vault.vault.azure.net/
# Cache
KeyManagement__Cache__ProviderType=Redis
KeyManagement__Cache__RedisConnectionString=localhost:6379
# Cache options
KeyManagementCache__EnableDistributedInvalidation=true
KeyManagementCache__InvalidationChannel=keymanagement:invalidation
Performance
Benchmark Results (BenchmarkDotNet)
| Method | Mean | Allocated |
|---------------------------|------------|-----------|
| RetrieveKey_Cached | 0.85 μs | 96 B |
| RetrieveKey_CacheMiss | 12.3 ms | 1.2 KB |
| GetMetadata_Cached | 0.62 μs | 48 B |
| GetCurrentVersion_Cached | 0.58 μs | 32 B |
| CreateKey | 85.2 ms | 4.5 KB |
| RotateKey | 95.7 ms | 5.2 KB |
| SignData_RSA2048 | 1.2 ms | 512 B |
| VerifySignature_RSA2048 | 0.15 ms | 256 B |
| SignData_ECDSA_P256 | 0.35 ms | 384 B |
| VerifySignature_ECDSA_P256| 0.12 ms | 192 B |
Run benchmarks:
cd benchmarks/Feedemy.KeyManagement.Benchmarks
dotnet run -c Release
Testing
Unit Tests (450+)
cd tests/Feedemy.KeyManagement.Tests
dotnet test
Coverage:
- Core services (KeyManagementService, KeyManagementAdminService)
- Domain services (Health, Validation, Versioning, Encryption)
- Cache services (Multi-layer, Invalidation, Warming)
- Storage coordination
- Repository patterns
- Background services
Integration Tests (120+)
cd tests/Feedemy.KeyManagement.IntegrationTests
dotnet test
Coverage:
- End-to-end workflows
- Cache invalidation propagation
- Automatic rotation
- Rollback scenarios
- Provider integration (SQL Server, PostgreSQL, Redis, Azure KV)
- Asymmetric key operations (RSA, ECDSA)
Architecture
See ARCHITECTURE.md for detailed architecture diagrams, component descriptions, and data flow.
High-Level Architecture
┌─────────────────────────────────────────────────────────┐
│ APPLICATION LAYER │
│ Controllers / Services / Background Jobs │
└──────────────────────┬──────────────────────────────────┘
│
┌──────────────┴──────────────┐
│ │
┌───────▼─────────┐ ┌─────────▼────────────┐
│ IKeyManagement │ │ IKeyManagementAdmin │
│ Service │ │ Service │
│ (Read Ops) │ │ (Write Ops) │
└───────┬─────────┘ └─────────┬────────────┘
│ │
└──────────────┬──────────────┘
│
┌──────────────────────▼──────────────────────────────────┐
│ DOMAIN SERVICES LAYER │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Health │ │ Validation │ │ Versioning │ │
│ │ Calculator │ │ Service │ │ Service │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Encryption │ │ Rotation │ │ Storage │ │
│ │Orchestrator│ │ Service │ │Coordinator │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└──────────────────────┬──────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────┐
│ INFRASTRUCTURE SERVICES LAYER │
│ ┌────────────┬────────────┬────────────┐ │
│ │ Cache │ Storage │ Persistence│ │
│ │ - Redis │ - DPAPI │ - SQL │ │
│ │ - Memory │ - Azure KV │ - Postgres │ │
│ │ - Invalidation│ - Linux AES│ - InMemory│ │
│ └────────────┴────────────┴────────────┘ │
└─────────────────────────────────────────────────────────┘
Migration Guides
From v2.x to v3.0
Breaking Changes:
- Removed
KeyNameenum - use strings instead - Removed
ToKeyString()andToKeyName()extension methods WarmCriticalKeysAsync()now requiresstring[]parameter
Migration Steps:
// Before (v2.x)
await keyService.RetrieveKeyAsync(KeyName.EncryptionKey);
var keyString = KeyName.EncryptionKey.ToKeyString();
// After (v3.0)
await keyService.RetrieveKeyAsync("EncryptionKey");
var keyString = "EncryptionKey"; // Direct string usage
See MIGRATION_GUIDE.md for complete migration instructions.
Documentation
- Architecture Guide - System architecture and data flows
- Migration Guide - Version migration instructions
- Analyzer Rules - Complete list of Roslyn analyzer rules
- Telemetry - OpenTelemetry integration guide
NuGet Packages
| Package | Version | Description |
|---|---|---|
| Feedemy.KeyManagement | 2.5.2 | Core library |
| Feedemy.KeyManagement.Providers.EntityFramework | 2.5.2 | SQL Server persistence |
| Feedemy.KeyManagement.Providers.Npgsql | 2.5.2 | PostgreSQL persistence |
| Feedemy.KeyManagement.Analyzers | 2.5.2 | Roslyn analyzers |
Roadmap
- HashiCorp Vault provider
- AWS Secrets Manager provider
- Multi-region replication
- Key import/export utilities
- Grafana dashboard templates
- Performance profiling tools
Contributing
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Write tests for new features
- Ensure all tests pass:
dotnet test - Submit a pull request
Code Style:
- Follow .NET coding conventions
- Use nullable reference types
- Add XML documentation for public APIs
- Write unit tests for business logic
- Write integration tests for workflows
License
Dual License - see LICENSE file for details.
- Personal & Educational Use: FREE
- Commercial Use: Requires paid license
Copyright (c) 2025 Feedemy
For commercial licensing inquiries: licensing@feedemy.com
Support
- Documentation: GitHub Wiki
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Acknowledgments
Built with:
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Feedemy.KeyManagement (>= 2.5.2)
- Microsoft.EntityFrameworkCore (>= 10.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.0)
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v2.3.0 - Initial PostgreSQL Provider Release
NEW PROVIDER:
- PostgreSQL support via Npgsql.EntityFrameworkCore.PostgreSQL
- Platform-independent persistence (alternative to SQL Server)
- Full feature parity with EntityFramework provider
- PostgreSQL 12+ support
COMPATIBILITY:
- Requires Feedemy.KeyManagement 2.3.0+
- .NET 9.0
- PostgreSQL 12+
- Npgsql.EntityFrameworkCore.PostgreSQL 9.0.0+