16 KiB
SecretumVault How-To Guide
Step-by-step instructions for common tasks with SecretumVault.
Table of Contents
- Getting Started
- Initialize Vault
- Unseal Vault
- Manage Secrets
- Configure Engines
- Setup Authorization
- Configure TLS
- Integrate with Kubernetes
- Backup & Restore
- Monitor & Troubleshoot
Getting Started
1. Start Vault Locally
Using Docker Compose (recommended for development):
# Navigate to project
cd secretumvault
# Build image
docker build -t secretumvault:latest .
# Start all services
docker-compose up -d
# Verify vault is running
curl http://localhost:8200/v1/sys/health
Using Cargo:
# Create configuration
cat > svault.toml <<'EOF'
[vault]
crypto_backend = "openssl"
[server]
address = "0.0.0.0"
port = 8200
[storage]
backend = "etcd"
[storage.etcd]
endpoints = ["http://localhost:2379"]
[seal]
seal_type = "shamir"
threshold = 2
shares = 3
[engines.kv]
path = "secret/"
versioned = true
[logging]
level = "info"
format = "json"
EOF
# Start vault (requires etcd running)
cargo run --release -- server --config svault.toml
2. Verify Health
curl http://localhost:8200/v1/sys/health
Response:
{
"initialized": false,
"sealed": true,
"standby": false,
"performance_standby": false,
"replication_performance_mode": "disabled",
"replication_dr_mode": "disabled",
"server_time_utc": 1703142600,
"version": "0.1.0"
}
Key fields:
initialized: false- Vault not initialized yetsealed: true- Master key is sealed (expected before initialization)
Initialize Vault
1. Generate Unseal Keys
Create a request to initialize vault with Shamir Secret Sharing:
curl -X POST http://localhost:8200/v1/sys/init \
-H "Content-Type: application/json" \
-d '{
"shares": 5,
"threshold": 3
}'
Parameters:
shares: 5- Total unseal keys generated (5 people get 1 key each)threshold: 3- Need 3 keys to unseal (quorum)
Response:
{
"keys": [
"key_1_base64_encoded",
"key_2_base64_encoded",
"key_3_base64_encoded",
"key_4_base64_encoded",
"key_5_base64_encoded"
],
"root_token": "root_token_abc123def456"
}
2. Store Keys Securely
CRITICAL: Store unseal keys immediately in a secure location!
Save in password manager (Bitwarden, 1Password, LastPass):
- Each unseal key separately (don't store all together)
- Distribute keys to different people/locations
- Test that stored keys are retrievable
Save root token separately:
- Store in same password manager
- Label clearly: "Root Token - SecretumVault"
- Keep temporary access only
3. Verify Initialization
curl http://localhost:8200/v1/sys/health
Response should now show initialized: true and sealed: true
Unseal Vault
Vault must be unsealed before it can serve requests.
1. Unseal with Keys
You need threshold keys (e.g., 3 of 5) to unseal.
Unseal with first key:
curl -X POST http://localhost:8200/v1/sys/unseal \
-H "Content-Type: application/json" \
-d '{
"key": "first_unseal_key_from_storage"
}'
Response:
{
"sealed": true,
"t": 3,
"n": 5,
"progress": 1
}
Progress shows 1/3 keys provided.
Unseal with second key:
curl -X POST http://localhost:8200/v1/sys/unseal \
-H "Content-Type: application/json" \
-d '{
"key": "second_unseal_key_from_storage"
}'
Response shows progress: 2/3
Unseal with third key (final):
curl -X POST http://localhost:8200/v1/sys/unseal \
-H "Content-Type: application/json" \
-d '{
"key": "third_unseal_key_from_storage"
}'
Response:
{
"sealed": false,
"t": 3,
"n": 5,
"progress": 0
}
sealed: false means vault is now unsealed!
2. Verify Unsealed State
curl http://localhost:8200/v1/sys/health
Should show sealed: false
3. Auto-Unseal (Future)
For production, configure auto-unseal via AWS KMS or GCP Cloud KMS (planned):
[seal]
seal_type = "aws-kms"
[seal.aws-kms]
key_id = "arn:aws:kms:us-east-1:account:key/id"
region = "us-east-1"
Manage Secrets
1. Store a Secret
HTTP Request:
curl -X POST http://localhost:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"username": "admin",
"password": "supersecret123",
"api_key": "sk_live_abc123"
}
}'
Environment variable setup:
# From initialization response
export VAULT_TOKEN="root_token_abc123"
Response:
{
"request_id": "req_123",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": null,
"wrap_info": null,
"warnings": null,
"auth": null
}
Status 201 Created indicates success.
2. Read a Secret
HTTP Request:
curl -X GET http://localhost:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN"
Response:
{
"request_id": "req_124",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"data": {
"username": "admin",
"password": "supersecret123",
"api_key": "sk_live_abc123"
},
"metadata": {
"created_time": "2025-12-21T10:30:00Z",
"deletion_time": "",
"destroyed": false,
"version": 1
}
}
}
Extract secret data:
# Get password field
curl -s http://localhost:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN" | jq '.data.data.password'
Output: "supersecret123"
3. Update a Secret
curl -X POST http://localhost:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"username": "admin",
"password": "newsecret456",
"api_key": "sk_live_abc123"
}
}'
New version created (version 2). Previous versions retained.
4. Delete a Secret
curl -X DELETE http://localhost:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN"
Soft delete: metadata retained, data destroyed.
5. List Secrets
curl -X LIST http://localhost:8200/v1/secret/metadata \
-H "X-Vault-Token: $VAULT_TOKEN"
Response:
{
"data": {
"keys": [
"myapp",
"database-prod",
"aws-credentials"
]
}
}
6. Restore from Version
View available versions:
curl -X GET http://localhost:8200/v1/secret/metadata/myapp \
-H "X-Vault-Token: $VAULT_TOKEN"
Response shows all versions with timestamps.
Get specific version:
curl -X GET http://localhost:8200/v1/secret/data/myapp?version=1 \
-H "X-Vault-Token: $VAULT_TOKEN"
Configure Engines
1. Enable Additional Engines
Edit svault.toml:
[engines.kv]
path = "secret/"
versioned = true
[engines.transit]
path = "transit/"
versioned = true
[engines.pki]
path = "pki/"
versioned = false
[engines.database]
path = "database/"
versioned = false
Restart vault:
# Docker Compose
docker-compose restart vault
# Or Cargo
# Kill running process (Ctrl+C) and restart
cargo run --release -- server --config svault.toml
2. Use Transit Engine (Encryption)
Create encryption key:
curl -X POST http://localhost:8200/v1/transit/keys/my-key \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"exportable": false,
"key_size": 256,
"type": "aes-gcm"
}'
Encrypt data:
# Plaintext must be base64 encoded
PLAINTEXT=$(echo -n "sensitive data" | base64)
curl -X POST http://localhost:8200/v1/transit/encrypt/my-key \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"plaintext\": \"$PLAINTEXT\"}"
Response:
{
"data": {
"ciphertext": "vault:v1:abc123def456..."
}
}
Decrypt data:
CIPHERTEXT="vault:v1:abc123def456..."
curl -X POST http://localhost:8200/v1/transit/decrypt/my-key \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"ciphertext\": \"$CIPHERTEXT\"}"
Response:
{
"data": {
"plaintext": "c2Vuc2l0aXZlIGRhdGE="
}
}
Decode plaintext:
echo "c2Vuc2l0aXZlIGRhdGE=" | base64 -d
# Output: sensitive data
3. Mount at Custom Path
Change mount path in config:
[engines.kv]
path = "app-secrets/" # Instead of "secret/"
versioned = true
Then access at:
curl http://localhost:8200/v1/app-secrets/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN"
Setup Authorization
1. Create Cedar Policies
Create policy directory:
mkdir -p /etc/secretumvault/policies
Create policy file:
cat > /etc/secretumvault/policies/default.cedar <<'EOF'
permit (
principal,
action,
resource
) when {
principal has policies &&
principal.policies.contains("admin")
};
deny (
principal,
action == Action::"write",
resource
) unless {
context.time_of_day < 20:00
};
EOF
Update config:
[auth]
cedar_policies_dir = "/etc/secretumvault/policies"
2. Create Auth Token
curl -X POST http://localhost:8200/v1/auth/token/create \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"policies": ["default", "app-reader"],
"ttl": "24h",
"renewable": true
}'
Response:
{
"auth": {
"client_token": "s.abc123def456",
"policies": ["default", "app-reader"],
"metadata": {
"created_time": "2025-12-21T10:30:00Z",
"ttl": "24h"
}
}
}
Use token:
export APP_TOKEN="s.abc123def456"
curl http://localhost:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $APP_TOKEN"
3. Renew Token
curl -X POST http://localhost:8200/v1/auth/token/renew \
-H "X-Vault-Token: $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"increment": "24h"
}'
4. Revoke Token
curl -X POST http://localhost:8200/v1/auth/token/revoke \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"token": "s.abc123def456"
}'
Configure TLS
1. Generate Self-Signed Certificate
For development:
openssl req -x509 -newkey rsa:4096 -keyout tls.key -out tls.crt \
-days 365 -nodes \
-subj "/CN=localhost/O=SecretumVault/C=US"
2. Configure Vault
Update svault.toml:
[server]
address = "0.0.0.0"
port = 8200
tls_cert = "/path/to/tls.crt"
tls_key = "/path/to/tls.key"
3. Access via HTTPS
# Allow self-signed certificate
curl --insecure https://localhost:8200/v1/sys/health \
-H "X-Vault-Token: $VAULT_TOKEN"
# Or with CA certificate
curl --cacert tls.crt https://localhost:8200/v1/sys/health \
-H "X-Vault-Token: $VAULT_TOKEN"
4. Production Certificate (Let's Encrypt)
For Kubernetes with cert-manager, use the Helm installation which handles automatic certificate renewal.
Integrate with Kubernetes
1. Deploy Vault
# Apply manifests
kubectl apply -f k8s/01-namespace.yaml
kubectl apply -f k8s/02-configmap.yaml
kubectl apply -f k8s/03-deployment.yaml
kubectl apply -f k8s/04-service.yaml
kubectl apply -f k8s/05-etcd.yaml
# Wait for pods
kubectl -n secretumvault wait --for=condition=ready pod -l app=vault --timeout=300s
2. Initialize and Unseal
Port-forward vault:
kubectl -n secretumvault port-forward svc/vault 8200:8200 &
Initialize (from earlier steps):
curl -X POST http://localhost:8200/v1/sys/init \
-H "Content-Type: application/json" \
-d '{"shares": 3, "threshold": 2}'
Save keys, then unseal (from earlier steps).
3. Create Kubernetes ServiceAccount
cat > /tmp/app-sa.yaml <<'EOF'
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp
namespace: default
EOF
kubectl apply -f /tmp/app-sa.yaml
4. Pod Secret Injection
Create ClusterRoleBinding to allow reading vault-config:
cat > /tmp/vault-reader.yaml <<'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: vault-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: vault-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: vault-reader
subjects:
- kind: ServiceAccount
name: myapp
namespace: default
EOF
kubectl apply -f /tmp/vault-reader.yaml
5. Deploy Application Pod
cat > /tmp/myapp-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: myapp
namespace: default
spec:
serviceAccountName: myapp
containers:
- name: app
image: myapp:latest
env:
- name: VAULT_ADDR
value: "http://vault.secretumvault.svc.cluster.local:8200"
- name: VAULT_TOKEN
valueFrom:
secretKeyRef:
name: vault-token
key: token
volumeMounts:
- name: vault-config
mountPath: /etc/vault
readOnly: true
volumes:
- name: vault-config
configMap:
name: vault-config
namespace: secretumvault
EOF
kubectl apply -f /tmp/myapp-pod.yaml
Backup & Restore
1. Backup Secrets
Export all secrets:
# List all secrets
SECRETS=$(curl -s http://localhost:8200/v1/secret/metadata \
-H "X-Vault-Token: $VAULT_TOKEN" | jq -r '.data.keys[]')
# Backup each secret
for secret in $SECRETS; do
curl -s http://localhost:8200/v1/secret/data/$secret \
-H "X-Vault-Token: $VAULT_TOKEN" > $secret-backup.json
done
2. Export with Encryption
Encrypt backup before storing:
# Create transit key for backups
curl -X POST http://localhost:8200/v1/transit/keys/backup-key \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": "aes-gcm"}'
# Backup and encrypt
for secret in $SECRETS; do
CONTENT=$(curl -s http://localhost:8200/v1/secret/data/$secret \
-H "X-Vault-Token: $VAULT_TOKEN" | base64)
ENCRYPTED=$(curl -s -X POST http://localhost:8200/v1/transit/encrypt/backup-key \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"plaintext\": \"$CONTENT\"}" | jq -r '.data.ciphertext')
echo "$ENCRYPTED" > $secret-backup.enc
done
3. Restore Secrets
# List backup files
for backup in *-backup.json; do
secret=${backup%-backup.json}
# Read backup
curl -X POST http://localhost:8200/v1/secret/data/$secret \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-d @$backup
done
Monitor & Troubleshoot
1. Check Vault Health
curl http://localhost:8200/v1/sys/health | jq .
Key fields to check:
sealed: Should befalseinitialized: Should betruestandby: Should befalse(or expected leader state)
2. View Metrics
Prometheus metrics endpoint:
curl http://localhost:9090/metrics | grep vault
Common metrics:
vault_secrets_stored_total- Total secrets storedvault_secrets_read_total- Total secrets readvault_operations_encrypt- Encryption operationsvault_tokens_created- Tokens created
3. Check Logs
Docker Compose:
docker-compose logs -f vault
Kubernetes:
kubectl -n secretumvault logs -f deployment/vault
Look for:
ERRORentries with detailsWARNfor unexpected but recoverable conditionsINFOfor normal operations
4. Verify Storage Connectivity
Check etcd from vault pod:
kubectl -n secretumvault exec deployment/vault -- \
curl http://vault-etcd-client:2379/health
5. Test Token Access
Validate token is working:
curl -X GET http://localhost:8200/v1/auth/token/self \
-H "X-Vault-Token: $VAULT_TOKEN" | jq '.auth'
Response shows token metadata and policies.
6. Common Issues
Issue: "sealed: true" after restart
- Solution: Run unseal procedure with stored keys
Issue: "permission denied" on secret read
- Solution: Check Cedar policies, verify token has correct policies
Issue: Storage connection error
- Solution: Verify backend endpoint in config (etcd DNS/IP)
Issue: High memory usage
- Solution: Check number of active leases, revoke old tokens
Issue: Slow operations
- Solution: Check storage backend performance, review metrics
For more details, see: