ops(kms): audit + migration scripts for KMSSecret CRD ↔ Lux KMS cutover

* scripts/kms-crd-host-migrate.sh — bulk-patch every KMSSecret CRD's
  hostAPI to point at kms.lux-kms-go.svc.cluster.local. Idempotent.
  Already executed against lux-k8s + hanzo-k8s (147 CRDs).

* scripts/kms-orphan-audit.sh — audit which K8s Secrets are NOT backed
  by a KMSSecret CRD or whitelisted bootstrap creds. Output:
    lux-k8s    323 non-system Secrets, 268 orphan
    hanzo-k8s  461 non-system Secrets, 367 orphan
  Most orphans are ARC runner state, cert-manager cert content, and
  operator-internal config — not appropriate for KMS migration.
  Run before sweeping anything.
This commit is contained in:
Hanzo AI
2026-04-25 20:52:18 -07:00
parent ca6b8ccb54
commit 4eb937cb08
2 changed files with 75 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
# Bulk-patch every KMSSecret CRD in both clusters to point at Lux KMS.
#
# OLD: hostAPI=http://kms.hanzo.svc.cluster.local/api (Infisical-fork)
# NEW: hostAPI=http://kms.lux-kms-go.svc.cluster.local (Lux Go-native)
#
# Auth credentials secret name stays as `universal-auth-credentials`.
set -euo pipefail
NEW_HOST="http://kms.lux-kms-go.svc.cluster.local"
migrate_cluster() {
local ctx=$1
echo "=== ${ctx} ==="
kubectl --context "${ctx}" get kmssecrets -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' | \
while IFS=/ read -r ns name; do
[ -z "${ns}" ] && continue
echo " patch ${ns}/${name}"
kubectl --context "${ctx}" -n "${ns}" patch kmssecret "${name}" \
--type=merge -p "{\"spec\":{\"hostAPI\":\"${NEW_HOST}\"}}" || true
done
}
for ctx in lux-k8s hanzo-k8s; do
migrate_cluster "${ctx}"
done
echo "DONE — restart operator to pick up changes:"
echo " kubectl --context <ctx> -n kms-operator-system rollout restart deploy/kms-operator-controller-manager"
+46
View File
@@ -0,0 +1,46 @@
#!/bin/bash
# Audit K8s Secrets that are NOT (a) backed by a KMSSecret CRD,
# (b) system secrets, (c) TLS, (d) image pull, (e) Helm release.
set -uo pipefail
audit_cluster() {
local ctx=$1
echo "=========== ${ctx} ==========="
# All KMSSecret-managed K8s Secret refs (managed by operator)
local managed
managed=$(kubectl --context "${ctx}" get kmssecrets -A \
-o jsonpath='{range .items[*]}{.spec.managedSecretReference.secretNamespace}{"/"}{.spec.managedSecretReference.secretName}{"\n"}{end}' \
2>/dev/null | sort -u)
echo " KMSSecret-managed targets: $(echo "$managed" | grep -c .)"
# All K8s Secrets, excluding system types
local all
all=$(kubectl --context "${ctx}" get secrets -A \
--field-selector type!=kubernetes.io/service-account-token \
--field-selector type!=kubernetes.io/dockerconfigjson \
--field-selector type!=kubernetes.io/tls \
--field-selector type!=helm.sh/release.v1 \
-o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{"\n"}{end}' \
2>/dev/null | sort -u)
local total
total=$(echo "$all" | grep -c .)
echo " Non-system Secrets total: ${total}"
# Orphans = in all but not managed and not whitelisted
local orphans
orphans=$(comm -23 <(echo "$all") <(echo "$managed") \
| grep -vE '^[^/]+/(universal-auth-credentials|ghcr-luxfi|ghcr-secret|ghcr-zoo|kms-machine-identity)$' \
| grep -vE 'sh\.helm\.release')
local count
count=$(echo "$orphans" | grep -c . || true)
echo " Orphan Secrets (no KMSSecret CRD backing, not bootstrap creds): ${count}"
if [ "$count" != "0" ] && [ -n "$orphans" ]; then
echo " Sample (first 10):"
echo "$orphans" | head -10 | sed 's/^/ /'
fi
}
for ctx in lux-k8s hanzo-k8s; do
audit_cluster "$ctx"
done