499 lines
13 KiB
Plaintext
Raw Permalink Normal View History

# SecretumVault Plugin Wrapper with HTTP Fallback
# Provides high-level functions for SecretumVault operations with graceful HTTP fallback
use ../config/accessor.nu *
# Check if SecretumVault plugin is available
def is-plugin-available [] {
(which secretumvault | length) > 0
}
# Check if SecretumVault plugin is enabled in config
def is-plugin-enabled [] {
config-get "plugins.secretumvault_enabled" true
}
# Get SecretumVault service URL
def get-secretumvault-url [] {
config-get "kms.secretumvault.server_url" "http://localhost:8200"
}
# Get SecretumVault auth token
def get-secretumvault-token [] {
let token = (
if ($env.SECRETUMVAULT_TOKEN? != null) {
$env.SECRETUMVAULT_TOKEN
} else {
""
}
)
if ($token | is-empty) {
config-get "kms.secretumvault.auth_token" ""
} else {
$token
}
}
# Get SecretumVault mount point
def get-secretumvault-mount-point [] {
config-get "kms.secretumvault.mount_point" "transit"
}
# Get default SecretumVault key name
def get-secretumvault-key-name [] {
config-get "kms.secretumvault.key_name" "provisioning-master"
}
# Helper to safely execute a closure and return null on error
def try-plugin [callback: closure] {
do -i $callback
}
# Encrypt data using SecretumVault plugin
export def plugin-secretumvault-encrypt [
plaintext: string
--key-id: string = "" # Encryption key ID
] {
let enabled = is-plugin-enabled
let available = is-plugin-available
let key_name = if ($key_id | is-empty) { get-secretumvault-key-name } else { $key_id }
if $enabled and $available {
let plugin_result = (try-plugin {
let args = if ($key_id | is-empty) {
[encrypt $plaintext]
} else {
[encrypt $plaintext --key-id $key_id]
}
secretumvault ...$args
})
if $plugin_result != null {
return $plugin_result
}
print "⚠️ Plugin SecretumVault encrypt failed, falling back to HTTP"
}
# HTTP fallback - call SecretumVault service directly
print "⚠️ Using HTTP fallback (plugin not available)"
let sv_url = (get-secretumvault-url)
let sv_token = (get-secretumvault-token)
let mount_point = (get-secretumvault-mount-point)
let url = $"($sv_url)/v1/($mount_point)/encrypt/($key_name)"
if ($sv_token | is-empty) {
error make {
msg: "SecretumVault authentication failed"
label: {
text: "SECRETUMVAULT_TOKEN not set"
span: (metadata $plaintext).span
}
}
}
let result = (do -i {
let plaintext_b64 = ($plaintext | encode base64)
let body = {plaintext: $plaintext_b64}
http post -H ["X-Vault-Token" $sv_token] $url $body
})
if $result != null {
return $result
}
error make {
msg: "SecretumVault encryption failed"
label: {
text: $"Failed to encrypt data with key ($key_name)"
span: (metadata $plaintext).span
}
}
}
# Decrypt data using SecretumVault plugin
export def plugin-secretumvault-decrypt [
ciphertext: string
--key-id: string = "" # Encryption key ID
] {
let enabled = is-plugin-enabled
let available = is-plugin-available
let key_name = if ($key_id | is-empty) { get-secretumvault-key-name } else { $key_id }
if $enabled and $available {
let plugin_result = (try-plugin {
let args = if ($key_id | is-empty) {
[decrypt $ciphertext]
} else {
[decrypt $ciphertext --key-id $key_id]
}
secretumvault ...$args
})
if $plugin_result != null {
return $plugin_result
}
print "⚠️ Plugin SecretumVault decrypt failed, falling back to HTTP"
}
# HTTP fallback - call SecretumVault service directly
print "⚠️ Using HTTP fallback (plugin not available)"
let sv_url = (get-secretumvault-url)
let sv_token = (get-secretumvault-token)
let mount_point = (get-secretumvault-mount-point)
let url = $"($sv_url)/v1/($mount_point)/decrypt/($key_name)"
if ($sv_token | is-empty) {
error make {
msg: "SecretumVault authentication failed"
label: {
text: "SECRETUMVAULT_TOKEN not set"
span: (metadata $ciphertext).span
}
}
}
let result = (do -i {
let body = {ciphertext: $ciphertext}
let response = (http post -H ["X-Vault-Token" $sv_token] $url $body)
if ($response.data.plaintext? != null) {
{
plaintext: ($response.data.plaintext | decode base64),
key_id: ($response.data.key_id? // $key_name)
}
} else {
$response
}
})
if $result != null {
return $result
}
error make {
msg: "SecretumVault decryption failed"
label: {
text: $"Failed to decrypt data with key ($key_name)"
span: (metadata $ciphertext).span
}
}
}
# Generate data key using SecretumVault plugin
export def plugin-secretumvault-generate-key [
--bits: int = 256 # Key size in bits (128, 256, 2048, 4096)
--key-id: string = "" # Encryption key ID
] {
let enabled = is-plugin-enabled
let available = is-plugin-available
let key_name = if ($key_id | is-empty) { get-secretumvault-key-name } else { $key_id }
if $enabled and $available {
let plugin_result = (try-plugin {
let args = if ($key_id | is-empty) {
[generate-key --bits $bits]
} else {
[generate-key --bits $bits --key-id $key_id]
}
secretumvault ...$args
})
if $plugin_result != null {
return $plugin_result
}
print "⚠️ Plugin SecretumVault generate-key failed, falling back to HTTP"
}
# HTTP fallback
print "⚠️ Using HTTP fallback (plugin not available)"
let sv_url = (get-secretumvault-url)
let sv_token = (get-secretumvault-token)
let mount_point = (get-secretumvault-mount-point)
let url = $"($sv_url)/v1/($mount_point)/datakey/plaintext/($key_name)"
if ($sv_token | is-empty) {
error make {
msg: "SecretumVault authentication failed"
label: {
text: "SECRETUMVAULT_TOKEN not set"
}
}
}
let result = (do -i {
let body = {bits: $bits}
http post -H ["X-Vault-Token" $sv_token] $url $body
})
if $result != null {
return $result
}
error make {
msg: "SecretumVault key generation failed"
label: {
text: $"Failed to generate key with ($bits) bits"
}
}
}
# Check SecretumVault health using plugin
export def plugin-secretumvault-health [] {
let enabled = is-plugin-enabled
let available = is-plugin-available
if $enabled and $available {
let plugin_result = (try-plugin {
secretumvault health
})
if $plugin_result != null {
return $plugin_result
}
print "⚠️ Plugin SecretumVault health check failed, falling back to HTTP"
}
# HTTP fallback
print "⚠️ Using HTTP fallback (plugin not available)"
let sv_url = (get-secretumvault-url)
let url = $"($sv_url)/v1/sys/health"
let result = (do -i {
http get $url
})
if $result != null {
return $result
}
{
healthy: false
status: "unavailable"
message: "SecretumVault service unreachable"
}
}
# Get SecretumVault version using plugin
export def plugin-secretumvault-version [] {
let enabled = is-plugin-enabled
let available = is-plugin-available
if $enabled and $available {
let plugin_result = (try-plugin {
secretumvault version
})
if $plugin_result != null {
return $plugin_result
}
print "⚠️ Plugin SecretumVault version failed, falling back to HTTP"
}
# HTTP fallback
print "⚠️ Using HTTP fallback (plugin not available)"
let sv_url = (get-secretumvault-url)
let url = $"($sv_url)/v1/sys/health"
let result = (do -i {
let response = (http get $url)
$response.version? // "unknown"
})
if $result != null {
return $result
}
"unavailable"
}
# Rotate encryption key using plugin
export def plugin-secretumvault-rotate-key [
--key-id: string = "" # Key ID to rotate
] {
let enabled = is-plugin-enabled
let available = is-plugin-available
let key_name = if ($key_id | is-empty) { get-secretumvault-key-name } else { $key_id }
if $enabled and $available {
let plugin_result = (try-plugin {
let args = if ($key_id | is-empty) {
[rotate-key]
} else {
[rotate-key --key-id $key_id]
}
secretumvault ...$args
})
if $plugin_result != null {
return $plugin_result
}
print "⚠️ Plugin SecretumVault rotate-key failed, falling back to HTTP"
}
# HTTP fallback
print "⚠️ Using HTTP fallback (plugin not available)"
let sv_url = (get-secretumvault-url)
let sv_token = (get-secretumvault-token)
let mount_point = (get-secretumvault-mount-point)
let url = $"($sv_url)/v1/($mount_point)/keys/($key_name)/rotate"
if ($sv_token | is-empty) {
error make {
msg: "SecretumVault authentication failed"
label: {
text: "SECRETUMVAULT_TOKEN not set"
span: (metadata $key_name).span
}
}
}
let result = (do -i {
http post -H ["X-Vault-Token" $sv_token] $url
})
if $result != null {
return $result
}
error make {
msg: "SecretumVault key rotation failed"
label: {
text: $"Failed to rotate key ($key_name)"
span: (metadata $key_name).span
}
}
}
# Get SecretumVault plugin status and configuration
export def plugin-secretumvault-info [] {
let plugin_available = is-plugin-available
let plugin_enabled = is-plugin-enabled
let sv_url = get-secretumvault-url
let mount_point = get-secretumvault-mount-point
let key_name = get-secretumvault-key-name
let has_token = (not (get-secretumvault-token | is-empty))
{
plugin_available: $plugin_available
plugin_enabled: $plugin_enabled
service_url: $sv_url
mount_point: $mount_point
default_key: $key_name
authenticated: $has_token
mode: (if ($plugin_enabled and $plugin_available) { "plugin (native)" } else { "http fallback" })
}
}
# Encrypt configuration file using SecretumVault
export def encrypt-config-file [
config_file: string
--output: string = "" # Output file path (default: <file>.enc)
--key-id: string = "" # Encryption key ID
] {
let out_file = if ($output | is-empty) {
$"($config_file).enc"
} else {
$output
}
let result = (do -i {
let content = (open $config_file --raw)
let encrypted = (plugin-secretumvault-encrypt $content --key-id $key_id)
# Save encrypted content
if ($encrypted | type) == "record" {
$encrypted.ciphertext | save --force $out_file
} else {
$encrypted | save --force $out_file
}
print $"✅ Configuration encrypted to: ($out_file)"
{
success: true
input_file: $config_file
output_file: $out_file
key_id: (if ($key_id | is-empty) { (get-secretumvault-key-name) } else { $key_id })
}
})
if $result == null {
error make {
msg: "Failed to encrypt configuration file"
label: {
text: "Check file permissions and SecretumVault service"
span: (metadata $config_file).span
}
}
}
$result
}
# Decrypt configuration file using SecretumVault
export def decrypt-config-file [
encrypted_file: string
--output: string = "" # Output file path (default: <file>.dec)
--key-id: string = "" # Encryption key ID
] {
let out_file = if ($output | is-empty) {
let base_name = ($encrypted_file | str replace '.enc' '')
$"($base_name).dec"
} else {
$output
}
let result = (do -i {
let encrypted_content = (open $encrypted_file --raw)
let decrypted = (plugin-secretumvault-decrypt $encrypted_content --key-id $key_id)
# Save decrypted content
if ($decrypted | type) == "record" {
if ($decrypted.plaintext? != null) {
$decrypted.plaintext | save --force $out_file
} else {
$decrypted | to json | save --force $out_file
}
} else {
$decrypted | save --force $out_file
}
print $"✅ Configuration decrypted to: ($out_file)"
{
success: true
input_file: $encrypted_file
output_file: $out_file
key_id: (if ($key_id | is-empty) { (get-secretumvault-key-name) } else { $key_id })
}
})
if $result == null {
error make {
msg: "Failed to decrypt configuration file"
label: {
text: "Check file permissions and SecretumVault service"
span: (metadata $encrypted_file).span
}
}
}
$result
}