Initial Commit
This commit is contained in:
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
# =====================================================================
|
||||
# Network namespace guard for owuitools-vmagent.
|
||||
#
|
||||
# WHY A SECOND GUARD AND NOT THE EXISTING ONE
|
||||
#
|
||||
# owuitools-netguard already exists and already does this for the api
|
||||
# container. The agent is not put behind it because their allowlists are
|
||||
# different in a way that matters: the agent needs Ollama, and Ollama has
|
||||
# no authentication and serves DELETE /api/delete. Adding it to the api
|
||||
# container's allowlist would mean a URL-validation bug in fetch_page
|
||||
# could delete the model the whole assistant runs on.
|
||||
#
|
||||
# So the agent gets its own namespace with a strictly smaller allowlist:
|
||||
# owuitools-vmgw, and nothing else. vmgw is the one that may talk to
|
||||
# Ollama and to Open WebUI, and it exposes exactly three paths.
|
||||
#
|
||||
# The agent's other channel - vmd - is a unix socket on a bind mount, so
|
||||
# it does not appear here at all. That is the point of using a socket:
|
||||
# a filesystem permission cannot be reached by a network bug.
|
||||
#
|
||||
# The result is a hard allowlist of ONE address and ONE port.
|
||||
# =====================================================================
|
||||
set -eu
|
||||
|
||||
# What this applied, kept with every other component's log. `exec` so the
|
||||
# redirection covers the verification output at the end too, which is the
|
||||
# part worth having: it is the difference between "the filter ran" and
|
||||
# "the filter is in force".
|
||||
LOG_DIR="${OWUITOOLS_LOG_DIR:-/logs}"
|
||||
if [ -d "$LOG_DIR" ] && [ -w "$LOG_DIR" ]; then
|
||||
exec > >(tee -a "$LOG_DIR/vmguard.log") 2>&1
|
||||
fi
|
||||
|
||||
# From docker-compose.yml, for the reason in netguard/firewall.sh: the
|
||||
# address is pinned there, and a second copy here is the one that gets
|
||||
# forgotten. It must stay equal to OWUITOOLS_VMGW_URL on the vmagent
|
||||
# container - that is the address the agent dials, and this is the only
|
||||
# address it is allowed to reach.
|
||||
GW_IP="${OWUITOOLS_VMGW_IP:-172.22.2.10}" # the only permitted destination
|
||||
GW_PORT="${OWUITOOLS_VMGW_PORT:-8000}"
|
||||
|
||||
echo "Configuring owuitools vmguard..."
|
||||
|
||||
# Fail closed before opening anything.
|
||||
iptables -w 10 -P INPUT DROP
|
||||
iptables -w 10 -P OUTPUT DROP
|
||||
iptables -w 10 -P FORWARD DROP
|
||||
|
||||
# Filter table only. Docker's embedded DNS resolver installs NAT rules in
|
||||
# this namespace; flushing nat would break name resolution.
|
||||
iptables -w 10 -F INPUT
|
||||
iptables -w 10 -F OUTPUT
|
||||
iptables -w 10 -F FORWARD
|
||||
|
||||
# Loopback: the embedded resolver at 127.0.0.11 and the agent's own
|
||||
# healthcheck.
|
||||
iptables -w 10 -A INPUT -i lo -j ACCEPT
|
||||
iptables -w 10 -A OUTPUT -o lo -j ACCEPT
|
||||
|
||||
iptables -w 10 -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||
iptables -w 10 -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
# The whole allowlist.
|
||||
iptables -w 10 -A OUTPUT -d "$GW_IP/32" -p tcp --dport "$GW_PORT" \
|
||||
-m conntrack --ctstate NEW -j ACCEPT
|
||||
|
||||
# Nothing may start a conversation with the agent. It claims work from a
|
||||
# shared volume and answers there; it serves nothing.
|
||||
|
||||
# Verify the rules that matter actually took, and that the policies are
|
||||
# still DROP. A firewall that silently failed to apply is worse than
|
||||
# none, because everything downstream carries on as though it were
|
||||
# enforced - the same assertion netguard/firewall.sh makes.
|
||||
iptables -w 10 -C OUTPUT -d "$GW_IP/32" -p tcp --dport "$GW_PORT" \
|
||||
-m conntrack --ctstate NEW -j ACCEPT
|
||||
|
||||
test "$(iptables -S INPUT | head -n 1)" = "-P INPUT DROP"
|
||||
test "$(iptables -S OUTPUT | head -n 1)" = "-P OUTPUT DROP"
|
||||
test "$(iptables -S FORWARD | head -n 1)" = "-P FORWARD DROP"
|
||||
|
||||
touch /tmp/firewall-ready
|
||||
|
||||
echo
|
||||
echo "owuitools vmguard ready."
|
||||
echo " outbound $GW_IP:$GW_PORT (vmgw) and nothing else"
|
||||
echo " inbound nothing"
|
||||
echo " the host, the LAN, Ollama and Open WebUI are NOT reachable directly"
|
||||
echo
|
||||
|
||||
trap 'exit 0' TERM INT
|
||||
while :; do
|
||||
sleep 3600 &
|
||||
wait $!
|
||||
done
|
||||
Reference in New Issue
Block a user