Introduction
I am using hashicorp vault to store secrets of devices, and I am writing my own functions in python for my personal usage. There is a hashicorp vault api wrapper module known as hvac, at first I attempted to use hvac but I found it to be extremely difficult to use and not enough examples. So I have decided to use requests module to call the REST API directly from python, this is much more controllable and easier to troubleshoot since I wrote the functions myself.
Initially I wrote some functions using hvac module – pyvault, but I decided to give up, as I found using hvac is difficult and has no real value add in my own opinion, so I started to write another sets of functions to use the kv version2 engine of Hashicorp vault which is pyvault2, writing my own api calls with the help of requests makes my own script easier to troubleshoot and manage since the functions are written by myself.
You can initialize and configure the vault through the web interface or through the vault command line, but these actions require human intervention, the python script is meant to do automation.
Initialize vault
This is needed to be done once. The initialization produces a dictionary of keys (seals), keys in base64 and one root token. This root token can do every modification in the hashicorp vault, I think user token can also be created by configuring roles and users, but I have not tried yet.
Uninitialized vault will look like above.
Make changes to your vault configuration under the constants directory, pyvault_config.py
, since my vault ip address is 192.168.1.200 I changed it:
VAULT_IP_ADDRESS = "192.168.1.200"
.
To initialize the vault with pyvault2:
from pyvault2.vault.hvault2 import vault_init """ Initialize the vault for the first time. The initialization produces a dictionary of seals, seals in base64 and a root token. This example will display the dictionary on the console, and save the dictionary to files and encrypted. Default secret_shares = 5, default secret_threshold = 3. """ if __name__ == '__main__': vault_init(show_tokens=True)
After the vault initialized these files will be created under the seal directory in your $HOME directory.
The vault will be sealed.
Because show_tokens=True
, the dictionary is shown in clear text.
Create new kv2 engine, and insert secrets
There is one cubbyhole engine enabled in a new vault, but for the example I will be creating a new kv version 2 engine, and store secrets into it. The set of functions I have written are using kv version 2 for now, gradually I will add more if I need more.
The below scripts will enable a new kv version 2 engine, and insert username, password into the engine.
from pyvault2.vault.hvault2 import enable_kv2_engine, create_update_kv2_secrets """ This example enables a new kv2 engine. Insert new secrets into the kv2 engine. To enable the kv2 engine, a mount point has to be specified. Then to insert the secrets a path has to be specified. In the function the backend type is set to kv and version 2. There are many backend types: kv, ldap, ssh, pki, aws...etc... """ enable_kv2_engine(path="First_Vault") create_update_kv2_secrets( username="cyruslab", password="P@ssw0rd21012020", description="If description is not specified, then is default to null.", mount_path="First_Vault", path="server1" )
The kv version 2 engine is created as shown below.
The server1 contains the secrets, I have just inserted by the script above.
The secrets below.
Update secrets in the same mount point and path
If there is changes in secrets, the same function is used to update the secrets, the condition is you must modify to the current version, the default keeps 10 revisions of the updates, if there are more than 10 versions then the last version will be modified.
So I would need to know the current version in the vault, and modify that version.
The below script is to modify the current version of the secrets.
from pyvault2.vault.hvault2 import create_update_kv2_secrets, get_kv2_secret_version """ Update the secrets. The Check-And-Set aka cas is the check to ensure the version upload is the same as current version._ """ if __name__ == "__main__": current_version = get_kv2_secret_version(mount_path="First_Vault", path="server1") create_update_kv2_secrets(username="cyruslab_modified", password="P@ssw0rd_m0d1f13d", mount_path="First_Vault", path="server1", cas=current_version)
As shown below, the version changes to 2, and the contents of the dictionary changed according to the script above.