Skip to main content
COSMICBYTEZLABS
NewsSecurityHOWTOsToolsStudyTraining
ProjectsChecklistsAI RankingsNewsletterStatusTagsAbout
Subscribe

Press Enter to search or Esc to close

News
Security
HOWTOs
Tools
Study
Training
Projects
Checklists
AI Rankings
Newsletter
Status
Tags
About
RSS Feed
Reading List
Subscribe

Stay in the Loop

Get the latest security alerts, tutorials, and tech insights delivered to your inbox.

Subscribe NowFree forever. No spam.
COSMICBYTEZLABS

Your trusted source for IT intelligence, cybersecurity insights, and hands-on technical guides.

429+ Articles
114+ Guides

CONTENT

  • Latest News
  • Security Alerts
  • HOWTOs
  • Projects
  • Exam Prep

RESOURCES

  • Search
  • Browse Tags
  • Newsletter Archive
  • Reading List
  • RSS Feed

COMPANY

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CosmicBytez Labs. All rights reserved.

System Status: Operational
  1. Home
  2. Projects
  3. HashiCorp Vault: Secrets Management for Your Homelab and
HashiCorp Vault: Secrets Management for Your Homelab and
PROJECTIntermediate

HashiCorp Vault: Secrets Management for Your Homelab and

Deploy HashiCorp Vault to centrally manage secrets, certificates, and dynamic credentials — eliminating hardcoded passwords from your infrastructure with...

Dylan H.

Platform Engineering

March 13, 2026
12 min read
4-6 hours

Tools & Technologies

HashiCorp VaultConsulTerraformDockersystemd

HashiCorp Vault: Secrets Management for Your Homelab and Enterprise

Hardcoded credentials in config files, .env files committed to Git, shared passwords stored in Notepad — if any of that sounds familiar, this project is for you. HashiCorp Vault is the industry-standard solution for centralizing secret storage, dynamic credential generation, and certificate management. By the end of this project you'll have a production-grade Vault cluster running in your lab, integrated with your applications, and generating short-lived credentials automatically.

Project Overview

What We're Building

┌─────────────────────────────────────────────────────────────────────┐
│                  HashiCorp Vault Lab Architecture                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   Clients                  Vault Cluster              Backends      │
│                                                                     │
│  ┌──────────┐             ┌────────────────┐         ┌──────────┐   │
│  │ Apps /   │──AppRole──▶ │  vault-01      │────────▶│ KV Store │   │
│  │ Services │             │  (Active)      │         └──────────┘   │
│  └──────────┘             │  :8200         │                        │
│                           └────────────────┘         ┌──────────┐   │
│  ┌──────────┐                    │ HA               │  PKI     │   │
│  │ DevOps   │──Token Auth──▶     │                  │  Engine  │   │
│  │ Engineers│             ┌────────────────┐         └──────────┘   │
│  └──────────┘             │  vault-02      │                        │
│                           │  (Standby)     │         ┌──────────┐   │
│  ┌──────────┐             │  :8200         │────────▶│ Database │   │
│  │ K8s Pods │──SA Auth───▶└────────────────┘         │ Dynamic  │   │
│  └──────────┘                    │                   │ Secrets  │   │
│                           ┌──────▼─────────┐         └──────────┘   │
│  ┌──────────┐             │  Consul        │                        │
│  │ LDAP     │──LDAP Auth─▶│  (Storage      │         ┌──────────┐   │
│  │ Users    │             │  + Service     │────────▶│  SSH CA  │   │
│  └──────────┘             │  Discovery)    │         │  Engine  │   │
│                           └────────────────┘         └──────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Prerequisites

  • 2+ Linux VMs (Ubuntu 22.04 recommended) — 2 vCPU, 4GB RAM each
  • Docker (for single-node dev mode option)
  • Basic understanding of TLS and public key cryptography
  • Familiarity with Linux CLI and systemd
  • An application or database to integrate with (PostgreSQL used in examples)

Why Vault?

ProblemWithout VaultWith Vault
DB passwordsHardcoded in .envDynamic, auto-rotated
TLS certificatesManual renewal, often forgottenAuto-issued, auto-renewed
API keysShared in Slack/emailScoped, audited, short-lived
SSH accessShared keys, no auditabilitySigned certificates, full audit log
Secret rotationManual, painfulAutomated, zero-downtime

Part 1: Installation

Step 1: Install Vault on Both Nodes

On both vault-01 and vault-02:

# Add HashiCorp GPG key and repo
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 -y vault consul
 
# Verify
vault version
consul version

Step 2: Configure Consul Storage Backend

Vault needs a storage backend. We'll use Consul for HA and built-in service discovery.

On both nodes — Consul config:

# /etc/consul.d/consul.hcl
datacenter = "homelab"
data_dir   = "/opt/consul"
log_level  = "INFO"
node_name  = "vault-01"  # change per node
 
bind_addr  = "0.0.0.0"
client_addr = "0.0.0.0"
 
server           = true
bootstrap_expect = 2
 
retry_join = ["192.168.1.20", "192.168.1.21"]
 
ui_config {
  enabled = true
}
 
performance {
  raft_multiplier = 1
}
# Start Consul
sudo systemctl enable consul
sudo systemctl start consul
 
# Verify cluster
consul members

Expected output:

Node      Address             Status  Type    Build   Protocol
vault-01  192.168.1.20:8301   alive   server  1.18.0  2
vault-02  192.168.1.21:8301   alive   server  1.18.0  2

Step 3: Generate TLS Certificates for Vault

Never run Vault without TLS in production.

# Generate a CA on vault-01
mkdir -p /etc/vault.d/tls && cd /etc/vault.d/tls
 
# Create CA key and cert
openssl genrsa -out vault-ca-key.pem 4096
openssl req -new -x509 -days 3650 \
  -key vault-ca-key.pem \
  -out vault-ca.pem \
  -subj "/CN=Vault CA/O=HomeLab"
 
# Create Vault server certificate
openssl genrsa -out vault-key.pem 2048
 
cat > vault-cert.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
 
[req_distinguished_name]
CN = vault.homelab.local
 
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
 
[alt_names]
DNS.1 = vault.homelab.local
DNS.2 = vault-01.homelab.local
DNS.3 = vault-02.homelab.local
IP.1  = 192.168.1.20
IP.2  = 192.168.1.21
IP.3  = 127.0.0.1
EOF
 
openssl req -new -key vault-key.pem -out vault.csr -config vault-cert.cnf
openssl x509 -req -days 825 \
  -in vault.csr \
  -CA vault-ca.pem -CAkey vault-ca-key.pem -CAcreateserial \
  -out vault-cert.pem \
  -extensions v3_req -extfile vault-cert.cnf
 
# Distribute CA cert to vault-02
scp vault-ca.pem vault-cert.pem vault-key.pem user@192.168.1.21:/etc/vault.d/tls/
 
# Set permissions
chmod 640 /etc/vault.d/tls/*.pem
chown vault:vault /etc/vault.d/tls/*.pem

Step 4: Configure Vault

# /etc/vault.d/vault.hcl
ui = true
log_level = "info"
 
storage "consul" {
  address = "127.0.0.1:8500"
  path    = "vault/"
  token   = ""  # Add Consul ACL token if enabled
}
 
listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_cert_file = "/etc/vault.d/tls/vault-cert.pem"
  tls_key_file  = "/etc/vault.d/tls/vault-key.pem"
  tls_min_version = "tls12"
}
 
api_addr     = "https://192.168.1.20:8200"  # Change per node
cluster_addr = "https://192.168.1.20:8201"
 
seal "shamir" {}
 
telemetry {
  prometheus_retention_time = "30s"
  disable_hostname           = true
}
# Enable and start Vault
sudo systemctl enable vault
sudo systemctl start vault
 
# Export Vault address
export VAULT_ADDR="https://vault.homelab.local:8200"
export VAULT_CACERT="/etc/vault.d/tls/vault-ca.pem"
 
# Check status (should show uninitialized)
vault status

Part 2: Initialization and Unsealing

Step 5: Initialize Vault

Run only on vault-01, only once:

# Initialize with 5 key shares, threshold of 3
vault operator init \
  -key-shares=5 \
  -key-threshold=3
 
# Save the output SECURELY — you will NOT see these again
# Example output:
# Unseal Key 1: abc123...
# Unseal Key 2: def456...
# Unseal Key 3: ghi789...
# Unseal Key 4: jkl012...
# Unseal Key 5: mno345...
# Initial Root Token: s.xxxxxxxxxxxxxxxxxxxx

CRITICAL: Store unseal keys in separate, secure locations. In production, distribute them to 5 different trusted people. Never store all keys in one place.

Step 6: Unseal Vault

# Provide 3 of 5 key shares (must run 3 times with different keys)
vault operator unseal  # Enter key 1
vault operator unseal  # Enter key 2
vault operator unseal  # Enter key 3
 
# Verify sealed = false
vault status

Status after unsealing:

Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         1.18.0
Cluster Name    vault-cluster-homelab
Cluster ID      abc123...
HA Enabled      true
HA Cluster      https://192.168.1.20:8201
HA Mode         active
Active Since    2026-03-13T12:00:00.000Z

Step 7: Auto-Unseal with AWS KMS (Optional but Recommended)

For production, manual unsealing is tedious. Auto-unseal with a KMS key is safer.

# Replace the shamir seal block with:
seal "awskms" {
  region     = "ca-central-1"
  kms_key_id = "alias/vault-auto-unseal"
}
# Or use Azure Key Vault
seal "azurekeyvault" {
  tenant_id      = "YOUR_TENANT_ID"
  client_id      = "YOUR_CLIENT_ID"
  client_secret  = "YOUR_CLIENT_SECRET"
  vault_name     = "vault-unseal-kv"
  key_name       = "vault-unseal-key"
}

Step 8: Create Admin Policy and Token

# Login with root token (first time only)
vault login
 
# Create admin policy
cat > admin-policy.hcl <<'EOF'
path "*" {
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
EOF
 
vault policy write admin admin-policy.hcl
 
# Create admin user (using userpass auth)
vault auth enable userpass
 
vault write auth/userpass/users/admin \
  password="$(openssl rand -base64 20)" \
  policies="admin"
 
# Revoke root token — don't leave it active
vault token revoke "$VAULT_TOKEN"

Part 3: Secrets Engines

Step 9: KV Secrets Engine (v2)

The KV engine is the simplest — a versioned key-value store for static secrets.

# Enable KV v2 at the path "secret/"
vault secrets enable -path=secret -version=2 kv
 
# Store secrets
vault kv put secret/myapp/database \
  username="dbuser" \
  password="$(openssl rand -base64 20)" \
  host="postgres.homelab.local" \
  port="5432"
 
# Read secrets
vault kv get secret/myapp/database
 
# Read specific field
vault kv get -field=password secret/myapp/database
 
# Version history
vault kv metadata get secret/myapp/database
 
# Roll back to previous version
vault kv rollback -version=1 secret/myapp/database

Output:

====== Secret Path ======
secret/data/myapp/database
 
======= Metadata =======
Key              Value
---              -----
created_time     2026-03-13T12:00:00.000Z
custom_metadata  <nil>
deletion_time    n/a
destroyed        false
version          2
 
====== Data ======
Key       Value
---       -----
host      postgres.homelab.local
password  Xk9mL2pQrT8vW5nZ6eYu
port      5432
username  dbuser

Step 10: Dynamic Database Secrets

This is where Vault gets powerful — generate temporary, unique database credentials per application.

# Enable the database secrets engine
vault secrets enable database
 
# Configure PostgreSQL connection
vault write database/config/myapp-postgres \
  plugin_name="postgresql-database-plugin" \
  connection_url="postgresql://{{username}}:{{password}}@postgres.homelab.local:5432/myapp?sslmode=disable" \
  allowed_roles="myapp-readonly,myapp-readwrite" \
  username="vault-admin" \
  password="vault-admin-password"
 
# Create a role with TTL-limited credentials
vault write database/roles/myapp-readonly \
  db_name="myapp-postgres" \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  revocation_statements="DROP ROLE IF EXISTS \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"
 
# Generate temporary credentials
vault read database/creds/myapp-readonly

Output — ephemeral credentials valid for 1 hour:

Key                Value
---                -----
lease_id           database/creds/myapp-readonly/abc123xyz
lease_duration     1h
lease_renewable    true
password           A1a-x9KpZm2LqNvRoWs4
username           v-userpass-myapp-readon-pX8mNbKtQr-1710331200

Step 11: PKI Secrets Engine (Internal CA)

Replace your self-signed cert mess with a proper certificate authority.

# Enable PKI engine for the root CA
vault secrets enable -path=pki pki
vault secrets tune -max-lease-ttl=87600h pki  # 10 years for root
 
# Generate root CA
vault write -field=certificate pki/root/generate/internal \
  common_name="HomeLab Root CA" \
  issuer_name="root-2026" \
  ttl="87600h" > /tmp/root_ca.crt
 
# Configure CRL and OCSP
vault write pki/config/cluster \
  path="https://vault.homelab.local:8200/v1/pki"
 
vault write pki/config/urls \
  issuing_certificates="https://vault.homelab.local:8200/v1/pki/ca" \
  crl_distribution_points="https://vault.homelab.local:8200/v1/pki/crl"
 
# Enable intermediate CA for issuing certs
vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=43800h pki_int  # 5 years max
 
# Generate intermediate CA CSR
vault write -format=json pki_int/intermediate/generate/internal \
  common_name="HomeLab Intermediate CA 2026" \
  issuer_name="homelab-intermediate" \
  | jq -r '.data.csr' > /tmp/pki_intermediate.csr
 
# Sign with root CA
vault write -format=json pki/root/sign-intermediate \
  issuer_ref="root-2026" \
  csr=@/tmp/pki_intermediate.csr \
  format=pem_bundle \
  ttl="43800h" \
  | jq -r '.data.certificate' > /tmp/intermediate.cert.pem
 
# Import signed cert back
vault write pki_int/intermediate/set-signed \
  certificate=@/tmp/intermediate.cert.pem
 
# Create a role for issuing certs
vault write pki_int/roles/homelab-server \
  allowed_domains="homelab.local" \
  allow_subdomains=true \
  max_ttl="720h" \
  generate_lease=true
 
# Issue a certificate
vault write pki_int/issue/homelab-server \
  common_name="grafana.homelab.local" \
  alt_names="grafana.homelab.local" \
  ttl="720h"

Part 4: Authentication Methods

Step 12: AppRole Authentication (for Applications)

AppRole is designed for machine-to-machine authentication with no secrets in code.

# Enable AppRole
vault auth enable approle
 
# Create a policy for the application
cat > myapp-policy.hcl <<'EOF'
path "secret/data/myapp/*" {
  capabilities = ["read"]
}
 
path "database/creds/myapp-readonly" {
  capabilities = ["read"]
}
 
path "pki_int/issue/homelab-server" {
  capabilities = ["create", "update"]
}
EOF
 
vault policy write myapp myapp-policy.hcl
 
# Create AppRole
vault write auth/approle/role/myapp \
  secret_id_ttl=10m \
  token_num_uses=10 \
  token_ttl=20m \
  token_max_ttl=30m \
  secret_id_num_uses=40 \
  policies="myapp"
 
# Get Role ID (not a secret — embed in app config)
vault read auth/approle/role/myapp/role-id
 
# Get Secret ID (treated as a secret — inject at runtime via CI/CD)
vault write -f auth/approle/role/myapp/secret-id

Application authentication flow:

# App authenticates and gets a token
ROLE_ID="<role-id>"
SECRET_ID="<secret-id>"
 
TOKEN=$(vault write -field=token auth/approle/login \
  role_id="$ROLE_ID" \
  secret_id="$SECRET_ID")
 
# Use token to read secrets
VAULT_TOKEN="$TOKEN" vault kv get secret/myapp/database

Step 13: Kubernetes Authentication

For pods running in Kubernetes to authenticate without static secrets.

# Enable Kubernetes auth
vault auth enable kubernetes
 
# Configure the Kubernetes auth backend
vault write auth/kubernetes/config \
  kubernetes_host="https://192.168.1.100:6443" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
  token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token \
  issuer="https://kubernetes.default.svc.cluster.local"
 
# Create a role for a specific service account
vault write auth/kubernetes/role/myapp-role \
  bound_service_account_names="myapp-sa" \
  bound_service_account_namespaces="production" \
  policies="myapp" \
  ttl="1h"

Kubernetes deployment using Vault Agent Injector:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: production
spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: "myapp-role"
        vault.hashicorp.com/agent-inject-secret-config.env: "secret/data/myapp/database"
        vault.hashicorp.com/agent-inject-template-config.env: |
          {{- with secret "secret/data/myapp/database" -}}
          export DB_USER="{{ .Data.data.username }}"
          export DB_PASS="{{ .Data.data.password }}"
          export DB_HOST="{{ .Data.data.host }}"
          {{- end }}
    spec:
      serviceAccountName: myapp-sa
      containers:
      - name: myapp
        image: myapp:latest
        command: ["/bin/sh", "-c"]
        args: ["source /vault/secrets/config.env && /app/start.sh"]

Step 14: LDAP / Active Directory Authentication

# Enable LDAP auth
vault auth enable ldap
 
# Configure for Active Directory
vault write auth/ldap/config \
  url="ldaps://dc01.homelab.local:636" \
  starttls=false \
  insecure_tls=false \
  binddn="CN=vault-svc,OU=Service Accounts,DC=homelab,DC=local" \
  bindpass="service-account-password" \
  userdn="OU=Users,DC=homelab,DC=local" \
  userattr="sAMAccountName" \
  groupdn="OU=Groups,DC=homelab,DC=local" \
  groupfilter="(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))" \
  groupattr="cn" \
  certificate=@/etc/vault.d/tls/dc-ca.pem
 
# Map AD group to Vault policy
vault write auth/ldap/groups/VaultAdmins \
  policies="admin"
 
vault write auth/ldap/groups/VaultUsers \
  policies="default,read-only"
 
# Test login
vault login -method=ldap username="jsmith"

Part 5: Audit Logging and Policy Management

Step 15: Enable Audit Logging

# Enable file audit log (always do this in production)
vault audit enable file file_path="/var/log/vault/audit.log"
 
# Optional: syslog backend for SIEM integration
vault audit enable syslog tag="vault" facility="AUTH"
 
# Verify audit is enabled
vault audit list -detailed

Sample audit log entry (JSON):

{
  "time": "2026-03-13T12:00:00.000Z",
  "type": "request",
  "auth": {
    "client_token": "hmac-sha256:abc...",
    "accessor": "hmac-sha256:def...",
    "policies": ["myapp"],
    "entity_id": "...",
    "display_name": "approle-myapp"
  },
  "request": {
    "id": "...",
    "operation": "read",
    "mount_type": "kv",
    "path": "secret/data/myapp/database",
    "remote_address": "192.168.1.50"
  },
  "response": {
    "mount_type": "kv"
  }
}

Step 16: Granular Policy Examples

# /etc/vault.d/policies/developer.hcl
# Developers can read dev secrets and generate their own DB creds
 
# Read dev environment secrets
path "secret/data/dev/*" {
  capabilities = ["read", "list"]
}
 
# Generate database creds for dev DB
path "database/creds/dev-readwrite" {
  capabilities = ["read"]
}
 
# Request their own TLS certs for dev
path "pki_int/issue/homelab-server" {
  capabilities = ["create", "update"]
  allowed_parameters = {
    "common_name" = ["*.dev.homelab.local"]
    "ttl"         = ["1h", "4h", "8h", "24h"]
  }
}
 
# View but not manage auth
path "auth/*" {
  capabilities = ["list"]
}
 
# Cannot access prod
path "secret/data/prod/*" {
  capabilities = []
}
# /etc/vault.d/policies/ci-cd.hcl
# CI/CD pipeline — read-only, specific paths
 
path "secret/data/ci/+/credentials" {
  capabilities = ["read"]
}
 
path "database/creds/app-migrate" {
  capabilities = ["read"]
}
 
# Allow issuing deploy certs
path "pki_int/issue/deploy-server" {
  capabilities = ["create", "update"]
  max_wrapping_ttl = "5m"
}

Part 6: Automated Secret Rotation

Step 17: Lease Renewal and Rotation Script

#!/bin/bash
# vault-rotate.sh — Rotate static secrets and notify apps
 
VAULT_ADDR="https://vault.homelab.local:8200"
VAULT_TOKEN="${VAULT_TOKEN:-$(cat /etc/vault-agent/token)}"
 
rotate_secret() {
  local path="$1"
  local key="$2"
  local new_value
  new_value=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 32)
 
  echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] Rotating $path/$key"
 
  vault kv patch \
    -address="$VAULT_ADDR" \
    -header="X-Vault-Token: $VAULT_TOKEN" \
    "$path" \
    "$key=$new_value"
 
  echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] Rotated $path/$key successfully"
}
 
# Rotate application API keys
rotate_secret "secret/prod/myapp" "api_key"
rotate_secret "secret/prod/myapp" "webhook_secret"
 
# Force renew expiring leases
vault lease renew "$(vault list sys/leases/lookup/database/creds/myapp-readonly | head -1)"
 
echo "Rotation complete."

Step 18: Vault Agent for Automatic Token Renewal

# /etc/vault-agent/config.hcl
vault {
  address     = "https://vault.homelab.local:8200"
  ca_cert     = "/etc/vault.d/tls/vault-ca.pem"
  retry {
    num_retries = 5
  }
}
 
auto_auth {
  method "approle" {
    mount_path = "auth/approle"
    config = {
      role_id_file_path   = "/etc/vault-agent/role_id"
      secret_id_file_path = "/etc/vault-agent/secret_id"
      remove_secret_id_file_after_reading = false
    }
  }
 
  sink "file" {
    config = {
      path = "/etc/vault-agent/token"
    }
  }
}
 
template {
  source      = "/etc/vault-agent/templates/database.env.tpl"
  destination = "/etc/myapp/database.env"
  command     = "systemctl restart myapp"
}
 
template {
  source      = "/etc/vault-agent/templates/tls.tpl"
  destination = "/etc/myapp/tls/server.crt"
  command     = "systemctl reload nginx"
}
# /etc/vault-agent/templates/database.env.tpl
{{ with secret "database/creds/myapp-readonly" }}
DB_USER="{{ .Data.username }}"
DB_PASS="{{ .Data.password }}"
DB_HOST="postgres.homelab.local"
DB_NAME="myapp"
{{ end }}

Verification Checklist

Cluster Health:

  • Both Vault nodes active/standby
  • Consul cluster healthy with 2+ members
  • Vault status shows Sealed: false
  • HA mode active with correct leader

Secrets Engines:

  • KV v2 engine mounted at secret/
  • Database dynamic creds generate successfully
  • PKI engine issuing certs signed by your CA
  • Issued cert verifiable with openssl verify

Authentication:

  • AppRole login returns valid token
  • Token has correct policy scope (test with vault token capabilities)
  • LDAP/AD login works for AD users
  • Kubernetes auth working from a test pod

Security Controls:

  • Audit log receiving entries
  • Root token revoked after initial setup
  • Least-privilege policies — developer cannot read prod
  • TLS enforced on all connections (no plaintext listener)

Troubleshooting

IssueCauseSolution
connection refusedVault sealed or not startedvault status, check systemctl status vault
permission deniedToken lacks policy capabilityvault token capabilities <path>
x509: certificate signed by unknown authorityCA not trustedExport VAULT_CACERT to your CA cert
DB creds expiring too fastTTL too shortAdjust default_ttl on database role
unseal key invalidWrong key usedUse correct key shard, check Shamir threshold
AppRole secret ID expiredsecret_id_ttl exceededRegenerate SecretID, consider secret_id_ttl=0 for non-expiring
Consul agent unhealthyNetwork issue between nodesCheck firewall, ports 8300-8302, 8500, 8600

Next Steps

After building your Vault cluster:

  1. External Secrets Operator — Sync Vault secrets to Kubernetes Secrets automatically
  2. Vault as SSH CA — Sign SSH keys with Vault for zero-trust SSH access
  3. Transit Secrets Engine — Use Vault as an encryption-as-a-service for application data
  4. Sentinel Policies (Vault Enterprise) — Advanced policy enforcement with code
  5. Vault + Terraform — Manage Vault configuration as code

Resources

  • HashiCorp Vault Documentation
  • Vault Getting Started Tutorial
  • AppRole Pull Authentication
  • Vault Agent with Kubernetes
  • Production Hardening Guide

Questions? Reach out in our community Discord!

Related Reading

  • How to Secure GitHub Actions Workflows with OIDC, SHA
  • Securing AI-Assisted Development with Claude Code
  • FortiGate SD-WAN Deployment
#HashiCorp Vault#Secrets Management#DevSecOps#PKI#Zero Trust#Homelab

Related Articles

Keycloak SSO: Self-Hosted Identity Provider for Your Homelab

Deploy Keycloak with Docker Compose and PostgreSQL to build a centralised single sign-on platform for your homelab services, with OIDC integration for...

11 min read

Securing AI-Assisted Development with Claude Code

Build guardrails around AI-generated code with Claude Code hooks, security-scanning agents, OWASP-aware prompting, and automated secret detection. A...

13 min read

FortiGate SD-WAN Deployment

Deploy enterprise SD-WAN with FortiGate featuring dual ISP failover, performance SLAs, application steering, and Zero Trust architecture integration.

5 min read
Back to all Projects