Skip to main content

max / makenotwork

4.4 KB · 133 lines History Blame Raw
1 #!/bin/bash
2 # Set up ClamAV daemon on the Makenotwork production host (Ubuntu 24.04).
3 #
4 # Idempotent: safe to re-run. Installs `clamav-daemon` and `clamav-freshclam`,
5 # configures clamd to listen on a Unix socket the makenotwork service can
6 # reach, enables both as systemd services, and waits for the first signature
7 # update to complete.
8 #
9 # After this script finishes successfully, add the following to
10 # /opt/makenotwork/.env (and restart makenotwork):
11 #
12 # CLAMAV_SOCKET=/var/run/clamav/clamd.ctl
13 #
14 # That env var trips the `clamav` layer from Skip to live. The dashboard's
15 # Pipeline Health card for `clamav` will flip from "down — last clean: never"
16 # to "ok" after the first upload completes through the worker.
17 #
18 # References:
19 # - Ubuntu clamav package: https://packages.ubuntu.com/noble/clamav-daemon
20 # - INSTREAM protocol docs: clamdscan(1), clamd.conf(5)
21
22 set -euo pipefail
23
24 SOCKET_PATH="/var/run/clamav/clamd.ctl"
25 CLAMD_CONF="/etc/clamav/clamd.conf"
26
27 require_root() {
28 if [ "$(id -u)" -ne 0 ]; then
29 echo "[clamav] error: must run as root" >&2
30 exit 1
31 fi
32 }
33
34 install_packages() {
35 if dpkg -l | grep -q "^ii clamav-daemon "; then
36 echo "[clamav] clamav-daemon already installed"
37 return
38 fi
39 echo "[clamav] installing clamav-daemon + clamav-freshclam..."
40 DEBIAN_FRONTEND=noninteractive apt-get update -qq
41 DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
42 clamav-daemon clamav-freshclam
43 }
44
45 configure_socket() {
46 # Confirm the default LocalSocket directive matches our expectation. If
47 # the operator (or a future package update) changes it, surface that
48 # rather than silently writing a path that disagrees with the env var.
49 local existing
50 existing=$(grep -E "^LocalSocket\s" "$CLAMD_CONF" | awk '{print $2}' || true)
51 if [ -n "$existing" ] && [ "$existing" != "$SOCKET_PATH" ]; then
52 echo "[clamav] error: $CLAMD_CONF has LocalSocket=$existing, expected $SOCKET_PATH" >&2
53 echo "[clamav] edit clamd.conf and re-run, or update SOCKET_PATH in this script." >&2
54 exit 1
55 fi
56 if [ -z "$existing" ]; then
57 echo "[clamav] adding LocalSocket directive to $CLAMD_CONF..."
58 echo "" >> "$CLAMD_CONF"
59 echo "LocalSocket $SOCKET_PATH" >> "$CLAMD_CONF"
60 fi
61 }
62
63 wait_for_initial_signatures() {
64 # freshclam pulls the initial signature DB on first boot. Until that's
65 # done, clamd will refuse to start. Poll up to 5 minutes.
66 echo "[clamav] waiting for freshclam to fetch initial signatures..."
67 local deadline=$(( $(date +%s) + 300 ))
68 while [ $(date +%s) -lt $deadline ]; do
69 if [ -f /var/lib/clamav/daily.cvd ] || [ -f /var/lib/clamav/daily.cld ]; then
70 echo "[clamav] signatures present"
71 return
72 fi
73 sleep 5
74 done
75 echo "[clamav] warn: signatures not present after 5 min; check 'journalctl -u clamav-freshclam'" >&2
76 }
77
78 enable_services() {
79 systemctl enable --now clamav-freshclam
80 # Reload clamd config (idempotent) and start the daemon.
81 systemctl restart clamav-daemon
82 systemctl enable clamav-daemon
83 }
84
85 verify_socket() {
86 echo "[clamav] verifying socket reachability..."
87 local deadline=$(( $(date +%s) + 60 ))
88 while [ $(date +%s) -lt $deadline ]; do
89 if [ -S "$SOCKET_PATH" ]; then
90 if echo "PING" | timeout 5 socat - "UNIX-CONNECT:$SOCKET_PATH" 2>/dev/null | grep -q PONG; then
91 echo "[clamav] OK: clamd responds at $SOCKET_PATH"
92 return
93 fi
94 fi
95 sleep 2
96 done
97 echo "[clamav] warn: clamd not responding at $SOCKET_PATH within 60s" >&2
98 echo "[clamav] check 'journalctl -u clamav-daemon' and 'systemctl status clamav-daemon'" >&2
99 exit 1
100 }
101
102 ensure_socat() {
103 if ! command -v socat >/dev/null 2>&1; then
104 DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends socat
105 fi
106 }
107
108 main() {
109 require_root
110 install_packages
111 configure_socket
112 wait_for_initial_signatures
113 enable_services
114 ensure_socat
115 verify_socket
116
117 cat <<EOF
118
119 [clamav] setup complete.
120
121 Next step — set the env var so makenotwork uses this clamd:
122
123 echo 'CLAMAV_SOCKET=$SOCKET_PATH' >> /opt/makenotwork/.env
124 systemctl restart makenotwork
125
126 The Pipeline Health card for 'clamav' will flip from down to ok after the
127 first upload passes through the scan worker.
128
129 EOF
130 }
131
132 main "$@"
133