AzureSecureAccess 1.2.0
dotnet add package AzureSecureAccess --version 1.2.0
NuGet\Install-Package AzureSecureAccess -Version 1.2.0
<PackageReference Include="AzureSecureAccess" Version="1.2.0" />
<PackageVersion Include="AzureSecureAccess" Version="1.2.0" />
<PackageReference Include="AzureSecureAccess" />
paket add AzureSecureAccess --version 1.2.0
#r "nuget: AzureSecureAccess, 1.2.0"
#:package AzureSecureAccess@1.2.0
#addin nuget:?package=AzureSecureAccess&version=1.2.0
#tool nuget:?package=AzureSecureAccess&version=1.2.0
Azure Secure Access
A modern .NET library for secure access to Azure Key Vault secrets, certificates, and encryption. Simplifies connecting to SQL Server databases using Always Encrypted with Azure Key Vault as the key store.
โจ Features
- Secrets Management: Retrieve and cache secrets from Azure Key Vault
- Flexible Authentication: Client Secret, Certificate, Managed Identity, or DefaultAzureCredential
- SQL Server Always Encrypted: First-class support with fluent builder API
- Certificate Providers: Load X509 certificates from file, OS store, or Key Vault
- Performance: Built-in caching to reduce API calls and latency
- Clean Architecture: Domain-driven namespaces for intuitive discovery
- Resilience: Built-in retry policies for Azure services using Polly
- Observability: Structured logging with
ILogger<T>across all providers (no secret values exposed)
๐ฆ Installation
dotnet add package AzureSecureAccess
๐ Quick Start
1. Authentication
Choose the authentication method that fits your scenario:
using AzureSecureAccess.Authentication;
// Client Secret (for service principals)
var credential = new ClientSecretCredentialProvider(tenantId, clientId, clientSecret);
// Certificate-based authentication
var credential = new CertificateCredentialProvider(tenantId, clientId, certificate);
// Managed Identity (Azure-hosted: App Service, AKS, VMs)
var credential = new ManagedIdentityCredentialProvider(); // System-assigned
var credential = new ManagedIdentityCredentialProvider(
ManagedIdentityId.FromUserAssignedClientId("client-id")); // User-assigned
// DefaultAzureCredential (tries multiple methods automatically)
var credential = new DefaultCredentialProvider();
2. Retrieving Secrets
using AzureSecureAccess.Secrets;
var secretProvider = new KeyVaultSecretProvider("my-keyvault", credential.GetCredential());
// Get the latest version of a secret
string apiKey = await secretProvider.GetSecretValueAsync("ApiKey");
// Get a specific version
string oldKey = await secretProvider.GetSecretVersionValueAsync("ApiKey", "abc123version");
With Caching (reduces API calls)
var baseProvider = new KeyVaultSecretProvider("my-keyvault", credential.GetCredential());
using var cachedProvider = new CachedSecretProvider(baseProvider, TimeSpan.FromMinutes(30));
// First call hits Key Vault, subsequent calls use cache for 30 minutes
string secret = await cachedProvider.GetSecretValueAsync("ApiKey");
3. Working with Certificates
using AzureSecureAccess.Certificates;
// From local file
var localProvider = LocalCertificateProvider.FromFile("/path/to/cert.pfx");
var cert = localProvider.GetCertificate();
// From OS certificate store (by thumbprint)
var storeProvider = LocalCertificateProvider.FromStore("ABC123THUMBPRINT");
var cert = storeProvider.GetCertificate();
// From Azure Key Vault
var kvCertProvider = new KeyVaultCertificateProvider("my-keyvault", credential.GetCredential());
var certWithPrivateKey = await kvCertProvider.GetCertificateAsync("MyCertificate");
Notes:
- PEM secrets (
application/x-pem-file) are supported on .NET 8+ and load using the native PEM APIs.
4. SQL Server with Always Encrypted
Basic Usage
using AzureSecureAccess.SqlServer;
var credential = new DefaultCredentialProvider();
AlwaysEncryptedProvider.RegisterKeyVaultProvider(credential.GetCredential());
using var connection = new SqlConnection(
"Server=myserver.database.windows.net;Database=MyDB;Column Encryption Setting=Enabled;");
await connection.OpenAsync();
// Encrypted columns are automatically decrypted!
Advanced: Fluent Builder with Key Vault Secrets
using AzureSecureAccess.SqlServer;
// Connection string stored directly
var connection = new SecureConnectionBuilder()
.WithCredential(new ManagedIdentityCredentialProvider())
.WithConnectionString("Server=...;Column Encryption Setting=Enabled;")
.Build(); // OK for local connection strings
// Connection string stored in Key Vault (with caching)
var connection = await new SecureConnectionBuilder()
.WithCredential(new DefaultCredentialProvider())
.WithConnectionStringFromKeyVault("my-keyvault", "SqlConnectionString")
.WithCaching(TimeSpan.FromMinutes(45)) // Cache the connection string
.BuildAsync(); // Required for Key Vault to avoid deadlocks
await connection.OpenAsync();
5. Resilience and Error Handling
The library includes built-in resilience using Polly to handle transient errors (network issues, throttling) and provides domain-specific exceptions for fatal errors.
- Automatic Retries: Operations are retried automatically on 408 (Timeout), 429 (Too Many Requests), and 5xx (Server Errors).
- Specific Exceptions:
KeyVaultSecretNotFoundException: When a secret does not exist (404).KeyVaultCertificateNotFoundException: When a certificate does not exist (404).KeyVaultAccessDeniedException: When permissions are missing (403).KeyVaultOperationException: For other Azure-related failures.
6. Observability and Diagnostics
All providers in the library support ILogger<T> for structured logging. You can pass your own logger or a ILoggerFactory to the fluent builders.
Key Features:
- Traceability: Logs include Azure resource names (Key Vault URI, certificate names) but never the actual values of secrets or certificates.
- Cache Insights:
CachedSecretProviderlogs HIT/MISS events to help optimize cache durations. - Authentication Visibility: Providers log which authentication method is being used (including Client ID and Tenant ID where applicable).
Example with SecureConnectionBuilder:
var connection = await new SecureConnectionBuilder()
.WithCredential(credential)
.WithConnectionStringFromKeyVault("my-vault", "MySecret")
.WithLoggerFactory(myLoggerFactory) // All internal operations will be logged
.BuildAsync();
๐ API Reference
Authentication Providers
| Provider | Use Case | Example |
|---|---|---|
ClientSecretCredentialProvider |
Service principal with secret | Dev/test environments |
CertificateCredentialProvider |
Service principal with certificate | High-security production |
ManagedIdentityCredentialProvider |
Azure-hosted resources | App Service, AKS, VMs, Functions |
DefaultCredentialProvider |
Automatic fallback chain | Local dev + production flexibility |
Secrets
| Class | Purpose |
|---|---|
ISecretReader |
Abstraction for secret retrieval (Read-only) |
ISecretManager |
Abstraction for secret management (Read/Write/Delete) |
KeyVaultSecretProvider |
Direct access to Azure Key Vault secrets |
CachedSecretProvider |
Decorator that caches secrets in memory (implements IDisposable) |
Certificates
| Class | Purpose |
|---|---|
ICertificateProvider |
Abstraction for certificate retrieval |
LocalCertificateProvider |
Load from file system or OS certificate store |
KeyVaultCertificateProvider |
Download certificates (with private keys) from Key Vault |
SQL Server
| Class | Purpose |
|---|---|
AlwaysEncryptedProvider |
Registers Azure Key Vault provider for Always Encrypted |
SecureConnectionBuilder |
Fluent API to build SQL connections with encryption + Key Vault integration |
๐๏ธ Architecture
The library is organized by domain, not technical layers:
AzureSecureAccess
โโโ Authentication/ โ How to authenticate with Azure
โโโ Secrets/ โ How to manage secrets
โโโ Certificates/ โ How to retrieve certificates
โโโ SqlServer/ โ How to connect to SQL Server with encryption
Each namespace answers a specific question:
Authentication: How do I prove I'm authorized?Secrets: Where are my configuration secrets?Certificates: Where are my X509 certificates?SqlServer: How do I connect securely to SQL Server?
๐ Security Best Practices
- Use Managed Identity in production โ Eliminates credential management
- Enable caching โ Reduces API calls but be mindful of secret rotation
- Use Always Encrypted โ Protects data at rest and in transit from DBAs
- Store connection strings in Key Vault โ Never hardcode credentials
- Apply the least privilege โ Grant only necessary Key Vault permissions
๐งช Testing
Unit Tests (default)
dotnet test -f net8.0
Integration Tests (Key Vault + Always Encrypted)
Integration tests only run when RUN_INTEGRATION_TESTS=true is set.
Required environment variables:
RUN_INTEGRATION_TESTS=trueAZURE_TENANT_IDAZURE_CLIENT_IDAZURE_CLIENT_SECRETAZURE_KEYVAULT_KEY_IDAZURE_KEYVAULT_NAME(required for Key Vault secret/certificate tests)AZURE_TESTS_KEEP_DB=true(optional, skips DB cleanup for debugging)
Alternative if you prefer to pass Key Vault name + key:
AZURE_KEYVAULT_NAMEAZURE_KEY_NAMEAZURE_KEY_VERSION
Provision a Key Vault + RSA key + app registration:
- Bash:
./scripts/provision-keyvault.sh <resource-group> <location> <keyvault-name> <app-name> - PowerShell:
./scripts/provision-keyvault.ps1 -ResourceGroup <rg> -Location <loc> -KeyVaultName <kv> -AppName <app>
Run integration tests:
RUN_INTEGRATION_TESTS=true dotnet test -f net8.0
Azure Pipelines Variable Group
The pipeline expects a variable group named AzureSecureAccess-Integration.
Create it in Azure DevOps and add these variables:
RUN_INTEGRATION_TESTS=true(orfalseto disable)AZURE_TENANT_IDAZURE_CLIENT_IDAZURE_CLIENT_SECRETAZURE_KEYVAULT_KEY_IDAZURE_KEYVAULT_NAMEAZURE_TESTS_KEEP_DB(optional)
If you want a different group name, update azure-pipelines.yml.
| 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 is compatible. 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 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
- Azure.Core (>= 1.51.1)
- Azure.Identity (>= 1.18.0)
- Azure.Security.KeyVault.Certificates (>= 4.8.0)
- Azure.Security.KeyVault.Secrets (>= 4.9.0)
- Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider (>= 6.1.2)
- Microsoft.Extensions.Caching.Memory (>= 10.0.3)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
- Polly (>= 8.6.5)
-
net8.0
- Azure.Core (>= 1.51.1)
- Azure.Identity (>= 1.18.0)
- Azure.Security.KeyVault.Certificates (>= 4.8.0)
- Azure.Security.KeyVault.Secrets (>= 4.9.0)
- Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider (>= 6.1.2)
- Microsoft.Extensions.Caching.Memory (>= 10.0.3)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
- Polly (>= 8.6.5)
-
net9.0
- Azure.Core (>= 1.51.1)
- Azure.Identity (>= 1.18.0)
- Azure.Security.KeyVault.Certificates (>= 4.8.0)
- Azure.Security.KeyVault.Secrets (>= 4.9.0)
- Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider (>= 6.1.2)
- Microsoft.Extensions.Caching.Memory (>= 10.0.3)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
- Polly (>= 8.6.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.