📑 Table of Contents

Privileged Access Management (PAM) is the discipline of controlling access to sensitive systems, accounts, and secrets. Static credentials—passwords written in config files or shared among teams—are a leading cause of security breaches. HashiCorp Vault solves this by providing centralized secrets management, dynamic credential generation, and fine-grained access policies. In this lab, you'll deploy Vault, configure secrets engines, implement dynamic database credentials, and build a just-in-time (JIT) access workflow.

🎯 Lab Overview & PAM Fundamentals

Privileged Access Management addresses the security risks associated with elevated credentials—database passwords, API keys, SSH keys, certificates, and administrative accounts. Traditional approaches of storing secrets in configuration files, environment variables, or spreadsheets create massive security risks: secrets sprawl, lack of audit trails, inability to rotate credentials, and no way to revoke access instantly. HashiCorp Vault provides a unified solution for managing secrets throughout their lifecycle, from secure storage to automatic rotation to detailed audit logging.

✅ Prerequisites

  • Docker & Docker Compose: Container management skills
  • Basic CLI: Comfortable with command-line tools
  • IAM Concepts: Understanding from LABs 5-6 (authentication, authorization)

What You Will Build

Learning Objectives

🏢 Enterprise Scenario: Eliminating Secrets Sprawl

You're the Security Engineer at FinanceApp Inc., and a recent security audit revealed disturbing findings:

"We found database credentials in 47 different locations—Git repositories, Jenkins configs, developers' laptops, and even Slack messages. The production database password hasn't been changed in 3 years because 'too many things would break.' We have no idea who has access to what. This is a breach waiting to happen."

  • Centralize all secrets in a single, auditable system
  • Eliminate static credentials with dynamic, short-lived secrets
  • Enable automatic rotation without breaking applications
  • Create audit trails showing every secret access
  • Implement least privilege with fine-grained policies

🎯 Skills You Will Gain

Secrets Management

Centralized secret storage patterns applicable to all enterprise environments.

Dynamic Credentials

Generate on-demand secrets for databases, cloud providers, and services.

Policy Design

Write access control policies using HashiCorp Configuration Language.

PKI Management

Build certificate authorities and issue dynamic TLS certificates.

AppRole Authentication

Secure machine-to-machine authentication for CI/CD and applications.

Audit & Compliance

Track every secret access for security and regulatory requirements.

📚 Vault Architecture & Core Concepts

Before deploying Vault, you must understand its architecture and key concepts. Vault is designed around the principle that secrets should be difficult to access, easy to audit, and possible to revoke instantly.

📖 What is HashiCorp Vault?

Vault is a secrets management tool that provides:

  • Secure Secret Storage: Encrypted storage for sensitive data
  • Dynamic Secrets: Generate credentials on-demand with automatic expiration
  • Data Encryption: Encrypt data without storing it (Encryption as a Service)
  • Leasing & Renewal: All secrets have a lease; applications must renew or re-fetch
  • Revocation: Revoke single secrets, trees of secrets, or entire authentication methods

Vault Core Components

🔐 Secrets Engines

Plugins that store, generate, or encrypt data. Examples: KV (key-value), Database, PKI, AWS, SSH. Each engine is mounted at a path.

🔑 Auth Methods

Plugins that verify identity. Examples: Token, UserPass, LDAP, OIDC, AppRole, AWS IAM. Successful auth returns a Vault token.

📋 Policies

Rules defining what secrets a token can access. Written in HCL or JSON. Default deny—must explicitly grant access.

🎫 Tokens

Primary authentication mechanism. All requests require a token. Tokens have policies attached defining capabilities.

⏱️ Leases

Time-bound validity for secrets. When lease expires, secret is revoked. Applications must renew or re-authenticate.

📝 Audit Devices

Log all requests and responses. Every operation is recorded. Essential for compliance and incident response.

▼ VAULT ARCHITECTURE ▼

1
Client Authentication

Client authenticates using Auth Method (token, userpass, LDAP, OIDC, AppRole)

2
Token Issuance

Vault issues token with attached policies defining access capabilities

3
Secret Request

Client requests secret from Secrets Engine path using token

4
Policy Check

Vault checks token's policies against requested path and operation

5
Secret Delivery

If allowed, secret is returned with lease information. Audit log records the access.

Secrets Engine Types

EngineTypeUse Case
KV (Key-Value)StaticStore arbitrary secrets (API keys, configs)
DatabaseDynamicGenerate time-limited database credentials
AWSDynamicGenerate IAM credentials or STS tokens
PKIDynamicIssue X.509 certificates
SSHDynamicSign SSH keys or generate OTP
TransitEncryptionEncrypt/decrypt data without storing it

📋 Prerequisites & Lab Environment

This lab requires Docker for running Vault and PostgreSQL. We'll deploy Vault in dev mode first, then progress to a more production-like configuration.

Device Badges Legend

Local MachineDocker host / terminal
Vault CLI/UIHashiCorp Vault
PostgreSQLDatabase server
Web BrowserVault UI

🔐 Module 1: Deploy HashiCorp Vault

Module 1: Vault Server Deployment

Deploy Vault in development mode and understand initialization concepts.

⏱️ 30-45 minutes🎯 5 steps📍 Local Machine

Vault has two operational modes: dev mode (for learning, automatically unsealed) and production mode (requires unsealing with master key shares). We'll start with dev mode to learn concepts, then understand production deployment patterns.

1

Create Lab Directory

Local Machine
mkdir -p ~/lab7-vault/{config,data,policies} cd ~/lab7-vault echo "Vault lab directory created"
2

Create Docker Compose for Vault

Local Machine
cat > ~/lab7-vault/docker-compose.yml << 'EOF' version: '3.9' services: vault: image: hashicorp/vault:1.15 container_name: vault cap_add: - IPC_LOCK environment: VAULT_DEV_ROOT_TOKEN_ID: root-token VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200 VAULT_ADDR: http://127.0.0.1:8200 ports: - "8200:8200" networks: - vault-network postgres: image: postgres:15-alpine container_name: vault-postgres environment: POSTGRES_DB: appdb POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres123 ports: - "5432:5432" networks: - vault-network networks: vault-network: driver: bridge EOF echo "Docker Compose file created"
3

Start Vault and PostgreSQL

Local Machine
cd ~/lab7-vault docker compose up -d echo "Waiting for services to start..." sleep 10 docker compose ps echo "" echo "Vault UI available at: http://localhost:8200" echo "Root Token: root-token"
4

Install Vault CLI

Install the Vault CLI for interacting with the server from your terminal.

Local Machine
# Option 1: Using Docker exec (no local install needed) alias vault='docker exec -e VAULT_ADDR=http://127.0.0.1:8200 -e VAULT_TOKEN=root-token vault vault' # Test the alias vault status # Option 2: Install locally (choose based on your OS) # macOS: brew install hashicorp/tap/vault # Ubuntu: # wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg # echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list # sudo apt update && sudo apt install vault
5

Configure Environment Variables

Local Machine
# Set environment variables for Vault CLI export VAULT_ADDR='http://127.0.0.1:8200' export VAULT_TOKEN='root-token' # Verify Vault is running and unsealed vault status # Expected output shows: # Sealed: false # Cluster Name: vault-cluster-xxx

✅ Module 1 Complete!

Vault is running in dev mode. In Module 2, we'll store our first secrets.

🗄️ Module 2: Static Secrets with KV Engine

Module 2: Key-Value Secrets Engine

Store, retrieve, and version static secrets using the KV secrets engine.

⏱️ 30-45 minutes🎯 5 steps📍 Vault CLI

The KV (Key-Value) secrets engine stores arbitrary secrets. KV v2 (default in Vault) supports versioning, allowing you to retrieve previous versions of secrets and see when they were modified.

6

Explore Default KV Engine

Vault CLI
# In dev mode, a KV v2 engine is mounted at 'secret/' # List all secrets engines vault secrets list # Expected output shows 'secret/' with type 'kv'
7

Store a Secret

Vault CLI
# Store a database credential vault kv put secret/database/prod \ username="app_user" \ password="SuperSecretP@ssw0rd!" \ host="db.example.com" \ port="5432" # Store an API key vault kv put secret/api/stripe \ api_key="sk_live_xxx123456789" \ webhook_secret="whsec_xxx987654321" echo "Secrets stored successfully"
8

Retrieve Secrets

Vault CLI
# Read the database secret vault kv get secret/database/prod # Get just the password field vault kv get -field=password secret/database/prod # Output in JSON format (useful for scripting) vault kv get -format=json secret/database/prod # List secrets at a path vault kv list secret/
9

Update and Version Secrets

Vault CLI
# Update the password (creates version 2) vault kv put secret/database/prod \ username="app_user" \ password="NewRotatedP@ssw0rd!" \ host="db.example.com" \ port="5432" # Get current version vault kv get secret/database/prod # Get version 1 (original) vault kv get -version=1 secret/database/prod # View metadata (all versions) vault kv metadata get secret/database/prod
10

Delete and Undelete Secrets

Vault CLI
# Soft delete (can be recovered) vault kv delete secret/database/prod # Try to read - returns no data vault kv get secret/database/prod # Undelete version 2 vault kv undelete -versions=2 secret/database/prod # Read again - data is back vault kv get secret/database/prod # Permanently destroy a version vault kv destroy -versions=1 secret/database/prod # Destroy all versions and metadata # vault kv metadata delete secret/database/prod

✅ Module 2 Complete!

You've mastered the KV secrets engine. In Module 3, we'll eliminate static secrets entirely with dynamic credentials.

⚡ Module 3: Dynamic Database Credentials

Module 3: On-Demand Database Credentials

Generate short-lived PostgreSQL credentials that automatically expire.

⏱️ 45-60 minutes🎯 6 steps📍 Vault + PostgreSQL

Dynamic secrets are Vault's killer feature. Instead of storing a static database password that everyone shares, Vault generates unique credentials for each request with automatic expiration. When an application needs database access, it requests credentials from Vault, uses them, and they automatically expire—eliminating credential sprawl.

📖 How Dynamic Database Credentials Work

  1. Admin configures Vault with database connection and root credentials
  2. Admin creates roles defining what SQL statements create users
  3. Application requests credentials from Vault
  4. Vault connects to database, creates temporary user with role's SQL
  5. Vault returns username/password to application with TTL
  6. When lease expires, Vault revokes the user from the database
11

Enable Database Secrets Engine

Vault CLI
# Enable the database secrets engine vault secrets enable database # Verify it's enabled vault secrets list | grep database
12

Configure PostgreSQL Connection

Vault CLI
# Configure the database connection vault write database/config/postgres \ plugin_name="postgresql-database-plugin" \ allowed_roles="readonly","readwrite" \ connection_url="postgresql://{{username}}:{{password}}@vault-postgres:5432/appdb?sslmode=disable" \ username="postgres" \ password="postgres123" # Note: Vault will use these root credentials to create/revoke users # The {{username}} and {{password}} are templates Vault fills in
13

Create Database Roles

Roles define what SQL statements Vault uses to create users. Different roles can have different permissions.

Vault CLI
# Create a read-only role vault write database/roles/readonly \ db_name="postgres" \ creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \ GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \ default_ttl="1h" \ max_ttl="24h" # Create a read-write role vault write database/roles/readwrite \ db_name="postgres" \ creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \ GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \ default_ttl="1h" \ max_ttl="24h" echo "Database roles created"
14

Generate Dynamic Credentials

Vault CLI
# Request read-only credentials vault read database/creds/readonly # Output shows: # - lease_id: Used to renew or revoke # - lease_duration: How long credentials are valid # - username: Dynamically generated (e.g., v-root-readonly-xxx) # - password: Random, unique password # Request another set - different credentials each time! vault read database/creds/readonly # Request read-write credentials vault read database/creds/readwrite
15

Test Database Connection

PostgreSQL
# Get credentials and save them CREDS=$(vault read -format=json database/creds/readonly) DB_USER=$(echo $CREDS | jq -r '.data.username') DB_PASS=$(echo $CREDS | jq -r '.data.password') echo "Username: $DB_USER" echo "Password: $DB_PASS" # Test connection with dynamic credentials docker exec -it vault-postgres psql -U "$DB_USER" -d appdb -c "SELECT current_user, now();"
16

Manage Leases

Vault CLI
# Get credentials and capture lease ID CREDS=$(vault read -format=json database/creds/readonly) LEASE_ID=$(echo $CREDS | jq -r '.lease_id') echo "Lease ID: $LEASE_ID" # Renew the lease (extend TTL) vault lease renew $LEASE_ID # Revoke early (immediately invalidates credentials) vault lease revoke $LEASE_ID # Try connecting again - should fail! # The user no longer exists in the database

✅ Module 3 Complete!

You've implemented dynamic database credentials! No more static passwords in config files. In Module 4, we'll configure authentication methods.

🔑 Module 4: Authentication Methods

Module 4: Configure Multiple Auth Methods

Set up authentication for humans (userpass) and machines (AppRole).

⏱️ 45-60 minutes🎯 6 steps📍 Vault CLI

Vault supports multiple authentication methods for different use cases. Human users might authenticate with username/password or LDAP, while applications use AppRole or cloud-native methods like AWS IAM. Each auth method returns a Vault token with attached policies.

17

Enable UserPass Auth Method

Vault CLI
# Enable userpass authentication vault auth enable userpass # List auth methods vault auth list
18

Create Users

Vault CLI
# Create a developer user vault write auth/userpass/users/alice \ password="alice123" \ policies="developer" # Create an ops user vault write auth/userpass/users/bob \ password="bob123" \ policies="ops" # Create an admin user vault write auth/userpass/users/admin \ password="admin123" \ policies="admin" echo "Users created"
19

Test UserPass Authentication

Vault CLI
# Login as alice vault login -method=userpass username=alice password=alice123 # Check current token info vault token lookup # Login back as root for remaining exercises export VAULT_TOKEN='root-token'
20

Enable AppRole Auth Method

AppRole is designed for machine authentication—applications and CI/CD pipelines.

Vault CLI
# Enable AppRole vault auth enable approle # Create an AppRole for a web application vault write auth/approle/role/webapp \ token_policies="webapp" \ token_ttl=1h \ token_max_ttl=4h \ secret_id_ttl=10m \ secret_id_num_uses=1 echo "AppRole created for webapp"
21

Authenticate with AppRole

Vault CLI
# Get the Role ID (like a username - can be shared) ROLE_ID=$(vault read -field=role_id auth/approle/role/webapp/role-id) echo "Role ID: $ROLE_ID" # Get a Secret ID (like a password - single use) SECRET_ID=$(vault write -f -field=secret_id auth/approle/role/webapp/secret-id) echo "Secret ID: $SECRET_ID" # Login with AppRole credentials vault write auth/approle/login \ role_id="$ROLE_ID" \ secret_id="$SECRET_ID" # Reset to root token export VAULT_TOKEN='root-token'
22

Understanding AppRole Security

Vault CLI
AppRole Best Practices: 1. Role ID: Semi-public, can be baked into configs - Identifies WHAT the application is 2. Secret ID: Private, delivered securely at runtime - Proves the application is AUTHORIZED - Should be single-use or time-limited 3. Delivery Methods: - CI/CD: Inject Secret ID as build variable - Kubernetes: Use Vault Agent sidecar - Cloud: Use response wrapping 4. Response Wrapping: Wrap Secret ID so only intended recipient can unwrap it (prevents man-in-middle)

✅ Module 4 Complete!

You've configured authentication for both humans and machines. In Module 5, we'll create policies to control access.

📋 Module 5: Policies & Access Control

Module 5: Fine-Grained Access Policies

Write policies that control exactly who can access which secrets.

⏱️ 45-60 minutes🎯 5 steps📍 Vault CLI

Vault policies use a default-deny model—users have no access unless explicitly granted. Policies are written in HCL (HashiCorp Configuration Language) and attached to tokens via auth methods. Understanding policy design is crucial for implementing least privilege.

23

Create Developer Policy

Local Machine
cat > ~/lab7-vault/policies/developer.hcl << 'EOF' # Developer Policy # Allows read access to development secrets and database credentials # Read development secrets path "secret/data/dev/*" { capabilities = ["read", "list"] } # Generate database credentials (read-only role only) path "database/creds/readonly" { capabilities = ["read"] } # List available database roles path "database/roles" { capabilities = ["list"] } # Deny access to production secrets path "secret/data/prod/*" { capabilities = ["deny"] } EOF # Write policy to Vault vault policy write developer ~/lab7-vault/policies/developer.hcl echo "Developer policy created"
24

Create Ops Policy

Local Machine
cat > ~/lab7-vault/policies/ops.hcl << 'EOF' # Operations Policy # Full access to secrets and database credentials # Full access to all secrets path "secret/data/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "secret/metadata/*" { capabilities = ["read", "list"] } # Generate any database credentials path "database/creds/*" { capabilities = ["read"] } # Manage database configuration path "database/config/*" { capabilities = ["read", "list"] } path "database/roles/*" { capabilities = ["read", "list"] } EOF vault policy write ops ~/lab7-vault/policies/ops.hcl echo "Ops policy created"
25

Create WebApp Policy

Local Machine
cat > ~/lab7-vault/policies/webapp.hcl << 'EOF' # Web Application Policy # Minimal permissions for production app # Read only specific secrets the app needs path "secret/data/prod/webapp" { capabilities = ["read"] } # Generate database credentials path "database/creds/readwrite" { capabilities = ["read"] } # Renew own token path "auth/token/renew-self" { capabilities = ["update"] } # Lookup own token path "auth/token/lookup-self" { capabilities = ["read"] } EOF vault policy write webapp ~/lab7-vault/policies/webapp.hcl echo "WebApp policy created"
26

Test Policy Enforcement

Vault CLI
# Create test secrets vault kv put secret/dev/api key="dev-key-123" vault kv put secret/prod/api key="prod-key-456" vault kv put secret/prod/webapp db_url="postgres://prod:5432" # Login as developer (alice) vault login -method=userpass username=alice password=alice123 # Try to read dev secret - should work vault kv get secret/dev/api # Try to read prod secret - should be DENIED vault kv get secret/prod/api # Error: permission denied # Try to get database credentials vault read database/creds/readonly # Should work vault read database/creds/readwrite # Should be DENIED # Reset to root export VAULT_TOKEN='root-token'
27

View All Policies

Vault CLI
# List all policies vault policy list # Read a specific policy vault policy read developer # Check capabilities for a path vault token capabilities secret/data/prod/api

✅ Module 5 Complete!

You've implemented fine-grained access control with Vault policies.

📜 Module 6: PKI Secrets Engine (Certificates)

Module 6: Build a Certificate Authority

Issue dynamic TLS certificates for services and applications.

⏱️ 45-60 minutes🎯 5 steps📍 Vault CLI

The PKI secrets engine generates X.509 certificates dynamically. Instead of manually managing certificates with long validity periods, Vault can issue short-lived certificates on demand. This is essential for zero-trust architectures and service mesh deployments.

28

Enable PKI Engine

Vault CLI
# Enable PKI secrets engine vault secrets enable pki # Tune the engine for longer max lease (1 year for CA) vault secrets tune -max-lease-ttl=8760h pki
29

Generate Root CA

Vault CLI
# Generate internal root CA vault write -field=certificate pki/root/generate/internal \ common_name="TechStart Root CA" \ ttl=8760h > ~/lab7-vault/ca_cert.crt echo "Root CA certificate generated" cat ~/lab7-vault/ca_cert.crt # Configure CA and CRL URLs vault write pki/config/urls \ issuing_certificates="http://127.0.0.1:8200/v1/pki/ca" \ crl_distribution_points="http://127.0.0.1:8200/v1/pki/crl"
30

Create Certificate Role

Vault CLI
# Create a role for issuing server certificates vault write pki/roles/server-cert \ allowed_domains="techstart.local,localhost" \ allow_subdomains=true \ allow_localhost=true \ max_ttl=720h \ key_type="rsa" \ key_bits=2048 echo "Certificate role created"
31

Issue a Certificate

Vault CLI
# Issue a certificate for api.techstart.local vault write pki/issue/server-cert \ common_name="api.techstart.local" \ ttl=24h # The output includes: # - certificate: The issued certificate # - private_key: The private key (only shown once!) # - ca_chain: The CA certificate chain # - serial_number: For revocation # Save certificate to file vault write -format=json pki/issue/server-cert \ common_name="web.techstart.local" \ ttl=24h > ~/lab7-vault/web_cert.json echo "Certificate issued and saved"
32

Revoke a Certificate

Vault CLI
# Get the serial number from issued cert SERIAL=$(cat ~/lab7-vault/web_cert.json | jq -r '.data.serial_number') # Revoke the certificate vault write pki/revoke serial_number="$SERIAL" # View CRL (Certificate Revocation List) curl -s http://127.0.0.1:8200/v1/pki/crl/pem

✅ Module 6 Complete!

You've built a Certificate Authority with Vault. Certificates are now dynamic secrets!

⏱️ Module 7: Just-in-Time Access Patterns

Module 7: Implement JIT Privileged Access

Create approval-based workflows for temporary elevated access.

⏱️ 30-45 minutes🎯 4 steps📍 Vault CLI

Just-in-Time (JIT) access is a PAM pattern where users don't have standing privileges. Instead, they request access when needed, access is granted for a limited time, and all requests are logged. This dramatically reduces the attack surface compared to always-on admin access.

📖 JIT Access Principles

  • No Standing Privileges: Users don't have admin access by default
  • Request-Based: Access must be explicitly requested
  • Time-Bounded: Access expires automatically after a short period
  • Audited: Every request and use is logged
  • Approval Workflow: (Advanced) Requests require manager approval
33

Create Emergency Access Role

Vault CLI
# Create a policy for emergency database access cat > ~/lab7-vault/policies/emergency-db.hcl << 'EOF' # Emergency Database Access # Short-lived full database access for incident response path "database/creds/readwrite" { capabilities = ["read"] } path "secret/data/prod/*" { capabilities = ["read"] } EOF vault policy write emergency-db ~/lab7-vault/policies/emergency-db.hcl # Create a token role that issues short-lived tokens vault write auth/token/roles/emergency \ allowed_policies="emergency-db" \ orphan=true \ token_period=0 \ token_explicit_max_ttl=1h \ token_no_default_policy=true
34

Request Emergency Access

Vault CLI
# Simulate: On-call engineer requests emergency access # In production, this might go through an approval system # Generate a short-lived emergency token EMERGENCY_TOKEN=$(vault token create \ -role=emergency \ -ttl=30m \ -display-name="incident-12345" \ -metadata="requestor=alice" \ -metadata="reason=database outage" \ -format=json | jq -r '.auth.client_token') echo "Emergency Token: $EMERGENCY_TOKEN" echo "Valid for: 30 minutes" echo "Metadata includes requestor and reason for audit" # Use the emergency token VAULT_TOKEN=$EMERGENCY_TOKEN vault read database/creds/readwrite # Reset to root export VAULT_TOKEN='root-token'
35

Enable Audit Logging

Vault CLI
# Enable file audit device vault audit enable file file_path=/vault/logs/audit.log # All requests are now logged! # View audit log docker exec vault cat /vault/logs/audit.log | jq '.' # Each log entry includes: # - Time # - Auth info (who) # - Request (what they asked for) # - Response (what they got) # - Errors (if any)
36

Review Access Audit

Vault CLI
# View recent audit entries docker exec vault tail -20 /vault/logs/audit.log | jq '.request.path, .auth.display_name' # In production, audit logs would be: # - Shipped to SIEM (Splunk, ELK, etc.) # - Retained for compliance # - Monitored for anomalies # - Used for access reviews

✅ Module 7 Complete!

You've implemented Just-in-Time access patterns for privileged operations.

🛡️ PAM Vulnerabilities & Best Practices

PAM systems are high-value targets because they protect the keys to the kingdom. Understanding common vulnerabilities helps you design more secure implementations.

CRITICAL

Root Token Exposure

The root token has unlimited privileges. If exposed, attackers have complete control.

🛡️ Mitigation
  • Revoke root token after initial setup
  • Use root only for emergency recovery
  • Generate new root token only when needed
CRITICAL

Unseal Key Compromise

Unseal keys decrypt Vault's master key. Compromised keys mean compromised secrets.

🛡️ Mitigation
  • Use Shamir's secret sharing (5 keys, 3 required)
  • Store keys in separate secure locations
  • Consider auto-unseal with cloud KMS
HIGH

Overly Permissive Policies

Policies granting broad access violate least privilege.

🛡️ Mitigation
  • Start with deny-all, add specific permissions
  • Use path templating for user-specific paths
  • Regular policy audits
HIGH

Long-Lived Tokens

Tokens with long TTLs or no expiration increase exposure window.

🛡️ Mitigation
  • Set appropriate token TTLs (hours, not days)
  • Implement token renewal for long-running apps
  • Use periodic tokens that must be renewed

✅ Vault Security Best Practices

  • ✅ Enable TLS for all Vault communication
  • ✅ Use auto-unseal with cloud KMS in production
  • ✅ Enable audit logging to multiple destinations
  • ✅ Implement least privilege policies
  • ✅ Use dynamic secrets instead of static where possible
  • ✅ Set appropriate TTLs for all tokens and leases
  • ✅ Use AppRole or cloud auth for applications
  • ✅ Regularly rotate root credentials for connected systems
  • ✅ Monitor audit logs for anomalies
  • ✅ Implement disaster recovery procedures

🎓 Key Takeaways

You've built a complete Privileged Access Management solution with HashiCorp Vault, eliminating static secrets and implementing enterprise-grade access controls.

Skills Mastered

What's Next

📚 Additional Resources

📖 Official Documentation
🔐 Security Resources
🎓 Certifications
🛠️ Tools & Integrations