265 lines
7.5 KiB
Text
265 lines
7.5 KiB
Text
#!/usr/bin/env nu
|
|
# Unified secrets management orchestrator
|
|
# Manages complete SOPS + vault-service workflow for all environments
|
|
# Usage: secrets-manage <action> [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 <file> --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 <action> [file] [--environment dev|staging|prod]"
|
|
print ""
|
|
print "Actions:"
|
|
print " status - Show SOPS + vault-service status"
|
|
print " init - Initialize environment (generate .sops.yaml)"
|
|
print " encrypt <file> - Encrypt configuration file"
|
|
print " decrypt <file> - 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"
|
|
}
|
|
}
|
|
}
|