The blog for Design Patterns, Linux, HA and Myself!
This document presents the installation steps for Hashicorp Vault and then proceeds with an example scenario involving
the userpass
username password based authentication, KV Secrets engine and Policy Authorization. This document is
divided into the following sections:
In this section we will look into vault installation process. It requires downloading the gpg
key, adding the
repository and installing the vault.
$ curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
OK
$ sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
Repository: 'deb [arch=amd64] https://apt.releases.hashicorp.com hirsute main'
:
Reading package lists... Done
$ sudo apt-get update && sudo apt-get install vault
Then update the vault configuration based on your preferences. I’ll be using the following configuration for vault:
$ cat /etc/vault/config.hcl
storage "file" {
path = "/opt/vault/data"
}
listener "tcp" {
address = "192.168.56.104:8200"
tls_disable = 0
tls_cert_file = "/etc/vault/certs/192.168.56.104.pem"
tls_key_file = "/etc/vault/certs/192.168.56.104-key.pem"
}
ui = true
This config file is not the default one, so we will need to update the SystemD service file as well so that Vault picks
up this configuration file. I’ve generated the certificates using mkcert
.
The service file is located at /usr/lib/systemd/system/vault.service
. The ExecStart
property needs to be updated here:
ExecStart=/usr/bin/vault server -config=/etc/vault/config.hcl
Once the file is changed, perform daemon reload and restart the Vault service:
$ systemctl daemon-reload
$ systemctl restart vault.service
$ systemctl status vault.service
Export the Vault URI so that we don’t have to pass it wth every command:
$ export VAULT_ADDR='https://192.168.56.104:8200'
Setup the Vault completion and update the .bashrc
so that it is executed after starting shell next time onwards. I’m
using .bashrc
here but this file will different if you’re using ZSH
or FISH
.
$ vault -autocomplete-install
$ complete -C /usr/local/bin/vault vault
$ source ~/.bashrc
After the initial startup Vault will always be SEALED
. We can check its status using:
$ vault status
Key Value
--- -----
Seal Type shamir
Initialized false
Sealed true
Total Shares 0
Threshold 0
Unseal Progress 0/0
Unseal Nonce n/a
Version 1.7.3
Storage Type file
HA Enabled false
Let’s start the unseal process. After executing the operator init
subcommand it will print out the list of all the
unseal keys and the Root Token. These keys and tokens are important and must be copied to a different place so that we
don’t lose them. The unsealing process will be done using the Unseal keys and the first time login will be done using
the Root Token.
$ vault operator init
Unseal Key 1: XjGtrLO9NQxORIls6pqzFRFS1BN8K1atfbFTnS9SXk0t
Unseal Key 2: K9ujZAorX2IqU0I2zs0aFHhpcyvLbaCO/gPlO/YNKJgP
Unseal Key 3: otplWPfKoVtuq4q5ti8HZIQ+shzmp6fVSoAmnzIYsN+R
Unseal Key 4: xjQWO5vPYVUXZvRaFDYND2d5JU8iF/foCMkifsmxfR4U
Unseal Key 5: 2Ne5s0OHSJT6kUnfLde1E+GvObRj/h6ppbPJjBEZrQi1
Initial Root Token: s.tgisePwqWHIYDkVRZZtKa06m
Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.
Vault does not store the generated master key. Without at least 3 key to
reconstruct the master key, Vault will remain permanently sealed!
It is possible to generate new unseal keys, provided you have a quorum of
existing unseal keys shares. See "vault operator rekey" for more information.
Vault listed all the 5 unseal keys, however, to unseal it we just need only 3 unseal keys. Their order do not matter.
Execute vault operator unseal
and pass the first unseal key. You’ll notice that the Unseal Progress
has changed to
1/3
. This way we need to pass all the 3 Unseal keys and finally the Sealed
status vaule will change to false
.
$ vault operator unseal
Unseal Key (will be hidden):
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed true
Total Shares 5
Threshold 3
Unseal Progress 1/3
Unseal Nonce 2bf63b58-c4ee-e584-3ff5-20705bc01017
Version 1.7.3
Storage Type file
HA Enabled false
$ vault operator unseal
Unseal Key (will be hidden):
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed true
Total Shares 5
Threshold 3
Unseal Progress 2/3
Unseal Nonce 2bf63b58-c4ee-e584-3ff5-20705bc01017
Version 1.7.3
Storage Type file
HA Enabled false
$ vault operator unseal
Unseal Key (will be hidden):
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 5
Threshold 3
Version 1.7.3
Storage Type file
Cluster Name vault-cluster-43a0999e
Cluster ID be8bfba1-72c5-743a-3458-a9d8932ce36c
HA Enabled false
The Vault status can also be checked using the following command:
$ vault status
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 5
Threshold 3
Version 1.7.3
Storage Type file
Cluster Name vault-cluster-43a0999e
Cluster ID be8bfba1-72c5-743a-3458-a9d8932ce36c
HA Enabled false
Let’s log in now using the Root Token:
$ vault login
Token (will be hidden):
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token s.tgisePwqWHIYDkVRZZtKa06m
token_accessor VtYVHHlIpMWwZpR5gVauhLrQ
token_duration ∞
token_renewable false
token_policies ["root"]
identity_policies []
policies ["root"]
To store the Key Value config parameters we need to first enable the KV
secrets engine using the following command:
$ vault secrets enable --path=servers kv
Success! Enabled the kv secrets engine at: servers/
Here the path is servers
. This means that the all keys that we will save in this secrets engine will always be
prepended by the servers/
path. This is where the secrets will be stored.
We can then find the path at which the secrets engines are mounted using the following command as well:
$ vault secrets list
Path Type Accessor Description
---- ---- -------- -----------
cubbyhole/ cubbyhole cubbyhole_7064544c per-token private secret storage
identity/ identity identity_7bac5daa identity store
servers/ kv kv_e047147c n/a
sys/ system system_875f4e5e system endpoints used for control, policy and debugging
Let’s enter some secrets into the KV secrets engine:
$ vault kv put servers/us-west id=us-west location=california
Success! Data written to: servers/us-west
$ vault kv put servers/us-east id=us-east location=newyork
Success! Data written to: servers/us-west
$ vault kv put servers/in-east id=in-east location=kolkata
Success! Data written to: servers/us-west
$ vault kv put servers/in-west id=in-west location=mumbai
Success! Data written to: servers/us-west
Here we’ve inserted 4 keys. Then we can get the list of all the secrets present inside the servers
path using the
list
sub command:
$ vault kv list servers
Keys
----
in-east
in-west
us-east
us-west
We can use get
subcommand with kv
to get the values:
$ vault kv get servers/in-west
====== Data ======
Key Value
--- -----
id in-west
location mumbai
$ vault kv get servers/in-east
====== Data ======
Key Value
--- -----
id in-east
location kolkata
In this section we will look into Vault Policies. We will create two policies:
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
servers/
path.servers/in-east
KV secret. path "servers/*" {
capabilities = ["list", "read"]
}
path "servers/in-east" {
capabilities = ["list", "read", "update"]
}
Let’s write them:
$ vault policy write admin policies/admin.hcl
Success! Uploaded policy: admin
$ vault policy write nonadmin policies/nonadmin.hcl
Success! Uploaded policy: nonadmin
To list out the policy execute vault policy list
:
$ vault policy list
admin
default
nonadmin
root
To read the policy execute:
$ vault policy read admin
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
$ vault policy read nonadmin
path "servers/*" {
capabilities = ["list", "read"]
}
path "servers/in-east" {
capabilities = ["list", "read", "update"]
}
To allow users to login and use Vault we need to enable the userpass
authentication first:
$ vault auth enable userpass
Success! Enabled userpass auth method at: userpass/
With this method enabled we can create users with username and password and assign them policies while creation. In this
example we will create two user: Admin and User1 and then assign them the admin
and nonadmin
policies
respectively.
$ vault write auth/userpass/users/admin password=admin policies=admin
Success! Data written to: auth/userpass/users/admin
$ vault write auth/userpass/users/user1 password=user1 policies=nonadmin
Success! Data written to: auth/userpass/users/user1
Let’s log in using the admin user’s credentials and verify if the correct polices are mapped and granted.
$ vault login -method=userpass username=admin
Password (will be hidden):
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token s.pe7gGITxX8hw1vRVAkxuoKEp
token_accessor 9QA0iDFsU6YYTZFHGCa0uHMD
token_duration 768h
token_renewable true
token_policies ["admin" "default"]
identity_policies []
policies ["admin" "default"]
token_meta_username admin
In the token_policies
section we can check that the token generated for the user has the admin
policies. Since we’ve
granted this user the permission to list all the secrets, it can perform that action:
$ vault secrets list
Path Type Accessor Description
---- ---- -------- -----------
cubbyhole/ cubbyhole cubbyhole_7064544c per-token private secret storage
identity/ identity identity_7bac5daa identity store
servers/ kv kv_e047147c n/a
sys/ system system_875f4e5e system endpoints used for control, policy and debugging
Likewise it can access the secrets that we had created earlier using the Root user.
$ vault kv get servers/in-east
====== Data ======
Key Value
--- -----
id in-east
location kolkata
$ vault kv get servers/in-west
====== Data ======
Key Value
--- -----
id in-west
location mumbai
Along with accessing them, it can edit them as well.
$ vault kv put servers/in-east id=in-east location=shillong
Success! Data written to: servers/in-east
$ vault kv get servers/in-east
====== Data ======
Key Value
--- -----
id in-east
location shillong
Let’s log in using the user User1.
$ vault login -method=userpass username=user1
Password (will be hidden):
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token s.ihNHc7SH49UH46v2N4PpTJYb
token_accessor h2SjkDcoZ56M2sasIX2J6DYI
token_duration 768h
token_renewable true
token_policies ["default" "nonadmin"]
identity_policies []
policies ["default" "nonadmin"]
token_meta_username user1
Since we’ve only granted the user the permission to view the servers
KV secrets, it cannot list the secrets:
$ vault secrets list
Error listing secrets engines: Error making API request.
URL: GET https://192.168.56.104:8200/v1/sys/mounts
Code: 403. Errors:
* 1 error occurred:
* permission denied
$ vault kv list servers
Keys
----
in-east
in-west
us-east
us-west
Along with permission to view the secrets, we’ve granted the user the permission to update the in-east
. Let’s test
that. If the user tries to update us-east
then it will get 403
Permission Denied error, however, if it can safely
perform the same operation with the in-east
key.
$ vault kv get servers/us-east
=== Data ===
Key Value
--- -----
id us-east
$ vault kv put servers/us-east location=123
Error writing data to servers/us-east: Error making API request.
URL: PUT https://192.168.56.104:8200/v1/servers/us-east
Code: 403. Errors:
* 1 error occurred:
* permission denied
$ vault kv put servers/in-east id=in-east location=kolkata
Success! Data written to: servers/in-east