Recently I was asked to create a new integration between Cisco ASD (Automated Software Distribution) and Sonatype Nexus Repository. As both expose a decent API, it wasn’t a complicated task (just a matter of about 800 lines of Python code).
However, one thing confused me… Cisco ASD and Nexus Repo required the following secrets/variables (see below). Hmmm… what is the best way to protect the values of these secrets/variables?
One way is to use Environment variables. That would be nice, but not enough because they are configured locally and they are visible (removable, configurable) if you know a few OS commands.
Another way is to use User inputs. For example:
client_id = getpass.getpass('Client ID: ') client_secret = getpass.getpass('Client Secret: ') repo_token = getpass.getpass('Nexus Repo Token ID: ')
But since we’ll have about eight sensitive inputs, that’s too much “copy and paste”. Another way is to use a secret manager such as AWS Secrets Manager, Azure Key Vault , Hashicorp Safe, and a few others.
In this article, I would like to know more about the Hasicorp Vault because it suited the client perfectly air pocket environment. In the future I will call her To jump for simplicity (don’t confuse it with Ansible Vault or any other vault).
So… what is a Secret Manager? Secret Manager is a secure storage system for API keys, passwords, certificates and other sensitive data. Secret Manager provides a central location and single source of truth to manage access and is capable of reporting/verifying secrets.
Ok.. and what’s so special To jump?
Vault is a Go application with a Rest/CLI interface.
Vault helps organizations manage access to secrets and transmit them securely.
Secrets are defined as any form of sensitive credentials that need to be controlled and monitored (e.g. API keys, SSH keys, RSA or OTP tokens)
Vault makes it easy to create detailed audit logs (who accessed what)
Vault provides “encryption as a service” encrypting data in transit (using TLS) and at rest (using AES 256-bit CBC encryption). This protects sensitive data from unauthorized access in two main ways: as it moves across the network as well as in your cloud storage and data centers.
Vault uses a token to let you see the information it contains, tokens can be created and revoked on demand.
Chest tokens are Lifetime and Limit of use configurable (for example, the following command creates a token that is valid ONLY for 1 hour and can be used ONLY twice: create vault token -ttl=1h-use-limit=2)
Let’s go through the installation and basic configuration of the Vault Development Server (Note: Development Mode SHOULD NOT be used in production because Dev Vault runs entirely in memory and boots unsealed with a single unsealing key. For production, please use the production server)
1. Go to HashiCorp Vault download page
2. Choose your operating system. For this article, we will choose Linux and Centos/RHEL
3. Install the Vault development server:
$ sudo yum install -y yum-utils Last metadata expiration check: 0:01:06 ago on Sun 11 Jul 2021 03:55:26 PM UTC. Package yum-utils-4.0.18-4.el8.noarch is already installed. Dependencies resolved. Nothing to do. Complete! $ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repoUpdating Subscription Management repositories. Adding repo from: https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo $ sudo yum -y install vault Updating Subscription Management repositories. Unable to read consumer identity Hashicorp Stable - x86_64 7.9 MB/s | 550 kB 00:00 Dependencies resolved.===================================================================================================================Package Architecture Version Repository Size===================================================================================================================Installing:vault x86_64 1.7.3-1 hashicorp 54 M Transaction Summary===================================================================================================================Install 1 Package Total download size: 54 M Installed size: 191 M Downloading Packages: vault-1.7.3-1.x86_64.rpm 33 MB/s | 54 MB 00:01 -------------------------------------------------------------------------------------------------------------------Total 33 MB/s | 54 MB 00:01 warning: /var/cache/dnf/hashicorp-164999f2fbadbd87/packages/vault-1.7.3-1.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID a3219f7b: NOKEY Hashicorp Stable - x86_64 167 kB/s | 3.1 kB 00:00 Importing GPG key 0xA3219F7B: Userid : "HashiCorp Security (HashiCorp Package Signing)
" Fingerprint: E8A0 32E0 94D8 EB4E A189 D270 DA41 8C88 A321 9F7B From : https://rpm.releases.hashicorp.com/gpgKey imported successfully Running transaction check Transaction check succeeded. Running transaction test Transaction test succeeded. Running transaction Preparing : 1/1 Running scriptlet: vault-1.7.3-1.x86_64 1/1 Installing : vault-1.7.3-1.x86_64 1/1 Running scriptlet: vault-1.7.3-1.x86_64 1/1 Generating Vault TLS key and self-signed certificate... Generating a RSA private key .........................................................++++ ....................................++++ writing new private key to 'tls.key'----- Vault TLS key and self-signed certificate have been generated in '/opt/vault/tls'. Verifying : vault-1.7.3-1.x86_64 1/1 Installed products updated. Installed: vault-1.7.3-1.x86_64 Complete!
4. Start Vault Dev Server: Vault Server -dev (make sure to enter the following two values: Unseal Key and Root Token)
$ vault server -dev ==> Vault server configuration: Api Address: http://127.0.0.1:8200 Cgo: disabled Cluster Address: https://127.0.0.1:8201 Go Version: go1.15.13 Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled") Log Level: info Mlock: supported: true, enabled: false Recovery Mode: false Storage: inmem Version: Vault v1.7.3 Version Sha: 5d517c864c8f10385bf65627891bcxxxxxxxxxxxxx ==> Vault server started! Log data will stream in below: 2021-07-11T00:21:20.779Z [INFO] proxy environment: http_proxy="" https_proxy="" no_proxy="" 2021-07-11T00:21:20.780Z [WARN] no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set 2021-07-11T00:21:20.781Z [INFO] core: security barrier not initialized 2021-07-11T00:21:20.782Z [INFO] core: security barrier initialized: stored=1 shares=1 threshold=1 2021-07-11T00:21:20.782Z [INFO] core: post-unseal setup starting 2021-07-11T00:21:20.793Z [INFO] core: loaded wrapping token key 2021-07-11T00:21:20.793Z [INFO] core: successfully setup plugin catalog: plugin-directory="" 2021-07-11T00:21:20.793Z [INFO] core: no mounts; adding default mount table 2021-07-11T00:21:20.796Z [INFO] core: successfully mounted backend: type=cubbyhole path=cubbyhole/ 2021-07-11T00:21:20.796Z [INFO] core: successfully mounted backend: type=system path=sys/ 2021-07-11T00:21:20.796Z [INFO] core: successfully mounted backend: type=identity path=identity/ 2021-07-11T00:21:20.800Z [INFO] core: successfully enabled credential backend: type=token path=token/ 2021-07-11T00:21:20.800Z [INFO] core: restoring leases 2021-07-11T00:21:20.800Z [INFO] rollback: starting rollback manager 2021-07-11T00:21:20.801Z [INFO] identity: entities restored 2021-07-11T00:21:20.801Z [INFO] identity: groups restored 2021-07-11T00:21:20.801Z [INFO] expiration: lease restore complete 2021-07-11T00:21:20.801Z [INFO] core: post-unseal setup complete 2021-07-11T00:21:20.802Z [INFO] core: root token generated 2021-07-11T00:21:20.802Z [INFO] core: pre-seal teardown starting 2021-07-11T00:21:20.802Z [INFO] rollback: stopping rollback manager 2021-07-11T00:21:20.802Z [INFO] core: pre-seal teardown complete 2021-07-11T00:21:20.802Z [INFO] core.cluster-listener.tcp: starting listener: listener_address=127.0.0.1:8201 2021-07-11T00:21:20.803Z [INFO] core.cluster-listener: serving cluster requests: cluster_listen_address=127.0.0.1:8201 2021-07-11T00:21:20.803Z [INFO] core: post-unseal setup starting 2021-07-11T00:21:20.803Z [INFO] core: loaded wrapping token key 2021-07-11T00:21:20.803Z [INFO] core: successfully setup plugin catalog: plugin-directory="" 2021-07-11T00:21:20.803Z [INFO] core: successfully mounted backend: type=system path=sys/ 2021-07-11T00:21:20.803Z [INFO] core: successfully mounted backend: type=identity path=identity/ 2021-07-11T00:21:20.803Z [INFO] core: successfully mounted backend: type=cubbyhole path=cubbyhole/ 2021-07-11T00:21:20.804Z [INFO] core: successfully enabled credential backend: type=token path=token/ 2021-07-11T00:21:20.805Z [INFO] core: restoring leases 2021-07-11T00:21:20.805Z [INFO] rollback: starting rollback manager 2021-07-11T00:21:20.805Z [INFO] identity: entities restored 2021-07-11T00:21:20.805Z [INFO] identity: groups restored 2021-07-11T00:21:20.805Z [INFO] expiration: lease restore complete 2021-07-11T00:21:20.805Z [INFO] core: post-unseal setup complete 2021-07-11T00:21:20.805Z [INFO] core: vault is unsealed 2021-07-11T00:21:20.808Z [INFO] core: successful mount: namespace="" path=secret/ type=kv 2021-07-11T00:21:20.818Z [INFO] secrets.kv.kv_405db499: collecting keys to upgrade 2021-07-11T00:21:20.818Z [INFO] secrets.kv.kv_405db499: done collecting keys: num_keys=1 2021-07-11T00:21:20.818Z [INFO] secrets.kv.kv_405db499: upgrading keys finished WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory and starts unsealed with a single unseal key. The root token is already authenticated to the CLI, so you can immediately begin using Vault. You may need to set the following environment variable: $ export VAULT_ADDR='http://127.0.0.1:8200' The unseal key and root token are displayed below in case you want to seal/unseal the Vault or re-authenticate. Unseal Key: HTxvqXgm+Y9+DwevmOZmNUUbeuZ9Yxxxxxxxxxxxxxxxx Root Token: s.4Gl4TLJb1D82OWxxxxxxxxxx Development mode should NOT be used in production installations!
5. Launch a new terminal session, copy and run the export VAULT_ADDR=’http://127.0.0.1:8200′ terminal output command. This will configure the Vault client to talk to the development server
6. Verify that Vault Dev Server is running: vault status
$ vault status Key Value --- ----- Seal Type shamir Initialized true Sealed false Total Shares 1 Threshold 1 Version 1.7.3 Storage Type inmem Cluster Name vault-cluster-xxxxxxxx Cluster ID 391d2141-a878-aab8-dc1e-xxxxxxxxxxx HA Enabled false
7. Write down one or more secrets: vault kv set secret/ap customer_id=123456789client_secret=987654321repo_token=a1b2c3d4e5
Note: This command creates three different secrets (customer identity, client_secret, and repo_token)
$ vault kv put secret/ap client_id=123456789 client_secret=987654321 repo_token=a1b2c3d4e5 Key Value --- -----created_time 2021-07-11T00:34:36.029268163Z deletion_time n/a destroyed false version 1
8. Check the vault secret: safe kv get secret/ap
$ vault kv get secret/ap ====== Metadata ====== Key Value --- -----created_time 2021-07-11T00:38:41.218990549Z deletion_time n/a destroyed false version 1 ======== Data ======== Key Value --- -----client_id 123456789 client_secret 987654321 repo_token a1b2c3d4e5
You have just set up your first Secret Vault!
Now let’s see how we can call Vault secret values using simple Python3 code.
Be sure to install and import both getpass and hvac (e.g. sudo pip3 install hvac)
Using your favorite editor, create a new file named hello.py
Copy and paste the following code
importgetpass importhvac VAULT_ADDR = 'http://127.0.0.1:8200'VAULT_TOKEN = getpass.getpass('Hashicorp Vault Token ID: ') client = hvac.Client() client = hvac.Client( url = VAULT_ADDR, token = VAULT_TOKEN ) response = client.secrets.kv.read_secret_version(path='ap') client_id = response['data']['data']['client_id'] client_secret = response['data']['data']['client_secret'] repo_token = response['data']['data']['repo_token'] print("Client ID: "+ client_id) print("Client Secret: "+ client_secret) print("Repo Token: "+ repo_token)
Let’s review the code:
Lines #1 – #2: Import required modules (Hasicorp Vault and getpass)
Line #4: Set HashiCorp Vault Server IP/Hostname
Line 5: Define a hidden user input to enter the Vault token ID
Lines 7-11: Vault function (note how we call the Vault address on line 9 and the Vault token on line 10)
Line 13: Generate the request to read secrets
Lines #15 – #17: parse the JSON response for each variable
Lines #19 – #21: Print analyzed variables
4. Run the Python code: python3 hello.py (when prompted, enter the “Root token” from step 4, above)
$ python3 hello.py Hashicorp Vault Token ID: [ --> Root Token: s.4Gl4TLJb1D82OWxxxxxxxxxx] Client ID: 123456789 Client Secret: 987654321 Repo Token: a1b2c3d4e5
You have successfully read Vault server secrets/variables using Python script!
This article aims to cover the basic features of Hasicorp Vault. Vault seems like a promising option to consider. Simple installation, highly customizable, tokenization concept, supports IaC approach. Built-in integration for the cloud makes the vault an ideal solution for managing the cloud as well as on-premises.
This article aims to cover the basic features of Hasicorp Vault.
The above procedure is a “POC Grade” which uses the root token to retrieve stored data. This is not a recommended use case for production.
You want to know more ? Want to learn more about installing and configuring the Production Vault? Please consult the official Documentation or contact the Cross-Domain TAB team.
We’d love to hear what you think. Ask a question or leave a comment below.
And stay connected with Cisco DevNet on social media!