prvng_core/nulib/kms/service.nu
Jesús Pérez 1fe83246d6
feat: integrate enterprise security system into core libraries
Adds KMS, secrets management, config encryption, and auth plugins to enable
zero-trust security architecture across the provisioning platform.
2025-10-09 16:36:27 +01:00

363 lines
8.7 KiB
Plaintext

#!/usr/bin/env nu
# KMS Service CLI Integration
# Provides commands to interact with the KMS service API
# Get KMS service base URL from environment or use default
def kms-url [] -> string {
$env.KMS_SERVICE_URL? | default "http://localhost:8081"
}
# Build KMS API endpoint URL
def kms-endpoint [path: string] -> string {
$"(kms-url)/api/v1/kms/(path)"
}
# Encrypt data using KMS
#
# Examples:
# "secret-data" | kms encrypt
# "api-key" | kms encrypt --context "env=prod,service=api"
export def "kms encrypt" [
--context: string # Encryption context (key1=val1,key2=val2)
--backend: string = "vault" # KMS backend (vault or aws-kms)
] -> string {
let input = $in
# Encode plaintext to base64
let plaintext_b64 = $input | encode base64
# Prepare request body
let body = {
plaintext: $plaintext_b64
context: $context
}
# Make API request
let response = http post (kms-endpoint "encrypt") $body | complete
if $response.exit_code != 0 {
error make {
msg: "KMS encrypt request failed"
label: {
text: $response.stderr
span: (metadata $input).span
}
}
}
let result = $response.stdout | from json
if ($result | get -i error | is-not-empty) {
error make {
msg: "KMS encryption failed"
label: {
text: $result.error
span: (metadata $input).span
}
}
}
$result.ciphertext
}
# Decrypt data using KMS
#
# Examples:
# "vault:v1:..." | kms decrypt
# $ciphertext | kms decrypt --context "env=prod,service=api"
export def "kms decrypt" [
--context: string # Encryption context (must match encryption context)
] -> string {
let ciphertext = $in
# Prepare request body
let body = {
ciphertext: $ciphertext
context: $context
}
# Make API request
let response = http post (kms-endpoint "decrypt") $body | complete
if $response.exit_code != 0 {
error make {
msg: "KMS decrypt request failed"
label: {
text: $response.stderr
span: (metadata $ciphertext).span
}
}
}
let result = $response.stdout | from json
if ($result | get -i error | is-not-empty) {
error make {
msg: "KMS decryption failed"
label: {
text: $result.error
span: (metadata $ciphertext).span
}
}
}
# Decode base64 plaintext
$result.plaintext | decode base64
}
# Generate a data key for envelope encryption
#
# Examples:
# kms generate-key
# kms generate-key --key-spec AES_128
export def "kms generate-key" [
--key-spec: string = "AES_256" # Key specification (AES_128, AES_256, RSA_2048, RSA_4096)
] -> record {
let body = {
key_spec: $key_spec
}
let response = http post (kms-endpoint "generate-key") $body | complete
if $response.exit_code != 0 {
error make {
msg: "KMS generate-key request failed"
label: {
text: $response.stderr
}
}
}
let result = $response.stdout | from json
if ($result | get -i error | is-not-empty) {
error make {
msg: "KMS key generation failed"
label: {
text: $result.error
}
}
}
{
plaintext: $result.plaintext
ciphertext: $result.ciphertext
key_id: $result.key_id
}
}
# Rotate KMS key
#
# Examples:
# kms rotate-key "arn:aws:kms:..."
export def "kms rotate-key" [
key_id: string # Key ID to rotate
] -> record {
let body = {
key_id: $key_id
}
let response = http post (kms-endpoint "rotate-key") $body | complete
if $response.exit_code != 0 {
error make {
msg: "KMS rotate-key request failed"
label: {
text: $response.stderr
span: (metadata $key_id).span
}
}
}
let result = $response.stdout | from json
if ($result | get -i error | is-not-empty) {
error make {
msg: "KMS key rotation failed"
label: {
text: $result.error
span: (metadata $key_id).span
}
}
}
{
new_key_id: $result.new_key_id
success: $result.success
}
}
# Check KMS service health
#
# Examples:
# kms health
export def "kms health" [] -> record {
let response = http get (kms-endpoint "health") | complete
if $response.exit_code != 0 {
return {
status: "unhealthy"
error: $response.stderr
}
}
$response.stdout | from json
}
# Get KMS service status
#
# Examples:
# kms status
export def "kms status" [] -> record {
let response = http get (kms-endpoint "status") | complete
if $response.exit_code != 0 {
error make {
msg: "KMS status request failed"
label: {
text: $response.stderr
}
}
}
$response.stdout | from json
}
# Encrypt file using KMS
#
# Examples:
# kms encrypt-file config.yaml
# kms encrypt-file secrets.json --output secrets.enc --context "env=prod"
export def "kms encrypt-file" [
input_file: path # File to encrypt
--output: path # Output file (default: <input>.enc)
--context: string # Encryption context
] {
if not ($input_file | path exists) {
error make {
msg: "Input file not found"
label: {
text: $input_file
span: (metadata $input_file).span
}
}
}
let output_file = if ($output | is-empty) {
$"($input_file).enc"
} else {
$output
}
print $"Encrypting ($input_file)..."
# Read file and encrypt
let plaintext = open --raw $input_file
let ciphertext = $plaintext | kms encrypt --context $context
# Save encrypted data
$ciphertext | save --raw $output_file
print $"✓ Encrypted file saved to ($output_file)"
}
# Decrypt file using KMS
#
# Examples:
# kms decrypt-file config.yaml.enc
# kms decrypt-file secrets.enc --output secrets.json --context "env=prod"
export def "kms decrypt-file" [
input_file: path # File to decrypt
--output: path # Output file (default: remove .enc extension)
--context: string # Encryption context (must match)
] {
if not ($input_file | path exists) {
error make {
msg: "Input file not found"
label: {
text: $input_file
span: (metadata $input_file).span
}
}
}
let output_file = if ($output | is-empty) {
if ($input_file | str ends-with ".enc") {
$input_file | str replace ".enc" ""
} else {
$"($input_file).dec"
}
} else {
$output
}
print $"Decrypting ($input_file)..."
# Read encrypted data and decrypt
let ciphertext = open --raw $input_file
let plaintext = $ciphertext | kms decrypt --context $context
# Save decrypted data
$plaintext | save --raw $output_file
print $"✓ Decrypted file saved to ($output_file)"
}
# Envelope encrypt data (AWS KMS only)
#
# Examples:
# "large-data" | kms envelope encrypt
export def "kms envelope encrypt" [] -> string {
let input = $in
let plaintext_b64 = $input | encode base64
let body = { plaintext: $plaintext_b64 }
let response = http post (kms-endpoint "envelope/encrypt") $body | complete
if $response.exit_code != 0 {
error make {
msg: "KMS envelope encrypt request failed"
label: { text: $response.stderr }
}
}
let result = $response.stdout | from json
if ($result | get -i error | is-not-empty) {
error make {
msg: "KMS envelope encryption failed"
label: { text: $result.error }
}
}
$result.ciphertext
}
# Envelope decrypt data (AWS KMS only)
#
# Examples:
# $envelope_ciphertext | kms envelope decrypt
export def "kms envelope decrypt" [] -> string {
let ciphertext = $in
let body = { ciphertext: $ciphertext }
let response = http post (kms-endpoint "envelope/decrypt") $body | complete
if $response.exit_code != 0 {
error make {
msg: "KMS envelope decrypt request failed"
label: { text: $response.stderr }
}
}
let result = $response.stdout | from json
if ($result | get -i error | is-not-empty) {
error make {
msg: "KMS envelope decryption failed"
label: { text: $result.error }
}
}
$result.plaintext | decode base64
}