Jesús Pérez aca491ba42
feat(encryption): integrate external encryption services with Nickel contracts
ADDED:
- encryption_bridge.rs: Service integration layer
- encryption_contract_parser.rs: Nickel contract parsing
- encryption_integration.rs: Integration tests (+442 lines)
- docs/ENCRYPTION-*.md: Quick start, setup, architecture
- examples/08-encryption: Usage examples
- scripts/encryption-test-setup.sh: Provisioning

MODIFIED:
- helpers.rs: +570 lines utility functions
- nickel/: Enhanced contract parsing & serialization
- form_parser.rs: Constraint interpolation improvements
- config/mod.rs: New configuration (+24 lines)
- typedialog/src/main.rs: CLI updates (+83 lines)
- Cargo.toml: encryption_bridge dependency
- Cargo.lock, SBOMs: Updated

AFFECTED BACKENDS: cli, tui, web (core-level changes)
2025-12-22 10:40:01 +00:00

8.5 KiB

SOPS + typedialog Integration Demo

Complete walkthrough of using SOPS backend with typedialog encryption.

Quick Start (5 minutes)

1. Install Prerequisites

# Install SOPS
brew install sops

# Verify installation
sops --version
which age-keygen

2. Setup SOPS Configuration

SOPS requires a .sops.yaml configuration file. For testing, we'll use Age (no external KMS).

Create .sops.yaml in your project root:

# Generate an Age key for SOPS
age-keygen -o ~/.age/sops-key.txt

# Extract public key
grep "^# public key:" ~/.age/sops-key.txt
# Output: # public key: age1xxxxxxxxxxxxxxxxxxxxxx

# Create .sops.yaml
cat > .sops.yaml << 'EOF'
creation_rules:
  - path_regex: .*
    age: age1xxxxxxxxxxxxxxxxxxxxxx  # Replace with your public key
EOF

# Verify config
cat .sops.yaml

3. Test SOPS Encryption Manually

# Create a test file
echo 'secret: my-password-123' > test-secret.yaml

# Encrypt with SOPS
sops -e -i test-secret.yaml

# View encrypted content (should look like YAML but encrypted)
cat test-secret.yaml

# Decrypt to verify
export SOPS_AGE_KEY_FILE=~/.age/sops-key.txt
sops -d test-secret.yaml

# Cleanup
rm test-secret.yaml

Expected Output:

secret: ENC[AES256_GCM,data:xxxxx,iv:xxxxx,tag:xxxxx,type:str]
sops:
    version: 3.9.0
    ...

When you decrypt, you should see:

secret: my-password-123

4. Test typedialog with SOPS

# Option A: Interactive (uses stdin)
typedialog form examples/08-encryption/simple-login.toml \
  --encrypt --backend sops \
  --format json

# You'll be prompted for:
#   Username: alice
#   Password: secretpass123

# Option B: Verify encryption works (redaction test)
typedialog form examples/08-encryption/simple-login.toml \
  --redact \
  --format json

# Output should show:
# {
#   "username": "alice",
#   "password": "[REDACTED]"
# }

5. Verify SOPS Ciphertext Format

After encryption, check the output format:

# The encrypted password should look like:
# "sops:v1:4f5a6b7c8d9e0f1a2b3c4d5e6f..."

# This format is:
#   - sops:v1: version prefix
#   - hex-encoded encrypted YAML content

# You can verify it's hex:
echo "4f5a6b7c8d9e0f1a" | xxd -r -p

Advanced: Multi-Backend Configuration

Using SOPS for Database Credentials

Edit examples/08-encryption/credentials.toml:

[[fields]]
name = "db_password"
type = "password"
prompt = "Database password"
required = true
sensitive = true
encryption_backend = "sops"
# SOPS reads configuration from .sops.yaml
# No additional config needed

Run with SOPS:

typedialog form examples/08-encryption/credentials.toml \
  --encrypt --backend sops \
  --format json

Field-Level Encryption

Different fields can use different backends:

# Field 1: Age encryption (local)
[[fields]]
name = "api_key"
type = "text"
sensitive = true
encryption_backend = "age"

# Field 2: SOPS encryption (team-friendly)
[[fields]]
name = "db_password"
type = "password"
sensitive = true
encryption_backend = "sops"

# Field 3: AWS KMS (enterprise)
[[fields]]
name = "master_key"
type = "password"
sensitive = true
encryption_backend = "awskms"

[fields.encryption_config]
region = "us-east-1"
key_id = "arn:aws:kms:us-east-1:..."

Same form, different backends per field! 🎉


SOPS with AWS KMS (Production Setup)

To use SOPS with AWS KMS instead of Age:

1. Configure .sops.yaml for AWS KMS

cat > .sops.yaml << 'EOF'
creation_rules:
  - path_regex: .*
    kms: arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012
    aws_region: us-east-1
EOF

2. Configure AWS Credentials

# Option A: AWS CLI
aws configure
export AWS_REGION=us-east-1

# Option B: Environment variables
export AWS_ACCESS_KEY_ID=xxxxx
export AWS_SECRET_ACCESS_KEY=xxxxx
export AWS_REGION=us-east-1

# Option C: IAM Role (on EC2/ECS)
# Credentials automatically detected

3. Test with SOPS

# Create test file
echo 'secret: my-secret' > test.yaml

# Encrypt with AWS KMS
sops -e -i test.yaml

# Decrypt (requires AWS credentials and KMS permissions)
sops -d test.yaml

# Use with typedialog
typedialog form examples/08-encryption/simple-login.toml \
  --encrypt --backend sops \
  --format json

SOPS with GCP KMS

1. Configure .sops.yaml for GCP KMS

cat > .sops.yaml << 'EOF'
creation_rules:
  - path_regex: .*
    gcp_kms:
      - resource_id: projects/MY_PROJECT/locations/global/keyRings/MY_KEYRING/cryptoKeys/MY_KEY
EOF

2. Configure GCP Credentials

# Option A: Service account key
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json

# Option B: gcloud authentication
gcloud auth application-default login

3. Test

sops -e -i test.yaml
sops -d test.yaml

Troubleshooting

Problem: "no identity matched key"

Cause: SOPS can't find the Age key

Solution:

# Set the Age key file
export SOPS_AGE_KEY_FILE=~/.age/sops-key.txt

# Or verify the key exists
ls -la ~/.age/sops-key.txt

# Or check .sops.yaml has correct public key
cat .sops.yaml
grep "^# public key:" ~/.age/sops-key.txt

Problem: "config file not found"

Cause: .sops.yaml not found in current directory or parent

Solution:

# Verify .sops.yaml exists
cat .sops.yaml

# Or create it
cat > .sops.yaml << 'EOF'
creation_rules:
  - path_regex: .*
    age: age1xxxxxxxxxxxxxxxxxxxxxx
EOF

Problem: typedialog says "SOPS encryption error: config file not found"

Cause: Same as above - SOPS config not found

Solution:

# Create .sops.yaml in the directory where you run typedialog
cat > .sops.yaml << 'EOF'
creation_rules:
  - path_regex: .*
    age: age1xxxxxxxxxxxxxxxxxxxxxx
EOF

# Then run typedialog in the same directory
typedialog form examples/08-encryption/simple-login.toml \
  --encrypt --backend sops --format json

Problem: "Backend 'sops' not available"

Cause: SOPS feature not enabled or sops binary not installed

Solution:

# Install sops
brew install sops

# Or rebuild typedialog with SOPS feature
cargo build --features encryption,sops

Testing Commands

Quick Verification (No Encryption Service Required)

# Redaction only - no SOPS needed
typedialog form examples/08-encryption/simple-login.toml --redact --format json

# Check Age backend (local)
age-keygen -o ~/.age/key.txt
typedialog form examples/08-encryption/simple-login.toml \
  --encrypt --backend age --key-file ~/.age/key.txt --format json

With SOPS Backend

# Setup (one-time)
age-keygen -o ~/.age/sops-key.txt
cat > .sops.yaml << 'EOF'
creation_rules:
  - path_regex: .*
    age: $(grep "^# public key:" ~/.age/sops-key.txt | sed 's/# public key: //')
EOF

# Test SOPS directly
echo 'secret: test' > test.yaml
export SOPS_AGE_KEY_FILE=~/.age/sops-key.txt
sops -e -i test.yaml
sops -d test.yaml

# Test with typedialog
typedialog form examples/08-encryption/simple-login.toml \
  --encrypt --backend sops --format json

Full Integration Test

# Run the integration test script
bash examples/08-encryption/sops-integration-test.sh

Output Examples

Redaction (No Service Required)

$ typedialog form examples/08-encryption/simple-login.toml --redact --format json
{
  "username": "alice",
  "password": "[REDACTED]"
}

Age Encryption

$ typedialog form examples/08-encryption/simple-login.toml \
    --encrypt --backend age --key-file ~/.age/key.txt --format json
{
  "username": "alice",
  "password": "age1muz6ah54ew9am7mzmy0m4w5arcegt056l9448sqy5ju27q5qaf3qjv35tr"
}

SOPS Encryption

$ typedialog form examples/08-encryption/simple-login.toml \
    --encrypt --backend sops --format json
{
  "username": "alice",
  "password": "sops:v1:4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f"
}

Key Points

SOPS Features:

  • Multi-KMS support (AWS, GCP, Azure) via .sops.yaml
  • File-based encryption (YAML/JSON/TOML)
  • Git-friendly (diffs show plaintext)
  • Team collaboration (shared key management)
  • Partial encryption (only sensitive fields)

typedialog Integration:

  • Field-level backend selection
  • Mixed backend support (Age + SOPS + KMS)
  • Automatic encryption/decryption
  • Transparent to user code

Deployment:

  • Dev: Age (local, no external service)
  • Staging: SOPS (team KMS)
  • Prod: AWS/GCP/Azure KMS (enterprise)

See Also