Self-hosted Vault & Configuration Manager โ securely store secrets and feature flags, then consume them at runtime via a Key Vault-compatible REST API or the native .NET client library.
| Feature | Details |
|---|---|
| ๐ Secret management | Versioned, per-environment secrets with enable/disable, expiry, and NotBefore support |
| โ๏ธ Configuration flags | Key-value configuration entries scoped per application and environment |
| ๐ API key auth | Per-application hashed API keys; rotate without downtime |
| ๐ก๏ธ AES-256-GCM encryption | All secret values encrypted at rest with HKDF-derived keys |
| ๐ Multi-environment | Each application can have unlimited named environments (e.g. local, staging, production) |
| ๐งฉ .NET client library | Drop-in IConfigurationSource โ pull secrets and flags directly into IConfiguration |
| ๐ณ Docker-first | Single docker compose up to run the entire stack |
| ๐ Swagger UI | Separate Management and Consumer API docs at /swagger |
grimoire-api/
โโโ ๐ฆ src/
โ โโโ Grimoire.Core # Domain entities & repository interfaces
โ โโโ Grimoire.Infrastructure # EF Core + SQLite, AES-GCM encryption, slug service
โ โโโ Grimoire.Api # ASP.NET Core 10 โ Management & Consumer REST APIs
โ โโโ Grimoire.Consumer # .NET client library (NuGet-ready)
โโโ ๐งช tests/
โโโ Grimoire.Tests # Unit tests (validators, slug service)
โโโ Grimoire.IntegrationTests # WebApplicationFactory integration tests
โโโ Grimoire.E2eTests # Testcontainers end-to-end tests
Client app Grimoire API SQLite DB
โโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโ
X-Api-Key โโโบ ConsumerApiKeyMiddleware โโโบ verify hash
โ
ConsumerSecretsController โโโบ SecretRepository โโโบ DB
โ โ
AES-256-GCM decrypt โโโโโโโโ EncryptedValue
โ
โโโ { name, value, properties }
# 1. Clone
git clone https://github.com/guibranco/grimoire-api.git
cd grimoire-api
# 2. Set your secrets (edit the compose file or use env vars)
export Management__AdminApiKey="your-admin-key"
export Encryption__MasterKey="your-32-char-minimum-master-key!!"
# 3. Run
docker compose up -d
# โ
API is now available at http://localhost:8080
# ๐ Swagger UI: http://localhost:8080/swaggerdotnet run --project src/Grimoire.Api \
--Management:AdminApiKey="your-admin-key" \
--Encryption:MasterKey="your-32-char-minimum-master-key!!"All management endpoints require a Bearer token matching Management:AdminApiKey.
All consumer endpoints require an X-Api-Key header with a valid application API key.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/management/applications |
List all applications |
POST |
/api/management/applications |
Create application (auto-seeds local env) |
GET |
/api/management/applications/{slug} |
Get application |
PUT |
/api/management/applications/{slug} |
Update application |
DELETE |
/api/management/applications/{slug} |
Soft-delete application |
POST |
/api/management/applications/{slug}/rotate-key |
๐ Rotate API key |
GET |
/api/management/applications/{slug}/environments |
List environments |
POST |
/api/management/applications/{slug}/environments |
Create environment |
DELETE |
/api/management/applications/{slug}/environments/{envSlug} |
Delete environment |
GET |
/api/management/applications/{slug}/secrets |
List secrets |
POST |
/api/management/applications/{slug}/secrets |
Create secret |
GET |
/api/management/applications/{slug}/secrets/{name} |
Get secret metadata |
POST |
/api/management/applications/{slug}/secrets/{name}/values |
Set secret value(s) |
GET |
/api/management/applications/{slug}/secrets/{name}/versions/{environmentSlug} |
List versions |
DELETE |
/api/management/applications/{slug}/secrets/{name} |
Delete secret |
GET |
/api/management/applications/{slug}/configurations |
List configurations |
POST |
/api/management/applications/{slug}/configurations |
Create configuration |
PUT |
/api/management/applications/{slug}/configurations/{env}/{key} |
Update configuration |
DELETE |
/api/management/applications/{slug}/configurations/{env}/{key} |
Delete configuration |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/consumer/secrets/{name}?environment={env} |
๐ Get decrypted secret value |
GET |
/api/consumer/configurations?environment={env} |
Get all configurations |
GET |
/api/consumer/configurations/{key}?environment={env} |
Get single configuration |
Install the Grimoire.Consumer package (or reference the project) and pull secrets directly into your IConfiguration:
// Program.cs โ drop-in IConfigurationSource
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddGrimoire(
baseUrl: "http://localhost:8080",
apiKey: "grm_your_api_key_here",
environment: "production"
);
// Use IConfiguration as normal โ secrets and configs are transparently available
var dbPassword = builder.Configuration["db-password"];
var featureEnabled = builder.Configuration["Feature:EnableDarkMode"];Or use the typed client directly:
var client = new GrimoireSecretClient(
baseUrl: "http://localhost:8080",
apiKey: "grm_your_api_key_here",
environment: "production"
);
var secret = await client.GetSecretAsync("db-password");
Console.WriteLine(secret.Value); // ๐ plain text
Console.WriteLine(secret.Properties.Enabled); // true/false
Console.WriteLine(secret.Properties.Version); // 2Settings can be provided via appsettings.json, environment variables (use __ as separator), or CLI args.
| Setting | Required | Default | Description |
|---|---|---|---|
ConnectionStrings:Default |
โ | grimoire.db |
SQLite connection string |
Management:AdminApiKey |
โ | (none) | Bearer token for Management API |
Encryption:MasterKey |
โ | (none) | Master key for HKDF derivation (โฅ 32 chars) |
Cors:AllowedOrigins |
โ | [] |
Allowed CORS origins |
Serilog:MinimumLevel:Default |
โ | Information |
Log level |
โ ๏ธ Security note: Never commit real values forAdminApiKeyorMasterKey.
Use environment variables, Docker secrets, or a secrets manager in production.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ Secret at rest โ
โ โ
โ MasterKey โโโบ HKDF-SHA256 โโโบ 256-bit AES key โ
โ plaintext โโโบ AES-256-GCM โโโบ nonce(12) + tag(16) + ๐ โ
โ (stored in SQLite as Base64) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ API key lifecycle โ
โ โ
โ GenerateApiKey() โ grm_{40 hex chars} โ
โ HashPassword() โ PBKDF2 hash stored in DB โ
โ VerifyHash() โ compared on every consumer request โ
โ RotateKey() โ new key issued, old hash replaced โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# ๐ฌ Unit + integration tests
dotnet test --filter "FullyQualifiedName!~E2eTests"
# ๐ณ E2E tests (requires Docker)
docker build -t grimoire-api:e2e .
GRIMOIRE_TEST_IMAGE=grimoire-api:e2e dotnet test tests/Grimoire.E2eTests
# ๐ With OpenCover coverage (for SonarCloud)
dotnet test --filter "FullyQualifiedName!~E2eTests" \
--collect:"XPlat Code Coverage" \
--results-directory ./coverage \
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover| Test Suite | Count | Type |
|---|---|---|
๐ฌ Grimoire.Tests |
43 | Unit โ validators, slug service |
๐ Grimoire.IntegrationTests |
50 | Integration โ full HTTP via WebApplicationFactory |
๐ณ Grimoire.E2eTests |
7 | End-to-end โ real Docker container via Testcontainers |
- .NET 10 SDK
- Docker Desktop (for E2E tests)
# Add a new migration
dotnet ef migrations add <MigrationName> \
--project src/Grimoire.Infrastructure \
--startup-project src/Grimoire.Api
# Apply to local DB
dotnet ef database update \
--project src/Grimoire.Infrastructure \
--startup-project src/Grimoire.ApiGrimoire.Api
โโโ Grimoire.Core
โโโ Grimoire.Infrastructure
โโโ Grimoire.Core
Grimoire.Consumer (standalone, no Api dependency)
src/Grimoire.Core/
Entities/ Application, AppEnvironment, Secret, SecretVersion, ConfigurationEntry
Interfaces/ IEncryptionService + 4 repository interfaces
src/Grimoire.Infrastructure/
Persistence/ GrimoireDbContext, EF entity configs, repositories, migrations
Services/ AesGcmEncryptionService, SlugService
src/Grimoire.Api/
Controllers/ Management/* and Consumer/*
DTOs/ Request/response records (CreateApplicationRequest, etc.)
Middleware/ AdminApiKeyMiddleware, ConsumerApiKeyMiddleware
Validators/ FluentValidation rules for all request types
src/Grimoire.Consumer/
GrimoireSecretClient.cs Typed HTTP client
GrimoireConfigurationClient.cs IConfigurationSource / IConfigurationProvider
GrimoireConfigurationExtensions.cs AddGrimoire() builder extension
- ๐ด Fork the repository
- ๐ฟ Create a feature branch:
git checkout -b feature/my-feature - โ Commit your changes and ensure all tests pass
- ๐ฌ Push and open a pull request against
main
All PRs are automatically analyzed by SonarCloud and must pass the CI pipeline (build + unit + integration tests). E2E tests run as a separate Docker job.
MIT ยฉ Guilherme Branco Stracini
Made with โค๏ธ and a sprinkle of ๐ฎ magic