From d11c9d7c4a328c529c3475ef2b1995d6b522d165 Mon Sep 17 00:00:00 2001 From: Adam Outler Date: Fri, 17 Oct 2025 16:36:48 -0400 Subject: [PATCH] Improve warnings. --- Dockerfile | 2 + docker-compose.yml | 4 +- install/production-filesystem/entrypoint.sh | 1 + .../services/check-app.sh | 4 +- .../services/check-cap.sh | 34 ++++++++------ .../services/check-first-run-config.sh | 13 +++++- .../services/check-first-run-db.sh | 13 +++++- .../services/check-ramdisk.sh | 46 ++++++++++++------- .../services/check-root.sh | 31 +++++++++++++ 9 files changed, 111 insertions(+), 37 deletions(-) create mode 100644 install/production-filesystem/services/check-root.sh diff --git a/Dockerfile b/Dockerfile index d4fe19b6c..c42db01cb 100755 --- a/Dockerfile +++ b/Dockerfile @@ -137,8 +137,10 @@ COPY --from=builder --chown=20212:20212 ${VIRTUAL_ENV} ${VIRTUAL_ENV} # although it may be quicker to do it before the copy, it keeps the image # layers smaller to do it after. RUN apk add libcap && \ + setcap cap_net_raw+ep /bin/busybox && \ setcap cap_net_raw,cap_net_admin+eip /usr/bin/nmap && \ setcap cap_net_raw,cap_net_admin+eip /usr/bin/arp-scan && \ + setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip /usr/bin/nbtscan && \ setcap cap_net_raw,cap_net_admin+eip /usr/bin/traceroute && \ setcap cap_net_raw,cap_net_admin+eip ${VIRTUAL_ENV_BIN}/scapy && \ /bin/sh /build/init-nginx.sh && \ diff --git a/docker-compose.yml b/docker-compose.yml index 4d7a577a9..92fd56f9e 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,8 +12,8 @@ services: cap_add: # Add only the necessary capabilities - NET_ADMIN # Required for ARP scanning - NET_RAW # Required for raw socket operations - security_opt: # Security options for the container - - no-new-privileges:true # Prevent privilege escalation + - NET_BIND_SERVICE # Required to bind to privileged ports (nbtscan) + volumes: - type: volume source: netalertx_config diff --git a/install/production-filesystem/entrypoint.sh b/install/production-filesystem/entrypoint.sh index c7103820b..85b585eea 100644 --- a/install/production-filesystem/entrypoint.sh +++ b/install/production-filesystem/entrypoint.sh @@ -12,6 +12,7 @@ echo ' set -u +bash /services/check-root.sh bash /services/check-cap.sh bash /services/check-ramdisk.sh bash /services/check-first-run-config.sh diff --git a/install/production-filesystem/services/check-app.sh b/install/production-filesystem/services/check-app.sh index 776ed3b68..d41dee964 100644 --- a/install/production-filesystem/services/check-app.sh +++ b/install/production-filesystem/services/check-app.sh @@ -2,6 +2,6 @@ # app-check.sh - Ensures /app/api/table_settings.json exists if [ ! -f /app/api/table_settings.json ]; then - mkdir -p /app/api - echo -ne '{}' > /app/api/table_settings.json + # mkdir -p /app/api + # echo -ne '{}' > /app/api/table_settings.json fi diff --git a/install/production-filesystem/services/check-cap.sh b/install/production-filesystem/services/check-cap.sh index 56dc3b475..b3de48c29 100644 --- a/install/production-filesystem/services/check-cap.sh +++ b/install/production-filesystem/services/check-cap.sh @@ -6,20 +6,26 @@ ERROR_OUTPUT=$(nmap --privileged -sS -p 20211 127.0.0.1 2>&1 >/dev/null) EXIT_CODE=$? -# If the exit code is exactly 126 AND the error message contains a known permission error... -if [ "$EXIT_CODE" -eq 126 ] && \ - echo "$ERROR_OUTPUT" | grep -q -e "Operation not permitted" -e "requires root privileges" +# Flag common capability errors regardless of exact exit code. +if [ "$EXIT_CODE" -ne 0 ] && \ + echo "$ERROR_OUTPUT" | grep -q -e "Operation not permitted" -e "requires root privileges" then - # ...then print the detailed warning. - echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️" >&2 - echo " ATTENTION: This container is running without elevated" >&2 - echo " network privileges (NET_RAW/NET_ADMIN)." >&2 - echo "" >&2 - echo " Advanced network tools that require raw socket access," >&2 - echo " like 'nmap -sS', will fail." >&2 - echo "" >&2 - echo " To fix this, restart the container with the following flags:" >&2 - echo " --cap-add=NET_RAW --cap-add=NET_ADMIN" >&2 - echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️" >&2 + YELLOW=$(printf '\033[1;33m') + RESET=$(printf '\033[0m') + >&2 printf "%s" "${YELLOW}" + >&2 cat <<'EOF' +══════════════════════════════════════════════════════════════════════════════ +⚠️ ATTENTION: Raw network capabilities are missing. + + Tools that rely on NET_RAW/NET_ADMIN/NET_BIND_SERVICE (e.g. nmap -sS, + arp-scan, nbtscan) will not function. Restart the container with: + + --cap-add=NET_RAW --cap-add=NET_ADMIN --cap-add=NET_BIND_SERVICE + + Without those caps, NetAlertX cannot inspect your network. Fix it before + trusting any results. +══════════════════════════════════════════════════════════════════════════════ +EOF + >&2 printf "%s" "${RESET}" exit 1 fi \ No newline at end of file diff --git a/install/production-filesystem/services/check-first-run-config.sh b/install/production-filesystem/services/check-first-run-config.sh index 44269df32..0a477837c 100644 --- a/install/production-filesystem/services/check-first-run-config.sh +++ b/install/production-filesystem/services/check-first-run-config.sh @@ -5,6 +5,17 @@ if [ ! -f /app/config/app.conf ]; then mkdir -p /app/config cp /app/back/app.conf /app/config/app.conf - echo "🆕 First run detected: Default configuration initialized." >&2 + CYAN='\033[1;36m' + RESET='\033[0m' + >&2 printf "%s" "${CYAN}" + >&2 cat <<'EOF' +══════════════════════════════════════════════════════════════════════════════ +🆕 First run detected. Default configuration written to /app/config/app.conf. + + Review your settings in the UI or edit the file directly before trusting + this instance in production. +══════════════════════════════════════════════════════════════════════════════ +EOF + >&2 printf "%s" "${RESET}" fi diff --git a/install/production-filesystem/services/check-first-run-db.sh b/install/production-filesystem/services/check-first-run-db.sh index 842be90ae..226971125 100644 --- a/install/production-filesystem/services/check-first-run-db.sh +++ b/install/production-filesystem/services/check-first-run-db.sh @@ -5,7 +5,18 @@ # if the db exists, exit test -f "${NETALERTX_DB_FILE}" && exit 0 -echo "First run detected, creating initial database schema in ${NETALERTX_DB_FILE}" +CYAN='\033[1;36m' +RESET='\033[0m' +>&2 printf "%s" "${CYAN}" +>&2 cat <&2 printf "%s" "${RESET}" # Write all text to db file until we see "end-of-database-schema" cat << end-of-database-schema > ${NETALERTX_DB_FILE} diff --git a/install/production-filesystem/services/check-ramdisk.sh b/install/production-filesystem/services/check-ramdisk.sh index 571a19d0b..c9fe00c89 100644 --- a/install/production-filesystem/services/check-ramdisk.sh +++ b/install/production-filesystem/services/check-ramdisk.sh @@ -1,31 +1,43 @@ #!/bin/sh -# ramdisk-check.sh - Verify critical paths are backed by ramdisk and warn on fallback storage. +# storage-check.sh - Verify critical paths use dedicated mounts. -warn_if_not_ramdisk() { +warn_if_not_dedicated_mount() { path="$1" - - if cat /proc/mounts| grep ${path} | grep -qE 'tmpfs|ramfs'; then + if awk -v target="${path}" '$5 == target {found=1} END {exit found ? 0 : 1}' /proc/self/mountinfo; then return 0 fi - cat >&2 <&2 printf "%s" "${YELLOW}" + >&2 cat <&2 printf "%s" "${RESET}" } -warn_if_not_ramdisk "${NETALERTX_API}" -warn_if_not_ramdisk "${NETALERTX_LOG}" +failures=0 +warn_if_not_dedicated_mount "${NETALERTX_API}" +warn_if_not_dedicated_mount "${NETALERTX_LOG}" + +if [ "${failures}" -ne 0 ]; then + exit 1 +fi if [ ! -f "${SYSTEM_NGINIX_CONFIG}/conf.active" ]; then echo "Note: Using default listen address ${LISTEN_ADDR}:${PORT} (no ${SYSTEM_NGINIX_CONFIG}/conf.active override)." diff --git a/install/production-filesystem/services/check-root.sh b/install/production-filesystem/services/check-root.sh new file mode 100644 index 000000000..eaf0c430b --- /dev/null +++ b/install/production-filesystem/services/check-root.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# check-root.sh - ensure the container is not running as root. + +CURRENT_UID="$(id -u)" + +if [ "${CURRENT_UID}" -eq 0 ]; then + YELLOW=$(printf '\033[1;33m') + RESET=$(printf '\033[0m') + >&2 printf "%s" "${YELLOW}" + >&2 cat <<'EOF' +══════════════════════════════════════════════════════════════════════════════ +⚠️ ATTENTION: NetAlertX is running as root (UID 0). + + This defeats every hardening safeguard built into the image. You just + handed a high-value network monitoring appliance full control over your + host. If an attacker compromises NetAlertX now, the entire machine goes + with it. + + Run the container as the dedicated 'netalertx' user instead: + * Keep the default USER in the image (20211:20211), or + * In docker-compose.yml, remove any 'user:' override that sets UID 0. + + Bottom line: never run security tooling as root unless you are actively + trying to get pwned. +══════════════════════════════════════════════════════════════════════════════ +EOF + >&2 printf "%s" "${RESET}" + exit 1 +fi + +exit 0