-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathinstall.sh
More file actions
123 lines (111 loc) · 4.95 KB
/
Copy pathinstall.sh
File metadata and controls
123 lines (111 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/bin/sh
# install.sh — install or update the ZFW host firewall on a ZimaOS host.
#
# Run this ON the ZimaOS host as root:
# sh install.sh
# (or, as the unprivileged user: echo '<password>' | sudo -S sh install.sh)
#
# It installs two pieces and starts the service:
# 1. the sysext module -> /var/lib/extensions/zfw.raw
# 2. the firewall engine -> /DATA/zfw/zfw (root:root, 0700)
# then merges the sysext and (re)starts zfw-ui.service. Re-running it
# updates an existing install in place.
set -eu
NAME="zfw"
EXT_DIR="/var/lib/extensions"
ENGINE_DIR="/DATA/zfw"
SERVICE="zfw-ui.service"
say() { echo "[zfw-install] $*"; }
die() { echo "[zfw-install] ERROR: $*" >&2; exit 1; }
SELF_DIR="$(cd "$(dirname "$0")" && pwd)"
# find_file echoes the first candidate path that exists, or dies.
find_file() {
desc="$1"
shift
for p in "$@"; do
[ -f "$p" ] && { echo "$p"; return 0; }
done
die "$desc not found (looked in: $*)"
}
# The build bundle (dist/) keeps both payload files next to this script
# under the generic name "zfw.raw"; the source repo dist/ keeps them
# per-arch (zfw-amd64.raw, zfw-arm64.raw). Map the host's uname -m to the
# Go arch the build produces so a source-repo install picks the right one.
case "$(uname -m 2>/dev/null)" in
x86_64|amd64) HOST_ARCH=amd64 ;;
aarch64|arm64) HOST_ARCH=arm64 ;;
*) HOST_ARCH="$(uname -m 2>/dev/null || echo unknown)" ;;
esac
RAW="$(find_file 'module zfw.raw' \
"$SELF_DIR/zfw.raw" \
"$SELF_DIR/dist/zfw-$HOST_ARCH.raw" \
"$SELF_DIR/dist/zfw.raw")"
ENGINE="$(find_file 'engine script zfw' "$SELF_DIR/zfw" "$SELF_DIR/engine/zfw")"
# --- preflight ---
[ "$(id -u)" -eq 0 ] || die "must run as root — try: sudo sh $0"
command -v systemd-sysext >/dev/null 2>&1 || die "systemd-sysext not found"
command -v systemctl >/dev/null 2>&1 || die "systemctl not found"
[ -d "$EXT_DIR" ] || die "$EXT_DIR missing — host does not support systemd-sysext"
say "module : $RAW"
say "engine : $ENGINE"
# --- verify the module checksum when the .sha256 is shipped alongside ---
#
# This detects corruption, not tampering: the .sha256 travels inside the same
# tarball as the .raw, so anyone who can rewrite one can rewrite the other. The
# authenticity anchor is the tarball SHA pinned in mod-store/zfw.yaml plus the
# HTTPS download (cosign signing is deliberately not wired up yet — see
# .github/workflows/ci.yml). Say so when the check is skipped, rather than
# leaving the operator to assume it ran.
if [ -f "$RAW.sha256" ] && command -v sha256sum >/dev/null 2>&1; then
( cd "$(dirname "$RAW")" && sha256sum -c "$(basename "$RAW").sha256" >/dev/null ) \
&& say "checksum OK (integrity only — verifies the download, not the publisher)" \
|| die "checksum mismatch on $RAW"
elif [ ! -f "$RAW.sha256" ]; then
say "WARNING: no $RAW.sha256 alongside the module — integrity NOT verified"
else
say "WARNING: sha256sum not available — integrity NOT verified"
fi
# --- 1. sysext module (atomic replace) ---
cp "$RAW" "$EXT_DIR/$NAME.raw.tmp"
chmod 0644 "$EXT_DIR/$NAME.raw.tmp"
mv "$EXT_DIR/$NAME.raw.tmp" "$EXT_DIR/$NAME.raw"
say "module installed -> $EXT_DIR/$NAME.raw"
# --- 2. firewall engine: root-owned and root-only — it is executed as root,
# so a non-root-writable path here would be a privilege-escalation hole.
#
# Refuse a symlinked engine dir before chown/chmod touch it. /DATA is writable by
# any container that bind-mounts it — the standard ZimaOS app pattern — so a
# malicious one can plant /DATA/zfw -> /etc ahead of a (re)install. mkdir -p is
# happy with an existing symlink, and chown/chmod then follow it: the script
# would chmod 0700 /etc as root, locking every non-root process out of the
# system's config, and drop the engine at /etc/zfw. Test the path itself, not
# what it points at.
if [ -L "$ENGINE_DIR" ]; then
die "$ENGINE_DIR is a symlink -> $(readlink "$ENGINE_DIR"). Refusing: this script chowns and chmods it as root. Remove the symlink and re-run."
fi
mkdir -p "$ENGINE_DIR"
chown root:root "$ENGINE_DIR"
chmod 0700 "$ENGINE_DIR"
cp "$ENGINE" "$ENGINE_DIR/$NAME.tmp"
chown root:root "$ENGINE_DIR/$NAME.tmp"
chmod 0700 "$ENGINE_DIR/$NAME.tmp"
mv "$ENGINE_DIR/$NAME.tmp" "$ENGINE_DIR/$NAME"
say "engine installed -> $ENGINE_DIR/$NAME (root:root 0700)"
# --- 3. merge the sysext overlay and (re)start the service ---
say "merging sysext overlay..."
systemd-sysext refresh
systemctl daemon-reload
# enable is best-effort: boot-persistence is actually provided by the
# zfw-ui-watchdog timer the daemon installs into /etc on first start
# (a unit that lives only in the sysext loses the boot race otherwise).
systemctl enable "$SERVICE" >/dev/null 2>&1 || true
systemctl restart "$SERVICE"
# --- 4. verify ---
sleep 2
systemctl is-active --quiet "$SERVICE" || {
systemctl --no-pager --lines=20 status "$SERVICE" || true
die "$SERVICE did not start — see the status output above"
}
say "done — $SERVICE is active"
say "open the ZFW Firewall tile in the ZimaOS dashboard, or browse to"
say " http://<this-host>/modules/zfw/index.html"