pvNugsSecretManagerNc10ProviderHVault 10.0.2

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

πŸ” pvNugsSecretManagerNc10ProviderHVault

NuGet Version NuGet Downloads License .NET

HashiCorp Vault provider for the pvWay Secret Manager stack on .NET 10. πŸš€

This package implements IPvNugsSecretProvider and is intended to be used together with:

  • pvNugsSecretManagerNc10 for orchestration, caching, and exception normalization
  • an application-defined IPvNugsSecretManager consumer such as a callerService

πŸ—οΈ Architecture

The current design is intentionally split into three layers:

  1. Caller service / application code injects IPvNugsSecretManager
  2. Secret manager package (pvNugsSecretManagerNc10) orchestrates calls, caching, and logging
  3. Provider package (pvNugsSecretManagerNc10ProviderHVault) talks to HashiCorp Vault
πŸ‘€ Caller service
    ↓ injects
πŸ” IPvNugsSecretManager
    ↓ delegates to
πŸ”· HVaultSecretProvider
    ↓ talks to
🏦 HashiCorp Vault

✨ Features

  • πŸ”‘ Static Secrets: Retrieve secrets from HashiCorp Vault Key-Value (v2) secrets engine
  • 🎫 Dynamic Credentials: Generate temporary database credentials with automatic expiration
  • πŸ” Multiple Authentication: Token-based and Kubernetes authentication
  • πŸ’Ύ Caching Support: Integrates with pvNugs Secret Manager caching layer
  • πŸ“ Comprehensive Logging: Built-in logging for all operations
  • πŸ›‘οΈ Type-Safe Configuration: Strongly-typed configuration using .NET Options pattern
  • ⚠️ Exception Handling: Custom exceptions with detailed error information

βœ… Supported behavior

  • βœ”οΈ GetStaticSecretAsync(...) retrieves a single secret by name from KV v2 store
  • βœ”οΈ GetStaticSecretsAsync(...) retrieves all secrets at a given path in KV v2 store
  • βœ”οΈ GetDynamicSecretAsync(...) generates temporary database credentials with TTL

Unlike Azure Key Vault, HashiCorp Vault natively supports dynamic credential generation for databases, making it ideal for zero-trust security architectures.


πŸ“¦ Installation

Install-Package pvNugsSecretManagerNc10ProviderHVault

Or with the .NET CLI:

dotnet add package pvNugsSecretManagerNc10ProviderHVault

πŸ“š Dependencies

This package depends on:

  • VaultSharp (HashiCorp Vault client library)
  • pvNugsLoggerNc10Abstractions
  • pvNugsSecretManagerNc10Abstractions

The application that uses this provider should also reference:

  • pvNugsSecretManagerNc10
  • one cache implementation and one logger implementation required by the secret manager package

βš™οΈ Configuration

The provider is bound from the PvNugsHVaultSecretProviderConfig section.

🎫 Token Authentication

Token authentication is the simplest method, suitable for development and scenarios where you have direct access to a Vault token.

appsettings.json:

{
  "PvNugsHVaultSecretProviderConfig": {
    "AuthMethod": "TokenAuth",
    "ServerUrl": "http://localhost:8200",
    "TokenFilePath": "vault-token.txt"
  }
}

vault-token.txt:

your-vault-token-here

☸️ Kubernetes Authentication

Kubernetes authentication is recommended for applications running inside a Kubernetes cluster.

appsettings.json:

{
  "PvNugsHVaultSecretProviderConfig": {
    "AuthMethod": "Kubernetes",
    "ServerUrl": "https://vault.example.com",
    "TokenFilePath": "/var/run/secrets/kubernetes.io/serviceaccount/token",
    "KubeMountPoint": "kubernetes",
    "KubeRoleName": "my-app-role",
    "KubeNameSpace": "production"
  }
}

πŸ”§ Service registration

using pvNugsSecretManagerNc10;
using pvNugsSecretManagerNc10Abstractions;
using pvNugsSecretManagerNc10ProviderHVault;

var builder = WebApplication.CreateBuilder(args);

// Register the provider first
builder.Services.TryAddPvNugsHVaultSecretProvider(builder.Configuration);

// Register the provider-agnostic manager
builder.Services.TryAddPvNugsSecretManager(builder.Configuration);

var app = builder.Build();

πŸ’‘ Usage

Your caller service should depend on IPvNugsSecretManager, not on the Vault provider directly.

πŸ”‘ Retrieving Static Secrets

Static secrets are stored in the Key-Value (v2) secrets engine.

Example:

using pvNugsSecretManagerNc10Abstractions;
using pvNugsSecretManagerNc10ProviderHVault;

var secretManager = serviceProvider.GetRequiredService<IPvNugsSecretManager>();

// Retrieve a single secret
var parameters = PvNugsHVaultSecretProviderParameters.CreateStaticParameters(
    mountPoint: "secret",           // KV mount point
    path: "myapp/config",           // Path to secret
    secretName: "api-key"           // Specific secret name
);

var apiKey = await secretManager.GetStaticSecretAsync(parameters);
Console.WriteLine($"API Key: {apiKey}");

// Retrieve all secrets at a path
var allParameters = PvNugsHVaultSecretProviderParameters.CreateStaticParameters(
    mountPoint: "secret",
    path: "myapp/config",
    secretName: null                // null retrieves all secrets
);

var allSecrets = await secretManager.GetStaticSecretsAsync(allParameters);
foreach (var secret in allSecrets)
{
    Console.WriteLine($"{secret.Key}: {secret.Value}");
}

🎫 Generating Dynamic Credentials

Dynamic credentials are temporary database credentials with automatic expiration.

Example:

var parameters = PvNugsHVaultSecretProviderParameters.CreateDynamicParameters(
    mountPoint: "database/postgres/pg5432",  // Database mount point
    roleName: "owner",                       // Database role
    timeToLive: "1h"                         // Optional: requested TTL
);

var credential = await secretManager.GetDynamicSecretAsync(parameters);

Console.WriteLine($"Username: {credential.Username}");
Console.WriteLine($"Password: {credential.Password}");
Console.WriteLine($"Expires: {credential.ExpirationDateUtc}");

// Use the credentials
var connectionString = $"Host=localhost;Username={credential.Username};Password={credential.Password};Database=mydb";

Time-To-Live Format:

The timeToLive parameter uses HashiCorp Vault's duration format (NOT .NET TimeSpan format):

  • "30s" - 30 seconds
  • "5m" - 5 minutes
  • "1h" - 1 hour
  • "24h" - 24 hours
  • "7d" - 7 days

Valid units: s (seconds), m (minutes), h (hours), d (days)


πŸ§ͺ Testing

πŸ“‹ Prerequisites

  1. Docker Desktop - Required for running the test environment
  2. .NET 10 SDK - Required for building and running the test console

🐳 Setting Up the Test Environment

The repository includes a complete Docker-based test environment with HashiCorp Vault, PostgreSQL databases, and pgAdmin.

Download the test files from GitHub:

Navigate to the test directory:

src/SecretManager/nc10/Testing/intTesting/pvNugsSecretManagerNc10VaultLab.it/

Files to download:

  • compose.yaml - Docker Compose configuration
  • servers.json - pgAdmin server configuration
  • Program.cs - Vault provisioning console

Start the test environment:

# Pull required Docker images
docker compose pull

# Start all services (Vault, PostgreSQL, pgAdmin)
docker compose up -d

# Verify services are running
docker compose ps

Services:

Service URL Purpose
Vault API http://localhost:8200 HashiCorp Vault server
Vault UI http://localhost:8200/ui Vault web interface
PostgreSQL (pg5432) localhost:5432 Test database 1
PostgreSQL (pg5433) localhost:5433 Test database 2
pgAdmin http://localhost:5050 PostgreSQL admin interface

Default Credentials:

  • Vault Token: dev-only-token
  • PostgreSQL Password: dev-only-password
  • pgAdmin Email: admin@example.com
  • pgAdmin Password: dev-only-password

βš™οΈ Provisioning Vault

Before running tests, you must provision Vault with the required configuration:

# Navigate to the provisioning console directory
cd src/SecretManager/nc10/Testing/intTesting/pvNugsSecretManagerNc10VaultLab.it/

# Run the provisioning console
dotnet run

What it does:

  • Creates Database secrets engines for both PostgreSQL instances
  • Configures database connections: pg5432 and pg5433
  • Creates the owner role with 1-minute default TTL (1-hour max)
  • Configures dynamic credential generation

Provisioned Vault Structure:

database/postgres/pg5432
    β”œβ”€β”€ connection: pg5432 β†’ postgres5432:5432
    └── role: owner (creates temporary database users)

database/postgres/pg5433
    β”œβ”€β”€ connection: pg5433 β†’ postgres5433:5432
    └── role: owner (creates temporary database users)

secret (Key-Value v2)
    └── secret-manager-test
        └── api-key: "my-super-secret-api-key"

▢️ Running the Tests

Once the environment is provisioned, run the integration tests:

# Navigate to the integration test console directory
cd src/SecretManager/nc10/Testing/intTesting/pvNugsSecretManagerNc10ProviderHVault.it/

# Ensure token.txt exists with content: dev-only-token
echo dev-only-token > token.txt

# Run the integration tests
dotnet run

Expected output:

Integration Testing Console for HashiCorp Vault SecretProvider .NET 10
Retrieving Static Secrets from PvNugsSecretManager
[TRACE] Static Secret Retrieved: my-super-secret-api-key
Retrieving Dynamic Secret from HashiCorp Vault with parameters: mountPoint='database/postgres/pg5432', role='owner'
[TRACE] Dynamic Secret Retrieved: v-token-owner-AbCdEfGh123 / P@ssw0rd123 / 2026-08-14 14:30:00Z

Cleanup:

# Stop and remove all containers
docker compose down

# Remove volumes (optional - clears all data)
docker compose down -v

πŸ” Inspecting Dynamic Credentials

You can verify that Vault is creating temporary database users using pgAdmin:

  1. Open http://localhost:5050
  2. Login with admin@example.com / dev-only-password
  3. Connect to pg5432 server (password: dev-only-password)
  4. Navigate to: Servers β†’ pg5432 β†’ Login/Group Roles
  5. You'll see dynamically created users like v-token-owner-AbCdEfGh123

πŸ“ API Reference

PvNugsHVaultSecretProviderParameters

Factory methods for creating parameter dictionaries:

// Static secrets
public static IReadOnlyDictionary<string, string> CreateStaticParameters(
    string mountPoint,      // KV mount point (e.g., "secret")
    string path,            // Path to secret (e.g., "myapp/config")
    string? secretName      // Optional: specific secret name
)

// Dynamic credentials
public static IReadOnlyDictionary<string, string> CreateDynamicParameters(
    string mountPoint,      // Database mount point (e.g., "database/postgres/pg5432")
    string roleName,        // Database role (e.g., "owner")
    string? timeToLive      // Optional: TTL in Vault format (e.g., "1h")
)

HVaultDatabaseSecret

Represents a dynamic database credential:

public class HVaultDatabaseSecret : IPvNugsDynamicCredential
{
    public string Username { get; set; }
    public string Password { get; set; }
    public TimeSpan TimeToLive { get; set; }
    public DateTime ExpiresOnUtc { get; set; }
    public DateTime ExpirationDateUtc { get; }  // Alias for ExpiresOnUtc
}

PvNugsHVaultSecretProviderConfig

Configuration options:

public class PvNugsHVaultSecretProviderConfig
{
    // Common settings
    public PvNugsHVaultSecretProviderAuthEnu AuthMethod { get; set; }
    public string ServerUrl { get; set; }
    public string TokenFilePath { get; set; }
    public string? Token { get; set; }  // Optional: set programmatically

    // Kubernetes-specific settings
    public string KubeMountPoint { get; set; }
    public string KubeRoleName { get; set; }
    public string KubeNameSpace { get; set; }
}

πŸ“ Architecture Details

Component Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Application Code                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   IPvNugsSecretManager                  β”‚
β”‚   (Caching Layer)                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   IPvNugsSecretProvider                 β”‚
β”‚   (HVaultSecretProvider)                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   HashiCorp Vault                       β”‚
β”‚   β”œβ”€β”€ KV Secrets Engine (v2)           β”‚
β”‚   └── Database Secrets Engine           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Class Hierarchy

HVaultSecretProvider : IPvNugsSecretProvider
    β”œβ”€β”€ GetStaticSecretsAsync()   β†’ Vault KV v2
    β”œβ”€β”€ GetStaticSecretAsync()    β†’ Vault KV v2
    └── GetDynamicSecretAsync()   β†’ Vault Database Engine

HVaultDatabaseSecret : IPvNugsDynamicCredential
    β”œβ”€β”€ Username
    β”œβ”€β”€ Password
    β”œβ”€β”€ TimeToLive
    └── ExpirationDateUtc

PvNugsHVaultException : Exception

πŸ›‘οΈ Security Considerations

🏭 Production Deployment

  1. Use HTTPS: Always use https:// for Vault server URLs in production
  2. Token Security: Never commit tokens to source control
  3. File Permissions: Ensure token files have restrictive permissions (chmod 600)
  4. Token Rotation: Implement regular token rotation policies
  5. Credential TTL: Set appropriate time-to-live values for dynamic credentials
  6. Network Security: Restrict Vault access to authorized networks only

⚠️ Vault DEV Mode Warning

⚠️ The Docker test environment runs Vault in DEV mode:

  • Data is stored in memory (not persistent)
  • Uses a static root token (dev-only-token)
  • TLS is disabled
  • NEVER use DEV mode in production

For production, use:

  • Sealed Vault with proper unsealing procedures
  • Persistent storage backend (Consul, etcd, cloud storage)
  • TLS encryption for all communication
  • Proper authentication methods (AppRole, Kubernetes, OIDC)
  • High availability configuration

πŸ”§ Troubleshooting

Common Issues

Problem: "Unable to connect to HashiCorp Vault"

  • Verify Vault is running: docker compose ps
  • Check Vault URL is correct: http://localhost:8200
  • Test connectivity: curl http://localhost:8200/v1/sys/health

Problem: "Token file not found"

  • Ensure token.txt exists in the correct directory
  • Verify TokenFilePath in configuration matches actual file path
  • Check file permissions

Problem: "PvNugsHVaultException occurred"

  • Check Vault logs: docker compose logs vault
  • Verify mount points and paths are correct
  • Ensure Vault has been provisioned (run the provisioning console)

Problem: Dynamic credentials fail

  • Verify the database secrets engine is enabled
  • Check database connection is configured correctly
  • Ensure the role exists: vault list database/postgres/pg5432/roles
  • Verify PostgreSQL is accessible from Vault container

Problem: "Sealed Vault"

  • In DEV mode, Vault should auto-unseal
  • If using production Vault, you must unseal it manually
  • Check Vault status: curl http://localhost:8200/v1/sys/health

Enabling Detailed Logging

Add to appsettings.json:

{
  "PvNugsLoggerConfig": {
    "MinLogLevel": "trace"
  }
}

This enables verbose logging for all Vault operations.


  • pvNugsSecretManagerNc10Abstractions: interfaces
  • pvNugsSecretManagerNc10: caching, logging, orchestration
  • pvNugsSecretManagerNc10ProviderHVault: HashiCorp Vault provider

πŸ“„ License

MIT β€” see LICENSE.


Happy Secret Managing! πŸ”

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

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
10.0.2 93 10/11/2026
10.0.1 254 8/18/2026
10.0.0 123 8/14/2026

Updated dependencies