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

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 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. 
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
1.0.0 127 7/6/2025