mrhamburg.SecretsManager 0.0.1

dotnet add package mrhamburg.SecretsManager --version 0.0.1
                    
NuGet\Install-Package mrhamburg.SecretsManager -Version 0.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="mrhamburg.SecretsManager" Version="0.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="mrhamburg.SecretsManager" Version="0.0.1" />
                    
Directory.Packages.props
<PackageReference Include="mrhamburg.SecretsManager" />
                    
Project file
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 mrhamburg.SecretsManager --version 0.0.1
                    
#r "nuget: mrhamburg.SecretsManager, 0.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 mrhamburg.SecretsManager@0.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=mrhamburg.SecretsManager&version=0.0.1
                    
Install as a Cake Addin
#tool nuget:?package=mrhamburg.SecretsManager&version=0.0.1
                    
Install as a Cake Tool

<p align="center"> <img src="hero.svg" alt="SecretsManager - Unified .NET Secret Management" width="800"> </p>

.NET 10.0 License: MIT OR Apache-2.0 CI Integration tests

A unified .NET abstraction layer over secret management backends, inspired by the External Secrets Operator for Kubernetes. Program against a single ISecretProvider interface regardless of where your secrets live.

Features

  • Unified API — Get, put, delete, version, and check secrets through one interface
  • Multiple backends — Filesystem, Azure Key Vault, Scaleway, AWS, Google Cloud, Oracle Vault, IBM Cloud, PostgreSQL, OVH, Passbolt, Aliyun KMS, Tencent Cloud, Infisical, HashiCorp Vault, CyberArk Conjur
  • Flexible configuration — Fluent API, environment variables, or YAML (ESO-style)
  • Secret versioning — First-class support for secret version history across all providers
  • JSON property extraction — Retrieve nested values from JSON secrets via dot-path queries
  • Zero unnecessary dependencies — Each provider is a separate package; only pull in what you use

NuGet package prefix: The SecretsManager package ID is already taken on nuget.org by another publisher, so every package in this project is published as mrhamburg.SecretsManager.*. The C# namespaces remain SecretsManager.*.

Providers

Provider Package Description
Core mrhamburg.SecretsManager Shared abstractions, builder, and runtime model types
FileSystem mrhamburg.SecretsManager.FileSystem Local encrypted file storage (AES-256-GCM)
Azure Key Vault mrhamburg.SecretsManager.AzureKeyVault Azure Key Vault via official SDK
Scaleway mrhamburg.SecretsManager.Scaleway Scaleway Secret Manager via REST API
IBM Cloud Secrets Manager mrhamburg.SecretsManager.IBMCloudSecretsManager IBM Cloud Secrets Manager via REST API
PostgreSQL mrhamburg.SecretsManager.PostgreSql PostgreSQL-backed encrypted storage with versioning
OVH mrhamburg.SecretsManager.OVH OVH Secret Manager / OKMS via REST API
AWS Secrets Manager mrhamburg.SecretsManager.AwsSecretsManager AWS Secrets Manager via AWS SDK
Oracle Vault mrhamburg.SecretsManager.OracleVault Oracle Cloud Secret Manager via OCI SDK
Google Cloud Secret Manager mrhamburg.SecretsManager.GoogleSecretManager Google Secret Manager via GCP SDK
Passbolt mrhamburg.SecretsManager.Passbolt Passbolt secret management via REST API
Aliyun KMS mrhamburg.SecretsManager.AliyunKms Aliyun KMS via REST API
Tencent Cloud mrhamburg.SecretsManager.TencentCloud Tencent Cloud Secrets Manager via REST API
Infisical mrhamburg.SecretsManager.Infisical Infisical via the official .NET SDK
HashiCorp Vault mrhamburg.SecretsManager.Vault HashiCorp Vault KV v2 engine via REST API
CyberArk Conjur mrhamburg.SecretsManager.Conjur CyberArk Conjur via REST API

Integration tests

Integration tests run each provider against a live service in CI. The table shows the latest result on main. A grey no check runs pill means the provider's CI secrets are not configured, so the job is skipped.

Provider Integration test config Latest status on main
FileSystem configs/filesystem.yaml FileSystem integration tests
Azure Key Vault configs/azure-keyvault.yaml Azure Key Vault integration tests
Scaleway configs/scaleway.yaml Scaleway integration tests
PostgreSQL configs/postgresql.yaml PostgreSQL integration tests
OVH configs/ovh.yaml OVH integration tests
AWS Secrets Manager configs/aws-secrets-manager.yaml AWS integration tests
Oracle Vault configs/oracle-vault.yaml Oracle Vault integration tests
Google Cloud Secret Manager configs/google-secret-manager.yaml Google Secret Manager integration tests
Passbolt configs/passbolt.yaml Passbolt integration tests
Aliyun KMS configs/aliyun-kms.yaml Aliyun KMS integration tests
IBM Cloud Secrets Manager configs/ibm-cloud-secrets-manager.yaml IBM Cloud Secrets Manager integration tests
Tencent Cloud configs/tencent-cloud.yaml Tencent Cloud integration tests
HashiCorp Vault configs/vault.yaml HashiCorp Vault integration tests
Infisical configs/infisical.yaml Infisical integration tests
CyberArk Conjur configs/conjur.yaml CyberArk Conjur integration tests

Passbolt is disabled in CI (if: false), so its badge stays grey until the job is enabled.

Quick Start

using SecretsManager;
using SecretsManager.FileSystem;

await using var provider = new SecretProviderBuilder()
    .WithFileSystem(opts =>
    {
        opts.BasePath = "/secrets";
        opts.EncryptionKey = "base64encodedkey==";
    })
    .Build();

// Store a secret
await provider.PutSecretAsync("api-key", "sk-secret-value");

// Retrieve it
var secret = await provider.GetSecretAsync("api-key");
Console.WriteLine(secret.Value);

// Check existence
if (await provider.SecretExistsAsync("api-key"))
    Console.WriteLine("Secret exists!");

// List versions
var versions = await provider.GetSecretVersionsAsync("api-key");

// Delete
await provider.DeleteSecretAsync("api-key");

Layers

Layers are decorators that wrap a provider to add operational capabilities like retries, timeouts, logging, and observability. They are applied in registration order using the builder's fluent API.

Available Layers

Layer Extension Method Description
ConcurrentLimiterLayer .WithConcurrentLimiter() Limits concurrent operations with an optional acquire timeout
RetryLayer .WithRetry() Retries failed operations with exponential backoff and jitter
TimeoutLayer .WithTimeout() Enforces a per-operation timeout
LoggingLayer .WithLogging() Logs start, success, failure, and retry events. Includes a Microsoft.Extensions.Logging adapter
AuditLayer .WithAudit() / .WithAuditSink() Writes durable per-access audit records without secret values
OtelMetricsLayer .WithOtelMetrics() Emits OpenTelemetry-compatible metrics (counters, histograms)
OtelTraceLayer .WithOtelTrace() Emits OpenTelemetry-compatible distributed traces

Layer Configuration

await using var provider = new SecretProviderBuilder()
    .WithFileSystem(opts =>
    {
        opts.BasePath = "/secrets";
        opts.EncryptionKey = "base64encodedkey==";   // omit only for throwaway local development
    })
    .WithConcurrentLimiter(opts => {
        opts.MaxConcurrentRequests = 10;
        opts.AcquireTimeout = TimeSpan.FromSeconds(5);
    })
    .WithRetry(opts => {
        opts.MaxAttempts = 3;
        opts.BaseDelay = TimeSpan.FromMilliseconds(100);
        opts.MaxDelay = TimeSpan.FromSeconds(2);
        opts.JitterFactor = 0.2;
    })
    .WithTimeout(opts => opts.Timeout = TimeSpan.FromSeconds(30))
    .WithLogging(opts => {
        opts.Logger = new LoggerSecretProviderLogger(logger);   // Microsoft.Extensions.Logging
        opts.OperationPrefix = "secrets";
    })
    .WithOtelMetrics(opts => {
        opts.MeterName = "SecretsManager";
        opts.MetricPrefix = "secrets.";
    })
    .WithOtelTrace(opts => {
        opts.ActivitySourceName = "SecretsManager";
        opts.RecordException = true;
    })
    .Build();

Layers are processed in registration order (outermost to innermost). The first registered layer wraps the provider, and each subsequent layer wraps the previous one.

Audit Trail

The audit layer writes one durable record per secret operation: operation, provider, key, version, outcome, timestamp, actor, trace id, and failure type. Records never contain secret values, and a failing sink does not change the operation's outcome by default.

var provider = new SecretProviderBuilder()
    .WithFileSystem(opts => opts.BasePath = "/secrets")
    .WithAudit(opts =>
    {
        opts.Sinks.Add(new FileSecretAuditSink("/var/log/secrets-audit.jsonl"));
    })
    .Build();

mrhamburg.SecretsManager.PostgreSql also ships PostgreSqlSecretAuditSink, available through .WithPostgreSqlAuditSink(...). See Audit Trail for actor propagation, scopes, failure modes, and the PostgreSQL table schema.

Configuration

SecretsManager supports four ways to configure a provider.

Fluent API

var provider = new SecretProviderBuilder()
    .WithFileSystem(opts =>
    {
        opts.BasePath = "/secrets";
        opts.EncryptionKey = "base64encodedkey==";
    })
    .Build();

Dependency Injection (IOptions<T>)

Bind options from appsettings.json through the DI container:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSecretsManager();
builder.Services.Configure<FileSystemOptions>(
    builder.Configuration.GetSection("SecretsManager:FileSystem"));

// Or bind and build in one step
var provider = new SecretProviderBuilder()
    .ConfigureFileSystem(builder.Configuration)
    .Build();
{
  "SecretsManager": {
    "FileSystem": {
      "BasePath": "/secrets",
      "EncryptionKey": "base64encodedkey=="
    }
  }
}

Environment Variables

export SECRETS_PROVIDER=filesystem
export SECRETS_FILESYSTEM_PATH=/secrets
export SECRETS_FILESYSTEM_ENCRYPTION_KEY=base64encodedkey==
var provider = new SecretProviderBuilder()
    .WithFileSystem()
    .FromEnvironment()
    .Build();

YAML (External Secrets Operator Style)

provider:
  filesystem:
    path: /secrets
    encryption:
      key: base64encodedkey==
var provider = new SecretProviderBuilder()
    .WithFileSystem()
    .FromYamlFile("secretstore.yaml")
    .Build();

Supported Provider Docs

See the full provider setup and configuration details in the docs:

API Reference

All providers implement ISecretProvider:

Method Description
GetSecretAsync(key, query?, ct) Retrieve a secret, optionally by version or JSON property path
PutSecretAsync(key, value, metadata?, ct) Create or update a secret
DeleteSecretAsync(key, ct) Delete a secret
GetSecretVersionsAsync(key, ct) List all versions of a secret
SecretExistsAsync(key, ct) Check existence without fetching the value

ISecretProvider extends IAsyncDisposable — use await using for proper cleanup.

Building from Source

dotnet build
dotnet test

Run tests with code coverage:

dotnet test --collect:"XPlat Code Coverage"

Adding a New Provider

  1. Create src/SecretsManager.<Name>/ with a project reference to the core SecretsManager library. Its package ID (mrhamburg.SecretsManager.<Name>) is derived automatically from the project name by src/Directory.Build.props
  2. Implement ISecretProvider
  3. Implement ISecretProviderFactory to map flat configuration dictionaries to your options
  4. Add a SecretProviderBuilderExtensions class with .With<Name>() extension method
  5. Add a test project under tests/SecretsManager.<Name>.Tests/
  6. Register both projects in SecretsManager.sln
  7. Add an integration-test CI job named Integration tests (<Name>), include it in the integration-status needs list, and add its badge row to README.md and docs/docs/providers/overview.md

License

This project is dual-licensed under your choice of:

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (15)

Showing the top 5 NuGet packages that depend on mrhamburg.SecretsManager:

Package Downloads
mrhamburg.SecretsManager.PostgreSql

PostgreSQL secret provider with AES-256-GCM encryption at rest for SecretsManager

mrhamburg.SecretsManager.OVH

OVHcloud secret provider for SecretsManager

mrhamburg.SecretsManager.Conjur

CyberArk Conjur secret provider for SecretsManager

mrhamburg.SecretsManager.FileSystem

Filesystem-backed secret provider with AES-256-GCM encryption for SecretsManager

mrhamburg.SecretsManager.AliyunKms

Aliyun KMS secret provider for SecretsManager

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.1 309 10/30/2026