The backup engine already drops to the backup user (sudo -E -u $docker_install_user) and backupLocationOwner == $docker_install_user, which is exactly what runFileOp/runFileWrite resolve to in both modes. So convert the raw-sudo data ops (mkdir/chmod/rm/find/cat/grep/mv/chown/tee on backup repos, location configs, keys, manifests) to runFileOp/runFileWrite — creating files as the owner directly, no root chown. backup_verify creates its scratch as the backup user (runFileOp mktemp) instead of chown-after. Binary installs (kopia tar/install, borg dnf) -> runSystem. The 44 sudo -u engine drops stay (already least-privilege; the scoped sudoers will grant them). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
114 lines
3.2 KiB
Bash
114 lines
3.2 KiB
Bash
#!/bin/bash
|
|
|
|
# LibrePortal-managed SSH key store for backup locations. Each location's
|
|
# private key lives at configs/backup/locations/<idx>/ssh.key. Public key
|
|
# is derived on the fly via ssh-keygen -y, so we never persist it
|
|
# separately. The CFG_BACKUP_LOC_<idx>_SSH_AUTH selector (key|password)
|
|
# is the only ssh-related value in the location.config file.
|
|
|
|
# Refresh locations.json so the editor reflects new key state (public key /
|
|
# "key set" status) right after a mutation. No-op if the generator isn't loaded.
|
|
backupSshKeyRefreshUi()
|
|
{
|
|
declare -f webuiGenerateBackupLocations >/dev/null 2>&1 && webuiGenerateBackupLocations >/dev/null 2>&1
|
|
return 0
|
|
}
|
|
|
|
backupSshKeyFile()
|
|
{
|
|
local idx="$1"
|
|
backupLocationSshKey "$idx"
|
|
}
|
|
|
|
backupSshKeyExists()
|
|
{
|
|
local idx="$1"
|
|
[[ -f "$(backupSshKeyFile "$idx")" ]]
|
|
}
|
|
|
|
# Decode a base64-encoded private key and write it to the location's key
|
|
# file. The frontend base64-encodes pasted multi-line keys so we can ship
|
|
# them through the existing single-line task command pipeline.
|
|
backupSshKeySet()
|
|
{
|
|
local idx="$1"
|
|
local key_b64="$2"
|
|
|
|
if [[ -z "$idx" || -z "$key_b64" ]]; then
|
|
isError "backupSshKeySet requires <idx> <base64-key>"
|
|
return 1
|
|
fi
|
|
|
|
backupLocationEnsureDir "$idx"
|
|
local owner
|
|
owner=$(backupLocationOwner)
|
|
local key_file
|
|
key_file=$(backupSshKeyFile "$idx")
|
|
|
|
local decoded
|
|
decoded=$(echo "$key_b64" | base64 -d 2>/dev/null)
|
|
if [[ -z "$decoded" ]]; then
|
|
isError "Failed to base64-decode the supplied key"
|
|
return 1
|
|
fi
|
|
|
|
echo "$decoded" | runFileWrite "$key_file" >/dev/null
|
|
runFileOp chown "$owner":"$owner" "$key_file"
|
|
runFileOp chmod 0600 "$key_file"
|
|
|
|
if ! sudo -u "$owner" ssh-keygen -y -f "$key_file" >/dev/null 2>&1; then
|
|
isError "Key written but ssh-keygen can't read it — check the format (OpenSSH PEM: ed25519, rsa, ecdsa)"
|
|
return 1
|
|
fi
|
|
|
|
isSuccessful "SSH key saved for location $idx"
|
|
backupSshKeyRefreshUi
|
|
}
|
|
|
|
backupSshKeyGenerate()
|
|
{
|
|
local idx="$1"
|
|
if [[ -z "$idx" ]]; then
|
|
isError "backupSshKeyGenerate requires <idx>"
|
|
return 1
|
|
fi
|
|
|
|
backupLocationEnsureDir "$idx"
|
|
local owner
|
|
owner=$(backupLocationOwner)
|
|
local key_file
|
|
key_file=$(backupSshKeyFile "$idx")
|
|
|
|
if [[ -f "$key_file" ]]; then
|
|
runFileOp rm -f "$key_file" "${key_file}.pub"
|
|
fi
|
|
|
|
sudo -u "$owner" ssh-keygen -t ed25519 -f "$key_file" -N "" -C "libreportal-loc-${idx}" -q
|
|
runFileOp chmod 0600 "$key_file"
|
|
[[ -f "${key_file}.pub" ]] && runFileOp rm -f "${key_file}.pub" # we re-derive when needed
|
|
|
|
isSuccessful "Generated ed25519 keypair for location $idx"
|
|
isNotice "Public key (paste into the remote host's ~/.ssh/authorized_keys):"
|
|
backupSshKeyPublic "$idx"
|
|
backupSshKeyRefreshUi
|
|
}
|
|
|
|
backupSshKeyPublic()
|
|
{
|
|
local idx="$1"
|
|
local key_file
|
|
key_file=$(backupSshKeyFile "$idx")
|
|
[[ -f "$key_file" ]] || return 1
|
|
sudo -u "$(backupLocationOwner)" ssh-keygen -y -f "$key_file" 2>/dev/null
|
|
}
|
|
|
|
backupSshKeyDelete()
|
|
{
|
|
local idx="$1"
|
|
local key_file
|
|
key_file=$(backupSshKeyFile "$idx")
|
|
[[ -f "$key_file" ]] && runFileOp rm -f "$key_file" "${key_file}.pub"
|
|
isSuccessful "SSH key removed for location $idx"
|
|
backupSshKeyRefreshUi
|
|
}
|