We will imagine we have a simple Python application that consumes resources from a Mongo database, and presents an API.
The records will be contained in the orders collection in the flask_app database. We will use Vault to control access to this resource.
mkdir ~/data/flask_app
sudo apt-get install mongodb
mongod --port 27017 --dbpath ~/data/flask_app
or
docker run --name mongo-server -d mongo -v ~/data/flask-app:/data/db
We need to add a user who can create other users. We have chosen to use a very permissive role within Mongo, but you can certainly further limit the access Vault has to the server by choosing more restrictive roles. Please see (https://docs.mongodb.com/manual/reference/built-in-roles/#userAdminAnyDatabase) for more information.
mongo --port 27017
or
docker run -it --link mongo-server:mongo --rm mongo sh -c 'exec mongo "$MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/test"'
use admin
db.createUser(
{
user: "admin_user",
pwd: "password",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
use flask_app
db.createCollection('orders')
db.createCollection('customers')
db.orders.insert({'created_on':Date()})
db.customers.insert({'created_on':Date()})
mongod --port 27017 --dbpath ~/data/flask_app --auth
vault mount mongodb
mkdir -p ~/vault_logs && touch ~/vault_logs/audit.log
vault audit-enable file file_path=~/vault_logs/audit.log
vault write mongodb/config/connection uri="mongodb://admin_user:password@127.0.0.1:27017/admin?ssl=false"
vault write mongodb/config/lease ttl=1h max_ttl=24h
vault write mongodb/roles/readonly db=flask_app roles='[ "read" ]'
vault write mongodb/roles/write db=flask_app roles='[ "readWrite" ]'
vault auth-enable approle
cat <<EOF > flask_app_role_worker_pol.hcl
path "auth/approle/role/flask_app/secret-id" {
capabilities = ["read","create","update"]
}
EOF
cat <<EOF > flask_app_role_provisioner_pol.hcl
path "auth/approle/role/flask_app/role-id" {
capabilities = ['read']
}
EOF
cat << EOF >flask_app_db_readonly_pol.hcl
path "mongodb/flask_app/roles/readonly" {
capabilities = ['read']
}
EOF
cat << EOF >flask_app_db_readwrite_pol.hcl
path "mongodb/flask_app/roles/write" {
capabilities = ['read']
}
EOF
The idea is a long lived app. Secret_id does not expire, and the token does get renewed periodically
vault write auth/approle/role/flask_app secret_id_ttl=0 \
token_num_uses=1 token_ttl=61m \
token_max_ttl=61m secret_id_num_uses=0
vault read auth/approle/role/flaskapp/role-id
vault write -f auth/approle/role/flask_app/secret-id
You have some choices. With approle you need to trust something. A common workflow would be to embed the approleID into the machine image using a tool like Packer. You could then place the secret id in some directory, into an environment variable, or directly into the config file using Terraform or after it's deployed using a configuration management tool.