95 lines
3.5 KiB
Text
95 lines
3.5 KiB
Text
#!/usr/bin/env nu
|
|
# Prepare: decrypt SOPS hcloud secret and deploy as k8s secret before install.
|
|
# Runs on the provisioning machine. SSH to server to create the secret.
|
|
|
|
let vars_path = ($env.PROVISIONING_VARS? | default "")
|
|
if ($vars_path | is-empty) or not ($vars_path | path exists) { exit 0 }
|
|
|
|
let wk_data = (open $vars_path)
|
|
let secret_name = ($wk_data | get -o taskserv.token_secret_name | default "hcloud")
|
|
let hostname = ($wk_data | get -o server.hostname | default "")
|
|
let server_ip = ($wk_data | get -o server.ip_addresses.pub | default "")
|
|
|
|
# Resolve workspace root for SOPS secrets
|
|
let ws_root = do {
|
|
let wss = ($env.PROVISIONING_WORKSPACES? | default "")
|
|
if ($wss | is-not-empty) { $wss | path dirname } else { "" }
|
|
}
|
|
|
|
if ($ws_root | is-empty) or ($server_ip | is-empty) {
|
|
print $"⚠ prepare: cannot resolve workspace or server IP — skipping secret deploy"
|
|
exit 0
|
|
}
|
|
|
|
# Find and decrypt the SOPS secret
|
|
let sops_file = ($ws_root | path join "infra" | path expand
|
|
| do -i { ls $in } | default []
|
|
| where type == "dir"
|
|
| each {|d| $d.name | path join "secrets" | path join $"($secret_name).sops.yaml" }
|
|
| where {|p| $p | path exists }
|
|
| get 0?
|
|
| default ""
|
|
)
|
|
|
|
if ($sops_file | is-empty) {
|
|
print $"⚠ prepare: ($secret_name).sops.yaml not found — secret must exist on cluster"
|
|
exit 0
|
|
}
|
|
|
|
# Resolve SOPS age key: SOPS_AGE_KEY_FILE or <infra_path>/.kage
|
|
let kage_path = if ($env.SOPS_AGE_KEY_FILE? | default "" | is-not-empty) {
|
|
$env.SOPS_AGE_KEY_FILE
|
|
} else {
|
|
let kloud_path = ($env.PROVISIONING_KLOUD_PATH? | default "")
|
|
if ($kloud_path | is-not-empty) and ($kloud_path | path join ".kage" | path exists) {
|
|
$kloud_path | path join ".kage"
|
|
} else { "" }
|
|
}
|
|
|
|
let decrypted = if ($kage_path | is-not-empty) {
|
|
(do -i { with-env { SOPS_AGE_KEY_FILE: $kage_path } { ^sops -d $sops_file } } | default "")
|
|
} else {
|
|
(do -i { ^sops -d $sops_file } | default "")
|
|
}
|
|
if ($decrypted | is-empty) {
|
|
print $"⚠ prepare: failed to decrypt ($sops_file)"
|
|
exit 0
|
|
}
|
|
|
|
let token = ($decrypted | from yaml | get -o token | default "")
|
|
if ($token | is-empty) {
|
|
print "⚠ prepare: token field not found in decrypted secret"
|
|
exit 0
|
|
}
|
|
|
|
# SSH to server and create the k8s secret (idempotent via --dry-run + apply)
|
|
let settings_src = ($env.PROVISIONING_SETTINGS_SRC_PATH? | default "")
|
|
let ssh_key = if ($settings_src | is-not-empty) {
|
|
# Try to find ssh key from provisioning config
|
|
let key = ($env.PROVISIONING_SSH_KEY? | default "~/.ssh/htz_ops")
|
|
$key | str replace "~" $env.HOME
|
|
} else { "" }
|
|
|
|
let ssh_opts = "-o StrictHostKeyChecking=accept-new -o ConnectTimeout=10"
|
|
let ssh_opts = if ($ssh_key | is-not-empty) and ($ssh_key | path exists) {
|
|
$"($ssh_opts) -i ($ssh_key)"
|
|
} else { $ssh_opts }
|
|
|
|
let script = $"#!/usr/bin/env bash
|
|
export PATH=/usr/local/bin:/usr/bin:/bin
|
|
if command -v k0s >/dev/null 2>&1 && k0s kubectl version --client=true >/dev/null 2>&1; then
|
|
KCT=\"k0s kubectl\"
|
|
elif command -v kubectl >/dev/null 2>&1; then
|
|
KCT=\"kubectl\"
|
|
else
|
|
echo \"ERROR: neither kubectl nor k0s found\" >&2; exit 1
|
|
fi
|
|
\$KCT -n kube-system create secret generic ($secret_name) --from-literal=token=($token) --dry-run=client -o yaml | \$KCT apply -f -
|
|
"
|
|
let res = (do -i { $script | ^ssh ...($ssh_opts | split row " ") $"root@($server_ip)" "bash -s" } | complete)
|
|
|
|
if $res.exit_code == 0 {
|
|
print $"✓ prepare: ($secret_name) secret deployed to kube-system on ($hostname)"
|
|
} else {
|
|
print $"⚠ prepare: failed to deploy secret — ($res.stderr)"
|
|
}
|