HashiCorp Vault — Practice Projects Exercises

3 minute read

Combine what you’ve built across all projects with these challenges.


Exercise 1 — Secure Microservice Pipeline

Task: Build a complete secret pipeline for a microservice.

  1. Create a KV path for the service config
  2. Set up dynamic PostgreSQL credentials
  3. Configure AppRole for the service
  4. Create a Vault Agent config that renders a .env file
Show Answer
# 1. KV secrets
vault secrets enable -path=microservices kv-v2
vault kv put microservices/payment-svc/config \
    redis_url="redis://cache:6379" \
    log_level="info" \
    rate_limit="1000"

# 2. Dynamic DB creds
vault write database/roles/payment-svc \
    db_name=webapp-db \
    creation_statements="CREATE ROLE \"\" WITH LOGIN PASSWORD '' VALID UNTIL ''; GRANT SELECT, INSERT, UPDATE ON payment_transactions TO \"\";" \
    default_ttl=1h max_ttl=4h

# 3. AppRole
vault policy write payment-svc - <<EOF
path "microservices/data/payment-svc/*" { capabilities = ["read"] }
path "database/creds/payment-svc" { capabilities = ["read"] }
path "sys/leases/renew" { capabilities = ["update"] }
EOF

vault write auth/approle/role/payment-svc \
    policies=payment-svc token_ttl=15m token_max_ttl=1h
# 4. Vault Agent config
template {
  contents = <<-EOT
    {{- with secret "microservices/data/payment-svc/config" }}
    REDIS_URL={{ .Data.data.redis_url }}
    LOG_LEVEL={{ .Data.data.log_level }}
    RATE_LIMIT={{ .Data.data.rate_limit }}
    {{- end }}
    {{- with secret "database/creds/payment-svc" }}
    DB_USER={{ .Data.username }}
    DB_PASS={{ .Data.password }}
    {{- end }}
  EOT
  destination = "/app/.env"
  command     = "kill -HUP $(pidof payment-svc)"
}

Exercise 2 — Certificate-Authenticated API

Task: Use Vault’s PKI to create a client certificate for API authentication.

  1. Create a PKI role for API clients
  2. Issue a client certificate
  3. Configure a server to verify client certs
  4. Test the mTLS connection
Show Answer
# 1. Create PKI role for API clients
vault write pki_int/roles/api-client \
    allowed_domains="api.example.com" \
    allow_subdomains=true \
    client_flag=true \
    server_flag=false \
    max_ttl=720h

# 2. Issue client certificate
vault write pki_int/issue/api-client \
    common_name="service-x.api.example.com" \
    ttl=720h
# Save: certificate → client.pem, private_key → client-key.pem

# 3. Server Nginx config
# ssl_client_certificate /etc/nginx/tls/ca-chain.pem;
# ssl_verify_client on;

# 4. Test
curl --cert client.pem --key client-key.pem \
    --cacert ca-chain.pem \
    https://api.example.com/v1/data

Exercise 3 — Multi-Environment Secret Management

Task: Organize secrets for dev, staging, and production environments.

Show Answer
# Create per-environment paths
for ENV in dev staging production; do
  vault kv put apps/${ENV}/webapp/config \
      environment="${ENV}" \
      debug="$([ "$ENV" = "dev" ] && echo true || echo false)" \
      replicas="$([ "$ENV" = "production" ] && echo 3 || echo 1)"

  vault kv put apps/${ENV}/webapp/database \
      host="db-${ENV}.example.com" \
      port="5432" \
      name="webapp_${ENV}"
done

# Create per-environment policies
for ENV in dev staging production; do
  vault policy write webapp-${ENV} - <<EOF
path "apps/data/${ENV}/webapp/*" {
  capabilities = ["read"]
}
EOF
done

# Dev team gets dev + staging
vault write auth/approle/role/webapp-dev \
    policies="webapp-dev,webapp-staging" \
    token_ttl=4h

# Production deploys get production only
vault write auth/approle/role/webapp-prod \
    policies="webapp-production" \
    token_ttl=15m

Exercise 4 — Transit Key Rotation Workflow

Task: Implement a complete key rotation workflow for the Transit engine.

Show Answer
# Create a key
vault write -f transit/keys/app-encryption

# Encrypt some data
CIPHER1=$(vault write -field=ciphertext transit/encrypt/app-encryption \
    plaintext=$(echo -n "secret-data-1" | base64))
CIPHER2=$(vault write -field=ciphertext transit/encrypt/app-encryption \
    plaintext=$(echo -n "secret-data-2" | base64))

echo "Before rotation:"
echo "  $CIPHER1"  # vault:v1:...
echo "  $CIPHER2"  # vault:v1:...

# Rotate the key
vault write -f transit/keys/app-encryption/rotate

# Rewrap existing ciphertexts
NEW_CIPHER1=$(vault write -field=ciphertext transit/rewrap/app-encryption \
    ciphertext="$CIPHER1")
NEW_CIPHER2=$(vault write -field=ciphertext transit/rewrap/app-encryption \
    ciphertext="$CIPHER2")

echo "After rotation + rewrap:"
echo "  $NEW_CIPHER1"  # vault:v2:...
echo "  $NEW_CIPHER2"  # vault:v2:...

# Both old and new ciphertexts can be decrypted
vault write transit/decrypt/app-encryption ciphertext="$CIPHER1"
vault write transit/decrypt/app-encryption ciphertext="$NEW_CIPHER1"

# Set minimum version (disable old key)
vault write transit/keys/app-encryption min_decryption_version=2

# Old ciphertexts can no longer be decrypted
vault write transit/decrypt/app-encryption ciphertext="$CIPHER1"
# Error! ❌

Exercise 5 — Disaster Recovery Drill

Task: Simulate a disaster and recover Vault from a backup.

Show Answer
# 1. Create baseline data
vault kv put secret/critical/api-key value=production-key-123
vault kv put secret/critical/db-pass value=super-secret-db-pass

# 2. Take a snapshot
vault operator raft snapshot save dr-drill-$(date +%Y%m%d).snap

# 3. Simulate "disaster" — add data that shouldn't exist after restore
vault kv put secret/critical/corrupted value=bad-data
vault kv delete secret/critical/api-key

# Verify bad state
vault kv get secret/critical/corrupted  # ✅ exists
vault kv get secret/critical/api-key    # ❌ deleted

# 4. Restore from snapshot
vault operator raft snapshot restore -force dr-drill-*.snap

# 5. Verify recovery
vault kv get secret/critical/api-key    # ✅ restored
vault kv get secret/critical/db-pass    # ✅ restored
vault kv get secret/critical/corrupted  # ❌ gone (pre-snapshot state)

echo "✅ DR drill successful — data restored to backup state"

What’s Next?

You’ve built complete projects covering all major Vault features. Now let’s look at where to go from here — certifications, related tools, and learning resources.

Next Chapter: Next Steps