Testing Vault: Next-Gen Secret Management

I mainly followed this tutorial. But This is very old. And I just posted an upgraded steps here that I learnt when getting error following the process in that old post.

Create a Digital Ocean Droplet and Get SSL cert

Install Vault

wget https://releases.hashicorp.com/vault/1.1.0/vault_1.1.0_linux_amd64.zip
sudo apt-get update
sudo apt-get install unzip
unzip vault_*.zip
sudo chown root:root vault
sudo mv vault /usr/local/bin/
vault -autocomplete-install
complete -C /usr/local/bin/vault vault

Finally, set a Linux capability flag on the binary. This adds extra security by letting the binary perform memory locking without unnecessarily elevating its privileges.

sudo setcap cap_ipc_lock=+ep /usr/local/bin/vault

You can now use the  vault command. Try checking Vault's version to make sure it works.

vault --version

Creating the Vault Unit File

First, create a  vault system user.

sudo useradd -r -d /var/lib/vault -s /bin/nologin vault

Here, we use  /var/lib/vault as the user's home directory. This will be used as the Vault data directory. We also set the shell to  /bin/nologin to restrict the user as a non-interactive system account. Set the ownership of  /var/lib/vault to the  vault user and the  vault group exclusively.

sudo install -o vault -g vault -m 750 -d /var/lib/vault

Then create vault.hcl file. My let's-encrypt certificate is issued for vault.knsakib.com. So, my configuration file is.

sudo mkdir --parents /etc/vault.d
sudo touch /etc/vault.d/vault.hcl
sudo chown --recursive vault:vault /etc/vault.d
sudo chmod 640 /etc/vault.d/vault.hcl
sudo nano /etc/vault.d/vault.hcl

The content is

ui = true
backend "file" {
	path = "/var/lib/vault"
api_addr = "https://vault.knsakib.com:8200"
listener "tcp" {
	address = "vault.knsakib.com:8200"
	tls_disable = 0
	tls_cert_file = "/etc/letsencrypt/live/vault.knsakib.com/fullchain.pem"
	tls_key_file = "/etc/letsencrypt/live/vault.knsakib.com/privkey.pem"

Next, to let Systemd manage the persistent Vault daemon, create a  unit file at  /etc/systemd/system/vault.service.

sudo nano /etc/systemd/system/vault.service

Add the following,

	Description="HashiCorp Vault - A tool for managing secrets"
	CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK
	ExecStart=/usr/local/bin/vault server -config=/etc/vault.d/vault.hcl
	ExecReload=/bin/kill --signal HUP $MAINPID

Using TLS

Finally, Vault needs permission to read the certificates you created with Certbot. By default, these certificates and private keys are only accessible by  root. To make these available securely, we'll create a special group called  pki to access these files. We will create the group and then add the  vault user to it.

Save and close the file, then create the  pki group.
sudo groupadd pki	
sudo chgrp -R pki /etc/letsencrypt/{archive,live}
sudo chmod -R g+rx /etc/letsencrypt/{archive,live}

Then add the  vault user to the  pki group. This will grant Vault access to the certificates so that it can serve requests securely over HTTPS.

sudo gpasswd -a vault pki	

As a final step for convenience, add a rule in  /etc/hosts to direct requests to Vault to  localhost.

By default, Vault will only listen for requests from the loopback interface ( lo , or address ). This is to ensure that the service is not exposed to the public internet before it has been properly secured. You can update this later, but for now, this configuration change will let us use the  vault  command and correctly resolve the HTTPS-secured domain name.

Replace  vault.knsakib.com in the following command with domain you acquired the Let's Encrypt certificate for:

echo vault.knsakib.com | sudo tee -a /etc/hosts
This appends the line vault.knsakib.com to  /etc/hosts so that any HTTP requests to  example.com are routed to  localhost.

Initializing Vault

	sudo systemctl enable vault
	sudo systemctl start vault
	sudo systemctl status vault
	. . .
	Active: active (running)
	. . .

Let's export VAULT_ADDR=https://vault.knsakib.com:8200

export VAULT_ADDR=https://vault.knsakib.com:8200

Initialize Vault with the aforementioned parameters:

vault operator init -key-shares=3 -key-threshold=2
vault operator unseal

Run the command 2 times and put the unsealing keys until it is unseal. Keep the root token safe when it is revealed. It is always a good practice to revoke when it's initial job done. That means initial policy and auth creation.

Reading and Writing Secrets

I want to read and write secrets, like it has to be done in the application using rest API, instead of CLI. But at first let's finish initial root token's work. Then we can revoke it.

export VAULT_TOKEN=####
vault secrets enable kv 
vault write kv/my-secret value="passwordblah!"
vault write kv/hello target=world

Let's write some policy.

sudo nano my-policy

The content is

path "secret/*" {
    capabilities = ["create"]
path "secret/foo" {
    capabilities = ["read"]
# Dev servers have version 2 of KV mounted by default, so will need these
# paths:
path "secret/data/*" {
    capabilities = ["create"]
path "secret/data/foo" {
    capabilities = ["read"]
vault policy fmt my-policy.hcl
vault policy list

Let's create a Auth Token associated with that policy,

vault token create -policy=my-policy

It will generate a new token. Let use that token in simple skeleton Node app. I will use this vault Node.js Client.

var Vault = require('node-vault-js');
var vault = new Vault({  
	endpoint: 'https://vault.knsakib.com:8200',  
	token: '####'
vault.read('kv/my-secret', function(err, result) {        
	if (err) { 
	    throw err 
console.log('Read with response: ', result)

It is a very simple app. I just want to see how I can call the API in my app. In fact. It is a next generation of secret management. We can now easily create another app whose sole purpose is using IAM service API (Google, AWS, Azure) to generate new short lived token every time. And Our app(the app that will consume the secret) will received each new tokens every time, which encrypted+short lived :). And the secrets will never leave the Vault! :)

by the way the output looks like after I ran the node index.js,

Read with response:  { 
	request_id: '########',
	lease_id: '',
	renewable: false,
	lease_duration: 2764800,
	data: { value: 'PASSWORD_VALUE' },
	wrap_info: null,
	warnings: null,
	auth: null 

Post a Comment