API keys: Varaverk_HOST1/HOST2 named keys, cross-host SSH setup, keys in master.conf for direct GraphQL access

This commit is contained in:
Gmer4Lfe
2026-06-03 18:34:19 -04:00
parent a55a3afad5
commit 7178be73a5
3 changed files with 273 additions and 117 deletions
+168 -56
View File
@@ -5,26 +5,31 @@
#
# PURPOSE
# ─────────────────────────────────────────────────────────────────────────────
# Creates/overwrites the Varaverk API key in the unraid-api service registry at
# array start. The registry is ephemeral — OS updates and service restarts clear
# it. This script re-registers the key every boot so Varaverk's enhanced
# monitoring self-heals without manual intervention.
# Creates/syncs the Varaverk API key in the Unraid registry. The registry is
# ephemeral — OS updates and service restarts clear it. This script re-registers
# every boot so monitoring self-heals without manual intervention.
#
# Also updates HOST*_UNRAID_API_KEY in the local host conf so the partnership
# page always reflects the live key value.
# Each host's key is named "Varaverk_HOST1", "Varaverk_HOST2", etc., and stored
# in master.conf (shared) so all hosts can call each other's GraphQL API directly
# for real-time monitoring without SSH.
#
# --all-hosts also SSHes to each partner, creates their key there, and writes
# all keys into master.conf. Run once from Settings → API Key → Setup
# to fully wire cross-host API access.
#
# ==============================================================================================
# RUNTIME MODES
# ==============================================================================================
#
# unraid_api_key_renew.sh
# Renew the key. Silent on success.
# Renew local key only — runs at array start, fast.
#
# unraid_api_key_renew.sh --all-hosts
# Renew local key AND SSH to each partner to create/sync their key.
# Writes all keys into master.conf and pushes to partners.
#
# unraid_api_key_renew.sh --dry-run
# Show what would happen — no changes made.
#
# unraid_api_key_renew.sh --log
# Verbose output.
#
# ==============================================================================================
@@ -37,11 +42,20 @@ acquire_lock
detect_hosts
# ──────────────────────────────────────────────────────────────────────────────
CONF_FILE="$SCRIPT_DIR/../Configurations/${MY_ID,,}.conf"
VAR_NAME="${MY_ID}_UNRAID_API_KEY"
# Parse --all-hosts from raw args (parse_args doesn't handle this flag)
ALL_HOSTS=false
for _arg in "$@"; do [[ "$_arg" == "--all-hosts" ]] && ALL_HOSTS=true; done
unset _arg
log "$ICON_GEAR Conf file: $CONF_FILE"
log "$ICON_GEAR Key var: $VAR_NAME"
CONF_FILE="$SCRIPT_DIR/../Configurations/${MY_ID,,}.conf"
MASTER_CONF="$SCRIPT_DIR/../Configurations/master.conf"
VAR_NAME="${MY_ID}_UNRAID_API_KEY"
KEY_NAME="Varaverk_${MY_ID}"
log "$ICON_GEAR Conf file: $CONF_FILE"
log "$ICON_GEAR Key name: $KEY_NAME"
log "$ICON_GEAR Key var: $VAR_NAME"
log "$ICON_GEAR All hosts: $ALL_HOSTS"
if [[ ! -f "$CONF_FILE" ]]; then
error "Conf file not found: $CONF_FILE"
@@ -49,63 +63,161 @@ if [[ ! -f "$CONF_FILE" ]]; then
fi
if [[ "$DRY_RUN" == true ]]; then
warn "DRY RUN — would check registry, renew only if key missing"
warn "DRY RUN — would check registry, renew if missing, write to host conf + master.conf"
[[ "$ALL_HOSTS" == true ]] && warn "DRY RUN — would also SSH to all partners and sync their keys"
exit 0
fi
# ── Helper: write a key variable into a conf file ─────────────────────────────
_write_key_to_conf() {
local conf="$1" var="$2" key="$3"
[[ ! -f "$conf" ]] && return 1
if grep -q "^\s*${var}\s*=" "$conf"; then
sed -i "s|^\(\s*${var}\s*=\s*\)\"[^\"]*\"|\1\"${key}\"|" "$conf"
else
echo " ${var}=\"${key}\"" >> "$conf"
fi
}
# ── Helper: push master.conf to all partners ──────────────────────────────────
_push_master() {
php -r "
require_once '/usr/local/emhttp/plugins/varaverk/include/config.php';
require_once '/usr/local/emhttp/plugins/varaverk/include/confform.php';
vv_push_master_conf();
" 2>/dev/null && log "master.conf pushed to partner(s)" || warn "master.conf push failed (partner offline?)"
}
# ──────────────────────────────────────────────────────────────────────────────
# Check if key already exists in the unraid-api registry before creating.
# --overwrite generates a new key value every time, invalidating the old one.
# Only renew if the registry has lost it.
log "Checking unraid-api registry for existing Varaverk key..."
EXISTING=$(timeout 5 /usr/local/sbin/unraid-api apikey --name "Varaverk" --json </dev/null 2>/dev/null)
# Step 1: Local key — check registry, create if missing, sync to conf
# ──────────────────────────────────────────────────────────────────────────────
echo ""
echo "━━━ $ICON_GEAR Local key ($KEY_NAME) ━━━"
EXISTING=$(timeout 5 /usr/local/sbin/unraid-api apikey --name "$KEY_NAME" --json </dev/null 2>/dev/null)
KEY=$(echo "$EXISTING" | jq -r '.key // empty' 2>/dev/null)
if [[ -n "$KEY" ]]; then
PREVIEW="${KEY:0:8}...${KEY: -4}"
# Always sync registry key → conf — prevents stale key mismatch after reboot/update
CONF_KEY=$(grep "^\s*${VAR_NAME}\s*=" "$CONF_FILE" 2>/dev/null | \
sed 's/.*="\(.*\)".*/\1/' | tr -d '[:space:]')
if [[ "$CONF_KEY" == "$KEY" ]]; then
CONF_KEY=$(grep "^\s*${VAR_NAME}\s*=" "$CONF_FILE" 2>/dev/null | sed 's/.*="\(.*\)".*/\1/' | tr -d '[:space:]')
MASTER_KEY=$(grep "^\s*${VAR_NAME}\s*=" "$MASTER_CONF" 2>/dev/null | sed 's/.*="\(.*\)".*/\1/' | tr -d '[:space:]')
if [[ "$CONF_KEY" == "$KEY" && "$MASTER_KEY" == "$KEY" ]]; then
echo "API key valid ✅ — $VAR_NAME = $PREVIEW"
log "Key in sync — no update needed"
exit 0
fi
log "Registry key differs from conf — syncing..."
if grep -q "^\s*${VAR_NAME}\s*=" "$CONF_FILE"; then
sed -i "s|^\(\s*${VAR_NAME}\s*=\s*\)\"[^\"]*\"|\1\"${KEY}\"|" "$CONF_FILE"
log "Key in sync across host conf + master.conf"
else
echo " ${VAR_NAME}=\"${KEY}\"" >> "$CONF_FILE"
log "Syncing key to conf files..."
_write_key_to_conf "$CONF_FILE" "$VAR_NAME" "$KEY"
_write_key_to_conf "$MASTER_CONF" "$VAR_NAME" "$KEY"
_push_master
warn "API key synced ✅ — $VAR_NAME = $PREVIEW"
fi
warn "API key synced to conf ✅ — $VAR_NAME = $PREVIEW"
exit 0
fi
else
log "Key not found in registry — creating $KEY_NAME..."
RAW=$(timeout 10 /usr/local/sbin/unraid-api apikey \
--name "$KEY_NAME" --create --overwrite \
--description "Varaverk plugin" --roles ADMIN --json </dev/null 2>&1)
log "Key not found in registry — creating new key..."
KEY=$(echo "$RAW" | jq -r '.key // empty' 2>/dev/null)
if [[ -z "$KEY" ]]; then
error "unraid-api returned no key: ${RAW:0:200}"
exit 1
fi
RAW=$(timeout 10 /usr/local/sbin/unraid-api apikey \
--name "Varaverk" --create --overwrite \
--description "Varaverk plugin" --roles ADMIN --json </dev/null 2>&1)
if [[ -z "$RAW" ]]; then
error "unraid-api returned no output"
exit 1
fi
KEY=$(echo "$RAW" | jq -r '.key // empty' 2>/dev/null)
if [[ -z "$KEY" ]]; then
error "No key in unraid-api response: ${RAW:0:200}"
exit 1
_write_key_to_conf "$CONF_FILE" "$VAR_NAME" "$KEY"
_write_key_to_conf "$MASTER_CONF" "$VAR_NAME" "$KEY"
_push_master
PREVIEW="${KEY:0:8}...${KEY: -4}"
warn "API key created ✅ — $VAR_NAME = $PREVIEW"
fi
# ──────────────────────────────────────────────────────────────────────────────
if grep -q "^\s*${VAR_NAME}\s*=" "$CONF_FILE"; then
sed -i "s|^\(\s*${VAR_NAME}\s*=\s*\)\"[^\"]*\"|\1\"${KEY}\"|" "$CONF_FILE"
else
# Field missing from conf — append it
echo " ${VAR_NAME}=\"${KEY}\"" >> "$CONF_FILE"
# Step 2 (--all-hosts): SSH to each partner, create their key, write to master.conf
# ──────────────────────────────────────────────────────────────────────────────
[[ "$ALL_HOSTS" != true ]] && exit 0
echo ""
echo "━━━ $ICON_SYNC Partner keys ━━━"
PARTNER_OK=0
PARTNER_FAIL=0
for host_var in HOST1 HOST2 HOST3 HOST4 HOST5 HOST6 HOST7 HOST8; do
[[ "$host_var" == "$MY_ID" ]] && continue
hostname="${!host_var:-}"
[[ -z "$hostname" ]] && continue
r_var_name="${host_var}_UNRAID_API_KEY"
r_key_name="Varaverk_${host_var}"
r_conf_path="/boot/config/plugins/varaverk/Configurations/${host_var,,}.conf"
echo " $host_var ($hostname)…"
REMOTE_IP=$(resolve_tailscale_ip "$hostname")
if [[ -z "$REMOTE_IP" ]]; then
warn " $host_var: cannot resolve Tailscale IP — skipping"
(( PARTNER_FAIL++ ))
continue
fi
# SSH: check for existing key, create if missing, return the key value
REMOTE_KEY=$(ssh -i "$SSH_KEY" \
-o ConnectTimeout=10 \
-o StrictHostKeyChecking=no \
-o BatchMode=yes \
"root@${REMOTE_IP}" "
EXISTING=\$(timeout 5 /usr/local/sbin/unraid-api apikey --name '${r_key_name}' --json </dev/null 2>/dev/null)
KEY=\$(echo \"\$EXISTING\" | jq -r '.key // empty' 2>/dev/null)
if [[ -n \"\$KEY\" ]]; then
echo \"\$KEY\"
else
timeout 10 /usr/local/sbin/unraid-api apikey \\
--name '${r_key_name}' --create --overwrite \\
--description 'Varaverk plugin' --roles ADMIN --json </dev/null 2>/dev/null \\
| jq -r '.key // empty' 2>/dev/null
fi
" 2>/dev/null | tr -d '[:space:]')
if [[ -z "$REMOTE_KEY" ]]; then
warn " $host_var: could not get key from $hostname — skipping"
(( PARTNER_FAIL++ ))
continue
fi
R_PREVIEW="${REMOTE_KEY:0:8}...${REMOTE_KEY: -4}"
# Write remote key to master.conf locally
_write_key_to_conf "$MASTER_CONF" "$r_var_name" "$REMOTE_KEY"
# Also write to remote's host*.conf so they have it locally
ssh -i "$SSH_KEY" \
-o ConnectTimeout=10 \
-o StrictHostKeyChecking=no \
-o BatchMode=yes \
"root@${REMOTE_IP}" "
CONF='${r_conf_path}'
if [[ -f \"\$CONF\" ]]; then
if grep -q '^\s*${r_var_name}\s*=' \"\$CONF\"; then
sed -i \"s|^\(\s*${r_var_name}\s*=\s*\)\\\"[^\\\"]*\\\"|\1\\\"${REMOTE_KEY}\\\"|\" \"\$CONF\"
else
echo ' ${r_var_name}=\\\"${REMOTE_KEY}\\\"' >> \"\$CONF\"
fi
fi
" 2>/dev/null
echo " $host_var: $r_key_name = $R_PREVIEW"
(( PARTNER_OK++ ))
done
# Push master.conf with all updated keys to all partners
if (( PARTNER_OK > 0 )); then
echo ""
echo " Pushing master.conf with all keys…"
_push_master
fi
PREVIEW="${KEY:0:8}...${KEY: -4}"
log "Writing new key to: $CONF_FILE"
warn "API key renewed $VAR_NAME = $PREVIEW (registry had lost it)"
echo ""
echo "━━━━━ $ICON_SUMMARY Key Setup Summary ━━━━━"
echo " Local: $VAR_NAME"
echo " Partners: $PARTNER_OK updated · $PARTNER_FAIL failed"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"