#!/usr/bin/env nu # Unified secrets management orchestrator # Manages complete SOPS + vault-service workflow for all environments # Usage: secrets-manage [options] use std log def get-vault-url [] { $env.VAULT_SERVICE_URL? // "http://localhost:9094" } def get-vault-token [] { $env.VAULT_SERVICE_TOKEN? // "" } def check-vault-connectivity [] { let url = get-vault-url let health_url = $"($url)/health" let response = (http get $health_url | complete) if $response.exit_code != 0 { error make { msg: "Vault service unreachable" label: { text: $"Cannot connect to ($health_url)" } } } true } def list-environments [] { ["dev", "staging", "prod"] } def check-environment-setup [environment: string] { let token = (get-vault-token) if ($token | is-empty) { print $"⚠️ VAULT_SERVICE_TOKEN not set (required for operations)" } let vault_url = (get-vault-url) print $"Environment: ($environment)" print $"Vault URL: ($vault_url)" print $"Token: $(if ($token | is-empty) { "not set" } else { "set" })" } def status [] { print "" print "====== SOPS + Vault-Service Status ======" print "" let connectivity_ok = (check-vault-connectivity) print $"✓ Vault-service connectivity: OK" print "" print "Available environments:" list-environments | each {|env_name| print $" • ($env_name)" } print "" print "Setup:" check-environment-setup "current" print "" } def init [environment: string] { if $environment not-in (list-environments) { error make { msg: "Invalid environment" label: { text: "Must be: dev, staging, or prod" } } } print "" print $"====== Initialize SOPS for ($environment) ======" print "" print "Step 1: Checking vault-service connectivity..." check-vault-connectivity print "✓ Vault-service is accessible" print "" print "Step 2: Generating .sops.yaml configuration..." let sops_init_result = ( nu provisioning/scripts/sops-init.nu --environment $environment --validate ) if ($sops_init_result.success) { print $"✓ SOPS configuration: ($sops_init_result.output_path)" } else { error make { msg: "Failed to generate SOPS configuration" label: { text: $sops_init_result } } } print "" print $"====== ($environment) environment initialized ======" print "" print "Next steps:" print " 1. Verify .sops.yaml: cat $sops_init_result.output_path" print " 2. Encrypt files: provisioning/scripts/secrets-encrypt.nu --environment $environment" print " 3. Commit to Git: git add config/secrets/$environment/" print "" } def encrypt [file: string, environment: string] { if not ($file | path exists) { error make { msg: "File not found" label: { text: $file } } } print "" print $"====== Encrypt ($file) for ($environment) ======" print "" let result = ( nu provisioning/scripts/secrets-encrypt.nu $file --environment $environment ) if ($result.success) { print $"✓ Encrypted: ($result.output)" print $"Ready to commit: git add ($result.output)" } else { error make { msg: "Encryption failed" } } print "" } def decrypt [file: string, environment: string] { if not ($file | path exists) { error make { msg: "File not found" label: { text: $file } } } print "" print $"====== Decrypt ($file) for ($environment) ======" print "⚠️ SENSITIVE OPERATION: Private key will be retrieved" print "" let token = (get-vault-token) if ($token | is-empty) { error make { msg: "VAULT_SERVICE_TOKEN required for decryption" label: { text: "Set environment variable" } } } let result = ( nu provisioning/scripts/secrets-decrypt.nu $file --environment $environment ) if ($result.success) { print $"✓ Decrypted: ($result.output)" print "⚠️ REMEMBER: Delete decrypted file after use" } else { error make { msg: "Decryption failed" } } print "" } def rotate [environment: string] { if $environment not-in (list-environments) { error make { msg: "Invalid environment" label: { text: "Must be: dev, staging, or prod" } } } print "" print $"====== Key Rotation for ($environment) ======" print "⚠️ This operation will:" print " 1. Generate new Age keypair in vault-service" print " 2. Re-encrypt all SOPS files with new key" print " 3. Update key version tracking" print "" let token = (get-vault-token) if ($token | is-empty) { error make { msg: "VAULT_SERVICE_TOKEN required for key rotation" label: { text: "Set environment variable" } } } let result = ( nu provisioning/scripts/secrets-rotate-keys.nu --environment $environment ) if ($result.success) { print $"✓ Key rotation complete" print $" Previous version: ($result.previous_version)" print $" New version: ($result.new_version)" print $" Files updated: ($result.files_updated)" if ($result.files_failed > 0) { print $" ⚠️ Files failed: ($result.files_failed)" } print "" print "Verification step:" print $" ($result.next_steps)" } else { error make { msg: "Key rotation failed" } } print "" } def main [ action: string = "status" file: string = "" --environment: string = "dev" ] { match $action { "status" => (status), "init" => (init $environment), "encrypt" => { if ($file | is-empty) { error make { msg: "File required for encrypt action" } } (encrypt $file $environment) }, "decrypt" => { if ($file | is-empty) { error make { msg: "File required for decrypt action" } } (decrypt $file $environment) }, "rotate" => (rotate $environment), "help" => { print "Secrets Management Orchestrator" print "" print "Usage: secrets-manage [file] [--environment dev|staging|prod]" print "" print "Actions:" print " status - Show SOPS + vault-service status" print " init - Initialize environment (generate .sops.yaml)" print " encrypt - Encrypt configuration file" print " decrypt - Decrypt SOPS file (requires token)" print " rotate - Rotate Age keys (requires token)" print " help - Show this help message" print "" print "Examples:" print " secrets-manage status" print " secrets-manage init --environment prod" print " secrets-manage encrypt config.yaml --environment dev" print " secrets-manage decrypt config.enc.yaml --environment dev" print " secrets-manage rotate --environment prod" }, _ => { print $"Unknown action: ($action)" print "Run 'secrets-manage help' for available commands" } } }