EonaCat.SecretVault.Client
1.0.0
Prefix Reserved
dotnet add package EonaCat.SecretVault.Client --version 1.0.0
NuGet\Install-Package EonaCat.SecretVault.Client -Version 1.0.0
<PackageReference Include="EonaCat.SecretVault.Client" Version="1.0.0" />
<PackageVersion Include="EonaCat.SecretVault.Client" Version="1.0.0" />
<PackageReference Include="EonaCat.SecretVault.Client" />
paket add EonaCat.SecretVault.Client --version 1.0.0
#r "nuget: EonaCat.SecretVault.Client, 1.0.0"
#:package EonaCat.SecretVault.Client@1.0.0
#addin nuget:?package=EonaCat.SecretVault.Client&version=1.0.0
#tool nuget:?package=EonaCat.SecretVault.Client&version=1.0.0
EonaCat.SecretVault
Generate a secure vault for storing secrets like API keys, passwords, and other sensitive information.
Overview
EonaCat.SecretVault is a secure multi-tenant offline vault for storing secrets using AES encryption and SQLite, protected with API key authentication and per-tenant encryption keys. It consists of a server that manages the storage and retrieval of secrets, and a client library that allows you to interact with the server. The server provides a RESTful API for storing and retrieving secrets, while the client library simplifies the interaction with the server.
Features
- Secure storage of secrets
- RESTful API for storing and retrieving secrets
- Client library for easy interaction with the server
- Multi-tenancy support
- Supports HMAC authentication for secure access
- Supports SQLite for data storage
- Audit logging
- Cross-platform compatibility
- Easy to use
- Open-source and free to use
Extra security notices:
- Rotate your API keys regularly.
- Use strong, unique API keys for each tenant.
- Ensure your
ROOT_PROTECTOR_KEY
is kept secret and secure. - Rotate the
ROOT_PROTECTOR_KEY
if you suspect it has been compromised. - Use HTTPS to encrypt data in transit.
API Keys
- API keys are generated as secure random 256-bit strings.
- Only SHA256 hashes of API keys are stored in the database.
- Incoming API keys are hashed and compared against stored hashes for authentication.
Per-Tenant Encryption Keys
- Each tenant has a unique 256-bit AES key, encrypted at rest with a master root key (
ROOT_PROTECTOR_KEY
). - Tenant keys are decrypted only in-memory during operations.
🧩 Multi-Tenant Support
Each API key is tied to a unique tenant. Secrets stored by one tenant cannot be retrieved by another.
Tenant mapping is defined in the TenantApiKey table:
ApiKey TenantId abc123-myapikey tenant-001 def456-otherkey tenant-002
🔍 Audit Logs
Every secret operation is logged in the AuditLogs table:
Id TenantId Action Key PerformedBy Timestamp 1 tenant-001 Store db-password apikey-user 2025-07-06 17:23:54 2 tenant-001 Retrieve db-password apikey-user 2025-07-06 17:25:04
HMAC Integrity (Optional) The server computes HMAC-SHA256 for internal verification.
You can expand this to validate incoming payloads by signing client-side with:
var hmac = new HMACSHA256(Convert.FromBase64String(masterKey));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(content));
Environment Variables
ROOT_PROTECTOR_KEY
: Base64-encoded 256-bit key to encrypt tenant keys.
Example of ROOT_PROTECTOR_KEY:
export ROOT_PROTECTOR_KEY="your-base64-encoded-256-bit-key"
e.g.:
export ROOT_PROTECTOR_KEY="c2VjcmV0cGFzc3dvcmQtbm90LXN0b3JlLWluLWRpc3BsYXktb3V0c2lkZS1lbnZpcm9ubWVudC1rZXktdG8tYmUtdXNlZC1mb3ItZW5jcnlwdGlvbi1rZXktZm9yLXNlY3JldC1zdG9yYWdl"
EonaCat.SecretVault.Client library
How to use the client:
using EonaCat.SecretVault.Client;
var vault = new SecretVaultClient("https://your-vault-url.com/", "your-api-key");
// Store a secret
await vault.StoreAsync("db-password", "S3cr3t!");
// Retrieve a secret
string? secret = await vault.RetrieveAsync("db-password");
Console.WriteLine($"Secret: {secret}");
// Delete a secret
await vault.DeleteAsync("db-password");
How to use the server:
Generating a new tenant:
string GenerateApiKey()
{
return Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));
}
string HashApiKey(string apiKey)
{
using var sha256 = SHA256.Create();
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(apiKey));
return Convert.ToBase64String(hash);
}
var rootKey = Environment.GetEnvironmentVariable("ROOT_PROTECTOR_KEY")!;
var tenantKey = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));
var encryptedTenantKey = TenantKeyProtector.EncryptTenantKey(tenantKey, rootKey);
var apiKey = GenerateApiKey();
var apiKeyHash = HashApiKey(apiKey);
_db.ApiKeys.Add(new TenantApiKey
{
ApiKey = newApiKey,
TenantId = "tenant-003",
EncryptionKey = newTenantKey,
EncryptedTenantKey = encryptedTenantKey,
ApiKeyHash = apiKeyHash
});
await _db.SaveChangesAsync();
Edit appsettings.json or use environment variables if needed (default uses SQLite):
{
"ConnectionStrings": {
"Default": "Data Source=EonaCatSecretVault.db"
}
}
Api usage:
Base URL: http://localhost:5000/api/secrets All requests must include:
X-Api-Key
header with your API key
Generate a new tenant:
POST /api/admin/generate-key?role=ReadWrite
Headers:
X-Api-Key: abc123-myapikey
### Response:
HTTP/1.1 200
Body:
{
"apiKey": "qY6LZ5i1dNpsQFF2kLE7uUd8Md5FeKfMY5r6KfzH7i8=",
"role": "ReadWrite"
}
Revoke an API key:
DELETE /api/admin/revoke-key?key=abc123-myapikey
Headers:
X-Api-Key: abc123-myapikey
Response:
HTTP/1.1 200 OK
Body:
"Key revoked"
List all API keys:
GET /api/admin/keys
Headers:
X-Api-Key: abc123-myapikey
Response:
HTTP/1.1 200 OK
Body:
[
{
"apiKey": "qY6LZ5i1dNpsQFF2kLE7uUd8Md5FeKfMY5r6KfzH7i8=",
"role": "ReadWrite",
"isActive": true,
"createdAt": "2025-07-06T17:00:00Z"
},
...
]
Store a secret:
POST /api/secrets/store?key=my-service-token
Headers:
Content-Type: application/json
X-Api-Key: abc123-myapikey
Response:
HTTP/1.1 200 OK
Retrieve a secret:
GET /api/secrets/retrieve?key=my-service-token
Headers:
X-Api-Key: abc123-myapikey
Response:
HTTP/1.1 200 OK
Body:
"super-secret-value"
using EonaCat.SecretVault.Data;
using EonaCat.SecretVault.Middleware;
using EonaCat.SecretVault.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
builder.Services.AddDbContext<SecretDbContext>(x => x.UseSqlite("Data Source=EonaCatSecretVault.db"));
builder.Services.AddScoped<SecretService>();
builder.Services.AddScoped<TenantKeyService>();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHsts();
app.UseHttpsRedirection();
app.UseMiddleware<ApiKeyMiddleware>();
app.MapControllers();
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<SecretDbContext>();
db.Database.EnsureCreated();
}
app.Run();
Curl Example:
curl -X POST http://localhost:5000/api/secrets/store?key=MYKEY \
-H "X-Api-Key: abc123-myapikey" \
-H "Content-Type: application/json" \
-d "\"sensitive-data\""
curl http://localhost:5000/api/secrets/retrieve?key=MYKEY \
-H "X-Api-Key: abc123-myapikey"
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 was computed. 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 was computed. 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. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- EonaCat.Json (>= 1.1.9)
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 |
---|---|---|
1.0.0 | 127 | 7/6/2025 |