HashiCorp Vault — Installation Exercises

3 minute read

Practice what you’ve learned about installing and configuring Vault with these hands-on exercises.


Exercise 1 — Start and Explore Dev Server

Task: Start a dev server, explore the defaults, and store your first secret.

  1. Start a dev server with root token lab-token
  2. In another terminal, set VAULT_ADDR and VAULT_TOKEN
  3. Run vault status and note the storage type and seal status
  4. List all secrets engines
  5. Store a secret at secret/exercise1 with color=blue and number=42
  6. Read back just the color field
Show Answer
# Terminal 1: Start dev server
vault server -dev -dev-root-token-id="lab-token"

# Terminal 2: Configure environment
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='lab-token'

# Check status
vault status
# Storage Type: inmem
# Sealed: false

# List secrets engines
vault secrets list
# cubbyhole/, identity/, secret/, sys/

# Store a secret
vault kv put secret/exercise1 color=blue number=42

# Read the color field
vault kv get -field=color secret/exercise1
# Output: blue

Exercise 2 — Docker Compose Dev Lab

Task: Create a Docker Compose file for a Vault dev server and interact with it.

  1. Write a docker-compose.yml that runs Vault 1.15 in dev mode
  2. Set the root token to docker-lab-token
  3. Start the container
  4. Use curl and jq to check Vault’s health endpoint
  5. Use curl to write a secret via the API
  6. Use the CLI to read the secret back
Show Answer
# docker-compose.yml
services:
  vault:
    image: hashicorp/vault:1.15
    container_name: vault-lab
    ports:
      - "8200:8200"
    environment:
      VAULT_DEV_ROOT_TOKEN_ID: docker-lab-token
      VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
    cap_add:
      - IPC_LOCK
# Start
docker compose up -d

# Check health
curl -s http://127.0.0.1:8200/v1/sys/health | jq

# Set environment
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='docker-lab-token'

# Write via API
curl -s \
    --header "X-Vault-Token: $VAULT_TOKEN" \
    --request POST \
    --data '{"data": {"exercise": "2", "tool": "docker"}}' \
    "$VAULT_ADDR/v1/secret/data/exercise2" | jq

# Read via CLI
vault kv get secret/exercise2

# Clean up
docker compose down

Exercise 3 — Production Configuration

Task: Write a production Vault configuration file (without actually running it).

Write a vault.hcl that includes:

  1. Raft storage at /opt/vault/data with node ID prod-vault-1
  2. TCP listener on all interfaces, port 8200, with TLS
  3. API address and cluster address
  4. UI enabled
  5. Memory lock enabled
  6. Prometheus telemetry with 24h retention
Show Answer
# vault.hcl — Production configuration

storage "raft" {
  path    = "/opt/vault/data"
  node_id = "prod-vault-1"
}

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_cert_file = "/opt/vault/tls/vault-cert.pem"
  tls_key_file  = "/opt/vault/tls/vault-key.pem"
}

api_addr     = "https://prod-vault-1.example.com:8200"
cluster_addr = "https://prod-vault-1.example.com:8201"

ui            = true
disable_mlock = false

telemetry {
  prometheus_retention_time = "24h"
  disable_hostname         = true
}

Key points:

  • disable_mlock = false ensures secrets aren’t swapped to disk
  • TLS is mandatory in production
  • api_addr is what clients use; cluster_addr is for inter-node traffic
  • Telemetry enables Prometheus scraping at /v1/sys/metrics

Exercise 4 — CLI Mastery

Task: Complete these CLI operations against a dev server:

  1. Create three secrets: secret/app/dev, secret/app/staging, secret/app/prod
  2. List all secrets under secret/app/
  3. Read secret/app/prod as JSON and pipe through jq
  4. Delete secret/app/dev
  5. Check that the delete was a soft-delete (metadata still exists)
  6. Permanently destroy secret/app/dev version 1
Show Answer
# Create secrets
vault kv put secret/app/dev db_host="dev-db.local" db_pass="dev123"
vault kv put secret/app/staging db_host="staging-db.local" db_pass="stage456"
vault kv put secret/app/prod db_host="prod-db.local" db_pass="pr0d789!"

# List secrets
vault kv list secret/app/
# Keys
# ----
# dev
# prod
# staging

# Read as JSON
vault kv get -format=json secret/app/prod | jq '.data.data'
# {
#   "db_host": "prod-db.local",
#   "db_pass": "pr0d789!"
# }

# Soft-delete
vault kv delete secret/app/dev

# Check metadata still exists
vault kv metadata get secret/app/dev
# Shows metadata with deletion_time set

# Permanently destroy version 1
vault kv destroy -versions=1 secret/app/dev

Exercise 5 — API Exploration

Task: Use only curl (no Vault CLI) to:

  1. Check if Vault is initialized and unsealed
  2. List all secrets engines
  3. Write a secret to secret/data/api-test with method=curl
  4. Read the secret back
  5. Delete the secret
Show Answer
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='my-root-token'

# 1. Health check
curl -s "$VAULT_ADDR/v1/sys/health" | jq '{initialized, sealed}'
# {"initialized": true, "sealed": false}

# 2. List secrets engines
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
    "$VAULT_ADDR/v1/sys/mounts" | jq 'keys'

# 3. Write a secret
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
    --request POST \
    --data '{"data": {"method": "curl"}}' \
    "$VAULT_ADDR/v1/secret/data/api-test" | jq

# 4. Read the secret
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
    "$VAULT_ADDR/v1/secret/data/api-test" | jq '.data.data'
# {"method": "curl"}

# 5. Delete the secret
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
    --request DELETE \
    "$VAULT_ADDR/v1/secret/data/api-test"

What’s Next?

You’ve installed Vault, explored the dev server, and mastered the CLI and API. Next, we’ll dive into secrets engines.

Next Chapter: Secrets Engines