A compact demo that shows how HashiCorp Vault's Database Secrets Engine can manage both static and dynamic credentials for Microsoft SQL Server and PostgreSQL.
The repo includes a Docker Compose file for local databases and a sample
setup.sql script to initialize the SQL Server databases and logins.
- Prerequisites
- Demo Setup
- Manual Vault configuration examples (static & dynamic roles)
- Cleanup
- Docker (to run database containers)
- HashiCorp Vault CLI (tested with Vault v1.20.x)
psqlclient for PostgreSQL testingsqlcmdclient for running T-SQL scripts against SQL Server- (Optional) SQL Server Management Studio for interactive inspection
- PowerShell 7.x is recommended for wrapper scripts in this repo (or adapt the commands for your shell)
These steps get the demo running locally with minimal friction.
- Clone the repository and change into it:
git clone <repo-url>
cd vault-db-secrets-engine-demo- Start the database containers (this repo's
docker-compose.ymlwill bring up SQL Server and PostgreSQL):
docker compose up -d- Initialize the SQL Server objects securely.
- Open
setup.sqlin SSMS (Query > SQLCMD Mode) and replace placeholders like<YOUR_PASSWORD>with secure values provided at runtime.
- Start a Vault dev server for testing:
vault server -dev- Configure Vault environment variables for the CLI:
$env:VAULT_ADDR = 'http://127.0.0.1:8200'
$env:VAULT_TOKEN = '<ROOT_TOKEN_FROM_DEV_SERVER>'- Enable the database secrets engine:
vault secrets enable databaseConfigure the database connection in Vault (static credentials example):
vault write database/config/mssql_static `
plugin_name=mssql-database-plugin `
connection_url='sqlserver://{{username}}:{{password}}@localhost:1433' `
allowed_roles="mssql_static" `
username="vault_login" `
password="<YOUR_PASSWORD>"Create a static role mapping (long rotation period used in demo to emulate static creds):
vault write database/static-roles/mssql_static `
db_name=mssql_static `
username="vault_static" `
rotation_statements="ALTER LOGIN [{{name}}] WITH PASSWORD = '{{password}}';" `
rotation_period="876000h"Read the credential (returns username/password):
vault read database/static-creds/mssql_staticConfigure connection (use a user with privilege to create logins/users):
vault write database/config/mssql_dynamic `
plugin_name=mssql-database-plugin `
connection_url='sqlserver://{{username}}:{{password}}@localhost:1433' `
allowed_roles="mssql_dynamic" `
username="vault_login" `
password="<YOUR_PASSWORD>"Role that creates a temporary login and user with SELECT privileges:
vault write database/roles/mssql_dynamic `
db_name=mssql_dynamic `
creation_statements="CREATE LOGIN [{{name}}] WITH PASSWORD = '{{password}}'; USE [test_db_2]; CREATE USER [{{name}}] FOR LOGIN [{{name}}]; GRANT SELECT ON SCHEMA::dbo TO [{{name}}];" `
revocation_statements="DROP USER IF EXISTS [{{name}}]; DROP LOGIN IF EXISTS [{{name}}];" `
default_ttl="1h" `
max_ttl="24h"Generate dynamic credentials:
vault read database/creds/mssql_dynamicConfigure connection to PostgreSQL (use a privileged account):
vault write database/config/postgresql_dynamic `
plugin_name="postgresql-database-plugin" `
allowed_roles="postgresql_dynamic" `
connection_url="postgresql://{{username}}:{{password}}@localhost:5432/test_db_1" `
username="vault_user" `
password="<YOUR_PASSWORD>" `
password_authentication="scram-sha-256"Role that creates a temporary PostgreSQL role with SELECT privileges:
vault write database/roles/postgresql_dynamic `
db_name="postgresql_dynamic" `
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" `
default_ttl="1h" `
max_ttl="24h"Generate a credential and connect using psql:
$creds = vault read -format=json database/creds/postgresql_dynamic | ConvertFrom-Json
psql -h localhost -p 5432 -U $creds.data.username -d test_db_1- Stop and remove containers:
docker compose down -v- Remove any generated logins/users you created during the demo (use SSMS or
sqlcmdto run cleanup statements).