refactor(desudo): funnel backup-engine privilege drop through runBackupOp
The borg/restic/kopia engines all dropped to the dedicated backup user via scattered 'sudo -E -u $docker_install_user'. Centralize that into a single runBackupOp helper so the backup subsystem has one audit point and the scoped sudoers needs only the (dockerinstall) drop rule. Also: - owncloud config heredoc tees -> runSystem (container-UID file) - webui_display_logins: fix the broken 'command -v sudo sqlite3' guard to 'command -v sqlite3' (body already runs sqlite3 via runInstallOp) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
parent
0dc86e62f6
commit
0b27ed1072
@ -89,7 +89,7 @@ appOwnCloudSetupConfig()
|
||||
|
||||
if [[ $public == "true" ]]; then
|
||||
# Add new lines at the end of the file
|
||||
sudo tee -a "$tmp_awk_output" > /dev/null <<EOL
|
||||
runSystem tee -a "$tmp_awk_output" > /dev/null <<EOL
|
||||
'overwrite.cli.url' => 'https://$host_setup/',
|
||||
'Overwriteprotocol' => 'https',
|
||||
'trusted_domains' =>
|
||||
@ -104,7 +104,7 @@ EOL
|
||||
checkSuccess "Add overwrite and trusted_domain (public) lines to the config"
|
||||
elif [[ $public == "false" ]]; then
|
||||
# Add new lines at the end of the file
|
||||
sudo tee -a "$tmp_awk_output" > /dev/null <<EOL
|
||||
runSystem tee -a "$tmp_awk_output" > /dev/null <<EOL
|
||||
'trusted_domains' =>
|
||||
array(
|
||||
0 => '$ip_setup',
|
||||
|
||||
@ -16,7 +16,7 @@ backupAppDeleteSnapshot()
|
||||
fi
|
||||
|
||||
resticEnvExport "$idx" || return 1
|
||||
sudo -E -u "$docker_install_user" restic forget "$snapshot_id" $([[ "$CFG_BACKUP_PRUNE_AFTER_FORGET" == "true" ]] && echo "--prune")
|
||||
runBackupOp restic forget "$snapshot_id" $([[ "$CFG_BACKUP_PRUNE_AFTER_FORGET" == "true" ]] && echo "--prune")
|
||||
local rc=$?
|
||||
resticEnvUnset
|
||||
if [[ $rc -eq 0 ]]; then
|
||||
@ -47,7 +47,7 @@ backupAppDeleteAll()
|
||||
continue
|
||||
fi
|
||||
resticEnvExport "$idx" || continue
|
||||
sudo -E -u "$docker_install_user" restic forget --tag "app=$app_name" $([[ "$CFG_BACKUP_PRUNE_AFTER_FORGET" == "true" ]] && echo "--prune")
|
||||
runBackupOp restic forget --tag "app=$app_name" $([[ "$CFG_BACKUP_PRUNE_AFTER_FORGET" == "true" ]] && echo "--prune")
|
||||
resticEnvUnset
|
||||
done < <(resticEnabledLocations)
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ borgBackupAppToLocation()
|
||||
# Logs to stderr; stdout is only the archive name for the caller's $().
|
||||
isNotice "Snapshotting $app_name → $loc_name (archive: $archive)" >&2
|
||||
|
||||
sudo -E -u "$docker_install_user" borg create \
|
||||
runBackupOp borg create \
|
||||
--comment "$comment" \
|
||||
--compression auto,zstd \
|
||||
"${exclude_args[@]}" \
|
||||
|
||||
@ -13,7 +13,7 @@ borgCheckLocation()
|
||||
fi
|
||||
|
||||
isNotice "Checking $(resticLocationName "$idx")${read_data:+ (full data verify)}"
|
||||
sudo -E -u "$docker_install_user" borg "${args[@]}"
|
||||
runBackupOp borg "${args[@]}"
|
||||
local rc=$?
|
||||
borgEnvUnset
|
||||
if [[ $rc -eq 0 ]]; then
|
||||
@ -29,7 +29,7 @@ borgLocationStats()
|
||||
local idx="$1"
|
||||
borgEnvExport "$idx" || return 1
|
||||
local raw
|
||||
raw=$(sudo -E -u "$docker_install_user" borg info --json 2>/dev/null)
|
||||
raw=$(runBackupOp borg info --json 2>/dev/null)
|
||||
borgEnvUnset
|
||||
[[ -z "$raw" ]] && { echo '{"total_size":0,"total_file_count":0}'; return 0; }
|
||||
|
||||
|
||||
@ -28,11 +28,11 @@ borgForgetApp()
|
||||
[[ -n "$keep_yearly" ]] && args+=(--keep-yearly "$keep_yearly")
|
||||
|
||||
isNotice "Applying retention for $app_name on $(resticLocationName "$idx")"
|
||||
sudo -E -u "$docker_install_user" borg "${args[@]}"
|
||||
runBackupOp borg "${args[@]}"
|
||||
local rc=$?
|
||||
|
||||
if [[ "$CFG_BACKUP_PRUNE_AFTER_FORGET" == "true" && $rc -eq 0 ]]; then
|
||||
sudo -E -u "$docker_install_user" borg compact
|
||||
runBackupOp borg compact
|
||||
fi
|
||||
|
||||
borgEnvUnset
|
||||
|
||||
@ -16,14 +16,14 @@ borgInitLocation()
|
||||
runFileOp chown -R "$docker_install_user":"$docker_install_user" "$BORG_REPO"
|
||||
fi
|
||||
|
||||
if sudo -E -u "$docker_install_user" borg info "$BORG_REPO" >/dev/null 2>&1; then
|
||||
if runBackupOp borg info "$BORG_REPO" >/dev/null 2>&1; then
|
||||
isNotice "$(resticLocationName "$idx") already initialized at $BORG_REPO"
|
||||
borgEnvUnset
|
||||
return 0
|
||||
fi
|
||||
|
||||
isNotice "Initializing $(resticLocationName "$idx") at $BORG_REPO"
|
||||
if sudo -E -u "$docker_install_user" borg init --encryption=repokey-blake2 "$BORG_REPO"; then
|
||||
if runBackupOp borg init --encryption=repokey-blake2 "$BORG_REPO"; then
|
||||
isSuccessful "$(resticLocationName "$idx") initialized"
|
||||
else
|
||||
isError "Failed to initialize $(resticLocationName "$idx")"
|
||||
|
||||
@ -19,10 +19,10 @@ borgRestoreSnapshot()
|
||||
local rc
|
||||
if [[ -n "$include_path" ]]; then
|
||||
local stripped="${include_path#/}"
|
||||
( cd "$target_dir" && sudo -E -u "$docker_install_user" borg extract "::$snapshot_id" "$stripped" )
|
||||
( cd "$target_dir" && runBackupOp borg extract "::$snapshot_id" "$stripped" )
|
||||
rc=$?
|
||||
else
|
||||
( cd "$target_dir" && sudo -E -u "$docker_install_user" borg extract "::$snapshot_id" )
|
||||
( cd "$target_dir" && runBackupOp borg extract "::$snapshot_id" )
|
||||
rc=$?
|
||||
fi
|
||||
borgEnvUnset
|
||||
@ -39,9 +39,9 @@ borgDumpFile()
|
||||
borgEnvExport "$idx" || return 1
|
||||
local stripped="${file_path#/}"
|
||||
if [[ -n "$target_file" ]]; then
|
||||
sudo -E -u "$docker_install_user" borg extract --stdout "::$snapshot_id" "$stripped" | runFileWrite "$target_file"
|
||||
runBackupOp borg extract --stdout "::$snapshot_id" "$stripped" | runFileWrite "$target_file"
|
||||
else
|
||||
sudo -E -u "$docker_install_user" borg extract --stdout "::$snapshot_id" "$stripped"
|
||||
runBackupOp borg extract --stdout "::$snapshot_id" "$stripped"
|
||||
fi
|
||||
local rc=$?
|
||||
borgEnvUnset
|
||||
|
||||
@ -19,7 +19,7 @@ borgSnapshotsJson()
|
||||
fi
|
||||
|
||||
local raw
|
||||
raw=$(sudo -E -u "$docker_install_user" borg "${args[@]}" 2>/dev/null)
|
||||
raw=$(runBackupOp borg "${args[@]}" 2>/dev/null)
|
||||
local rc=$?
|
||||
borgEnvUnset
|
||||
[[ $rc -ne 0 || -z "$raw" ]] && { echo "[]"; return $rc; }
|
||||
@ -63,7 +63,7 @@ borgSnapshotLatestId()
|
||||
|
||||
borgEnvExport "$idx" || return 1
|
||||
local id
|
||||
id=$(sudo -E -u "$docker_install_user" borg list --json --glob-archives "${app_name}-${host}-*" --last 1 2>/dev/null \
|
||||
id=$(runBackupOp borg list --json --glob-archives "${app_name}-${host}-*" --last 1 2>/dev/null \
|
||||
| grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
borgEnvUnset
|
||||
echo "$id"
|
||||
@ -74,7 +74,7 @@ borgSnapshotListFiles()
|
||||
local idx="$1"
|
||||
local snapshot_id="$2"
|
||||
borgEnvExport "$idx" || return 1
|
||||
sudo -E -u "$docker_install_user" borg list --json-lines "::$snapshot_id" 2>/dev/null
|
||||
runBackupOp borg list --json-lines "::$snapshot_id" 2>/dev/null
|
||||
local rc=$?
|
||||
borgEnvUnset
|
||||
return $rc
|
||||
|
||||
@ -41,7 +41,7 @@ kopiaBackupAppToLocation()
|
||||
fi
|
||||
|
||||
local output
|
||||
output=$(sudo -E -u "$docker_install_user" kopia snapshot create "$source_path" "${tags[@]}" --json 2>&1)
|
||||
output=$(runBackupOp kopia snapshot create "$source_path" "${tags[@]}" --json 2>&1)
|
||||
local rc=$?
|
||||
|
||||
[[ "$wrote_ignore" == true ]] && runFileOp rm -f "$ignore_file"
|
||||
|
||||
@ -15,7 +15,7 @@ kopiaCheckLocation()
|
||||
fi
|
||||
|
||||
isNotice "Checking $(resticLocationName "$idx") with Kopia${read_data:+ (data sample: ${read_data}%)}"
|
||||
sudo -E -u "$docker_install_user" kopia "${args[@]}"
|
||||
runBackupOp kopia "${args[@]}"
|
||||
local rc=$?
|
||||
kopiaEnvUnset
|
||||
if [[ $rc -eq 0 ]]; then
|
||||
@ -31,7 +31,7 @@ kopiaLocationStats()
|
||||
local idx="$1"
|
||||
kopiaEnvExport "$idx" || return 1
|
||||
local raw
|
||||
raw=$(sudo -E -u "$docker_install_user" kopia repository status --json 2>/dev/null)
|
||||
raw=$(runBackupOp kopia repository status --json 2>/dev/null)
|
||||
kopiaEnvUnset
|
||||
[[ -z "$raw" ]] && { echo '{"total_size":0,"total_file_count":0}'; return 0; }
|
||||
|
||||
|
||||
@ -33,10 +33,10 @@ kopiaForgetApp()
|
||||
[[ -n "$keep_monthly" ]] && policy_args+=(--keep-monthly "$keep_monthly")
|
||||
[[ -n "$keep_yearly" ]] && policy_args+=(--keep-annual "$keep_yearly")
|
||||
|
||||
sudo -E -u "$docker_install_user" kopia "${policy_args[@]}" >/dev/null 2>&1
|
||||
runBackupOp kopia "${policy_args[@]}" >/dev/null 2>&1
|
||||
|
||||
isNotice "Running Kopia maintenance for $app_name on $(resticLocationName "$idx")"
|
||||
sudo -E -u "$docker_install_user" kopia maintenance run --full
|
||||
runBackupOp kopia maintenance run --full
|
||||
local rc=$?
|
||||
kopiaEnvUnset
|
||||
return $rc
|
||||
|
||||
@ -16,7 +16,7 @@ kopiaInitLocation()
|
||||
|
||||
# Already initialized? `kopia repository status` returns 0 only if the
|
||||
# config file is connected to a repo.
|
||||
if sudo -E -u "$docker_install_user" kopia repository status --json >/dev/null 2>&1; then
|
||||
if runBackupOp kopia repository status --json >/dev/null 2>&1; then
|
||||
isNotice "$(resticLocationName "$idx") already initialized"
|
||||
kopiaEnvUnset
|
||||
return 0
|
||||
@ -60,7 +60,7 @@ kopiaInitLocation()
|
||||
esac
|
||||
|
||||
isNotice "Initializing $(resticLocationName "$idx") with Kopia"
|
||||
if sudo -E -u "$docker_install_user" kopia "${args[@]}"; then
|
||||
if runBackupOp kopia "${args[@]}"; then
|
||||
isSuccessful "$(resticLocationName "$idx") initialized"
|
||||
else
|
||||
isError "Failed to initialize $(resticLocationName "$idx") with Kopia"
|
||||
|
||||
@ -24,7 +24,7 @@ kopiaRestoreSnapshot()
|
||||
final_target="$target_dir/${include_path#/}"
|
||||
runFileOp mkdir -p "$final_target"
|
||||
fi
|
||||
sudo -E -u "$docker_install_user" kopia snapshot restore "$snapshot_id" "$final_target"
|
||||
runBackupOp kopia snapshot restore "$snapshot_id" "$final_target"
|
||||
local rc=$?
|
||||
kopiaEnvUnset
|
||||
return $rc
|
||||
@ -40,9 +40,9 @@ kopiaDumpFile()
|
||||
kopiaEnvExport "$idx" || return 1
|
||||
# `kopia show` writes the file contents from a snapshot to stdout.
|
||||
if [[ -n "$target_file" ]]; then
|
||||
sudo -E -u "$docker_install_user" kopia show "${snapshot_id}:${file_path}" | sudo tee "$target_file" >/dev/null
|
||||
runBackupOp kopia show "${snapshot_id}:${file_path}" | sudo tee "$target_file" >/dev/null
|
||||
else
|
||||
sudo -E -u "$docker_install_user" kopia show "${snapshot_id}:${file_path}"
|
||||
runBackupOp kopia show "${snapshot_id}:${file_path}"
|
||||
fi
|
||||
local rc=$?
|
||||
kopiaEnvUnset
|
||||
|
||||
@ -14,7 +14,7 @@ kopiaSnapshotsJson()
|
||||
local args=(snapshot list --all --json)
|
||||
|
||||
local raw
|
||||
raw=$(sudo -E -u "$docker_install_user" kopia "${args[@]}" 2>/dev/null)
|
||||
raw=$(runBackupOp kopia "${args[@]}" 2>/dev/null)
|
||||
local rc=$?
|
||||
kopiaEnvUnset
|
||||
[[ $rc -ne 0 || -z "$raw" ]] && { echo "[]"; return $rc; }
|
||||
@ -62,7 +62,7 @@ kopiaSnapshotListFiles()
|
||||
local idx="$1"
|
||||
local snapshot_id="$2"
|
||||
kopiaEnvExport "$idx" || return 1
|
||||
sudo -E -u "$docker_install_user" kopia snapshot list "$snapshot_id" --json 2>/dev/null
|
||||
runBackupOp kopia snapshot list "$snapshot_id" --json 2>/dev/null
|
||||
local rc=$?
|
||||
kopiaEnvUnset
|
||||
return $rc
|
||||
|
||||
@ -36,7 +36,7 @@ resticBackupAppToLocation()
|
||||
# the caller captures it with $() and feeds it to verify/retention.
|
||||
isNotice "Snapshotting $app_name → $loc_name" >&2
|
||||
local output
|
||||
output=$(sudo -E -u "$docker_install_user" restic backup \
|
||||
output=$(runBackupOp restic backup \
|
||||
--host "$host_tag" \
|
||||
"${extra_tags[@]}" \
|
||||
"${exclude_args[@]}" \
|
||||
|
||||
@ -15,7 +15,7 @@ resticCheckLocation()
|
||||
fi
|
||||
|
||||
isNotice "Checking $(resticLocationName "$idx")${read_data:+ (sample: ${read_data}%)}"
|
||||
sudo -E -u "$docker_install_user" restic "${args[@]}"
|
||||
runBackupOp restic "${args[@]}"
|
||||
local rc=$?
|
||||
resticEnvUnset
|
||||
if [[ $rc -eq 0 ]]; then
|
||||
@ -42,7 +42,7 @@ resticLocationStats()
|
||||
{
|
||||
local idx="$1"
|
||||
resticEnvExport "$idx" || return 1
|
||||
sudo -E -u "$docker_install_user" restic stats --json --no-lock 2>/dev/null
|
||||
runBackupOp restic stats --json --no-lock 2>/dev/null
|
||||
local rc=$?
|
||||
resticEnvUnset
|
||||
return $rc
|
||||
|
||||
@ -10,9 +10,9 @@ resticDumpFile()
|
||||
resticEnvExport "$idx" || return 1
|
||||
|
||||
if [[ -n "$target_file" ]]; then
|
||||
sudo -E -u "$docker_install_user" restic dump "$snapshot_id" "$file_path" | sudo tee "$target_file" >/dev/null
|
||||
runBackupOp restic dump "$snapshot_id" "$file_path" | sudo tee "$target_file" >/dev/null
|
||||
else
|
||||
sudo -E -u "$docker_install_user" restic dump "$snapshot_id" "$file_path"
|
||||
runBackupOp restic dump "$snapshot_id" "$file_path"
|
||||
fi
|
||||
local rc=$?
|
||||
resticEnvUnset
|
||||
|
||||
@ -28,7 +28,7 @@ resticForgetApp()
|
||||
[[ "$CFG_BACKUP_PRUNE_AFTER_FORGET" == "true" ]] && args+=(--prune)
|
||||
|
||||
isNotice "Applying retention for $app_name on $(resticLocationName "$idx")"
|
||||
sudo -E -u "$docker_install_user" restic "${args[@]}"
|
||||
runBackupOp restic "${args[@]}"
|
||||
local rc=$?
|
||||
resticEnvUnset
|
||||
return $rc
|
||||
|
||||
@ -16,14 +16,14 @@ resticInitLocation()
|
||||
runFileOp chown -R "$docker_install_user":"$docker_install_user" "$RESTIC_REPOSITORY"
|
||||
fi
|
||||
|
||||
if sudo -E -u "$docker_install_user" restic snapshots --json --no-lock >/dev/null 2>&1; then
|
||||
if runBackupOp restic snapshots --json --no-lock >/dev/null 2>&1; then
|
||||
isNotice "$(resticLocationName "$idx") already initialized at $RESTIC_REPOSITORY"
|
||||
resticEnvUnset
|
||||
return 0
|
||||
fi
|
||||
|
||||
isNotice "Initializing $(resticLocationName "$idx") at $RESTIC_REPOSITORY"
|
||||
if sudo -E -u "$docker_install_user" restic init; then
|
||||
if runBackupOp restic init; then
|
||||
isSuccessful "$(resticLocationName "$idx") initialized"
|
||||
else
|
||||
isError "Failed to initialize $(resticLocationName "$idx")"
|
||||
|
||||
@ -20,7 +20,7 @@ resticRestoreSnapshot()
|
||||
[[ -n "$include_path" ]] && args+=(--include "$include_path")
|
||||
|
||||
isNotice "Restoring ${snapshot_id:0:8} from $(resticLocationName "$idx") → $target_dir"
|
||||
sudo -E -u "$docker_install_user" restic "${args[@]}"
|
||||
runBackupOp restic "${args[@]}"
|
||||
local rc=$?
|
||||
resticEnvUnset
|
||||
return $rc
|
||||
|
||||
@ -12,7 +12,7 @@ resticSnapshotsJson()
|
||||
[[ -n "$app_filter" ]] && args+=(--tag "app=$app_filter")
|
||||
[[ -n "$host_filter" ]] && args+=(--host "$host_filter")
|
||||
|
||||
sudo -E -u "$docker_install_user" restic "${args[@]}" 2>/dev/null
|
||||
runBackupOp restic "${args[@]}" 2>/dev/null
|
||||
local rc=$?
|
||||
resticEnvUnset
|
||||
return $rc
|
||||
@ -26,7 +26,7 @@ resticSnapshotLatestId()
|
||||
|
||||
resticEnvExport "$idx" || return 1
|
||||
local id
|
||||
id=$(sudo -E -u "$docker_install_user" restic snapshots \
|
||||
id=$(runBackupOp restic snapshots \
|
||||
--tag "app=$app_name" --host "$host" \
|
||||
--latest 1 --json --no-lock 2>/dev/null | \
|
||||
grep -o '"short_id":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
@ -40,7 +40,7 @@ resticSnapshotListFiles()
|
||||
local snapshot_id="$2"
|
||||
|
||||
resticEnvExport "$idx" || return 1
|
||||
sudo -E -u "$docker_install_user" restic ls --json --no-lock "$snapshot_id" 2>/dev/null
|
||||
runBackupOp restic ls --json --no-lock "$snapshot_id" 2>/dev/null
|
||||
local rc=$?
|
||||
resticEnvUnset
|
||||
return $rc
|
||||
|
||||
@ -77,6 +77,15 @@ runInstallWrite() {
|
||||
runAsManager tee "${append_flag[@]}" "$dest" >/dev/null
|
||||
}
|
||||
|
||||
# Backup-engine command (borg/restic/kopia) run AS the dedicated backup user
|
||||
# ($docker_install_user), with the environment preserved (-E) so the repo
|
||||
# password and BORG_/RESTIC_/KOPIA_ env vars reach the tool. Never root — the
|
||||
# scoped sudoers lets the manager drop to this user. Single funnel so the
|
||||
# backup subsystem's privilege drop has one audit point.
|
||||
runBackupOp() {
|
||||
sudo -E -u "$docker_install_user" "$@"
|
||||
}
|
||||
|
||||
# Genuine system-administration command (ufw/systemctl/apt/sysctl/useradd, /etc
|
||||
# edits). Needs real root in both modes; funnelled through one place so it can
|
||||
# later be confined to a scoped sudoers allowlist.
|
||||
|
||||
@ -10,7 +10,7 @@ getLibrePortalWebUIUrls()
|
||||
local db_file="${db_file:-database.db}"
|
||||
|
||||
# Check if sqlite3 is available and database exists
|
||||
if command -v sudo sqlite3 &> /dev/null && [ -f "$docker_dir/$db_file" ]; then
|
||||
if command -v sqlite3 &> /dev/null && [ -f "$docker_dir/$db_file" ]; then
|
||||
# Check if LibrePortal app is installed
|
||||
local libreportal_check=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE name = 'libreportal' AND status = 1;" 2>/dev/null)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user