# Configuration Encryption CLI Commands # Provides user-friendly commands for config encryption operations use encryption.nu * use accessor.nu * # Encrypt a configuration file export def "config encrypt" [ file: path # Configuration file to encrypt --output (-o): path # Output path (default: .enc) --kms (-k): string = "age" # KMS backend: age, aws-kms, vault, cosmian --in-place (-i) # Encrypt in-place (overwrites original) --debug (-d) # Enable debug output ] { if not ($file | path exists) { print $"āŒ File not found: ($file)" return } print $"šŸ”’ Encrypting configuration file: ($file)" print $" Backend: ($kms)" if $in_place { print $" Mode: In-place (will overwrite original)" } else if ($output | is-not-empty) { print $" Output: ($output)" } else { print $" Output: ($file).enc" } try { if $in_place { encrypt-config $file --kms=$kms --in-place --debug=$debug } else { encrypt-config $file $output --kms=$kms --debug=$debug } } catch { |err| print $"āŒ Encryption failed: ($err.msg)" } } # Decrypt a configuration file export def "config decrypt" [ file: path # Encrypted configuration file --output (-o): path # Output path (default: removes .enc extension) --in-place (-i) # Decrypt in-place (overwrites original) --debug (-d) # Enable debug output ] { if not ($file | path exists) { print $"āŒ File not found: ($file)" return } print $"šŸ”“ Decrypting configuration file: ($file)" try { if $in_place { decrypt-config $file --in-place --debug=$debug } else { decrypt-config $file $output --debug=$debug } } catch { |err| print $"āŒ Decryption failed: ($err.msg)" } } # Edit encrypted configuration file securely export def "config edit-secure" [ file: path # Encrypted configuration file --editor (-e): string # Editor to use (default: $EDITOR or vim) --debug (-d) # Enable debug output ] { if not ($file | path exists) { print $"āŒ File not found: ($file)" return } try { if ($editor | is-not-empty) { edit-encrypted-config $file --editor=$editor --debug=$debug } else { edit-encrypted-config $file --debug=$debug } } catch { |err| print $"āŒ Edit failed: ($err.msg)" } } # Rotate encryption keys for a configuration file export def "config rotate-keys" [ file: path # Encrypted configuration file new_key: string # New key ID or recipient --debug (-d) # Enable debug output ] { if not ($file | path exists) { print $"āŒ File not found: ($file)" return } print $"šŸ”„ Rotating encryption keys" print $" File: ($file)" print $" New key: ($new_key)" try { rotate-encryption-keys $file $new_key --debug=$debug } catch { |err| print $"āŒ Key rotation failed: ($err.msg)" } } # Check if a configuration file is encrypted export def "config is-encrypted" [ file: path # Configuration file to check ] { if not ($file | path exists) { print $"āŒ File not found: ($file)" return } let encrypted = (is-encrypted-config $file) if $encrypted { print $"šŸ”’ File is encrypted: ($file)" } else { print $"šŸ”“ File is not encrypted: ($file)" } $encrypted } # Validate encryption configuration and setup export def "config validate-encryption" [] { print $"šŸ” Validating encryption configuration..." print "" let validation = (validate-encryption-config) # Show summary print $"šŸ“Š Encryption Configuration Summary" print $"==================================" print $" SOPS installed: ($validation.summary.sops_installed)" print $" Age backend: ($validation.summary.age_backend)" print $" KMS enabled: ($validation.summary.kms_enabled)" print $" Errors: ($validation.summary.total_errors)" print $" Warnings: ($validation.summary.total_warnings)" print "" # Show errors if ($validation.errors | length) > 0 { print $"āŒ Errors:" for error in $validation.errors { print $" • ($error.message)" } print "" } # Show warnings if ($validation.warnings | length) > 0 { print $"āš ļø Warnings:" for warning in $validation.warnings { print $" • ($warning.message)" } print "" } if $validation.valid { print $"āœ… Encryption configuration is valid" } else { print $"āŒ Encryption configuration has errors" } $validation } # Scan directory for unencrypted sensitive configurations export def "config scan-sensitive" [ directory: path = "." # Directory to scan --recursive (-r) # Scan recursively ] { if not ($directory | path exists) { print $"āŒ Directory not found: ($directory)" return } print $"šŸ” Scanning for unencrypted sensitive configs in: ($directory)" let results = (scan-unencrypted-configs $directory --recursive=$recursive) if ($results | is-empty) { print $"āœ… No unencrypted sensitive configs found" } else { print $"\nāš ļø Found ($results | length) unencrypted sensitive configs:" print "" print $results print "" print $"šŸ’” Run 'config encrypt-all ($directory)' to encrypt them" } $results } # Encrypt all sensitive configurations in directory export def "config encrypt-all" [ directory: path = "." # Directory to encrypt --kms (-k): string = "age" # KMS backend: age, aws-kms, vault, cosmian --recursive (-r) # Scan recursively --dry-run (-n) # Dry run (no actual encryption) ] { if not ($directory | path exists) { print $"āŒ Directory not found: ($directory)" return } try { encrypt-sensitive-configs $directory --kms=$kms --recursive=$recursive --dry-run=$dry_run } catch { |err| print $"āŒ Bulk encryption failed: ($err.msg)" } } # Show encryption information for configuration export def "config encryption-info" [ file: path # Configuration file ] { if not ($file | path exists) { print $"āŒ File not found: ($file)" return } print $"šŸ“‹ Encryption Information" print $"========================" print $" File: ($file)" let encrypted = (is-encrypted-config $file) print $" Encrypted: ($encrypted)" if $encrypted { # Try to extract SOPS metadata try { let content = (open $file --raw) if ($content | str contains "sops:") { print $" Type: SOPS encrypted" # Extract some metadata (without decrypting) if ($content | str contains "age:") { print $" Backend: Age" } if ($content | str contains "kms:") { print $" Backend: AWS KMS" } if ($content | str contains "vault:") { print $" Backend: Vault" } } } catch { print $" Type: Encrypted (unknown format)" } } else { let sensitive = (contains-sensitive-data $file) print $" Contains sensitive data: ($sensitive)" if $sensitive { print "" print $"āš ļø This file contains sensitive data but is not encrypted!" print $"šŸ’” Run 'config encrypt ($file)' to encrypt it" } } } # Initialize encryption setup (generate keys, create SOPS config) export def "config init-encryption" [ --kms (-k): string = "age" # KMS backend to initialize: age, aws-kms, vault --force (-f) # Force re-initialization ] { print $"šŸ”§ Initializing encryption setup with ($kms)" print "" match $kms { "age" => { # Check if age is installed let age_check = (^which age | complete) if $age_check.exit_code != 0 { print $"āŒ Age is not installed" print $"šŸ’” Install with: brew install age" return } # Generate age key if not exists let age_key_file = ($env.HOME | path join ".config" | path join "sops" | path join "age" | path join "keys.txt") let age_key_dir = ($age_key_file | path dirname) if ($age_key_file | path exists) and not $force { print $"āœ… Age key already exists: ($age_key_file)" print $" Use --force to regenerate" } else { # Create directory mkdir $age_key_dir # Generate new age key print $"šŸ”‘ Generating new Age key..." let key_output = (^age-keygen -o $age_key_file | complete) if $key_output.exit_code == 0 { print $"āœ… Age key generated: ($age_key_file)" # Extract recipient let key_content = (open $age_key_file --raw) let recipient = ($key_content | lines | where ($it | str starts-with "# public key:") | first | split row ": " | get 1) print $" Public key (recipient): ($recipient)" print "" print $"šŸ’” Set this environment variable:" print $" export SOPS_AGE_RECIPIENTS=($recipient)" } else { print $"āŒ Failed to generate Age key" return } } # Create .sops.yaml if not exists let sops_config = ($env.PWD | path join ".sops.yaml") if not ($sops_config | path exists) or $force { print $"šŸ“ Creating SOPS configuration: ($sops_config)" let key_content = (open $age_key_file --raw) let recipient = ($key_content | lines | where ($it | str starts-with "# public key:") | first | split row ": " | get 1) let sops_yaml = $"creation_rules: - path_regex: .*\\.enc\\.yaml$ age: ($recipient) - path_regex: .*\\.enc\\.yml$ age: ($recipient) - path_regex: .*\\.enc\\.toml$ age: ($recipient) - path_regex: .*\\.enc\\.json$ age: ($recipient) - path_regex: workspace/.*/config/secure\\.yaml$ age: ($recipient) " $sops_yaml | save --force $sops_config print $"āœ… SOPS configuration created" } } "aws-kms" => { print $"āš ļø AWS KMS requires manual configuration" print $"šŸ’” Follow these steps:" print $" 1. Create KMS key in AWS Console" print $" 2. Update .sops.yaml with KMS ARN" print $" 3. Configure AWS credentials" } "vault" | "cosmian" => { print $"āš ļø ($kms) KMS requires manual configuration" print $"šŸ’” Configure KMS settings in config file" } _ => { print $"āŒ Unknown KMS backend: ($kms)" print $" Supported: age, aws-kms, vault, cosmian" } } print "" print $"āœ… Encryption initialization completed" } # Main help command export def main [] { print "Configuration Encryption Commands" print "=================================" print "" print "Encryption/Decryption:" print " config encrypt Encrypt configuration file" print " config decrypt Decrypt configuration file" print " config edit-secure Edit encrypted file securely" print " config rotate-keys Rotate encryption keys" print "" print "Information:" print " config is-encrypted Check if file is encrypted" print " config encryption-info Show encryption details" print " config validate-encryption Validate encryption setup" print "" print "Bulk Operations:" print " config scan-sensitive Find unencrypted sensitive configs" print " config encrypt-all Encrypt all sensitive configs" print "" print "Setup:" print " config init-encryption Initialize encryption (generate keys)" print "" print "Examples:" print " config encrypt workspace/config/secure.yaml" print " config edit-secure workspace/config/secure.enc.yaml" print " config scan-sensitive workspace/config --recursive" print " config init-encryption --kms age" }