/web-blog-vault

to demo a flask python app talking to mongodb and using dynamic secrets with vault using the API

Primary LanguagePython

Web blog

This is a simple web blog to demo use cases with Hashicorp Vault. The app communicates directly with Vault using the API. This is for local demos only. web-blog-demo on Gitlab is used in the cloud on K8s.

It uses python, flask, bootstrap, mongodb, consul, and vault.

Start the mongod instance with no authentication

sudo mongod --port 27017 --dbpath /Users/sam/Deployments/HashiCorp/mongo_data

Create admin user creds

From the mongo client inside the admin database run the following:

use admin
db.createUser(
  {
    user: "sam",
    pwd: "test123", // or cleartext password
    roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
  }
)

Exit the mongo client

Start the mongod instance with authentication enabled

sudo mongod --auth --port 27017 --dbpath /Users/sam/Deployments/HashiCorp/mongo_data

Start a new terminal window and authenticate as an admin user

mongo --port 27017  --authenticationDatabase "admin" -u "sam" -p "test123"

Using File Storage Backend

Start the vault server using a config file.

vault server -config=vaultConfig.hcl

Content of the config file are below:

storage "file" {
  path = "/Users/sam/Deployments/HashiCorp/vault_data"
}

listener "tcp" {
 address     = "127.0.0.1:8200"
 tls_disable = 1
}

disable_mlock = true

Initializing the Vault

export VAULT_ADDR='http://127.0.0.1:8200'
vault operator init -key-shares=1 -key-threshold=1

You get the following output. In production you typically would use Vault's PGP and Keybase.io support to encrypt each of these keys so only one person has access to one key only.

Unseal Key 1: 258G83eRO8SMqFWBRs9Bn+8yAdK7HVgtMiAkgOdh5iA=

Initial Root Token: s.ewt0JUqVxTVnU7fW04ZiKiYh

Unseal the Vault

Run the following command to unseal

vault operator unseal

Authenticate with the initial root token

vault login s.ewt0JUqVxTVnU7fW04ZiKiYh

Enable the database secrets engine

vault secrets enable database

Configure Vault with the mongoDB plugin

vault write database/config/my-mongodb-database \
    plugin_name=mongodb-database-plugin \
    allowed_roles="my-role" \
    connection_url="mongodb://{{username}}:{{password}}@127.0.0.1:27017/admin" \
    username="sam" \
    password="test123"

Configure a role that maps a name in Vault to a MongoDB command that executes and creates the database credential

vault write database/roles/my-role \
    db_name=my-mongodb-database \
    creation_statements='{ "db": "admin", "roles": [{ "role": "readWriteAnyDatabase" }, {"role": "read", "db": "foo"}] }' \
    default_ttl="10s" \
    max_ttl="24h"

Manually Test

vault read database/creds/my-role

Sample Request

Change the X-Vault-Token value below to work for yours.

$ curl \
    --header "X-Vault-Token: s.ewt0JUqVxTVnU7fW04ZiKiYh" \
    http://127.0.0.1:8200/v1/database/creds/my-role

Sample Response

{
  "data": {
    "username": "root-1430158508-126",
    "password": "132ae3ef-5a64-7499-351e-bfe59f3a2a21"
  }
}

Python Example

Change the X-Vault-Token value below to yours.

response = requests.get(
'http://127.0.0.1:8200/v1/database/creds/my-role',
params={'q': 'requests+language:python'},
headers={'X-Vault-Token': 's.ewt0JUqVxTVnU7fW04ZiKiYh'},
)
json_response = response.json()
Database.USER = json_response['data']['username']
Database.PASSWORD = json_response['data']['password']
Database.URI = f'mongodb://{Database.USER}:{Database.PASSWORD}@{Database.SERVER}:{Database.PORT}'

Demo Steps

  1. Make sure you're logged out of the app. Have the VS code screen with the teriminal output showing. Also have the VS code screen side by side to the Chrome screen. My email is sam and password is test123 to access the app.
  2. Comment and uncomment the lines in databse.py and .env to show the static hard-coded creds scenario.
  3. Log into the app
  4. Show the stdout in VS code's terminal showing the hard-coded username and password are the same as those in the .env file.
  5. Browse the Blogs page to show that the creds don't expire.
  6. Log out of the app
  7. Comment and uncomment the lines in databse.py and .env to show the dynamic secrets scenario using Vault
  8. Log into the app
  9. Show the stdout in VS code's terminal showing the auto-generated username and password by vault.
  10. Browse the Blogs page to show that the creds expire and we get a message saying mongoDB auth failed due to creds expiring. Rotating creds now. Then we get new creds.
  11. Pivot over to a terminal with the mongo client running. Make sure you're logged in as an admin. Run the commands: use admin and show users. Show how the creds appear and disappear based on the timeout. You will need to browse the web blog to generate new creds.