696 lines
17 KiB
Markdown
696 lines
17 KiB
Markdown
|
|
# HOW-TO: Configure and Run Encryption Services for typedialog
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
This guide walks through setting up **Age** (local file-based encryption) and **RustyVault** (HTTP-based encryption service) to test the typedialog encryption pipeline end-to-end.
|
||
|
|
|
||
|
|
**Service Matrix:**
|
||
|
|
|
||
|
|
| Backend | Type | Setup Complexity | Network | Requires |
|
||
|
|
|---------|------|------------------|---------|----------|
|
||
|
|
| **Age** | Local file-based | Trivial | None | age CLI tool |
|
||
|
|
| **RustyVault** | HTTP vault server | Moderate | localhost:8200 | Docker or manual build |
|
||
|
|
| **SOPS** | External tool | Complex | Varies | sops CLI + backends |
|
||
|
|
|
||
|
|
This guide covers Age (trivial) and RustyVault (moderate). SOPS is skipped for now.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part 1: Age Backend (Local File Encryption)
|
||
|
|
|
||
|
|
### What is Age?
|
||
|
|
|
||
|
|
Age is a simple, modern encryption tool using X25519 keys. Perfect for development because:
|
||
|
|
- No daemon/service required
|
||
|
|
- Keys stored as plaintext files
|
||
|
|
- Single binary
|
||
|
|
|
||
|
|
### Installation
|
||
|
|
|
||
|
|
**macOS (via Homebrew):**
|
||
|
|
```bash
|
||
|
|
brew install age
|
||
|
|
```
|
||
|
|
|
||
|
|
**Linux (Ubuntu/Debian):**
|
||
|
|
```bash
|
||
|
|
sudo apt-get install age
|
||
|
|
```
|
||
|
|
|
||
|
|
**Manual (any OS):**
|
||
|
|
```bash
|
||
|
|
# Download from https://github.com/FiloSottile/age/releases
|
||
|
|
# Extract and add to PATH
|
||
|
|
tar xzf age-v1.1.1-linux-amd64.tar.gz
|
||
|
|
sudo mv age/age /usr/local/bin/
|
||
|
|
sudo mv age/age-keygen /usr/local/bin/
|
||
|
|
```
|
||
|
|
|
||
|
|
**Verify installation:**
|
||
|
|
```bash
|
||
|
|
age --version
|
||
|
|
# age v1.1.1
|
||
|
|
```
|
||
|
|
|
||
|
|
### Generate Age Key Pair
|
||
|
|
|
||
|
|
Age uses a single private key file that contains both public and private components. The public key is derived from the private key.
|
||
|
|
|
||
|
|
**Generate keys for testing:**
|
||
|
|
```bash
|
||
|
|
# Create a test directory
|
||
|
|
mkdir -p ~/.age
|
||
|
|
|
||
|
|
# Generate private key
|
||
|
|
age-keygen -o ~/.age/key.txt
|
||
|
|
|
||
|
|
# Output will show:
|
||
|
|
# Public key: age1...xxx (save this, shown in file)
|
||
|
|
# Written to /home/user/.age/key.txt
|
||
|
|
```
|
||
|
|
|
||
|
|
**Verify key generation:**
|
||
|
|
```bash
|
||
|
|
# Check private key exists
|
||
|
|
cat ~/.age/key.txt
|
||
|
|
# Output: AGE-SECRET-KEY-1XXXX...
|
||
|
|
|
||
|
|
# Extract public key (age CLI does this automatically)
|
||
|
|
grep "^public key:" ~/.age/key.txt | cut -d' ' -f3
|
||
|
|
```
|
||
|
|
|
||
|
|
### Test Age Encryption Locally
|
||
|
|
|
||
|
|
**Create a test plaintext file:**
|
||
|
|
```bash
|
||
|
|
echo "This is a secret message" > test_message.txt
|
||
|
|
```
|
||
|
|
|
||
|
|
**Encrypt with age:**
|
||
|
|
```bash
|
||
|
|
# Get public key from private key
|
||
|
|
PUBLIC_KEY=$(grep "^public key:" ~/.age/key.txt | cut -d' ' -f3)
|
||
|
|
|
||
|
|
# Encrypt
|
||
|
|
age -r "$PUBLIC_KEY" test_message.txt > test_message.age
|
||
|
|
|
||
|
|
# Verify ciphertext is unreadable
|
||
|
|
cat test_message.age
|
||
|
|
# Output: AGE-ENCRYPTION-V1...binary...
|
||
|
|
```
|
||
|
|
|
||
|
|
**Decrypt with age:**
|
||
|
|
```bash
|
||
|
|
# Decrypt (will prompt for passphrase if key is encrypted)
|
||
|
|
age -d -i ~/.age/key.txt test_message.age
|
||
|
|
|
||
|
|
# Output: This is a secret message
|
||
|
|
```
|
||
|
|
|
||
|
|
### Configure typedialog to Use Age
|
||
|
|
|
||
|
|
**Environment variables:**
|
||
|
|
```bash
|
||
|
|
export AGE_KEY_FILE="$HOME/.age/key.txt"
|
||
|
|
```
|
||
|
|
|
||
|
|
**CLI flags:**
|
||
|
|
```bash
|
||
|
|
# Redact mode (no encryption needed)
|
||
|
|
typedialog form examples/08-encryption/simple-login.toml --redact --format json
|
||
|
|
|
||
|
|
# Encrypt mode (requires Age backend)
|
||
|
|
typedialog form examples/08-encryption/simple-login.toml --encrypt --backend age --key-file ~/.age/key.txt --format json
|
||
|
|
```
|
||
|
|
|
||
|
|
See `examples/08-encryption/README.md` for more example forms and test cases.
|
||
|
|
|
||
|
|
**TOML form configuration:**
|
||
|
|
```toml
|
||
|
|
[[fields]]
|
||
|
|
name = "password"
|
||
|
|
type = "password"
|
||
|
|
prompt = "Enter password"
|
||
|
|
sensitive = true
|
||
|
|
encryption_backend = "age"
|
||
|
|
|
||
|
|
[fields.encryption_config]
|
||
|
|
key = "~/.age/key.txt"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part 2: RustyVault Backend (HTTP Service)
|
||
|
|
|
||
|
|
### What is RustyVault?
|
||
|
|
|
||
|
|
RustyVault is a Rust implementation of HashiCorp Vault's Transit API:
|
||
|
|
- HTTP-based encryption/decryption service
|
||
|
|
- Suitable for production environments
|
||
|
|
- API-compatible with Vault Transit secrets engine
|
||
|
|
|
||
|
|
### Installation & Setup
|
||
|
|
|
||
|
|
**Option A: Docker (Recommended for testing)**
|
||
|
|
|
||
|
|
RustyVault provides official Docker images. Check availability:
|
||
|
|
```bash
|
||
|
|
# Search Docker Hub
|
||
|
|
docker search rustyvault
|
||
|
|
|
||
|
|
# Or build from source
|
||
|
|
git clone https://github.com/Tongsuo-Project/RustyVault.git
|
||
|
|
cd RustyVault
|
||
|
|
docker build -t rustyvault:latest .
|
||
|
|
```
|
||
|
|
|
||
|
|
**Option B: Manual Build (if Docker not available)**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Prerequisites: Rust toolchain
|
||
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||
|
|
|
||
|
|
# Clone and build
|
||
|
|
git clone https://github.com/Tongsuo-Project/RustyVault.git
|
||
|
|
cd RustyVault
|
||
|
|
cargo build --release
|
||
|
|
|
||
|
|
# Binary at: target/release/rustyvault
|
||
|
|
```
|
||
|
|
|
||
|
|
### Run RustyVault Service
|
||
|
|
|
||
|
|
**Using Docker (single command):**
|
||
|
|
```bash
|
||
|
|
docker run -d \
|
||
|
|
--name rustyvault \
|
||
|
|
-p 8200:8200 \
|
||
|
|
-e RUSTYVAULT_LOG_LEVEL=info \
|
||
|
|
rustyvault:latest
|
||
|
|
|
||
|
|
# Verify it started
|
||
|
|
docker logs rustyvault | head -20
|
||
|
|
```
|
||
|
|
|
||
|
|
**Using local binary:**
|
||
|
|
```bash
|
||
|
|
# Create config directory
|
||
|
|
mkdir -p ~/.rustyvault
|
||
|
|
cd ~/.rustyvault
|
||
|
|
|
||
|
|
# Create minimal config (rustyvault.toml)
|
||
|
|
cat > config.toml <<'EOF'
|
||
|
|
[server]
|
||
|
|
address = "127.0.0.1:8200"
|
||
|
|
tls_disable = true
|
||
|
|
|
||
|
|
[backend]
|
||
|
|
type = "inmem" # In-memory storage (ephemeral)
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Run service
|
||
|
|
~/RustyVault/target/release/rustyvault server -c config.toml
|
||
|
|
```
|
||
|
|
|
||
|
|
**Verify service is running:**
|
||
|
|
```bash
|
||
|
|
# In another terminal
|
||
|
|
curl -s http://localhost:8200/v1/sys/health | jq .
|
||
|
|
# Should return health status JSON
|
||
|
|
```
|
||
|
|
|
||
|
|
### Configure RustyVault for Encryption
|
||
|
|
|
||
|
|
**Initialize RustyVault (first time only):**
|
||
|
|
```bash
|
||
|
|
# Generate initial token
|
||
|
|
VAULT_INIT=$(curl -s -X POST http://localhost:8200/v1/sys/init \
|
||
|
|
-d '{"secret_shares": 1, "secret_threshold": 1}' | jq -r .keys[0])
|
||
|
|
|
||
|
|
# Unseal vault
|
||
|
|
curl -s -X PUT http://localhost:8200/v1/sys/unseal \
|
||
|
|
-d "{\"key\": \"$VAULT_INIT\"}" > /dev/null
|
||
|
|
|
||
|
|
# Save root token
|
||
|
|
ROOT_TOKEN=$(curl -s -X POST http://localhost:8200/v1/sys/unseal \
|
||
|
|
-d "{\"key\": \"$VAULT_INIT\"}" | jq -r .auth.client_token)
|
||
|
|
|
||
|
|
export VAULT_TOKEN="$ROOT_TOKEN"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Enable Transit secrets engine:**
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8200/v1/sys/mounts/transit \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
||
|
|
-d '{"type": "transit"}' | jq .
|
||
|
|
```
|
||
|
|
|
||
|
|
**Create encryption key:**
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8200/v1/transit/keys/typedialog-key \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
||
|
|
-d '{}' | jq .
|
||
|
|
|
||
|
|
# Verify key created
|
||
|
|
curl -s http://localhost:8200/v1/transit/keys/typedialog-key \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN" | jq .
|
||
|
|
```
|
||
|
|
|
||
|
|
### Test RustyVault Encryption
|
||
|
|
|
||
|
|
**Encrypt data via HTTP:**
|
||
|
|
```bash
|
||
|
|
# Plaintext (base64 encoded)
|
||
|
|
PLAINTEXT=$(echo -n "my-secret-password" | base64)
|
||
|
|
|
||
|
|
curl -s -X POST http://localhost:8200/v1/transit/encrypt/typedialog-key \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
||
|
|
-d "{\"plaintext\": \"$PLAINTEXT\"}" | jq .data.ciphertext
|
||
|
|
```
|
||
|
|
|
||
|
|
**Decrypt data via HTTP:**
|
||
|
|
```bash
|
||
|
|
# From encryption output above
|
||
|
|
CIPHERTEXT="vault:v1:..."
|
||
|
|
|
||
|
|
curl -s -X POST http://localhost:8200/v1/transit/decrypt/typedialog-key \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
||
|
|
-d "{\"ciphertext\": \"$CIPHERTEXT\"}" | jq -r .data.plaintext | base64 -d
|
||
|
|
```
|
||
|
|
|
||
|
|
### Configure typedialog to Use RustyVault
|
||
|
|
|
||
|
|
**Environment variables:**
|
||
|
|
```bash
|
||
|
|
export VAULT_ADDR="http://localhost:8200"
|
||
|
|
export VAULT_TOKEN="s.xxxx..." # Token from above
|
||
|
|
```
|
||
|
|
|
||
|
|
**CLI flags:**
|
||
|
|
```bash
|
||
|
|
typedialog form examples/08-encryption/credentials.toml \
|
||
|
|
--encrypt \
|
||
|
|
--backend rustyvault \
|
||
|
|
--vault-addr http://localhost:8200 \
|
||
|
|
--vault-token "s.xxxx..." \
|
||
|
|
--vault-key-path "transit/keys/typedialog-key" \
|
||
|
|
--format json
|
||
|
|
```
|
||
|
|
|
||
|
|
This form includes field-level RustyVault configuration in the `vault_token` field.
|
||
|
|
|
||
|
|
**TOML form configuration:**
|
||
|
|
```toml
|
||
|
|
[[fields]]
|
||
|
|
name = "password"
|
||
|
|
type = "password"
|
||
|
|
prompt = "Enter password"
|
||
|
|
sensitive = true
|
||
|
|
encryption_backend = "rustyvault"
|
||
|
|
|
||
|
|
[fields.encryption_config]
|
||
|
|
vault_addr = "http://localhost:8200"
|
||
|
|
vault_token = "s.xxxx..."
|
||
|
|
key_path = "transit/keys/typedialog-key"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part 3: Complete Integration Test Workflow
|
||
|
|
|
||
|
|
### Script: Setup Everything
|
||
|
|
|
||
|
|
Create `scripts/encryption-test-setup.sh`:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/usr/bin/env bash
|
||
|
|
set -e
|
||
|
|
|
||
|
|
echo "=== typedialog Encryption Services Setup ==="
|
||
|
|
|
||
|
|
# Age Setup
|
||
|
|
echo "1. Setting up Age..."
|
||
|
|
if ! command -v age &> /dev/null; then
|
||
|
|
echo " ✗ age not installed. Run: brew install age"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
mkdir -p ~/.age
|
||
|
|
if [ ! -f ~/.age/key.txt ]; then
|
||
|
|
echo " → Generating Age keys..."
|
||
|
|
age-keygen -o ~/.age/key.txt
|
||
|
|
fi
|
||
|
|
export AGE_KEY_FILE="$HOME/.age/key.txt"
|
||
|
|
echo " ✓ Age configured at: $AGE_KEY_FILE"
|
||
|
|
|
||
|
|
# RustyVault Setup (Docker)
|
||
|
|
echo ""
|
||
|
|
echo "2. Setting up RustyVault (Docker)..."
|
||
|
|
if ! command -v docker &> /dev/null; then
|
||
|
|
echo " ⚠ Docker not installed, skipping RustyVault"
|
||
|
|
echo " → Install Docker or skip RustyVault tests"
|
||
|
|
else
|
||
|
|
if ! docker ps | grep -q rustyvault; then
|
||
|
|
echo " → Starting RustyVault container..."
|
||
|
|
docker run -d \
|
||
|
|
--name rustyvault \
|
||
|
|
-p 8200:8200 \
|
||
|
|
-e RUSTYVAULT_LOG_LEVEL=info \
|
||
|
|
rustyvault:latest
|
||
|
|
sleep 2
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Initialize vault
|
||
|
|
echo " → Initializing RustyVault..."
|
||
|
|
VAULT_INIT=$(curl -s -X POST http://localhost:8200/v1/sys/init \
|
||
|
|
-d '{"secret_shares": 1, "secret_threshold": 1}' | jq -r .keys[0])
|
||
|
|
|
||
|
|
curl -s -X PUT http://localhost:8200/v1/sys/unseal \
|
||
|
|
-d "{\"key\": \"$VAULT_INIT\"}" > /dev/null
|
||
|
|
|
||
|
|
# Get root token
|
||
|
|
RESPONSE=$(curl -s -X GET http://localhost:8200/v1/sys/unseal \
|
||
|
|
-H "X-Vault-Token: $VAULT_INIT")
|
||
|
|
export VAULT_TOKEN=$(echo "$RESPONSE" | jq -r .auth.client_token // "root")
|
||
|
|
export VAULT_ADDR="http://localhost:8200"
|
||
|
|
|
||
|
|
# Enable transit
|
||
|
|
curl -s -X POST http://localhost:8200/v1/sys/mounts/transit \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
||
|
|
-d '{"type": "transit"}' > /dev/null 2>&1 || true
|
||
|
|
|
||
|
|
# Create key
|
||
|
|
curl -s -X POST http://localhost:8200/v1/transit/keys/typedialog-key \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
||
|
|
-d '{}' > /dev/null 2>&1 || true
|
||
|
|
|
||
|
|
echo " ✓ RustyVault running at: http://localhost:8200"
|
||
|
|
echo " ✓ Token: $VAULT_TOKEN"
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
echo "=== Setup Complete ==="
|
||
|
|
echo ""
|
||
|
|
echo "Test Age encryption:"
|
||
|
|
echo " typedialog form test.toml --encrypt --backend age --key-file ~/.age/key.txt"
|
||
|
|
echo ""
|
||
|
|
echo "Test RustyVault encryption:"
|
||
|
|
echo " export VAULT_ADDR='http://localhost:8200'"
|
||
|
|
echo " export VAULT_TOKEN='$VAULT_TOKEN'"
|
||
|
|
echo " typedialog form test.toml --encrypt --backend rustyvault --vault-key-path 'transit/keys/typedialog-key'"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Make executable and run:**
|
||
|
|
```bash
|
||
|
|
chmod +x scripts/encryption-test-setup.sh
|
||
|
|
./scripts/encryption-test-setup.sh
|
||
|
|
```
|
||
|
|
|
||
|
|
### Test Case 1: Age Redaction (No Service Required)
|
||
|
|
|
||
|
|
**Option A: Use pre-built example (Recommended)**
|
||
|
|
```bash
|
||
|
|
typedialog form examples/08-encryption/simple-login.toml --redact --format json
|
||
|
|
|
||
|
|
# Expected output:
|
||
|
|
# {"username": "alice", "password": "[REDACTED]"}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Option B: Create form manually**
|
||
|
|
```bash
|
||
|
|
# Create test form
|
||
|
|
cat > test_redaction.toml <<'EOF'
|
||
|
|
name = "test_form"
|
||
|
|
display_mode = "complete"
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "username"
|
||
|
|
type = "text"
|
||
|
|
prompt = "Username"
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "password"
|
||
|
|
type = "password"
|
||
|
|
prompt = "Password"
|
||
|
|
sensitive = true
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Test redaction (requires no service)
|
||
|
|
typedialog form test_redaction.toml --redact --format json
|
||
|
|
```
|
||
|
|
|
||
|
|
### Test Case 2: Age Encryption (Service Not Required, Key File Required)
|
||
|
|
|
||
|
|
**Option A: Use pre-built example (Recommended)**
|
||
|
|
```bash
|
||
|
|
# Prerequisites: Age key generated (from setup script)
|
||
|
|
./scripts/encryption-test-setup.sh
|
||
|
|
|
||
|
|
# Test with simple form
|
||
|
|
typedialog form examples/08-encryption/simple-login.toml \
|
||
|
|
--encrypt --backend age --key-file ~/.age/key.txt --format json
|
||
|
|
|
||
|
|
# Expected output: password field contains age ciphertext
|
||
|
|
# {"username": "alice", "password": "age1muz6ah54ew9am7mzmy0m4w5..."}
|
||
|
|
|
||
|
|
# Or test with full credentials form
|
||
|
|
typedialog form examples/08-encryption/credentials.toml \
|
||
|
|
--encrypt --backend age --key-file ~/.age/key.txt --format json
|
||
|
|
```
|
||
|
|
|
||
|
|
**Option B: Create form manually**
|
||
|
|
```bash
|
||
|
|
# Generate Age key if not exists
|
||
|
|
mkdir -p ~/.age
|
||
|
|
if [ ! -f ~/.age/key.txt ]; then
|
||
|
|
age-keygen -o ~/.age/key.txt
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Create test form
|
||
|
|
cat > test_age_encrypt.toml <<'EOF'
|
||
|
|
name = "test_form"
|
||
|
|
display_mode = "complete"
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "username"
|
||
|
|
type = "text"
|
||
|
|
prompt = "Username"
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "password"
|
||
|
|
type = "password"
|
||
|
|
prompt = "Password"
|
||
|
|
sensitive = true
|
||
|
|
encryption_backend = "age"
|
||
|
|
|
||
|
|
[fields.encryption_config]
|
||
|
|
key = "~/.age/key.txt"
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Test encryption (requires Age key file)
|
||
|
|
typedialog form test_age_encrypt.toml --encrypt --backend age --key-file ~/.age/key.txt --format json
|
||
|
|
```
|
||
|
|
|
||
|
|
### Test Case 3: RustyVault Encryption (Service Required)
|
||
|
|
|
||
|
|
**Prerequisites: RustyVault running**
|
||
|
|
```bash
|
||
|
|
# Start RustyVault and setup (requires Docker)
|
||
|
|
./scripts/encryption-test-setup.sh
|
||
|
|
|
||
|
|
# Verify service is healthy
|
||
|
|
curl http://localhost:8200/v1/sys/health | jq .
|
||
|
|
```
|
||
|
|
|
||
|
|
**Option A: Use pre-built example (Recommended)**
|
||
|
|
```bash
|
||
|
|
# Export Vault credentials
|
||
|
|
export VAULT_ADDR="http://localhost:8200"
|
||
|
|
export VAULT_TOKEN="root"
|
||
|
|
|
||
|
|
# Test with simple form
|
||
|
|
typedialog form examples/08-encryption/simple-login.toml \
|
||
|
|
--encrypt --backend rustyvault \
|
||
|
|
--vault-key-path "transit/keys/typedialog-key" \
|
||
|
|
--format json
|
||
|
|
|
||
|
|
# Expected output: password field contains vault ciphertext
|
||
|
|
# {"username": "alice", "password": "vault:v1:K8..."}
|
||
|
|
|
||
|
|
# Or test with full credentials form (demonstrates field-level config)
|
||
|
|
typedialog form examples/08-encryption/credentials.toml \
|
||
|
|
--encrypt --backend rustyvault \
|
||
|
|
--vault-key-path "transit/keys/typedialog-key" \
|
||
|
|
--format json
|
||
|
|
```
|
||
|
|
|
||
|
|
**Option B: Create form manually**
|
||
|
|
```bash
|
||
|
|
cat > test_vault_encrypt.toml <<'EOF'
|
||
|
|
name = "test_form"
|
||
|
|
display_mode = "complete"
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "username"
|
||
|
|
type = "text"
|
||
|
|
prompt = "Username"
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "password"
|
||
|
|
type = "password"
|
||
|
|
prompt = "Password"
|
||
|
|
sensitive = true
|
||
|
|
encryption_backend = "rustyvault"
|
||
|
|
|
||
|
|
[fields.encryption_config]
|
||
|
|
vault_addr = "http://localhost:8200"
|
||
|
|
key_path = "transit/keys/typedialog-key"
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Test encryption with RustyVault
|
||
|
|
export VAULT_TOKEN="s.xxxx" # From setup output
|
||
|
|
export VAULT_ADDR="http://localhost:8200"
|
||
|
|
|
||
|
|
typedialog form test_vault_encrypt.toml \
|
||
|
|
--encrypt \
|
||
|
|
--backend rustyvault \
|
||
|
|
--vault-addr http://localhost:8200 \
|
||
|
|
--vault-token "$VAULT_TOKEN" \
|
||
|
|
--vault-key-path "transit/keys/typedialog-key" \
|
||
|
|
--format json
|
||
|
|
|
||
|
|
# Expected output: password field contains vault ciphertext
|
||
|
|
# {"username": "alice", "password": "vault:v1:..."}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part 4: Run Actual Integration Tests
|
||
|
|
|
||
|
|
### Test Case: Age Roundtrip (Encrypt → Decrypt)
|
||
|
|
|
||
|
|
Once Age is set up, these test scenarios validate the pipeline:
|
||
|
|
|
||
|
|
**Scenario 1: Redaction works (no encryption service)**
|
||
|
|
```bash
|
||
|
|
cargo test --test nickel_integration test_encryption_roundtrip_with_redaction -- --nocapture
|
||
|
|
|
||
|
|
# Expected: PASS - redacts sensitive fields
|
||
|
|
```
|
||
|
|
|
||
|
|
**Scenario 2: Metadata mapping works**
|
||
|
|
```bash
|
||
|
|
cargo test --test nickel_integration test_encryption_metadata_to_field_definition -- --nocapture
|
||
|
|
|
||
|
|
# Expected: PASS - EncryptionMetadata maps to FieldDefinition
|
||
|
|
```
|
||
|
|
|
||
|
|
**Scenario 3: Auto-detection of password fields**
|
||
|
|
```bash
|
||
|
|
cargo test --test nickel_integration test_encryption_auto_detection_from_field_type -- --nocapture
|
||
|
|
|
||
|
|
# Expected: PASS - Password fields auto-marked as sensitive
|
||
|
|
```
|
||
|
|
|
||
|
|
### Run All Encryption Tests
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cargo test --test nickel_integration test_encryption -- --nocapture
|
||
|
|
```
|
||
|
|
|
||
|
|
**Current status:**
|
||
|
|
- ✅ 5 tests passing (redaction, metadata mapping)
|
||
|
|
- ⏳ 0 tests for actual Age encryption roundtrip (not yet implemented)
|
||
|
|
- ⏳ 0 tests for RustyVault integration (backend not implemented)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part 5: Troubleshooting
|
||
|
|
|
||
|
|
### Age Issues
|
||
|
|
|
||
|
|
**Problem: `age: command not found`**
|
||
|
|
```bash
|
||
|
|
# Install age
|
||
|
|
brew install age # macOS
|
||
|
|
sudo apt install age # Linux
|
||
|
|
```
|
||
|
|
|
||
|
|
**Problem: Permission denied on ~/.age/key.txt**
|
||
|
|
```bash
|
||
|
|
chmod 600 ~/.age/key.txt
|
||
|
|
```
|
||
|
|
|
||
|
|
**Problem: Invalid key format**
|
||
|
|
```bash
|
||
|
|
# Regenerate keys
|
||
|
|
rm ~/.age/key.txt
|
||
|
|
age-keygen -o ~/.age/key.txt
|
||
|
|
```
|
||
|
|
|
||
|
|
### RustyVault Issues
|
||
|
|
|
||
|
|
**Problem: Docker container won't start**
|
||
|
|
```bash
|
||
|
|
# Check logs
|
||
|
|
docker logs rustyvault
|
||
|
|
|
||
|
|
# Remove and restart
|
||
|
|
docker rm -f rustyvault
|
||
|
|
docker run -d --name rustyvault -p 8200:8200 rustyvault:latest
|
||
|
|
```
|
||
|
|
|
||
|
|
**Problem: Vault initialization fails**
|
||
|
|
```bash
|
||
|
|
# Check if vault is responding
|
||
|
|
curl -s http://localhost:8200/v1/sys/health
|
||
|
|
|
||
|
|
# If not, restart container
|
||
|
|
docker restart rustyvault
|
||
|
|
```
|
||
|
|
|
||
|
|
**Problem: Transit API not working**
|
||
|
|
```bash
|
||
|
|
# Verify token
|
||
|
|
echo $VAULT_TOKEN
|
||
|
|
|
||
|
|
# Check auth
|
||
|
|
curl -s http://localhost:8200/v1/sys/mounts \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Problem: Can't connect from typedialog**
|
||
|
|
```bash
|
||
|
|
# Verify network
|
||
|
|
curl -s http://localhost:8200/v1/sys/health | jq .
|
||
|
|
|
||
|
|
# Check environment variables
|
||
|
|
echo $VAULT_ADDR
|
||
|
|
echo $VAULT_TOKEN
|
||
|
|
|
||
|
|
# Test encryption endpoint
|
||
|
|
curl -s -X POST http://localhost:8200/v1/transit/encrypt/typedialog-key \
|
||
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
||
|
|
-d '{"plaintext": "dGVzdA=="}' | jq .
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Part 6: Next Steps
|
||
|
|
|
||
|
|
Once services are running, implement:
|
||
|
|
|
||
|
|
1. **test_age_encrypt_roundtrip** - Encrypt with Age, decrypt, verify plaintext
|
||
|
|
2. **test_rustyvault_encrypt_roundtrip** - Encrypt with RustyVault, decrypt, verify
|
||
|
|
3. **test_cli_encrypt_age** - Run `typedialog form --encrypt --backend age`, verify output is ciphertext
|
||
|
|
4. **test_cli_encrypt_rustyvault** - Run `typedialog form --encrypt --backend rustyvault`, verify output is ciphertext
|
||
|
|
5. **Integration test script** - Single script that tests all pipelines end-to-end
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## References
|
||
|
|
|
||
|
|
- **Age**: https://github.com/FiloSottile/age
|
||
|
|
- **RustyVault**: https://github.com/Tongsuo-Project/RustyVault
|
||
|
|
- **HashiCorp Vault Transit**: https://www.vaultproject.io/api-docs/secret/transit
|