bigboy-alma-deploy/scripts/configure-llama-firewall.sh

104 lines
No EOL
4.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Built standing on the shoulders of billions of dwarves
# Created by John A. Hoeven with the ethical assistance of Claude AI
# Licence: The Unlicense — https://unlicense.org
# ---------------------------------------------------------------------------
# configure-llama-firewall.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Role: Orchestrator
# ---------------------------------------------------------------------------
# Purpose: Open the reverse-proxy HTTP port for llama-server's web UI,
# restricted to the same two LAN ranges already used for SSH
# (see the kickstart's own firewalld zone file). This was
# previously only run as one-off firewall-cmd commands typed
# directly during the Phase 5 deployment session — never
# tracked anywhere. This script is that missing artifact.
# Target: BigBoy — AlmaLinux 10.2, firewalld already enabled from the
# kickstart (SSH rules already in place via a direct zone-file
# write during install — see CLAUDE.md for why firewall-cmd
# itself doesn't work inside a kickstart %post chroot; that
# limitation does not apply here, since this runs against a
# live, fully-booted system with firewalld actually running).
# Entry: ./configure-llama-firewall.sh
# Depends: firewalld (already enabled)
# Note: Idempotent — firewall-cmd's --add-rich-rule is itself
# idempotent (adding an already-present rule is a no-op, not
# an error), so this is safe to re-run.
# ---------------------------------------------------------------------------
# No 'set -e' — every operation checked and logged explicitly (CE OS standard §1.8).
# ── Configuration ────────────────────────────────────────────────────────
#
# These ranges must match firewall_allowed_ranges in
# ansible/group_vars/bigboy.yml — if that file is ever updated, update
# this script too, or better, formalize this into an actual Ansible role
# that reads the variable directly rather than duplicating the values
# here (see ansible/README.md's "Known Deferred" section — Phase 4/5
# aren't yet real roles, this script is the same category of gap).
ALLOWED_RANGES=(
"192.168.1.0/24" # home LAN — current
"192.168.0.0/24" # workbench bench LAN — used during initial deploy
)
HTTP_ZONE="public"
LOG_DIR="${HOME}/.local/logs/firewall-config"
LOG_FILE="${LOG_DIR}/config-$(date '+%Y-%m-%d_%H%M%S').log"
mkdir -p "${LOG_DIR}"
_log() {
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "${1}" | tee -a "${LOG_FILE}"
}
# ── Pre-flight ───────────────────────────────────────────────────────────
if [[ "${EUID}" -eq 0 ]]; then
_log "ERROR: do not run this as root directly — it invokes sudo only"
_log "for the specific steps that need it."
exit 1
fi
if ! systemctl is-active --quiet firewalld; then
_log "ERROR: firewalld is not active. This script assumes it's already"
_log "enabled (per the kickstart). Check 'systemctl status firewalld'"
_log "before proceeding — something else is wrong if it's not running."
exit 1
fi
# ── Confirmation ─────────────────────────────────────────────────────────
_log "About to open HTTP (port 80, llama-server's reverse proxy) for:"
for range in "${ALLOWED_RANGES[@]}"; do
_log " - ${range}"
done
printf 'Proceed? [y/N] '
read -r response
case "${response}" in
[yY]|[yY][eE][sS]) ;;
*) _log "Aborted by user."; exit 0 ;;
esac
# ── Apply rules ──────────────────────────────────────────────────────────
for range in "${ALLOWED_RANGES[@]}"; do
_log "Adding rich rule for ${range}"
if ! sudo firewall-cmd --permanent --zone="${HTTP_ZONE}" \
--add-rich-rule="rule family=\"ipv4\" source address=\"${range}\" service name=\"http\" accept" \
>>"${LOG_FILE}" 2>&1; then
_log "ERROR: failed to add rich rule for ${range} — see ${LOG_FILE}"
exit 1
fi
done
_log "Reloading firewalld to apply changes"
if ! sudo firewall-cmd --reload >>"${LOG_FILE}" 2>&1; then
_log "ERROR: firewall-cmd --reload failed — see ${LOG_FILE}"
exit 1
fi
_log ""
_log "Done. Confirm with:"
_log " sudo firewall-cmd --zone=${HTTP_ZONE} --list-rich-rules"
_log ""
_log "Full log: ${LOG_FILE}"