HashiCorp Vault: Step-by-Step Tutorial: Vault CLI on Linux — KV Secrets, Userpass Auth, Policy, and CRUD

This lab uses Vault CLI on Linux and demonstrates the full flow:

  1. Start Vault
  2. Enable KV secrets engine
  3. Enable userpass auth
  4. Create a user without policy
  5. Login as the user and fail to CRUD secrets
  6. Create a policy
  7. Attach policy to user
  8. Login again and perform CRUD successfully

Vault’s kv command works with both KV v1 and KV v2, but for KV v2 the CLI path and policy path are different. HashiCorp recommends using the -mount flag to avoid confusion with KV v2 paths. (HashiCorp Developer)


1. Prerequisites

You need a Linux machine with Vault installed. Vault is available as a precompiled binary and through Linux package managers such as apt and yum. (HashiCorp Developer)

For Ubuntu/Debian:

sudo apt update
sudo apt install -y gpg wget

wget -O- https://apt.releases.hashicorp.com/gpg | \
  sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | \
  sudo tee /etc/apt/sources.list.d/hashicorp.list

sudo apt update
sudo apt install -y vault

Verify:

vault version
vault -help

2. Start Vault Dev Server

For this lab, use Vault dev mode. This is only for learning, not production.

Open Terminal 1:

vault server -dev -dev-root-token-id=root

Keep this terminal running.

Open Terminal 2 and export Vault address and root token:

export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='root'

Verify Vault status:

vault status

Expected:

Sealed      false

Login with root token:

vault login root

3. Enable KV Secrets Engine

We will enable KV v2 at path devops.

vault secrets enable -path=devops kv-v2

Expected:

Success! Enabled the kv-v2 secrets engine at: devops/

Check enabled secrets engines:

vault secrets list

Expected output should include:

devops/    kv

KV v2 stores versioned secrets and uses special API paths such as devops/data/... for secret data and devops/metadata/... for listing/metadata operations. (HashiCorp Developer)


4. Enable Userpass Auth Method

Enable the userpass authentication method:

vault auth enable userpass

Expected:

Success! Enabled the userpass auth method at: userpass/

The userpass auth method allows users to authenticate with a username and password stored directly in Vault under the users/ path. (HashiCorp Developer)

Verify auth methods:

vault auth list

Expected output should include:

userpass/    userpass

5. Create a User Without Policy

Create a user called devuser, but do not attach any custom policy yet.

vault write auth/userpass/users/devuser \
  password='DevUser@123'

Expected:

Success! Data written to: auth/userpass/users/devuser

At this point, the user can login, but cannot access the devops secrets engine because Vault policies are deny-by-default unless access is explicitly granted. (HashiCorp Developer)


6. Login as the User

Login as devuser:

vault login -method=userpass \
  username=devuser \
  password='DevUser@123'

Expected output:

Success! You are now authenticated.
token_policies    ["default"]

Check current token:

vault token lookup

You should see only the default policy.


7. Try CRUD Secret as User — It Should Fail

Try to Create Secret

vault kv put -mount=devops app1/db \
  username='admin' \
  password='secret123'

Expected failure:

Error writing data to devops/data/app1/db: Error making API request.

Code: 403. Errors:

* permission denied

Try to Read Secret

vault kv get -mount=devops app1/db

Expected:

permission denied

This failure is correct. The user authenticated successfully, but authorization failed because no policy allows access to devops/data/*.


8. Login Back as Root Admin

Now switch back to root token so we can create a policy.

vault login root

Or:

export VAULT_TOKEN='root'

Confirm:

vault token lookup

Expected:

policies    [root]

9. Create a Policy to Allow CRUD on KV Secrets

Create a policy file:

cat > devops-crud-policy.hcl <<'EOF'
# Allow create, read, update, and delete secret data in KV v2
path "devops/data/*" {
  capabilities = ["create", "read", "update", "delete"]
}

# Allow listing secrets and reading metadata in KV v2
path "devops/metadata" {
  capabilities = ["list"]
}

path "devops/metadata/*" {
  capabilities = ["read", "list", "delete"]
}
EOF

Important: for KV v2, vault kv put/get/delete uses the user-friendly command path, but the policy must target devops/data/*. Listing uses devops/metadata/*. HashiCorp’s KV docs show that KV v2 maps kv get, kv put, and kv delete to secret/data/<key_path>, while kv list maps to secret/metadata/<key_path>. (HashiCorp Developer)

Upload the policy:

vault policy write devops-crud devops-crud-policy.hcl

Expected:

Success! Uploaded policy: devops-crud

Verify policy:

vault policy read devops-crud

10. Attach Policy to Userpass User

Update the existing devuser and attach the devops-crud policy:

vault write auth/userpass/users/devuser \
  password='DevUser@123' \
  policies='devops-crud'

Expected:

Success! Data written to: auth/userpass/users/devuser

In userpass, users are configured under auth/userpass/users/<username>, and policies can be associated during user creation or update. (HashiCorp Developer)


11. Login Again as User

vault login -method=userpass \
  username=devuser \
  password='DevUser@123'

Expected:

Success! You are now authenticated.
token_policies    ["default" "devops-crud"]

Confirm:

vault token lookup

You should now see:

policies    [default devops-crud]

12. Perform CRUD Secret Using User

Now the same user should be able to create, read, update, and delete secrets.


C — Create Secret

vault kv put -mount=devops app1/db \
  username='admin' \
  password='secret123'

Expected:

== Secret Path ==
devops/data/app1/db

======= Metadata =======
version    1

R — Read Secret

vault kv get -mount=devops app1/db

Expected:

== Secret Path ==
devops/data/app1/db

====== Data ======
Key         Value
---         -----
password    secret123
username    admin

U — Update Secret

vault kv put -mount=devops app1/db \
  username='admin' \
  password='newSecret456'

Expected:

== Secret Path ==
devops/data/app1/db

======= Metadata =======
version    2

Read again:

vault kv get -mount=devops app1/db

Expected:

password    newSecret456
username    admin

L — List Secrets

vault kv list -mount=devops app1

Expected:

Keys
----
db

D — Delete Secret

vault kv delete -mount=devops app1/db

Expected:

Success! Data deleted, if it existed, at: devops/data/app1/db

Try to read again:

vault kv get -mount=devops app1/db

Expected:

No value found at devops/data/app1/db

In KV v2, kv delete marks a version as deleted; it does not permanently destroy the underlying version data. Permanent removal uses vault kv destroy, and full metadata removal uses vault kv metadata delete. (HashiCorp Developer)


13. Optional: Permanently Remove Secret Metadata

Because KV v2 keeps metadata and versions, you may still see the path in metadata unless you delete it.

vault kv metadata delete -mount=devops app1/db

Expected:

Success! Data deleted, if it existed, at: devops/metadata/app1/db

14. Useful Verification Commands

Check secrets engines:

vault secrets list

Check auth methods:

vault auth list

Check current login token:

vault token lookup

Check policies:

vault policy list
vault policy read devops-crud

Check user by reading config as root:

vault read auth/userpass/users/devuser

15. Cleanup Lab

Login as root:

vault login root

Delete user:

vault delete auth/userpass/users/devuser

Delete policy:

vault policy delete devops-crud

Disable auth method:

vault auth disable userpass

Disable secrets engine:

vault secrets disable devops

Stop Vault dev server by pressing:

CTRL + C

Final Flow Summary

StepCommand AreaPurpose
1vault server -devStart lab Vault server
2vault secrets enable -path=devops kv-v2Enable KV secrets engine
3vault auth enable userpassEnable username/password login
4vault write auth/userpass/users/devuserCreate user without policy
5vault login -method=userpassLogin as user
6vault kv put/getFails because user has no policy
7vault policy writeCreate CRUD policy
8vault write auth/userpass/users/devuser policies=...Attach policy
9vault login -method=userpassLogin again with policy
10vault kv put/get/list/deleteCRUD succeeds

This lab proves the key Vault concept: authentication only proves who the user is; policy decides what the user can do.

Related Posts

Low-Level Authentication Flow Design for Student, Trainer, and Consultant Services Using Keycloak

Yes — the clean low-level flow should use Keycloak as the central Identity Provider, and Student / Trainer / Consultant services should never handle passwords directly. Recommended…

Read More

How to Use Two GitHub Accounts on One Mac with Different SSH Keys

Managing two GitHub accounts on the same Mac is very common. For example, you may have: The problem starts when both accounts use GitHub SSH URLs like…

Read More

Github: GitHub CLI gh — Install, Authenticate, and Use GitHub from the Terminal

1. What is gh? gh is the official GitHub command-line interface. It brings GitHub features such as repositories, pull requests, issues, GitHub Actions, Codespaces, releases, secrets, variables,…

Read More

Datadog: Application Error Tracking in EKS using Datadog, DogStatsD, APM, Logs, and Error Tracking

Master Guide: Application Error Tracking in EKS using Datadog, DogStatsD, APM, Logs, and Error Tracking First, tiny naming correction: it is DogStatsD, not DogStashD. DogStatsD is Datadog’s…

Read More

MongoDB – Complete End-to-End MongoDB Tutorial Blog: From Basics to Advanced

MongoDB is a NoSQL document database. Instead of storing data in rows and columns like a relational database, MongoDB stores data as documents inside collections. These documents…

Read More