GitHub - Emrek-stack/hashicorp-vault-sample · GitHub
Skip to content

Emrek-stack/hashicorp-vault-sample

Repository files navigation

Vault Raft + Nginx + .NET Vault Client Sample

Real-world quality, end-to-end runnable HashiCorp Vault OSS (Raft) cluster with Nginx front door, a reusable .NET client package, and an ASP.NET Core WebAPI sample.

Requirements

  • .NET SDK 9.x (preview acceptable for now)
  • Docker + Docker Compose

Architecture

                    +-------------------+
                    |  Sample.WebApi    |
                    |  Company.VaultClient
                    +---------+---------+
                              |
                              | https://localhost:8443
                              v
                      +-------+--------+
                      |  Nginx (TLS)   |
                      |  reverse proxy |
                      +-------+--------+
                              |
              +---------------+----------------+
              |        internal Docker net     |
              v               v                v
         +----+----+      +---+----+       +----+----+
         | Vault 1 |<---->| Vault 2|<----->| Vault 3 |
         | Raft    |      | Raft   |       | Raft    |
         +----+----+      +---+----+       +----+----+
              |
              v
         +-----------+
         | Postgres* |
         +-----------+

* Optional dynamic DB creds demo via Vault database engine

Local Run

cd infra/compose
cp .env.example .env
bash ../vault/scripts/00-generate-certs.sh
docker compose up -d
bash ../vault/scripts/10-bootstrap-vault.sh
bash ../vault/scripts/20-smoke-test.sh
cd ../../
dotnet test
dotnet run --project src/Sample.WebApi

AppRole Credentials

Bootstrap writes local-only credentials to infra/compose/.secrets/approle.json (gitignored). Export to env:

export VAULT_ROLE_ID=$(python3 - <<'PY'
import json
print(json.load(open('infra/compose/.secrets/approle.json'))['role_id'])
PY
)
export VAULT_SECRET_ID=$(python3 - <<'PY'
import json
print(json.load(open('infra/compose/.secrets/approle.json'))['secret_id'])
PY
)

Sample API Endpoints

  • GET /api/secrets/app-config
  • POST /api/secrets/app-config
  • GET /api/crypto/encrypt?text=...
  • GET /api/crypto/decrypt?cipher=...
  • GET /api/db/whoami (requires Postgres and database engine enabled)
  • GET /health

Database defaults:

  • POSTGRES_HOST=localhost
  • POSTGRES_PORT=5432
  • POSTGRES_DB=appdb

Vault Init/Unseal (Local Demo)

  • 10-bootstrap-vault.sh runs vault operator init with a single Shamir key.
  • Unseal key + root token are stored in infra/compose/.secrets/vault-init.json (gitignored).
  • This is LOCAL DEMO ONLY. Never store unseal keys in git or on shared machines.

Prod Auto-Unseal (KMS Notes)

For production, remove Shamir keys and configure auto-unseal with a cloud KMS:

  • AWS KMS: set seal "awskms" in Vault config and attach IAM policy for decrypt/encrypt.
  • Azure Key Vault: set seal "azurekeyvault" with AAD credentials.
  • GCP KMS: set seal "gcpckms" with service account key.

After enabling auto-unseal, the bootstrap script should only initialize and skip manual unseal.

Security & Best Practices

  • TLS enabled for Vault and Nginx; self-signed certs for local dev.
  • AppRole auth with least-privilege policy (infra/vault/policies/webapi.hcl).
  • Audit device enabled to file volume for immutable audit trail.
  • Tokens are renewed automatically; no secret values are logged.
  • Nginx is the only exposed entry point; Vault API stays on internal Docker network.

Nginx Reverse Proxy Notes

  • Upstream includes all three Vault nodes.
  • proxy_next_upstream retries on 307/308 redirects to avoid leaking internal node URLs to clients.
  • Headers X-Vault-Request and X-Vault-Token are forwarded.

Troubleshooting

  • 503 / standby: Leader changed; retry, or check docker logs vault-1 and vault operator raft list-peers.
  • TLS errors: Run bash infra/vault/scripts/00-generate-certs.sh and ensure AllowInsecureDevTls=true locally.
  • Clock skew: Vault tokens are time sensitive; ensure host time is synced.
  • Permission denied: Validate policies in infra/vault/policies/webapi.hcl and AppRole binding.

Repo Layout

  • infra/compose Docker Compose, .env example
  • infra/vault Vault configs, policies, scripts
  • infra/nginx Nginx config and certs
  • src/Company.VaultClient NuGet package
  • src/Sample.WebApi ASP.NET Core API
  • tests Unit + integration tests

CI

GitHub Actions runs:

  • dotnet restore/build/test
  • Docker compose + bootstrap + smoke test
  • dotnet pack for the NuGet package

Smoke Test Commands

From repo root:

cd infra/compose
cp .env.example .env
bash ../vault/scripts/00-generate-certs.sh
docker compose up -d
bash ../vault/scripts/10-bootstrap-vault.sh
bash ../vault/scripts/20-smoke-test.sh

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors