sync: auto-sync from HOWARD-HOME at 2026-06-21 12:00:27
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-06-21 12:00:27
This commit is contained in:
@@ -46,7 +46,8 @@ path is Cascades — override with the script's vault-path arg per client.
|
||||
- **[WORKING] pfSense gateway compatibility layer via SSH** — `scripts/pfsense-ssh.sh <slug> <verb>`.
|
||||
DECISION (Mike 2026-06-16): **no RESTAPI package needed** — VPN + SSH shell reads the same data and makes
|
||||
changes. Cred = `clients/<slug>/pfsense-firewall` (host + admin user/pass), system OpenSSH via askpass.
|
||||
Validated live on Cascades (pfSense Plus 25.07).
|
||||
SSH port: `--port N` flag > optional vault `port`/`credentials.port` field > default 22 (e.g. the ACG
|
||||
office box on 2248 — store `port: 2248` in its vault entry). Validated live on Cascades (pfSense Plus 25.07).
|
||||
- **Reads (no gate):** `audit` (WAN/DHCP/states/DNS/NIC health), `dhcp` (pool pressure), `pf-list`
|
||||
(NAT port-forwards), `fw-list` (filter rules), `showblock [--if wan]` (active easyrule blocks),
|
||||
`run "<cmd>"` (arbitrary; incl. changes — operator-gated, no dry-run).
|
||||
|
||||
@@ -138,6 +138,8 @@ Writes (DRY-RUN default; `--apply` to commit — `write_config` + `filter_config
|
||||
`php`, which bootstraps `$config` via `config.inc` (do NOT re-require util/functions/filter — "cannot redeclare"
|
||||
fatal). Each write backs up `/cf/conf/config.xml` to `/tmp` first; `write_config()` also keeps pfSense's own
|
||||
config history. Cred = `clients/<slug>/pfsense-firewall` (host + admin user/pass), system OpenSSH via askpass.
|
||||
- [x] **SSH port configurable** (2026-06-21): `--port N` > vault `port`/`credentials.port` field > default 22.
|
||||
Unblocks non-standard-port boxes like the ACG office gateway (2248) — store `port: 2248` in its vault entry.
|
||||
- [x] **Dispatch rewired:** `gw-control.sh` / `gw-audit.sh` now prefer the SSH backend (keyed on
|
||||
`clients/<slug>/pfsense-firewall`) and route the same verbs to it; dispatch runs BEFORE UOS site resolution so a
|
||||
pfSense-only slug works. REST path is the dormant fallback.
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
# VPN + SSH shell we can read the same data and make changes directly. (Confirmed on Cascades pfSense Plus
|
||||
# 25.07: admin SSH drops straight to a shell, no menu gotcha.)
|
||||
#
|
||||
# Cred from the vault: clients/<slug>/pfsense-firewall (top-level `host`, credentials.username/password).
|
||||
# Cred from the vault: clients/<slug>/pfsense-firewall (top-level `host`, credentials.username/password,
|
||||
# optional `port` — else `--port N`, else default 22; e.g. the ACG office box is on 2248).
|
||||
# Uses SYSTEM OpenSSH via an SSH_ASKPASS helper (no sshpass dependency); runs each call as `sh -s` over a
|
||||
# heredoc so awk/quoting is clean.
|
||||
#
|
||||
@@ -33,25 +34,34 @@ HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
GWC_PHP="$HERE/pfsense-gwc.php"
|
||||
SLUG="${1:?usage: pfsense-ssh.sh <slug> <action> [args] [--apply]}"
|
||||
ACT="${2:?action: audit|dhcp|pf-list|fw-list|pf-*|fw-*|block-ips|unblock|showblock|run|shell}"; shift 2 || true
|
||||
RAWARGS=("$@") # preserved verbatim for `run`
|
||||
APPLY=0; BLOCK_IF="wan"; POS=()
|
||||
APPLY=0; BLOCK_IF="wan"; PORT=""; POS=()
|
||||
while [ $# -gt 0 ]; do case "$1" in
|
||||
--apply) APPLY=1; shift;;
|
||||
--if) BLOCK_IF="${2:?--if needs an interface}"; shift 2;;
|
||||
--port) PORT="${2:?--port needs a number}"; shift 2;;
|
||||
*) POS+=("$1"); shift;;
|
||||
esac; done
|
||||
VP="clients/$SLUG/pfsense-firewall"
|
||||
HOST="$(bash "$VAULT" get-field "$VP" host 2>/dev/null || bash "$VAULT" get-field "$VP" credentials.host 2>/dev/null || true)"
|
||||
U="$(bash "$VAULT" get-field "$VP" credentials.username 2>/dev/null || true)"
|
||||
PP="$(bash "$VAULT" get-field "$VP" credentials.password 2>/dev/null || true)"; export PP
|
||||
# SSH port precedence: --port flag > vault `port`/`credentials.port` field > default 22.
|
||||
# (vault get-field returns the literal "null" for a missing field, so normalize "" and "null".)
|
||||
if [ -z "$PORT" ]; then
|
||||
for pf in port credentials.port; do
|
||||
v="$(bash "$VAULT" get-field "$VP" "$pf" 2>/dev/null || true)"
|
||||
case "$v" in ""|null) ;; *) PORT="$v"; break;; esac
|
||||
done
|
||||
fi
|
||||
PORT="${PORT:-22}"
|
||||
if [ -z "$HOST" ] || [ -z "$U" ] || [ -z "$PP" ]; then
|
||||
echo "[BLOCKED] need host + admin creds at vault:$VP (fields: host, credentials.username, credentials.password)"; exit 2; fi
|
||||
if [ "$ACT" = "shell" ]; then echo "ssh ${U}@${HOST} # password in vault:$VP"; exit 0; fi
|
||||
if [ "$ACT" = "shell" ]; then echo "ssh -p ${PORT} ${U}@${HOST} # password in vault:$VP"; exit 0; fi
|
||||
|
||||
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
|
||||
ASKP="$TMP/a.sh"; printf '#!/bin/sh\nprintf "%%s\\n" "$PP"\n' >"$ASKP"; chmod +x "$ASKP"
|
||||
# pfssh: feed remote sh a script on stdin; password via askpass (stderr noise dropped)
|
||||
pfssh(){ SSH_ASKPASS="$ASKP" SSH_ASKPASS_REQUIRE=force DISPLAY=:0 ssh \
|
||||
pfssh(){ SSH_ASKPASS="$ASKP" SSH_ASKPASS_REQUIRE=force DISPLAY=:0 ssh -p "$PORT" \
|
||||
-o ConnectTimeout=12 -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null \
|
||||
-o PreferredAuthentications=password -o PubkeyAuthentication=no -o NumberOfPasswordPrompts=1 \
|
||||
"$U@$HOST" 'sh -s' 2>/dev/null; }
|
||||
@@ -69,10 +79,10 @@ run_gwc(){
|
||||
} | pfssh
|
||||
}
|
||||
|
||||
echo "[INFO] pfSense $ACT @ $U@$HOST (vault:$VP)"
|
||||
echo "[INFO] pfSense $ACT @ $U@$HOST:$PORT (vault:$VP)"
|
||||
case "$ACT" in
|
||||
run)
|
||||
CMD="${RAWARGS[*]}"; [ -n "$CMD" ] || { echo "[ERROR] run needs a command"; exit 1; }
|
||||
CMD="${POS[*]}"; [ -n "$CMD" ] || { echo "[ERROR] run needs a command"; exit 1; }
|
||||
printf '%s\n' "$CMD" | pfssh ;;
|
||||
|
||||
pf-list) run_gwc pf-list 0 "" "" "" ;;
|
||||
|
||||
Reference in New Issue
Block a user