Identity resolution and credential injection service for Argus database proxy.
Monopam is the bridge between Argus (Go database firewall) and your credential store (HashiCorp Vault). When a user connects through Argus, it calls Monopam's /api/db/resolve endpoint to determine the real database target and credentials for that session.
User → psql → Argus(:19999) → [handshake] → POST /api/db/resolve → Monopam → Vault
↓
resolved target
+ credential returned
# Run in development mode (in-memory credentials)
dotnet run --project src/Monopam.Api
# Test it
curl -X POST http://localhost:5000/api/db/resolve \
-H "Content-Type: application/json" \
-d '{"username":"jane_app","database":"production","protocol":"postgresql"}'# Run in production mode (Vault-backed credentials)
ASPNETCORE_ENVIRONMENT=Production \
ASPNETCORE_URLS=http://0.0.0.0:5000 \
Monopam__Vault__Address=http://vault:8200 \
Monopam__Vault__Token=$(cat /etc/vault-token) \
dotnet run --project src/Monopam.ApiMonopam.Api ← ASP.NET Core 9 Web API
└── POST /api/db/resolve
└── /healthz, /readyz, /api/status
│
▼
Monopam.Core ← Domain logic (pure C#, no framework deps)
├── DatabaseController — Orchestrator: resolve → fetch → return
├── ConfigurationTargetResolver — 3-tier matching (exact → user → wildcard)
├── InMemoryCredentialStore — Dev/test store (guarded by IsProduction())
└── Models/ — ResolveRequest, ResolvedTarget, ResolveError
│
▼
Monopam.Vault ← HashiCorp Vault integration
└── VaultCredentialStore — Direct HTTP to KV v2 (no VaultSharp)
└── VaultOptions — Address, Token/AppRole, configurable
Request:
{
"username": "jane_app",
"database": "production",
"client_ip": "10.0.1.50",
"protocol": "postgresql"
}Response (200):
{
"host": "db-primary.internal",
"port": 5432,
"protocol": "postgresql",
"username": "monopam_svc",
"password": "vault-secret-abc",
"auth_method": "scram_sha_256",
"roles": ["db_reader", "app_service"],
"policy_tags": {"environment": "production"}
}Error (403):
{
"code": "TARGET_NOT_FOUND",
"message": "No database target configured for user 'unknown_user'"
}{
"Monopam": {
"Targets": [
{
"id": "production-pg",
"host": "db-primary.internal",
"port": 5432,
"protocol": "postgresql",
"roles": ["db_reader"]
}
],
"Mappings": [
{
"username": "jane_app",
"database": "production",
"targetId": "production-pg"
},
{
"username": "dev_*",
"targetId": "staging-pg"
}
]
}
}Matching priority: exact match (username + database) → user match (username only) → wildcard (dev_*) → catch-all (*).
Secrets stored at secret/monopam/targets/{targetId}:
vault kv put secret/monopam/targets/production-pg \
username=monopam_svc \
password=$(openssl rand -base64 32) \
auth_method=scram_sha_256| Environment Variable | Purpose |
|---|---|
Monopam__Vault__Address |
Vault server URL |
Monopam__Vault__Token |
Vault authentication token |
VAULT_TOKEN |
Fallback if Token not set |
| Project | Path | Tests |
|---|---|---|
| Monopam.Api | src/Monopam.Api/ |
9 integration tests |
| Monopam.Core | src/Monopam.Core/ |
8 unit tests |
| Monopam.Vault | src/Monopam.Vault/ |
— (requires live Vault) |
dotnet test # Run all tests
dotnet run --project src/Monopam.Api # Start the APIMIT