936 lines
16 KiB
Markdown
Raw Normal View History

2025-12-22 21:34:01 +00:00
# SecretumVault How-To Guide
Step-by-step instructions for common tasks with SecretumVault.
## Table of Contents
1. [Getting Started](#getting-started)
2. [Initialize Vault](#initialize-vault)
3. [Unseal Vault](#unseal-vault)
4. [Manage Secrets](#manage-secrets)
5. [Configure Engines](#configure-engines)
6. [Setup Authorization](#setup-authorization)
7. [Configure TLS](#configure-tls)
8. [Integrate with Kubernetes](#integrate-with-kubernetes)
9. [Backup & Restore](#backup--restore)
10. [Monitor & Troubleshoot](#monitor--troubleshoot)
---
## Getting Started
### 1. Start Vault Locally
**Using Docker Compose** (recommended for development):
```bash
# 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**:
```bash
# 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
```bash
curl http://localhost:8200/v1/sys/health
```
Response:
```json
{
"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 yet
- `sealed: true` - Master key is sealed (expected before initialization)
---
## Initialize Vault
### 1. Generate Unseal Keys
Create a request to initialize vault with Shamir Secret Sharing:
```bash
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:
```json
{
"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
```bash
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:**
```bash
curl -X POST http://localhost:8200/v1/sys/unseal \
-H "Content-Type: application/json" \
-d '{
"key": "first_unseal_key_from_storage"
}'
```
Response:
```json
{
"sealed": true,
"t": 3,
"n": 5,
"progress": 1
}
```
Progress shows 1/3 keys provided.
**Unseal with second key:**
```bash
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):**
```bash
curl -X POST http://localhost:8200/v1/sys/unseal \
-H "Content-Type: application/json" \
-d '{
"key": "third_unseal_key_from_storage"
}'
```
Response:
```json
{
"sealed": false,
"t": 3,
"n": 5,
"progress": 0
}
```
`sealed: false` means vault is now unsealed!
### 2. Verify Unsealed State
```bash
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):
```toml
[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:**
```bash
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:
```bash
# From initialization response
export VAULT_TOKEN="root_token_abc123"
```
Response:
```json
{
"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:**
```bash
curl -X GET http://localhost:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN"
```
Response:
```json
{
"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:
```bash
# 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
```bash
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
```bash
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
```bash
curl -X LIST http://localhost:8200/v1/secret/metadata \
-H "X-Vault-Token: $VAULT_TOKEN"
```
Response:
```json
{
"data": {
"keys": [
"myapp",
"database-prod",
"aws-credentials"
]
}
}
```
### 6. Restore from Version
View available versions:
```bash
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:
```bash
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`:
```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:
```bash
# 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:
```bash
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:
```bash
# 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:
```json
{
"data": {
"ciphertext": "vault:v1:abc123def456..."
}
}
```
Decrypt data:
```bash
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:
```json
{
"data": {
"plaintext": "c2Vuc2l0aXZlIGRhdGE="
}
}
```
Decode plaintext:
```bash
echo "c2Vuc2l0aXZlIGRhdGE=" | base64 -d
# Output: sensitive data
```
### 3. Mount at Custom Path
Change mount path in config:
```toml
[engines.kv]
path = "app-secrets/" # Instead of "secret/"
versioned = true
```
Then access at:
```bash
curl http://localhost:8200/v1/app-secrets/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN"
```
---
## Setup Authorization
### 1. Create Cedar Policies
Create policy directory:
```bash
mkdir -p /etc/secretumvault/policies
```
Create policy file:
```bash
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:
```toml
[auth]
cedar_policies_dir = "/etc/secretumvault/policies"
```
### 2. Create Auth Token
```bash
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:
```json
{
"auth": {
"client_token": "s.abc123def456",
"policies": ["default", "app-reader"],
"metadata": {
"created_time": "2025-12-21T10:30:00Z",
"ttl": "24h"
}
}
}
```
Use token:
```bash
export APP_TOKEN="s.abc123def456"
curl http://localhost:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $APP_TOKEN"
```
### 3. Renew Token
```bash
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
```bash
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:
```bash
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`:
```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
```bash
# 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
```bash
# 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:
```bash
kubectl -n secretumvault port-forward svc/vault 8200:8200 &
```
Initialize (from earlier steps):
```bash
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
```bash
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:
```bash
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
```bash
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:
```bash
# 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:
```bash
# 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
```bash
# 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
```bash
curl http://localhost:8200/v1/sys/health | jq .
```
Key fields to check:
- `sealed`: Should be `false`
- `initialized`: Should be `true`
- `standby`: Should be `false` (or expected leader state)
### 2. View Metrics
Prometheus metrics endpoint:
```bash
curl http://localhost:9090/metrics | grep vault
```
Common metrics:
- `vault_secrets_stored_total` - Total secrets stored
- `vault_secrets_read_total` - Total secrets read
- `vault_operations_encrypt` - Encryption operations
- `vault_tokens_created` - Tokens created
### 3. Check Logs
Docker Compose:
```bash
docker-compose logs -f vault
```
Kubernetes:
```bash
kubectl -n secretumvault logs -f deployment/vault
```
Look for:
- `ERROR` entries with details
- `WARN` for unexpected but recoverable conditions
- `INFO` for normal operations
### 4. Verify Storage Connectivity
Check etcd from vault pod:
```bash
kubectl -n secretumvault exec deployment/vault -- \
curl http://vault-etcd-client:2379/health
```
### 5. Test Token Access
Validate token is working:
```bash
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:
- [Architecture Guide](ARCHITECTURE.md)
- [Configuration Reference](CONFIGURATION.md)
- [Deployment Guide](../DEPLOYMENT.md)