HashiQube - DevOps Lab
Youtube Channel Medium Posts Riaan Nolan Linkedin Riaan Nolan Hashicorp Ambassador

.

Database Credentials with HashiCorp Vault

Dynamic database credentials provisioning and lifecycle management

🚀 About

In this HashiQube DevOps lab, you'll get hands-on experience with HashiCorp Vault's database secrets engine. Learn how Vault can securely provision and manage credentials for your databases, eliminating the need for static credentials and enhancing your security posture.

This lab will guide you through integrating three popular database systems with HashiCorp Vault:

  • Oracle MySQL
  • Microsoft SQL Server
  • PostgreSQL

📚 Database Engines

🔵 Oracle MySQL

MySQL Logo

Provision MySQL

Open in GitHub Codespaces

bash docker/docker.sh
bash vault/vault.sh
bash database/mysql.sh
vagrant up --provision-with basetools,docker,docsify,vault,mysql
docker compose exec hashiqube /bin/bash
bash hashiqube/basetools.sh
bash docker/docker.sh
bash docsify/docsify.sh
bash vault/vault.sh
bash database/mysql.sh

Verifying MySQL Installation

Let's verify that our MySQL container is up and accepting connections:

vagrant ssh -c "mysql -h 127.0.0.1 -u root -ppassword -e \"show databases;\""

Output:

mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| db                 |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

Configuring Vault with MySQL

  1. Start Vault

    vagrant up --provision-with basetools,docker,docsify,vault
  2. Unseal Vault and Login

    Use the unseal keys and root token provided in the output to unseal Vault and log in.

    Vault Logged In

    Vault UI after successful login

  3. Enable the Database Secrets Engine

    Navigate to "Enable new Engine" in the top right, select "Database" and click "Next".

    Enable Database Engine

    Select the Database secrets engine

    Confirm Database Engine

    Confirm and enable the Database secrets engine

  4. Create Vault User in MySQL

    vagrant ssh -c "mysql -h 127.0.0.1 -u root -ppassword -e \"CREATE USER 'vault'@'%' IDENTIFIED BY 'password';\""
    
    vagrant ssh -c "mysql -h 127.0.0.1 -u root -ppassword -e \"GRANT ALL PRIVILEGES ON *.* TO 'vault'@'%' WITH GRANT OPTION;\""
    
    vagrant ssh -c "mysql -h 127.0.0.1 -u root -ppassword -e \"GRANT CREATE USER ON *.* to 'vault'@'%';\""
  5. Configure MySQL in Vault

    vagrant ssh -c "vault write database/config/db plugin_name=mysql-database-plugin connection_url='{{username}}:{{password}}@tcp(localhost:3306)/' allowed_roles='mysql-role' username='vault' password='password'"
  6. Create a Database Role

    vagrant ssh -c "vault write database/roles/mysql-role db_name=db creation_statements=\"CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT ALL PRIVILEGES ON db.* TO '{{name}}'@'%';\" default_ttl='1h' max_ttl='24h'"

    Output:

    Success! Data written to: database/roles/mysql-role

Generating and Using Dynamic Credentials

  1. Check Current MySQL Users

    vagrant ssh -c "mysql -h 127.0.0.1 -u root -ppassword -e \"SELECT User, Host from mysql.user;\""

    Output:

    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------------+-----------+
    | User             | Host      |
    +------------------+-----------+
    | root             | %         |
    | vault            | %         |
    | mysql.infoschema | localhost |
    | mysql.session    | localhost |
    | mysql.sys        | localhost |
    | root             | localhost |
    +------------------+-----------+
  2. Generate Credentials from Vault

    vagrant ssh -c "vault read database/creds/mysql-role"

    Output:

    Key                Value
    ---                -----
    lease_id           database/creds/mysql-role/IhHPq0RcdmDdTIjsfLBePLcp
    lease_duration     1h
    lease_renewable    true
    password           A1a-0bdhOg0OiZQV0TTP
    username           v-root-mysqlrole-zV7t3V0bJFZZJTg
  3. Verify New User Existence

    vagrant ssh -c "mysql -h 127.0.0.1 -u root -ppassword -e \"SELECT User, Host from mysql.user;\""

    Output:

    mysql: [Warning] Using a password on the command line interface can be insecure.
    +-----------------------------------+-----------+
    | User                              | Host      |
    +-----------------------------------+-----------+
    | root                              | %         |
    | v-root-mysql-role-zV7t3V0bJFZZJTg | %         |
    | vault                             | %         |
    | mysql.infoschema                  | localhost |
    | mysql.session                     | localhost |
    | mysql.sys                         | localhost |
    | root                              | localhost |
    +-----------------------------------+-----------+
  4. Retrieve Credentials via API

    vagrant ssh -c "curl --header 'X-Vault-Token:s.h7kojucmDDULDmxHAyr7jhrE' http://localhost:8200/v1/database/creds/mysql-role"

    Output:

    {
    "request_id":"23116091-f72b-80f9-fb0e-6ce5418bae1d",
    "lease_id":"database/creds/mysql-role/7wMxCUzNcEaOrvCspBhXnjTM",
    "renewable":true,
    "lease_duration":3600,
    "data":{
      "password":"A1a-XhNU8s4P0Ph5Se9O",
      "username":"v-root-mysql-role-kmFADTyAAfv7LS0"
    },
    "wrap_info":null,
    "warnings":null,
    "auth":null
    }
  5. Using Credentials in Applications

    response=$(curl --header "X-Vault-Token:s.h7kojucmDDULDmxHAyr7jhrE" http://localhost:8200/v1/database/creds/mysql-role)
    export DBPASSWORD=$(echo $response | jq -r .data.password)
    export DBUSERNAME=$(echo $response | jq -r .data.username)
    
    docker run --name webapp -d -p 8080:80 --rm -e DATABASE_URL=mysql+pymysql://DBUSERNAME:[email protected]/db webapp:latest
  6. Credential Lifecycle Management

    After the lease expires (1 hour in our configuration), Vault automatically revokes the credentials:

    vagrant ssh -c "mysql -h 127.0.0.1 -u root -ppassword -e \"SELECT User, Host from mysql.user;\""

    Output after credential expiration:

    mysql: [Warning] Using a password on the command line interface can be insecure.
    +------------------+-----------+
    | User             | Host      |
    +------------------+-----------+
    | root             | %         |
    | vault            | %         |
    | mysql.infoschema | localhost |
    | mysql.session    | localhost |
    | mysql.sys        | localhost |
    | root             | localhost |
    +------------------+-----------+

MySQL Provisioner Script

The script below automates the setup of MySQL in your HashiQube environment:

#!/bin/bash
# https://hub.docker.com/_/mysql
# https://www.vaultproject.io/docs/secrets/mysql/index.html

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Environment Variables from /etc/environment"
echo -e '\e[38;5;198m'"++++ "
set -a; source /etc/environment; set +a;

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Docker Daemon is running (Dependency)"
echo -e '\e[38;5;198m'"++++ "
if pgrep -x "dockerd" >/dev/null
then
  echo -e '\e[38;5;198m'"++++ Docker is running"
else
  echo -e '\e[38;5;198m'"++++ Ensure Docker is running.."
  sudo bash /vagrant/docker/docker.sh
fi

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Cleanup"
echo -e '\e[38;5;198m'"++++ "
sudo docker stop mysql
sudo docker rm mysql
yes | sudo docker system prune -a
yes | sudo docker system prune --volumes

arch=$(lscpu | grep "Architecture" | awk '{print $NF}')
if [[ $arch == x86_64* ]]; then
  ARCH="amd64"
elif  [[ $arch == aarch64 ]]; then
  ARCH="arm64"
fi

if pgrep -x "vault" >/dev/null
then
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Vault is running"
  echo -e '\e[38;5;198m'"++++ "
else
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Ensure Vault is running.."
  echo -e '\e[38;5;198m'"++++ "
  sudo bash /vagrant/vault/vault.sh
fi

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Environment Variables from /etc/environment"
echo -e '\e[38;5;198m'"++++ "
set -a; source /etc/environment; set +a;

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Vault Status"
echo -e '\e[38;5;198m'"++++ "
vault status

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Bring up a MySQL database on Docker"
echo -e '\e[38;5;198m'"++++ "
sudo DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install mysql-client
if [[ $arch == x86_64* ]]; then
  sudo docker run \
  --memory 1024M \
  --name mysql \
  -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=mysqldb \
  -p 3306:3306 \
  -d mysql:latest \
  --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
elif  [[ $arch == aarch64 ]]; then
  sudo docker run \
  --memory 1024M \
  --name mysql \
  -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=mysqldb \
  -p 3306:3306 \
  -d arm64v8/mysql:latest \
  --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
fi

sleep 60;
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Show databases"
echo -e '\e[38;5;198m'"++++ "
mysql -h 127.0.0.1 -u root -ppassword -e "show databases;"
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Create Vault MySQL user"
echo -e '\e[38;5;198m'"++++ "
mysql -h 127.0.0.1 -u root -ppassword -e "CREATE USER 'vault'@'%' IDENTIFIED BY 'password';"
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Grant MySQL user \"vault\" acces"
echo -e '\e[38;5;198m'"++++ "
mysql -h 127.0.0.1 -u root -ppassword -e "GRANT ALL PRIVILEGES ON *.* TO 'vault'@'%' WITH GRANT OPTION;"
mysql -h 127.0.0.1 -u root -ppassword -e "GRANT CREATE USER ON *.* to 'vault'@'%';"
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Enable Vault secrets database engine"
echo -e '\e[38;5;198m'"++++ "
vault secrets enable database
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Create Vault database mysqldb config"
echo -e '\e[38;5;198m'"++++ "
vault write database/config/mysqldb plugin_name=mysql-database-plugin connection_url='{{username}}:{{password}}@tcp(localhost:3306)/' allowed_roles='mysql-role' username='vault' password='password'
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Create Vault role"
echo -e '\e[38;5;198m'"++++ "
vault write database/roles/mysql-role db_name=mysqldb creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT ALL PRIVILEGES ON mysqldb.* TO '{{name}}'@'%';" default_ttl='5m' max_ttl='5m'
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Show MySQL users"
echo -e '\e[38;5;198m'"++++ "
mysql -h 127.0.0.1 -u root -ppassword -e "SELECT User, Host from mysql.user;"
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ask Vault to create MySQL user with access"
echo -e '\e[38;5;198m'"++++ "
vault read database/creds/mysql-role
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Now show MySQL users again, with new Vault user created"
echo -e '\e[38;5;198m'"++++ "
mysql -h 127.0.0.1 -u root -ppassword -e "SELECT User, Host from mysql.user;"
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Instructions"
echo -e '\e[38;5;198m'"++++ mysql -h 127.0.0.1 -u root -ppassword"
echo -e '\e[38;5;198m'"++++ "

🔴 Microsoft SQL Server

Microsoft SQL Logo

Provision Microsoft SQL Server

Open in GitHub Codespaces

bash docker/docker.sh
bash vault/vault.sh
bash database/mssql.sh
vagrant up --provision-with basetools,docker,docsify,vault,mssql
docker compose exec hashiqube /bin/bash
bash hashiqube/basetools.sh
bash docker/docker.sh
bash docsify/docsify.sh
bash vault/vault.sh
bash database/mssql.sh

Configuring Microsoft SQL Server with Vault

  1. Create a Database

    vagrant ssh
    docker exec -it mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P P@ssw0rd -Q "CREATE DATABASE mssql"
  2. Verify Database Creation

    docker exec -it mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P P@ssw0rd -Q "SELECT name, database_id, create_date FROM sys.databases"

    Output:

    name                                                                                                                             database_id create_date
    -------------------------------------------------------------------------------------------------------------------------------- ----------- -----------------------
    master                                                                                                                                     1 2003-04-08 09:13:36.390
    tempdb                                                                                                                                     2 2019-11-20 03:23:54.157
    model                                                                                                                                      3 2003-04-08 09:13:36.390
    msdb                                                                                                                                       4 2018-06-13 18:27:29.220
    mssql                                                                                                                                      5 2019-11-20 03:24:03.043
    
    (5 rows affected)
  3. Enable Database Secrets Engine in Vault (if not already enabled)

    vault secrets enable database
  4. Configure MSSQL in Vault

    vault write database/config/mssql \
      plugin_name=mssql-database-plugin \
      connection_url='sqlserver://{{username}}:{{password}}@localhost:1433' \
      allowed_roles="mssql" \
      username="sa" \
      password="P@ssw0rd"
  5. Create a Database Role

    vault write database/roles/mssql \
      db_name=mssql \
      creation_statements="CREATE LOGIN [{{name}}] WITH PASSWORD = '{{password}}'; \
      CREATE USER [{{name}}] FOR LOGIN [{{name}}]; \
      GRANT SELECT ON SCHEMA::dbo TO [{{name}}];" \
      default_ttl="1h" \
      max_ttl="24h"

Generating and Using Dynamic Credentials

  1. Generate Credentials from Vault

    vault read database/creds/mssql
  2. Verify Credential Creation

    docker exec -it mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U v-root-mssql-5nBk5IA9hydRgzOkgB8M-1574220338 -P A1a-dninssZ6v3mNBOfK -Q "SELECT * FROM sys.server_principals"
  3. Credential Lifecycle Management

    After the lease expires (1 hour in our configuration), attempting to use the credentials will fail:

    docker exec -it mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U v-root-mssql-5nBk5IA9hydRgzOkgB8M-1574220338 -P A1a-dninssZ6v3mNBOfK -Q "SELECT * FROM sys.server_principals"

    Output after credential expiration:

    Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : Login failed for user 'v-root-mssql-5nBk5IA9hydRgzOkgB8M-1574220338'..

Microsoft SQL Server Provisioner Script

The script below automates the setup of Microsoft SQL Server in your HashiQube environment:

#!/bin/bash
# https://hub.docker.com/_/microsoft-mssql-server
# https://www.vaultproject.io/docs/secrets/databases/mssql.html

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Environment Variables from /etc/environment"
echo -e '\e[38;5;198m'"++++ "
set -a; source /etc/environment; set +a;

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Docker Daemon is running (Dependency)"
echo -e '\e[38;5;198m'"++++ "
if pgrep -x "dockerd" >/dev/null
then
  echo -e '\e[38;5;198m'"++++ Docker is running"
else
  echo -e '\e[38;5;198m'"++++ Ensure Docker is running.."
  sudo bash /vagrant/docker/docker.sh
fi

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Cleanup"
echo -e '\e[38;5;198m'"++++ "
sudo docker stop mssql
sudo docker rm mssql
yes | sudo docker system prune -a
yes | sudo docker system prune --volumes

if pgrep -x "vault" >/dev/null
then
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Vault is running"
  echo -e '\e[38;5;198m'"++++ "
else
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Ensure Vault is running.."
  echo -e '\e[38;5;198m'"++++ "
  sudo bash /vagrant/vault/vault.sh
fi
export VAULT_ADDR=http://127.0.0.1:8200
vault status

# yes | sudo docker system prune -a
# yes | sudo docker system prune --volumes
sudo docker run \
  --name mssql \
  -e ACCEPT_EULA=Y -e SA_PASSWORD=P@ssw0rd -e MSSQL_PID=Express \
  -p 1433:1433 \
  -d mcr.microsoft.com/mssql/server:2017-CU8-ubuntu
echo -e '\e[38;5;198m'"++++ Instructions"
echo -e '\e[38;5;198m'"++++ vagrant ssh"
echo -e '\e[38;5;198m'"++++ docker exec -it mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P P@ssw0rd -Q \"CREATE DATABASE mssql\""
echo -e '\e[38;5;198m'"++++ docker exec -it mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P P@ssw0rd -Q \"SELECT name, database_id, create_date FROM sys.databases\""
echo -e '\e[38;5;198m'"++++ vault secrets enable database"
echo -e '\e[38;5;198m'"++++ vault write database/config/mssql \ \n  plugin_name=mssql-database-plugin \ \n  connection_url='sqlserver://{{username}}:{{password}}@localhost:1433' \ \n  allowed_roles=\"mssql\" \ \n  username=\"sa\" \ \n  password=\"P@ssw0rd\""
echo -e '\e[38;5;198m'"++++ docker exec -it mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P P@ssw0rd -Q \"SELECT * FROM sysusers\""
echo -e '\e[38;5;198m'"++++ vault write database/roles/mssql \ \n  db_name=mssql \ \n  creation_statements=\"CREATE LOGIN [{{name}}] WITH PASSWORD = '{{password}}'; \ \n  CREATE USER [{{name}}] FOR LOGIN [{{name}}]; \ \n  GRANT SELECT ON SCHEMA::dbo TO [{{name}}];\" \ \n  default_ttl=\"1h\" \ \n  max_ttl=\"24h\""
echo -e '\e[38;5;198m'"++++ vault read database/creds/mssql"
# TODO: above it not working as expected, I am getting errors
#  - * 1 error occurred:
#      * "my-role" is not an allowed role
#  - * 1 error occurred:
#      * mssql: Incorrect syntax near 'A1a'.

🟢 PostgreSQL

PostgreSQL Logo

Provision PostgreSQL

Open in GitHub Codespaces

bash docker/docker.sh
bash vault/vault.sh
bash database/postgresql.sh
vagrant up --provision-with basetools,docker,docsify,vault,postgresql
docker compose exec hashiqube /bin/bash
bash hashiqube/basetools.sh
bash docker/docker.sh
bash docsify/docsify.sh
bash vault/vault.sh
bash database/postgresql.sh

PostgreSQL Provisioner Script

The script below automates the setup of PostgreSQL in your HashiQube environment:

#!/bin/bash
# https://hub.docker.com/_/postgres
# https://www.vaultproject.io/docs/secrets/databases/postgresql

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Environment Variables from /etc/environment"
echo -e '\e[38;5;198m'"++++ "
set -a; source /etc/environment; set +a;

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Docker Daemon is running (Dependency)"
echo -e '\e[38;5;198m'"++++ "
if pgrep -x "dockerd" >/dev/null
then
  echo -e '\e[38;5;198m'"++++ Docker is running"
else
  echo -e '\e[38;5;198m'"++++ Ensure Docker is running.."
  sudo bash /vagrant/docker/docker.sh
fi

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Cleanup"
echo -e '\e[38;5;198m'"++++ "
sudo docker stop postgres
sudo docker rm postgres
yes | sudo docker system prune -a
yes | sudo docker system prune --volumes

if pgrep -x "vault" >/dev/null
then
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Vault is running"
  echo -e '\e[38;5;198m'"++++ "
else
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Ensure Vault is running.."
  echo -e '\e[38;5;198m'"++++ "
  sudo bash /vagrant/vault/vault.sh
fi
export VAULT_ADDR=http://127.0.0.1:8200
vault status

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure postgres docker container is running"
echo -e '\e[38;5;198m'"++++ "
sudo docker run --name postgres -e POSTGRES_USER=root \
         -e POSTGRES_PASSWORD=rootpassword \
         -d -p 5432:5432 postgres

sleep 15;

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure postgresql-client is installed"
echo -e '\e[38;5;198m'"++++ "
sudo apt-get install -y postgresql-client libpq-dev python3.10-dev

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Source /etc/environment"
echo -e '\e[38;5;198m'"++++ "
source /etc/environment

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Show users in database"
echo -e '\e[38;5;198m'"++++ "
sudo docker exec postgres psql -U root -c '\du'

sleep 15;

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Vault token lookup"
echo -e '\e[38;5;198m'"++++ "
vault token lookup

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Enable Vault Database PostgreSQL secret engine"
echo -e '\e[38;5;198m'"++++ "
vault secrets enable database

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Configure PostgreSQL "
echo -e '\e[38;5;198m'"++++ "
vault write database/config/postgresql \
    plugin_name=postgresql-database-plugin \
    allowed_roles=postgresql-role \
    connection_url='postgresql://root:rootpassword@localhost:5432/postgres?sslmode=disable'

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Create a role"
echo -e '\e[38;5;198m'"++++ "
vault write database/roles/postgresql-role db_name=postgresql \
        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

echo -e '\e[38;5;198m'"++++ "  
echo -e '\e[38;5;198m'"++++ Create policy"
echo -e '\e[38;5;198m'"++++ "
vault policy write apps  -<<EOF
# Get credentials from the database secrets engine
path "database/creds/postgresql-role" {
  capabilities = [ "read" ]
}
EOF

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Create a new token with apps policy attached"
echo -e '\e[38;5;198m'"++++ "
VAULT_TOKEN_APPS=$(vault token create -policy="apps" -field token)

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ New Token: $VAULT_TOKEN_APPS"
echo -e '\e[38;5;198m'"++++ "

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Create new connection with token"
echo -e '\e[38;5;198m'"++++ "
VAULT_TOKEN=$VAULT_TOKEN_APPS vault read database/creds/postgresql-role

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Now show users in database again with new user created"
echo -e '\e[38;5;198m'"++++ "
sudo docker exec postgres psql -U root -c '\du'

🔑 Key Benefits

  1. Enhanced Security - Eliminate static, long-lived credentials that can be compromised
  2. Automatic Rotation - Credentials are automatically rotated based on configured TTLs
  3. Fine-grained Access Control - Create specific roles with limited permissions
  4. Audit Trail - Track who accessed which credentials and when
  5. Simplified Credential Management - Centralized management of all database credentials
  6. Reduced Operational Overhead - No need to manually rotate credentials or manage password reset schedules

🔍 How It Works

  1. Vault is configured with connection details to the database, using a privileged account that can create users
  2. When an application needs database access, it authenticates to Vault and requests credentials
  3. Vault creates a unique set of credentials with the requested permissions and returns them to the application
  4. The credentials have a time-to-live (TTL) setting, after which Vault automatically revokes them
  5. If needed, the application can renew the credentials before they expire

🛠️ Additional Use Cases

  • CI/CD Pipelines - Provide temporary credentials for database migrations and tests
  • Microservices - Each service gets its own set of credentials with minimal required permissions
  • Development Environments - Easily create and manage credentials for developers without sharing access
  • Cross-environment Consistency - Use the same workflow in development, staging, and production

📚 Further Reading