Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration Encryption Guide

Version: 1.0.0 Last Updated: 2025-10-08 Status: Production Ready

Overview

The Provisioning Platform includes a comprehensive configuration encryption system that provides:

  • Transparent Encryption/Decryption: Configs are automatically decrypted on load
  • Multiple KMS Backends: Age, AWS KMS, HashiCorp Vault, Cosmian KMS
  • Memory-Only Decryption: Secrets never written to disk in plaintext
  • SOPS Integration: Industry-standard encryption with SOPS
  • Sensitive Data Detection: Automatic scanning for unencrypted sensitive data

Table of Contents

  1. Prerequisites
  2. Quick Start
  3. Configuration Encryption
  4. KMS Backends
  5. CLI Commands
  6. Integration with Config Loader
  7. Best Practices
  8. Troubleshooting

Prerequisites

Required Tools

  1. SOPS (v3.10.2+)

    # macOS
    brew install sops
    
    # Linux
    wget https://github.com/mozilla/sops/releases/download/v3.10.2/sops-v3.10.2.linux.amd64
    sudo mv sops-v3.10.2.linux.amd64 /usr/local/bin/sops
    sudo chmod +x /usr/local/bin/sops
    
  2. Age (for Age backend - recommended)

    # macOS
    brew install age
    
    # Linux
    apt install age
    
  3. AWS CLI (for AWS KMS backend - optional)

    brew install awscli
    

Verify Installation

# Check SOPS
sops --version

# Check Age
age --version

# Check AWS CLI (optional)
aws --version

Quick Start

1. Initialize Encryption

Generate Age keys and create SOPS configuration:

provisioning config init-encryption --kms age

This will:

  • Generate Age key pair in ~/.config/sops/age/keys.txt
  • Display your public key (recipient)
  • Create .sops.yaml in your project

2. Set Environment Variables

Add to your shell profile (~/.zshrc or ~/.bashrc):

# Age encryption
export SOPS_AGE_RECIPIENTS="age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"
export PROVISIONING_KAGE="$HOME/.config/sops/age/keys.txt"

Replace the recipient with your actual public key.

3. Validate Setup

provisioning config validate-encryption

Expected output:

✅ Encryption configuration is valid
   SOPS installed: true
   Age backend: true
   KMS enabled: false
   Errors: 0
   Warnings: 0

4. Encrypt Your First Config

# Create a config with sensitive data
cat > workspace/config/secure.yaml <<EOF
database:
  host: localhost
  password: supersecret123
  api_key: key_abc123
EOF

# Encrypt it
provisioning config encrypt workspace/config/secure.yaml --in-place

# Verify it's encrypted
provisioning config is-encrypted workspace/config/secure.yaml

Configuration Encryption

File Naming Conventions

Encrypted files should follow these patterns:

  • *.enc.yaml - Encrypted YAML files
  • *.enc.yml - Encrypted YAML files (alternative)
  • *.enc.toml - Encrypted TOML files
  • secure.yaml - Files in workspace/config/

The .sops.yaml configuration automatically applies encryption rules based on file paths.

Encrypt a Configuration File

Basic Encryption

# Encrypt and create new file
provisioning config encrypt secrets.yaml

# Output: secrets.yaml.enc

In-Place Encryption

# Encrypt and replace original
provisioning config encrypt secrets.yaml --in-place

Specify Output Path

# Encrypt to specific location
provisioning config encrypt secrets.yaml --output workspace/config/secure.enc.yaml

Choose KMS Backend

# Use Age (default)
provisioning config encrypt secrets.yaml --kms age

# Use AWS KMS
provisioning config encrypt secrets.yaml --kms aws-kms

# Use Vault
provisioning config encrypt secrets.yaml --kms vault

Decrypt a Configuration File

# Decrypt to new file
provisioning config decrypt secrets.enc.yaml

# Decrypt in-place
provisioning config decrypt secrets.enc.yaml --in-place

# Decrypt to specific location
provisioning config decrypt secrets.enc.yaml --output plaintext.yaml

Edit Encrypted Files

The system provides a secure editing workflow:

# Edit encrypted file (auto decrypt -> edit -> re-encrypt)
provisioning config edit-secure workspace/config/secure.enc.yaml

This will:

  1. Decrypt the file temporarily
  2. Open in your $EDITOR (vim/nano/etc)
  3. Re-encrypt when you save and close
  4. Remove temporary decrypted file

Check Encryption Status

# Check if file is encrypted
provisioning config is-encrypted workspace/config/secure.yaml

# Get detailed encryption info
provisioning config encryption-info workspace/config/secure.yaml

KMS Backends

Pros:

  • Simple file-based keys
  • No external dependencies
  • Fast and secure
  • Works offline

Setup:

# Initialize
provisioning config init-encryption --kms age

# Set environment variables
export SOPS_AGE_RECIPIENTS="age1..."  # Your public key
export PROVISIONING_KAGE="$HOME/.config/sops/age/keys.txt"

Encrypt/Decrypt:

provisioning config encrypt secrets.yaml --kms age
provisioning config decrypt secrets.enc.yaml

AWS KMS (Production)

Pros:

  • Centralized key management
  • Audit logging
  • IAM integration
  • Key rotation

Setup:

  1. Create KMS key in AWS Console
  2. Configure AWS credentials:
    aws configure
    
  3. Update .sops.yaml:
    creation_rules:
      - path_regex: .*\.enc\.yaml$
        kms: "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
    

Encrypt/Decrypt:

provisioning config encrypt secrets.yaml --kms aws-kms
provisioning config decrypt secrets.enc.yaml

HashiCorp Vault (Enterprise)

Pros:

  • Dynamic secrets
  • Centralized secret management
  • Audit logging
  • Policy-based access

Setup:

  1. Configure Vault address and token:

    export VAULT_ADDR="https://vault.example.com:8200"
    export VAULT_TOKEN="s.xxxxxxxxxxxxxx"
    
  2. Update configuration:

    # workspace/config/provisioning.yaml
    kms:
      enabled: true
      mode: "remote"
      vault:
        address: "https://vault.example.com:8200"
        transit_key: "provisioning"
    

Encrypt/Decrypt:

provisioning config encrypt secrets.yaml --kms vault
provisioning config decrypt secrets.enc.yaml

Cosmian KMS (Confidential Computing)

Pros:

  • Confidential computing support
  • Zero-knowledge architecture
  • Post-quantum ready
  • Cloud-agnostic

Setup:

  1. Deploy Cosmian KMS server
  2. Update configuration:
    kms:
      enabled: true
      mode: "remote"
      remote:
        endpoint: "https://kms.example.com:9998"
        auth_method: "certificate"
        client_cert: "/path/to/client.crt"
        client_key: "/path/to/client.key"
    

Encrypt/Decrypt:

provisioning config encrypt secrets.yaml --kms cosmian
provisioning config decrypt secrets.enc.yaml

CLI Commands

Configuration Encryption Commands

CommandDescription
config encrypt <file>Encrypt configuration file
config decrypt <file>Decrypt configuration file
config edit-secure <file>Edit encrypted file securely
config rotate-keys <file> <key>Rotate encryption keys
config is-encrypted <file>Check if file is encrypted
config encryption-info <file>Show encryption details
config validate-encryptionValidate encryption setup
config scan-sensitive <dir>Find unencrypted sensitive configs
config encrypt-all <dir>Encrypt all sensitive configs
config init-encryptionInitialize encryption (generate keys)

Examples

# Encrypt workspace config
provisioning config encrypt workspace/config/secure.yaml --in-place

# Edit encrypted file
provisioning config edit-secure workspace/config/secure.yaml

# Scan for unencrypted sensitive configs
provisioning config scan-sensitive workspace/config --recursive

# Encrypt all sensitive configs in workspace
provisioning config encrypt-all workspace/config --kms age --recursive

# Check encryption status
provisioning config is-encrypted workspace/config/secure.yaml

# Get detailed info
provisioning config encryption-info workspace/config/secure.yaml

# Validate setup
provisioning config validate-encryption

Integration with Config Loader

Automatic Decryption

The config loader automatically detects and decrypts encrypted files:

# Load encrypted config (automatically decrypted in memory)
use lib_provisioning/config/loader.nu

let config = (load-provisioning-config --debug)

Key Features:

  • Transparent: No code changes needed
  • Memory-Only: Decrypted content never written to disk
  • Fallback: If decryption fails, attempts to load as plain file
  • Debug Support: Shows decryption status with --debug flag

Manual Loading

use lib_provisioning/config/encryption.nu

# Load encrypted config
let secure_config = (load-encrypted-config "workspace/config/secure.enc.yaml")

# Memory-only decryption (no file created)
let decrypted_content = (decrypt-config-memory "workspace/config/secure.enc.yaml")

Configuration Hierarchy with Encryption

The system supports encrypted files at any level:

1. workspace/{name}/config/provisioning.yaml        ← Can be encrypted
2. workspace/{name}/config/providers/*.toml         ← Can be encrypted
3. workspace/{name}/config/platform/*.toml          ← Can be encrypted
4. ~/.../provisioning/ws_{name}.yaml                ← Can be encrypted
5. Environment variables (PROVISIONING_*)           ← Plain text

Best Practices

1. Encrypt All Sensitive Data

Always encrypt configs containing:

  • Passwords
  • API keys
  • Secret keys
  • Private keys
  • Tokens
  • Credentials

Scan for unencrypted sensitive data:

provisioning config scan-sensitive workspace --recursive

2. Use Appropriate KMS Backend

EnvironmentRecommended Backend
DevelopmentAge (file-based)
StagingAWS KMS or Vault
ProductionAWS KMS or Vault
CI/CDAWS KMS with IAM roles

3. Key Management

Age Keys:

  • Store private keys securely: ~/.config/sops/age/keys.txt
  • Set file permissions: chmod 600 ~/.config/sops/age/keys.txt
  • Backup keys securely (encrypted backup)
  • Never commit private keys to git

AWS KMS:

  • Use separate keys per environment
  • Enable key rotation
  • Use IAM policies for access control
  • Monitor usage with CloudTrail

Vault:

  • Use transit engine for encryption
  • Enable audit logging
  • Implement least-privilege policies
  • Regular policy reviews

4. File Organization

workspace/
└── config/
    ├── provisioning.yaml         # Plain (no secrets)
    ├── secure.yaml                # Encrypted (SOPS auto-detects)
    ├── providers/
    │   ├── aws.toml               # Plain (no secrets)
    │   └── aws-credentials.enc.toml  # Encrypted
    └── platform/
        └── database.enc.yaml      # Encrypted

5. Git Integration

Add to .gitignore:

# Unencrypted sensitive files
**/secrets.yaml
**/credentials.yaml
**/*.dec.yaml
**/*.dec.toml

# Temporary decrypted files
*.tmp.yaml
*.tmp.toml

Commit encrypted files:

# Encrypted files are safe to commit
git add workspace/config/secure.enc.yaml
git commit -m "Add encrypted configuration"

6. Rotation Strategy

Regular Key Rotation:

# Generate new Age key
age-keygen -o ~/.config/sops/age/keys-new.txt

# Update .sops.yaml with new recipient

# Rotate keys for file
provisioning config rotate-keys workspace/config/secure.yaml <new-key-id>

Frequency:

  • Development: Annually
  • Production: Quarterly
  • After team member departure: Immediately

7. Audit and Monitoring

Track encryption status:

# Regular scans
provisioning config scan-sensitive workspace --recursive

# Validate encryption setup
provisioning config validate-encryption

Monitor access (with Vault/AWS KMS):

  • Enable audit logging
  • Review access patterns
  • Alert on anomalies

Troubleshooting

SOPS Not Found

Error:

SOPS binary not found

Solution:

# Install SOPS
brew install sops

# Verify
sops --version

Age Key Not Found

Error:

Age key file not found: ~/.config/sops/age/keys.txt

Solution:

# Generate new key
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt

# Set environment variable
export PROVISIONING_KAGE="$HOME/.config/sops/age/keys.txt"

SOPS_AGE_RECIPIENTS Not Set

Error:

no AGE_RECIPIENTS for file.yaml

Solution:

# Extract public key from private key
grep "public key:" ~/.config/sops/age/keys.txt

# Set environment variable
export SOPS_AGE_RECIPIENTS="age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"

Decryption Failed

Error:

Failed to decrypt configuration file

Solutions:

  1. Wrong key:

    # Verify you have the correct private key
    provisioning config validate-encryption
    
  2. File corrupted:

    # Check file integrity
    sops --decrypt workspace/config/secure.yaml
    
  3. Wrong backend:

    # Check SOPS metadata in file
    head -20 workspace/config/secure.yaml
    

AWS KMS Access Denied

Error:

AccessDeniedException: User is not authorized to perform: kms:Decrypt

Solution:

# Check AWS credentials
aws sts get-caller-identity

# Verify KMS key policy allows your IAM user/role
aws kms describe-key --key-id <key-arn>

Vault Connection Failed

Error:

Vault encryption failed: connection refused

Solution:

# Verify Vault address
echo $VAULT_ADDR

# Check connectivity
curl -k $VAULT_ADDR/v1/sys/health

# Verify token
vault token lookup

Security Considerations

Threat Model

Protected Against:

  • ✅ Plaintext secrets in git
  • ✅ Accidental secret exposure
  • ✅ Unauthorized file access
  • ✅ Key compromise (with rotation)

Not Protected Against:

  • ❌ Memory dumps during decryption
  • ❌ Root/admin access to running process
  • ❌ Compromised Age/KMS keys
  • ❌ Social engineering

Security Best Practices

  1. Principle of Least Privilege: Only grant decryption access to those who need it
  2. Key Separation: Use different keys for different environments
  3. Regular Audits: Review who has access to keys
  4. Secure Key Storage: Never store private keys in git
  5. Rotation: Regularly rotate encryption keys
  6. Monitoring: Monitor decryption operations (with AWS KMS/Vault)

Additional Resources

  • SOPS Documentation: https://github.com/mozilla/sops
  • Age Encryption: https://age-encryption.org/
  • AWS KMS: https://aws.amazon.com/kms/
  • HashiCorp Vault: https://www.vaultproject.io/
  • Cosmian KMS: https://www.cosmian.com/

Support

For issues or questions:

  • Check troubleshooting section above
  • Run: provisioning config validate-encryption
  • Review logs with --debug flag

Last Updated: 2025-10-08 Version: 1.0.0