The login banner on subopi/pfvsvrpi systems was bleeding into the sudo
check output, making SUDOOK results look garbled and broken. Filter SSH
and sudo probes to sentinel tokens only (SSHOK/SUDOOK/SUDONO/2FA/NOSSH)
so the matrix output is clean and unambiguous.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
68 lines
2.7 KiB
Bash
68 lines
2.7 KiB
Bash
#!/usr/bin/bash
|
|
# access-matrix.sh — definitive access verification across all Linux Tailscale nodes.
|
|
# Uses the correct SSH user(s) per system type, checks sudo where applicable.
|
|
# Routes through remote.sh (the only allowed ssh path).
|
|
set -u
|
|
cd /home/reachableceo/projects/PFVCluster || exit 1
|
|
|
|
# Policy-excluded systems (never attempt access)
|
|
EXCLUDE=':tsys-cloudron:pfv-bms:tsys-umbrel:tsys-ucs-01:tsys-ucs-02:stlpc-bizoffice:ultix-highside:'
|
|
|
|
# Determine the SSH user(s) for a given hostname and whether sudo is expected.
|
|
# Returns "user1:user2:...:sudoflag" where sudoflag is "yes" or "no".
|
|
users_for() {
|
|
local name="$1"
|
|
case "$name" in
|
|
pfv-tsys[0-9]) echo "root:no" ;;
|
|
*-proxmox-datacenter) echo "root:no" ;;
|
|
*-proxmox-pve) echo "root:no" ;;
|
|
*-proxmox-pbs) echo "root:no" ;;
|
|
*-proxmox-mailgw*) echo "root:no" ;;
|
|
*-proxmox-backup*) echo "root:no" ;;
|
|
tsys-ucs-*) echo "root:no" ;;
|
|
ultix-streaming) echo "root:no" ;;
|
|
stlpc-*) echo "root:labuser:no" ;;
|
|
ultix-field) echo "ultixfield:yes" ;;
|
|
subopi*) echo "subodev:yes" ;;
|
|
*) echo "localuser:yes" ;;
|
|
esac
|
|
}
|
|
|
|
check_user() {
|
|
local ip="$1" user="$2" expect_sudo="$3"
|
|
local out sudo
|
|
out=$(VM_IP="$ip" VM_USER="$user" bash tests/remote.sh vm 'echo SSHOK; id -un' </dev/null 2>&1 | grep -oE 'SSHOK|keyboard-interactive|Connection refused' | head -1)
|
|
case "$out" in
|
|
SSHOK)
|
|
if [ "$expect_sudo" = "yes" ]; then
|
|
sudo=$(VM_IP="$ip" VM_USER="$user" bash tests/remote.sh vm 'sudo -n true 2>/dev/null && echo SUDOOK || echo SUDONO' </dev/null 2>&1 | grep -oE 'SUDOOK|SUDONO' | head -1)
|
|
printf '%s(%s)' "$user" "${sudo:-?}"
|
|
else
|
|
printf '%s(ok)' "$user"
|
|
fi
|
|
;;
|
|
keyboard-interactive) printf '%s(2FA)' "$user" ;;
|
|
'Connection refused') printf '%s(NOSSH)' "$user" ;;
|
|
*) printf '%s(NOKEY)' "$user" ;;
|
|
esac
|
|
}
|
|
|
|
printf '%-32s %-16s %s\n' "NAME" "TS-IP" "ACCESS"
|
|
printf '%-32s %-16s %s\n' "----" "-----" "------"
|
|
|
|
tailscale status 2>/dev/null | awk '$4=="linux" {print $2, $1}' | sort | while read -r name ip; do
|
|
[ -n "$name" ] || continue
|
|
case "$EXCLUDE" in *":$name:"*) printf '%-32s %-16s %s\n' "$name" "$ip" "EXCLUDED"; continue;; esac
|
|
|
|
map=$(users_for "$name")
|
|
expect_sudo="${map##*:}"
|
|
users="${map%:*}"
|
|
result=""
|
|
IFS=':' read -ra user_list <<< "$users"
|
|
for u in "${user_list[@]}"; do
|
|
r=$(check_user "$ip" "$u" "$expect_sudo")
|
|
[ -z "$result" ] && result="$r" || result="$result $r"
|
|
done
|
|
printf '%-32s %-16s %s\n' "$name" "$ip" "$result"
|
|
done
|