112 lines
3 KiB
Text
Executable file
112 lines
3 KiB
Text
Executable file
#!/usr/bin/env nu
|
|
# SOPS decryption with vault-service age keys
|
|
# Decrypts SOPS-encrypted files using Age private key from vault-service
|
|
# Usage: secrets-decrypt <file> [--environment dev|staging|prod] [--output <file>]
|
|
|
|
use std log
|
|
|
|
def get-vault-url [] {
|
|
$env.VAULT_SERVICE_URL? // "http://localhost:9094"
|
|
}
|
|
|
|
def get-vault-token [] {
|
|
$env.VAULT_SERVICE_TOKEN? // ""
|
|
}
|
|
|
|
def fetch-age-private-key [environment: string] {
|
|
let url = $"(get-vault-url)/api/v1/age/get-private?env=($environment)"
|
|
let token = (get-vault-token)
|
|
|
|
if ($token | is-empty) {
|
|
error make {
|
|
msg: "VAULT_SERVICE_TOKEN required for private key retrieval"
|
|
label: {
|
|
text: "Set environment variable or pass token"
|
|
span: (metadata $environment).span
|
|
}
|
|
}
|
|
}
|
|
|
|
let response = (http get -H {"X-Vault-Token": $token} $url | complete)
|
|
|
|
if $response.exit_code != 0 {
|
|
error make {
|
|
msg: "Failed to fetch age private key"
|
|
label: {
|
|
text: "vault-service rejected request (check token and permissions)"
|
|
span: (metadata $environment).span
|
|
}
|
|
}
|
|
}
|
|
|
|
let json = ($response.stdout | from json)
|
|
$json.private_key
|
|
}
|
|
|
|
def main [
|
|
file: string
|
|
--environment: string = "dev"
|
|
--output: string = ""
|
|
] {
|
|
let input_path = if ($file | path exists) {
|
|
$file
|
|
} else {
|
|
error make {
|
|
msg: "File not found"
|
|
label: {
|
|
text: $file
|
|
span: (metadata $file).span
|
|
}
|
|
}
|
|
}
|
|
|
|
# Validate environment
|
|
if $environment not-in ["dev", "staging", "prod"] {
|
|
error make {
|
|
msg: "Invalid environment"
|
|
label: {
|
|
text: "Must be: dev, staging, or prod"
|
|
span: (metadata $file).span
|
|
}
|
|
}
|
|
}
|
|
|
|
let output_path = if ($output | is-empty) {
|
|
let base = ($input_path | str replace '.enc' '')
|
|
$"($base).dec"
|
|
} else {
|
|
$output
|
|
}
|
|
|
|
print $"SENSITIVE: Fetching Age private key for ($environment) from vault-service..."
|
|
let privkey = (fetch-age-private-key $environment)
|
|
print "✓ Age private key retrieved (check audit logs for access tracking)"
|
|
|
|
print $"Decrypting ($input_path) with SOPS..."
|
|
let result = (
|
|
with-env {"SOPS_AGE_KEY": $privkey} {
|
|
^sops --decrypt --input-type "yaml" --output-type "yaml" --output $output_path $input_path
|
|
| complete
|
|
}
|
|
)
|
|
|
|
if $result.exit_code != 0 {
|
|
let stderr = $result.stderr
|
|
error make {
|
|
msg: "SOPS decryption failed"
|
|
label: {
|
|
text: $stderr
|
|
span: (metadata $file).span
|
|
}
|
|
}
|
|
}
|
|
|
|
print $"✓ Decrypted file: ($output_path)"
|
|
{
|
|
success: true
|
|
input: $input_path
|
|
output: $output_path
|
|
environment: $environment
|
|
message: "Private key was used from vault-service and is NOT stored locally"
|
|
}
|
|
}
|