provisioning-catalog/playbooks/rotate_keys/run.nu

81 lines
4.4 KiB
Text
Raw Permalink Normal View History

#!/usr/bin/env nu
# rotate_keys/run.nu — validate, propose, sign, activate, verify, revoke
def main [
--workspace: string = ""
--key-type: string = ""
--new-key-path: string = ""
--new-pubkey-path: string = ""
--ops-vm-host: string = ""
--dry-run
]: nothing -> nothing {
let ws = if ($workspace | is-not-empty) { $workspace } else { $env.PLAYBOOK_PARAM_WORKSPACE? | default "" }
let ktype = if ($key_type | is-not-empty) { $key_type } else { $env.PLAYBOOK_PARAM_KEY_TYPE? | default "" }
let new_key = if ($new_key_path | is-not-empty) { $new_key_path } else { $env.PLAYBOOK_PARAM_NEW_KEY_PATH? | default "" }
let new_pubkey = if ($new_pubkey_path | is-not-empty) { $new_pubkey_path } else { $env.PLAYBOOK_PARAM_NEW_PUBKEY_PATH? | default "" }
let vm_host = if ($ops_vm_host | is-not-empty) { $ops_vm_host } else { $env.PLAYBOOK_PARAM_OPS_VM_HOST? | default "" }
if ($ws | is-empty) { error make { msg: "workspace is required" } }
if ($ktype | is-empty) { error make { msg: "key-type is required (ops-controller | keeper | operator)" } }
if ($new_key | is-empty) { error make { msg: "new-key-path is required" } }
let valid_types = ["ops-controller", "keeper", "operator"]
if not ($valid_types | any { |t| $t == $ktype }) {
error make { msg: $"Invalid key-type '($ktype)'. Must be one of: ($valid_types | str join ', ')" }
}
let playbook_dir = $env.PLAYBOOK_DIR? | default ($env.FILE_PWD | path expand)
let dry_flag = if $dry_run { "--dry-run" } else { "" }
print $"[rotate_keys] workspace=($ws) key-type=($ktype) dry-run=($dry_run)"
print ""
print "[step 1/7] validating new keypair..."
let r1 = do { ^nu ($playbook_dir | path join "steps/validate_new_key.nu") --key-type $ktype --new-key-path $new_key --new-pubkey-path $new_pubkey $dry_flag } | complete
if $r1.exit_code != 0 { error make { msg: $"Key validation failed: ($r1.stderr | str trim)" } }
print $r1.stdout
print "[step 2/7] proposing delegation patch..."
let r2 = do { ^nu ($playbook_dir | path join "steps/propose_delegation_patch.nu") --workspace $ws --key-type $ktype --new-pubkey-path $new_pubkey $dry_flag } | complete
if $r2.exit_code != 0 { error make { msg: $"Delegation patch proposal failed: ($r2.stderr | str trim)" } }
print $r2.stdout
print "[step 3/7] awaiting quorum signatures on delegation patch..."
let r3 = do { ^nu ($playbook_dir | path join "steps/sign_delegation_patch.nu") --workspace $ws --key-type $ktype $dry_flag } | complete
if $r3.exit_code != 0 { error make { msg: $"Delegation patch signing failed: ($r3.stderr | str trim)" } }
print $r3.stdout
print "[step 4/7] activating new key..."
let r4 = do { ^nu ($playbook_dir | path join "steps/activate_new_key.nu") --workspace $ws --key-type $ktype --new-key-path $new_key --ops-vm-host $vm_host $dry_flag } | complete
if $r4.exit_code != 0 {
print $"ERROR: key activation failed — initiating rollback: ($r4.stderr | str trim)"
print "ROLLBACK REQUIRED: restore old key from backup and re-run propose/sign/activate cycle"
error make { msg: "activate_new_key failed — manual rollback required" }
}
print $r4.stdout
print "[step 5/7] verifying continuity..."
let r5 = do { ^nu ($playbook_dir | path join "steps/verify_continuity.nu") --workspace $ws --key-type $ktype $dry_flag } | complete
if $r5.exit_code != 0 {
print $" WARNING: continuity verification failed: ($r5.stderr | str trim)"
} else {
print $r5.stdout
}
print "[step 6/7] revoking old key..."
let r6 = do { ^nu ($playbook_dir | path join "steps/revoke_old_key.nu") --workspace $ws --key-type $ktype $dry_flag } | complete
if $r6.exit_code != 0 {
print $" WARNING: old key revocation reported errors: ($r6.stderr | str trim)"
} else {
print $r6.stdout
}
print "[step 7/7] emitting key-rotation audit event..."
let r7 = do { ^nu ($playbook_dir | path join "steps/emit_audit.nu") --workspace $ws --event-type "key_rotation" --key-type $ktype $dry_flag } | complete
if $r7.exit_code != 0 { print $" WARNING: audit emit failed: ($r7.stderr | str trim)" }
print ""
print "[rotate_keys] complete"
print $"Verify: new ($ktype) key is active, old key rejected by target service"
}