Getting Started
Prerequisites
Before using Vault.Extension.Configuration, ensure you have:
- .NET 8.0 or later installed
- Access to a HashiCorp Vault server
- Appropriate authentication credentials (token, AWS IAM role, or custom method)
Installation
Install the NuGet package using one of the following methods:
.NET CLI
dotnet add package Vault.Extension.Configuration
Package Manager Console
Install-Package Vault.Extension.Configuration
PackageReference
Add to your .csproj file:
<PackageReference Include="Vault.Extension.Configuration" Version="*" />
Basic Setup
Step 1: Register Vault Services
Use the AddVault extension method on IServiceCollection to register Vault services:
using Vault.Extentions;
using Vault.Options;
using Vault.Enum;
var builder = WebApplication.CreateBuilder(args);
// Register VaultService with dependency injection
builder.Services.AddVault(
builder.Configuration,
new VaultOptions
{
AuthenticationType = VaultAuthenticationType.Local,
Configuration = new VaultLocalConfiguration
{
VaultUrl = "https://vault.example.com",
MountPoint = "secret",
TokenFilePath = "~/.vault-token"
}
},
environment: "production");
var app = builder.Build();
// Initialize Vault providers (required!)
app.UseVault();
app.Run();
Step 2: Choose Your Authentication Method
The library supports three authentication methods:
Option A: Local Token (Development)
Best for local development with a Vault token file:
var vaultOptions = new VaultOptions
{
AuthenticationType = VaultAuthenticationType.Local,
Configuration = new VaultLocalConfiguration
{
VaultUrl = "https://vault.example.com",
MountPoint = "secret",
TokenFilePath = "~/.vault-token",
IgnoreSslErrors = false // Only true for development
}
};
builder.Services.AddVault(builder.Configuration, vaultOptions, environment: "development");
Option B: AWS IAM (Production on AWS)
Ideal for applications running on AWS infrastructure:
var vaultOptions = new VaultOptions
{
AuthenticationType = VaultAuthenticationType.AWS_IAM,
Configuration = new VaultAwsConfiguration
{
VaultUrl = "https://vault.example.com",
MountPoint = "secret",
Environment = "production",
AwsAuthMountPoint = "aws",
AwsIamRoleName = "my-app-role" // Optional
}
};
builder.Services.AddVault(builder.Configuration, vaultOptions, environment: "production");
Option C: Custom Authentication
For other authentication methods (AppRole, LDAP, UserPass, Kubernetes, etc.):
using VaultSharp.V1.AuthMethods.AppRole;
var vaultOptions = new VaultOptions
{
AuthenticationType = VaultAuthenticationType.Custom,
Configuration = new VaultDefaultConfiguration
{
VaultUrl = "https://vault.example.com",
MountPoint = "secret"
},
CustomAuthMethodInfo = new AppRoleAuthMethodInfo("my-role-id", "my-secret-id")
};
builder.Services.AddVault(builder.Configuration, vaultOptions, environment: "production");
Using Secrets in Your Application
Method 1: IConfiguration (Recommended for Static Configuration)
Secrets are automatically loaded into the configuration system:
public class DatabaseService
{
private readonly IConfiguration _configuration;
public DatabaseService(IConfiguration configuration)
{
_configuration = configuration;
}
public void Connect()
{
// Access secrets like any other configuration value
var connectionString = _configuration["Database:ConnectionString"];
var password = _configuration["Database:Password"];
// Use the secrets
Console.WriteLine($"Connecting with password: {password?.Substring(0, 3)}...");
}
}
Method 2: IOptions Pattern (Strongly-Typed Configuration)
Bind Vault secrets to strongly-typed classes:
// Define your settings class
public class DatabaseSettings
{
public string ConnectionString { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public int Timeout { get; set; } = 30;
}
// In Program.cs - bind configuration section
builder.Services.Configure<DatabaseSettings>(
builder.Configuration.GetSection("Database"));
// Use in your services with type safety
public class DatabaseService
{
private readonly DatabaseSettings _settings;
public DatabaseService(IOptions<DatabaseSettings> options)
{
_settings = options.Value;
}
public void Connect()
{
var fullConnectionString = $"{_settings.ConnectionString};Password={_settings.Password};Timeout={_settings.Timeout}";
// Use connection string
}
}
Method 3: IVaultService (Dynamic Secret Retrieval)
For runtime secret access and dynamic scenarios:
using Vault.Abstractions;
public class SecretManager
{
private readonly IVaultService _vaultService;
public SecretManager(IVaultService vaultService)
{
_vaultService = vaultService;
}
// Get a single secret value
public async Task<string?> GetApiKeyAsync()
{
var apiKey = await _vaultService.GetSecretValueAsync("production", "ApiKey");
return apiKey?.ToString();
}
// Get all secrets for an environment
public async Task<Dictionary<string, object>> LoadAllSecretsAsync()
{
return await _vaultService.GetSecretsAsync("production");
}
// Get nested secret using dot notation
public async Task<string?> GetNestedValueAsync()
{
// Access nested structure: { "Api": { "Settings": { "Key": "value" } } }
var value = await _vaultService.GetNestedSecretValueAsync("production", "Api.Settings.Key");
return value?.ToString();
}
// List all available environments
public async Task<IEnumerable<string>> GetEnvironmentsAsync()
{
return await _vaultService.ListEnvironmentsAsync();
}
}
Complete Example
Here's a complete example combining all three approaches:
using Vault.Extentions;
using Vault.Options;
using Vault.Enum;
using Vault.Abstractions;
var builder = WebApplication.CreateBuilder(args);
// 1. Configure Vault
var vaultOptions = new VaultOptions
{
AuthenticationType = VaultAuthenticationType.AWS_IAM,
Configuration = new VaultAwsConfiguration
{
VaultUrl = "https://vault.example.com",
MountPoint = "myapp",
Environment = "production"
}
};
builder.Services.AddVault(builder.Configuration, vaultOptions, environment: "production");
// 2. Register strongly-typed configuration
public class ApiSettings
{
public string ApiKey { get; set; } = string.Empty;
public string BaseUrl { get; set; } = string.Empty;
}
builder.Services.Configure<ApiSettings>(builder.Configuration.GetSection("Api"));
// 3. Register your services
builder.Services.AddScoped<SecretManager>();
var app = builder.Build();
// Initialize Vault (required!)
app.UseVault();
// Example endpoints showing all three usage patterns
app.MapGet("/config", (IConfiguration config) =>
{
return new
{
apiKey = config["Api:ApiKey"],
baseUrl = config["Api:BaseUrl"]
};
});
app.MapGet("/options", (IOptions<ApiSettings> options) =>
{
return new { settings = options.Value };
});
app.MapGet("/vault", async (IVaultService vault) =>
{
return await vault.GetSecretsAsync("production");
});
app.Run();
Vault Server Setup
Required Vault Configuration
Enable KV Secrets Engine (v2):
vault secrets enable -path=secret kv-v2Create secrets for your environment:
# Simple key-value secrets vault kv put secret/production \ ApiKey="your-api-key" \ Database:ConnectionString="Server=..." \ Database:Password="secret-password" # Nested structure vault kv put secret/production \ Api.Settings.Key="api-key" \ Api.Settings.BaseUrl="https://api.example.com"Configure authentication method:
For Local (token-based):
# Generate a token vault token create -policy=secret-read # Save token to file (e.g., ~/.vault-token)For AWS IAM:
vault auth enable aws vault write auth/aws/role/myapp-production-role \ auth_type=iam \ bound_iam_principal_arn="arn:aws:iam::123456789:role/my-app-role" \ policies=myapp-production-policy \ max_ttl=1hFor AppRole:
vault auth enable approle vault write auth/approle/role/my-app \ token_policies=secret-read \ token_ttl=1h vault read auth/approle/role/my-app/role-id vault write -f auth/approle/role/my-app/secret-idCreate policy for secret access:
vault policy write myapp-production-policy - <<EOF path "secret/data/production/*" { capabilities = ["read", "list"] } path "secret/metadata/production/*" { capabilities = ["read", "list"] } EOF
Important: UseVault() Call
You must call app.UseVault() after building your application! This initializes the Vault configuration providers:
var app = builder.Build();
// This is REQUIRED - do not forget!
app.UseVault();
app.MapControllers();
app.Run();
Without UseVault(), secrets won't be loaded into the configuration system.
Error Handling
The library provides specific exceptions for different scenarios:
using Vault.Exceptions;
try
{
var vaultOptions = new VaultOptions { /* ... */ };
builder.Services.AddVault(builder.Configuration, vaultOptions, environment: "production");
var app = builder.Build();
app.UseVault();
}
catch (VaultConfigurationException ex)
{
// Configuration validation errors
Console.Error.WriteLine($"Configuration error: {ex.Message}");
throw;
}
catch (VaultAuthenticationException ex)
{
// Authentication failures
Console.Error.WriteLine($"Authentication failed: {ex.Message}");
throw;
}
catch (FileNotFoundException ex) when (ex.Message.Contains("Token file"))
{
// Missing token file (Local authentication)
Console.Error.WriteLine($"Token file not found: {ex.Message}");
throw;
}
Best Practices
1. Use Environment-Specific Configuration
var environment = builder.Environment.EnvironmentName; // "Development", "Production", etc.
var vaultOptions = new VaultOptions
{
AuthenticationType = builder.Environment.IsDevelopment()
? VaultAuthenticationType.Local
: VaultAuthenticationType.AWS_IAM,
Configuration = builder.Environment.IsDevelopment()
? new VaultLocalConfiguration
{
VaultUrl = "http://localhost:8200",
MountPoint = "secret",
TokenFilePath = "~/.vault-token",
IgnoreSslErrors = true // Only in development!
}
: new VaultAwsConfiguration
{
VaultUrl = "https://vault.production.example.com",
MountPoint = "myapp",
Environment = "production"
}
};
builder.Services.AddVault(builder.Configuration, vaultOptions, environment: environment);
2. Use Environment Variables for Vault Configuration
var vaultOptions = new VaultOptions
{
AuthenticationType = VaultAuthenticationType.Local,
Configuration = new VaultLocalConfiguration
{
VaultUrl = Environment.GetEnvironmentVariable("VAULT_URL")
?? throw new InvalidOperationException("VAULT_URL not set"),
MountPoint = Environment.GetEnvironmentVariable("VAULT_MOUNT_POINT") ?? "secret",
TokenFilePath = Environment.GetEnvironmentVariable("VAULT_TOKEN_FILE") ?? "~/.vault-token"
}
};
3. Never Disable SSL in Production
var vaultOptions = new VaultOptions
{
Configuration = new VaultLocalConfiguration
{
VaultUrl = "https://vault.example.com",
MountPoint = "secret",
TokenFilePath = "~/.vault-token",
// NEVER set to true in production!
IgnoreSslErrors = builder.Environment.IsDevelopment()
}
};
4. Validate Configuration Early
try
{
var app = builder.Build();
app.UseVault();
await app.RunAsync();
}
catch (VaultConfigurationException ex)
{
Console.Error.WriteLine($"Vault configuration invalid: {ex.Message}");
Environment.Exit(1);
}
5. Choose the Right Access Pattern
- IConfiguration: Best for secrets needed at startup (database connections, API keys loaded once)
- IOptions
: Best for strongly-typed configuration with validation - IVaultService: Best for dynamic secret retrieval, refreshing secrets, or runtime access
Troubleshooting
"VaultService not registered" error
Ensure you call AddVault() before building the application:
builder.Services.AddVault(builder.Configuration, vaultOptions, environment: "production");
var app = builder.Build();
Secrets not appearing in IConfiguration
- Verify you called
app.UseVault()after building - Check the environment parameter matches your Vault path
- Ensure secrets exist at
{MountPoint}/data/{environment}/(KV v2) - Verify authentication and permissions
Authentication failures
Local: Check token file exists, is readable, and contains a valid token
cat ~/.vault-token vault token lookupAWS IAM: Ensure the EC2/ECS instance has the correct IAM role attached
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/AppRole: Verify role-id and secret-id are correct
vault write auth/approle/login role_id="..." secret_id="..."
SSL certificate errors
For production, ensure proper certificates. For development:
IgnoreSslErrors = builder.Environment.IsDevelopment()
Or configure your system to trust the Vault CA certificate.
"Unable to load service index" or connection errors
- Verify Vault URL is accessible from your application
- Check firewall rules and network connectivity
- Ensure Vault is running:
vault status
Next Steps
- Learn about all Features and advanced capabilities
- See example projects in the GitHub repository