This lab uses Vault CLI on Linux and demonstrates the full flow:
- Start Vault
- Enable KV secrets engine
- Enable
userpassauth - Create a user without policy
- Login as the user and fail to CRUD secrets
- Create a policy
- Attach policy to user
- 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
| Step | Command Area | Purpose |
|---|---|---|
| 1 | vault server -dev | Start lab Vault server |
| 2 | vault secrets enable -path=devops kv-v2 | Enable KV secrets engine |
| 3 | vault auth enable userpass | Enable username/password login |
| 4 | vault write auth/userpass/users/devuser | Create user without policy |
| 5 | vault login -method=userpass | Login as user |
| 6 | vault kv put/get | Fails because user has no policy |
| 7 | vault policy write | Create CRUD policy |
| 8 | vault write auth/userpass/users/devuser policies=... | Attach policy |
| 9 | vault login -method=userpass | Login again with policy |
| 10 | vault kv put/get/list/delete | CRUD succeeds |
This lab proves the key Vault concept: authentication only proves who the user is; policy decides what the user can do.