/ vault

Fun and Profit With Vault Part 3

In the last post I set up HashiCorp vault to run as a daemon on my OSX laptop. I also put the unseal keys and root token into my LastPass to keep them in a central location that is accessible via the laptop and other devices if necessary. This also keeps the unseal key from being placed directly on the filesystem of the laptop somewhere.

Protecting the keys is important for two reasons, really. One, they are a secret. But also, if I put them in a file, and then for some reason delete or modify that file accidentally, and Vault is sealed before I realize it happened...well, up the creek, as they say.

That's all well and good, but after rebooting the laptop a few times, and playing with the vault seal command; unsealing the vault with the keys became kind of a pain. In a production environment, where Vault is probably up and running for very long stretches of time without being sealed, and real secrets are being kept, it's fine. However, for my laptop, ugh. The first thing I did was create a script called unseal.sh to do this for me. But that's a problem becuase I now have the keys on disk again. I thought about encrypting the shell script. That would work ok. But in the mean time, I found out that LastPass has a CLI. I didn't know that before, and I really wanted to encorporate that into the unseal process.

Installing the LastPass CLI

Since, I'm running on OSX, the documentation for the CLI recommends using Homebrew as the easiest method of installation. I rebuilt this laptop not too long ago, so I hadn't had a reason to have Homebrew installed yet. Installing that is the first step. Following the Homebrew installation page, I ran:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

I've omitted the output of this command, because it is very long and detailed. Suffice it to say, homebrew did a bunch of things and installed itself without issue.

Now that brew is installed, I can get the LastPass CLI lpass installed (also too much output to put here):

brew install lastpass-cli --with-pinentry

I now have the lpass command available to me for command line fun.

Learning lpass

lpass is pretty straight forward. It allows for performing a bunch of LastPass stuff from the command line, as the name suggests. Just typing the command gives us the standard usage type information

lpass
Usage:
  lpass {--help|--version}
  lpass login [--trust] [--plaintext-key [--force, -f]] [--color=auto|never|always] USERNAME
  lpass logout [--force, -f] [--color=auto|never|always]
  lpass passwd
  lpass show [--sync=auto|now|no] [--clip, -c] [--expand-multi, -x] [--all|--username|--password|--url|--notes|--field=FIELD|--id|--name|--attach=ATTACHID] [--basic-regexp, -G|--fixed-strings, -F] [--color=auto|never|always] {UNIQUENAME|UNIQUEID}
  lpass ls [--sync=auto|now|no] [--long, -l] [-m] [-u] [--color=auto|never|always] [GROUP]
  lpass mv [--color=auto|never|always] {UNIQUENAME|UNIQUEID} GROUP
  lpass add [--sync=auto|now|no] [--non-interactive] [--color=auto|never|always] {--username|--password|--url|--notes|--field=FIELD|--note-type=NOTETYPE} NAME
  lpass edit [--sync=auto|now|no] [--non-interactive] [--color=auto|never|always] {--name|--username|--password|--url|--notes|--field=FIELD} {NAME|UNIQUEID}
  lpass generate [--sync=auto|now|no] [--clip, -c] [--username=USERNAME] [--url=URL] [--no-symbols] {NAME|UNIQUEID} LENGTH
  lpass duplicate [--sync=auto|now|no] [--color=auto|never|always] {UNIQUENAME|UNIQUEID}
  lpass rm [--sync=auto|now|no] [--color=auto|never|always] {UNIQUENAME|UNIQUEID}
  lpass status [--quiet, -q] [--color=auto|never|always]
  lpass sync [--background, -b] [--color=auto|never|always]
  lpass export [--sync=auto|now|no] [--color=auto|never|always] [--fields=FIELDLIST]
  lpass import [CSV_FILENAME]
  lpass share subcommand sharename ...

There is a lot of cool stuff there to think about. What I'm after right now, though, will need login, show and logout. According to the usage on the show subcommand, I could pass in the username and password directly. That would require me to have the LastPass password on disk, or in some other layer of protection. I'm not interested in that. Unseal is a manual type thing in it's basic form anyway, so having to put in the password to get to the data in LastPass isn't a big deal. My idea is to:

  1. Log into LastPass
  2. Retrieve the relevant information to unseal Vault
  3. Log out of LastPass

Unsealing with lpass

Step 1: Login

Lets start building the script step by step. First step is to do the login, so here is the first part of the script I'm calling ~/vault-stuff/unseal.sh.

# 1. Login to LastPass: will require manual entry of LastPass password
lpass login my_user_name

Running this command will bring up a text based prompt for my password:
lpass_login

If you provide the correct password, you will see a success message.

Step 2: Retrieve Vault information

Now that I'm logged in, I can retrieve the information that I stored in LastPass, most importantly, the unseal keys.

lpass show 'vault seals and token'
laptop vault/vault seals and token [id: **redacted**]
URL: http://sn
Notes: Unseal Key 1: tt/9Pz0a2zrCxcuaJwOfNv3oRbrM26XzWW7XTvFiYFJ/
Unseal Key 2: igN3kQIqel61o3UXFvNUksVXvscYXpr9pf9kq+rrL7w4
Unseal Key 3: W6bqfaitfHjgm0HavZCNbIxNuz6FqZATECVNkCpOlEQk
Unseal Key 4: 5rXPhU4/XNVGIYVKcnPBdtooKT94K1ASo9tx4u8AI/wf
Unseal Key 5: wjkZAJUOivD+Z+CeaR2lPoMGjir3nfK+687rlgFhpUcN
Initial Root Token: b1a61244-65ff-75ce-1126-9b5f5cfda220

That's the same information I placed into LastPass in the previous blog entry. But It's not super helpful. I only need three of the keys to unseal Vault. I can put some logic into unseal.sh to use the first three keys it finds. I mean, sure it's not terrible, but I want to play around a bit here. I'm going to encode the unseal script into the same LastPass entry. There is probably a better way to do it, but I'm going to start each line of the script section with something that denotes it for what it is. Then I will use a single line in the unseal.sh script to pull out those lines and run them. Not only is it interesting, it totally hides the unseal mechanism from view. Here is the above entry with the added script lines (denoted with 'vc::'):

Unseal Key 1: tt/9Pz0a2zrCxcuaJwOfNv3oRbrM26XzWW7XTvFiYFJ/
Unseal Key 2: igN3kQIqel61o3UXFvNUksVXvscYXpr9pf9kq+rrL7w4
Unseal Key 3: W6bqfaitfHjgm0HavZCNbIxNuz6FqZATECVNkCpOlEQk
Unseal Key 4: 5rXPhU4/XNVGIYVKcnPBdtooKT94K1ASo9tx4u8AI/wf
Unseal Key 5: wjkZAJUOivD+Z+CeaR2lPoMGjir3nfK+687rlgFhpUcN
Initial Root Token: b1a61244-65ff-75ce-1126-9b5f5cfda220

vc::echo -e "\n***Submitting key #1***"
vc::vault unseal tt/9Pz0a2zrCxcuaJwOfNv3oRbrM26XzWW7XTvFiYFJ/
vc::echo -e "\n***Submitting key #2***"
vc::vault unseal igN3kQIqel61o3UXFvNUksVXvscYXpr9pf9kq+rrL7w4
vc::echo -e "\n***Submitting key #3***"
vc::vault unseal W6bqfaitfHjgm0HavZCNbIxNuz6FqZATECVNkCpOlEQk
vc::echo -e "\n***Checking Vault status***"
vc::vault status

Since I now have the actual logic for the unseal in my LastPass entry, I can pull it out in unseal.sh like this:

# 2. Pull down vault information, run all lines beginning that start with 'vault'
lpass show 'vault seals and token' | grep  ^vc | awk -F'::' '{print $2}' | bash

Step 3: Logout

This one is dead simple:

# 3. Logout of LastPass forcefully
lpass logout -f

All together now

# Unseal vault with LastPass stored credentials
# 1. Login to LastPass: will require manual entry of LastPass password
lpass login my_user_name

# 2. Pull down vault information, run all lines beginning that start with 'vault'
lpass show 'vault seals and token' | grep  ^vc | awk -F'::' '{print $2}' | bash

# 3. Logout of LastPass forcefully
lpass logout -f

And now to seal Vault, then unseal with the script:

vault seal
Vault is now sealed.
./unseal.sh 
Success: Logged in as my_user_name.

***Submitting key #1***
Sealed: true
Key Shares: 5
Key Threshold: 3
Unseal Progress: 1
Unseal Nonce: 9831c257-5624-4c5a-a539-143e689c46f8

***Submitting key #2***
Sealed: true
Key Shares: 5
Key Threshold: 3
Unseal Progress: 2
Unseal Nonce: 9831c257-5624-4c5a-a539-143e689c46f8

***Submitting key #3***
Sealed: false
Key Shares: 5
Key Threshold: 3
Unseal Progress: 0
Unseal Nonce: 

***Checking Vault status***
Type: shamir
Sealed: false
Key Shares: 5
Key Threshold: 3
Unseal Progress: 0
Unseal Nonce: 
Version: 0.9.0
Cluster Name: vault-cluster-dc228e99
Cluster ID: f09d1904-67c6-4e4a-4118-b629649017eb

High-Availability Enabled: false
Log out: complete.

That worked great!

In the output above output I can see the three keys being passed in and Vault status showing that it's now unsealed. Mission accomplished.

Stay tuned for more development of this idea, and checkout the other entries if you haven't already.