On this page
- Overview
- Current Setup
- Access Points
- Team Access
- Secret Structure
- Common Operations
- PSS Backend Integration
- Caddy Proxy Configuration
- Unsealing Vault
- Audit Logging
- systemd Service
- Security Best Practices
- Troubleshooting
- Environment Variables
- API Usage
- Backup & Recovery
- Next Steps
- Support
HashiCorp Vault Setup & Configuration
This guide covers the setup, configuration, and usage of HashiCorp Vault for secrets management at Orcta Technologies.
Overview
HashiCorp Vault is our centralized secrets management solution. It provides:
- Centralized secret storage - All credentials in one secure location
- Dynamic credentials - Auto-rotating database passwords
- Audit logging - Complete trail of who accessed what
- Least privilege access - Role-based policies for team members
- Encryption as a service - Transit engine for data encryption
Current Setup
- Vault Version: v2.0.3
- Storage Backend: File
(
/opt/vault/data) - Listener: localhost:8200 (proxied via Caddy)
- UI: Available at
https://vault.orctatech.com/ui - Service:
vault.service(systemd, starts on boot)
Access Points
Direct Access (via Tailscale)
ssh orcta_vps
export VAULT_SKIP_VERIFY=true
export VAULT_ADDR='https://127.0.0.1:8200'
vault login -method=userpass username=cto password='your-password'Web UI Access
https://vault.orctatech.com/ui
Note: Requires DNS record
vault.orctatech.com → 158.220.100.30
Team Access
| Role | Username | Access Level | Use Case |
|---|---|---|---|
| CTO | cto |
Full access | Infrastructure, secret rotation |
| DevOps | devops |
Read all, write infra | Deployment, monitoring |
| Developer | developer1 |
Read-only dev/services | Local development |
| CI/CD | cicd |
Write CI, read services | GitHub Actions, pipelines |
Secret Structure
secret/
├── orcta/
│ ├── pss/ # PSS Backend
│ │ ├── database # PostgreSQL credentials
│ │ ├── valkey # Valkey/Redis credentials
│ │ ├── jwt # JWT secrets
│ │ ├── uploadthing # File upload service
│ │ ├── email # Email service (Resend)
│ │ ├── auth # Better Auth secrets
│ │ └── app # Application config
│ ├── stack/ # Orcta Stack
│ ├── mentorship/ # Mentorship Platform
│ ├── docs-mcp/ # Documentation MCP
│ ├── dev/ # Development secrets
│ ├── prod/ # Production secrets
│ ├── infra/ # Infrastructure secrets
│ └── admin/ # Admin credentials
Common Operations
Login
export VAULT_SKIP_VERIFY=true
export VAULT_ADDR='https://127.0.0.1:8200'
vault login -method=userpass username=YOUR_USERNAME password=YOUR_PASSWORDRead a Secret
vault kv get secret/orcta/pss/database
vault kv get -field=password secret/orcta/pss/databaseWrite a Secret
vault kv put secret/orcta/myapp/config \
api_key="abc123" \
db_password="secret456"List Secrets
vault kv list secret/orcta/
vault kv list secret/orcta/pss/Delete a Secret
vault kv delete secret/orcta/pss/old-secretPSS Backend Integration
The PSS backend was our pilot project for Vault integration.
Fetch Script
/usr/local/bin/fetch-pss-secretsThis script:
- Authenticates to Vault
- Fetches all PSS secrets
- Generates
.envfile at/srv/apps/ORCTA-BACKEND-PSS/.env
Usage
# Manual fetch
/usr/local/bin/fetch-pss-secrets
# Or integrate into deployment
./fetch-pss-secrets && docker compose up -dCaddy Proxy Configuration
Vault is proxied through Caddy for HTTPS access:
vault.orctatech.com {
reverse_proxy localhost:8200 {
transport http {
tls_insecure_skip_verify
}
}
encode zstd gzip
log {
output file /var/log/caddy/vault.access.log
format json
}
import security
header {
X-Frame-Options "SAMEORIGIN"
}
}
Unsealing Vault
Vault seals on restart and requires 3 of 5 unseal keys:
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>Unseal Keys (stored securely offline):
1. 7GUabmWbJNrw3IHRiBCugkCsaghxAGIrf7Cq0Kx27d+N
2. u053Y77SME9N5jXdlOosmuAnXHueO8nPC0J9DdZIhdIH
3. rsTB0S4oDjkHjB4UU+YZdjcS/EslKKNzByXTKcDNgoYV
4. kRrQcZ5J01jiSExyOO7GWQQkaTvX+Z0pWMC9daifBbje
5. oyQqHhJ1FfHXcIcf3dJ+3pEudqF7Rt0tUwjW8ZzJxdaq
Audit Logging
All Vault operations are logged to
/var/log/vault/audit.log.
View Logs
sudo tail -f /var/log/vault/audit.logSearch for User
sudo grep "username" /var/log/vault/audit.logsystemd Service
Vault runs as a systemd service:
# Check status
sudo systemctl status vault
# Restart
sudo systemctl restart vault
# View logs
sudo journalctl -u vault -fSecurity Best Practices
Do’s
✅ Use short-lived tokens - Login again when token expires
✅ Store tokens securely - Never commit to git
✅ Use least privilege - Only access what you need
✅ Rotate secrets regularly - Use Vault’s rotation features
✅ Audit access - Check /var/log/vault/audit.log
Don’ts
❌ Never hardcode secrets - Always use Vault
❌ Never share tokens - Each user gets their own
❌ Never store tokens in git - Use .gitignore
❌ Never use root token - Use your personal token
❌ Never disable audit logging - Compliance requirement
Troubleshooting
“Permission Denied” Error
# Check your policies
vault token lookup
# Check what you can access
vault kv list secret/orcta/“Vault is Sealed” Error
# Unseal Vault (need 3 of 5 keys)
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>“Token Expired” Error
# Re-login
vault login -method=userpass username=YOUR_USERNAME password=YOUR_PASSWORDCheck Audit Logs
# View recent audit events
sudo tail -f /var/log/vault/audit.log
# Search for specific user
sudo grep "username" /var/log/vault/audit.logEnvironment Variables
Set these in your shell profile (~/.bashrc or
~/.zshrc):
# Vault
export VAULT_SKIP_VERIFY=true
export VAULT_ADDR='https://127.0.0.1:8200'
# Or for remote access via Tailscale
export VAULT_ADDR='https://100.125.3.44:8200'API Usage
REST API Example
# Login
curl -s -k -X POST https://127.0.0.1:8200/v1/auth/userpass/login/cto \
-d '{"password":"your-password"}'
# Read secret
curl -s -k -H "X-Vault-Token: YOUR_TOKEN" \
https://127.0.0.1:8200/v1/secret/data/orcta/pss/database
# Write secret
curl -s -k -X POST -H "X-Vault-Token: YOUR_TOKEN" \
-d '{"data":{"key":"value"}}' \
https://127.0.0.1:8200/v1/secret/data/orcta/myapp/configJavaScript/Node.js
const axios = require('axios');
const VAULT_ADDR = 'https://127.0.0.1:8200';
const VAULT_TOKEN = 'your-token';
async function getSecret(path) {
const response = await axios.get(
`${VAULT_ADDR}/v1/secret/data/${path}`,
{
headers: { 'X-Vault-Token': VAULT_TOKEN },
httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false })
}
);
return response.data.data.data;
}
// Usage
const dbSecret = await getSecret('orcta/pss/database');
console.log(dbSecret.password);Backup & Recovery
Backup
# Backup Vault data
sudo tar -czf /backup/vault-backup-$(date +%Y%m%d).tar.gz /opt/vault/dataRecovery
# Stop Vault
sudo systemctl stop vault
# Restore data
sudo tar -xzf /backup/vault-backup-YYYYMMDD.tar.gz -C /
# Start Vault
sudo systemctl start vault
# Unseal
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>Next Steps
Support
- Documentation: https://www.vaultproject.io/docs
- CTO Contact: Bernard
- Audit Logs:
/var/log/vault/audit.log - Vault Logs:
sudo journalctl -u vault -f