Set container parameters

This commit is contained in:
Adam Outler
2025-10-12 15:05:20 -04:00
parent be73e3a7f5
commit 1be91559d2
16 changed files with 301 additions and 182 deletions
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
set -euo pipefail
read -r -p "Are you sure you want to destroy your host docker containers and images? Type YES to continue: " reply
if [[ "${reply}" == "YES" ]]; then
docker system prune -af
docker builder prune -af
else
echo "Aborted."
exit 1
fi
+1 -1
View File
@@ -78,7 +78,7 @@ configure_source() {
sudo mount -o uid=$(id -u netalertx),gid=$(id -g netalertx),mode=775 -t tmpfs -o size=256M tmpfs "${NETALERTX_LOG}" sudo mount -o uid=$(id -u netalertx),gid=$(id -g netalertx),mode=775 -t tmpfs -o size=256M tmpfs "${NETALERTX_LOG}"
sudo mount -o uid=$(id -u netalertx),gid=$(id -g netalertx),mode=775 -t tmpfs -o size=256M tmpfs "${NETALERTX_API}" sudo mount -o uid=$(id -u netalertx),gid=$(id -g netalertx),mode=775 -t tmpfs -o size=256M tmpfs "${NETALERTX_API}"
mkdir -p ${NETALERTX_PLUGINS_LOG} mkdir -p ${NETALERTX_PLUGINS_LOG}
touch ${NETALERTX_PLUGINS_LOG}/.git-placeholder ${NETALERTX_API}/.git-placeholder touch ${NETALERTX_PLUGINS_LOG}/.dockerignore ${NETALERTX_API}/.dockerignore
# tmpfs mounts configured with netalertx ownership and 775 permissions above # tmpfs mounts configured with netalertx ownership and 775 permissions above
touch /app/log/nginx_error.log touch /app/log/nginx_error.log
+18 -6
View File
@@ -1,6 +1,7 @@
This is NetAlertX — network monitoring & alerting. # NetAlertX AI Assistant Instructions
This is NetAlertX — network monitoring & alerting. NetAlertX provides Network inventory, awareness, insight, categorization, intruder and presence detection. This is a heavily community driven project, welcoming of all contributions.
Purpose: Guide AI assistants to follow NetAlertX architecture, conventions, and safety practices. Be concise, opinionated, and prefer existing helpers/settings over new code or hardcoded values. You are to expected to be concise, opinionated, and biased toward security and simplicity.
## Architecture (what runs where) ## Architecture (what runs where)
- Backend (Python): main loop + GraphQL/REST endpoints orchestrate scans, plugins, workflows, notifications, and JSON export. - Backend (Python): main loop + GraphQL/REST endpoints orchestrate scans, plugins, workflows, notifications, and JSON export.
@@ -29,9 +30,9 @@ Backend loop phases (see `server/__main__.py` and `server/plugin.py`): `once`, `
* other: Miscellaneous plugins. Runs at various times. Data source: self / Template. * other: Miscellaneous plugins. Runs at various times. Data source: self / Template.
### Plugin logging & outputs ### Plugin logging & outputs
- Always log via `mylog()` like other plugins do (no `print()`). Example: `mylog('verbose', [f'[{pluginName}] In script'])`. - Use logging as shown in other plugins.
- Collect results with `Plugin_Objects.add_object(...)` during processing and call `plugin_objects.write_result_file()` exactly once at the end of the script. - Collect results with `Plugin_Objects.add_object(...)` during processing and call `plugin_objects.write_result_file()` exactly once at the end of the script.
- Prefer to log a brief summary before writing (e.g., total objects added) to aid troubleshooting; keep logs concise at `verbose` level unless debugging. - Prefer to log a brief summary before writing (e.g., total objects added) to aid troubleshooting; keep logs concise at `info` level and use `verbose` or `debug` for extra context.
- Do not write ad‑hoc files for results; the only consumable output is `last_result.<PREF>.log` generated by `Plugin_Objects`. - Do not write ad‑hoc files for results; the only consumable output is `last_result.<PREF>.log` generated by `Plugin_Objects`.
## API/Endpoints quick map ## API/Endpoints quick map
@@ -58,5 +59,16 @@ Backend loop phases (see `server/__main__.py` and `server/plugin.py`): `once`, `
- Docs: `docs/PLUGINS_DEV.md`, `docs/SETTINGS_SYSTEM.md`, `docs/API_*.md`, `docs/DEBUG_*.md` - Docs: `docs/PLUGINS_DEV.md`, `docs/SETTINGS_SYSTEM.md`, `docs/API_*.md`, `docs/DEBUG_*.md`
- Logs: backend `/app/log/app.log`, plugin logs under `/app/log/plugins/`, nginx/php logs under `/var/log/*` - Logs: backend `/app/log/app.log`, plugin logs under `/app/log/plugins/`, nginx/php logs under `/var/log/*`
Assistant expectations ## Assistant expectations:
- Reference concrete files/paths. Use existing helpers/settings. Keep changes idempotent and safe. Offer a quick validation step (log line, API hit, or JSON export) for anything you add. - Be concise, opinionated, and biased toward security and simplicity.
- Reference concrete files/paths/environmental variables.
- Use existing helpers/settings.
- Offer a quick validation step (log line, API hit, or JSON export) for anything you add.
- Be blunt about risks and when you offer suggestions ensure they're also blunt,
- Ask for confirmation before making changes that run code or change multiple files.
- Make statements actionable and specific; propose exact edits.
- Request confirmation before applying changes that affect more than a single, clearly scoped line or file.
- Ask the user to debug something for an actionable value if you're unsure.
- Be sure to offer choices when appropriate.
- Always understand the intent of the user's request and undo/redo as needed.
- Above all, use the simplest possible code that meets the need so it can be easily audited and maintained.
+1 -1
View File
@@ -24,7 +24,7 @@
{ {
"label": "[Any] Docker system and build Prune", "label": "[Any] Docker system and build Prune",
"type": "shell", "type": "shell",
"command": "docker system prune -af && docker builder prune -af", "command": ".devcontainer/scripts/confirm-docker-prune.sh",
"presentation": { "presentation": {
"echo": true, "echo": true,
"reveal": "always", "reveal": "always",
+55 -46
View File
@@ -6,12 +6,13 @@ ENV PYTHONUNBUFFERED=1
ENV PATH="/opt/venv/bin:$PATH" ENV PATH="/opt/venv/bin:$PATH"
# Install build dependencies # Install build dependencies
COPY requirements.txt /tmp/requirements.txt
RUN apk add --no-cache bash shadow python3 python3-dev gcc musl-dev libffi-dev openssl-dev git \ RUN apk add --no-cache bash shadow python3 python3-dev gcc musl-dev libffi-dev openssl-dev git \
&& python -m venv /opt/venv && python -m venv /opt/venv
RUN pip install -r /tmp/requirements.txt
# From this point on the Venv is owned by root without any read/write/execute permissions for root or group.
RUN pip install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors unifi-sm-api tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag zeroconf simplejson future six urllib3 httplib2 git+https://github.com/foreign-sub/aiofreepybox.git # This makes it easy to copy into hardened stage without worrying about permissions and keeps image size small
RUN chmod -R u-rwx,g-rwx /opt RUN chmod -R u-rwx,g-rwx /opt
# second stage is the main runtime stage with just the minimum required to run the application # second stage is the main runtime stage with just the minimum required to run the application
@@ -20,8 +21,6 @@ FROM alpine:3.22 AS runner
ARG INSTALL_DIR=/app ARG INSTALL_DIR=/app
ENV PATH="/opt/venv/bin:/usr/bin:/sbin:/bin:$PATH"
# NetAlertX app directories # NetAlertX app directories
ENV NETALERTX_APP=${INSTALL_DIR} ENV NETALERTX_APP=${INSTALL_DIR}
ENV NETALERTX_CONFIG=${NETALERTX_APP}/config ENV NETALERTX_CONFIG=${NETALERTX_APP}/config
@@ -33,6 +32,7 @@ ENV NETALERTX_DB_FILE=${NETALERTX_DB}/app.db
ENV NETALERTX_BACK=${NETALERTX_APP}/back ENV NETALERTX_BACK=${NETALERTX_APP}/back
ENV NETALERTX_LOG=${NETALERTX_APP}/log ENV NETALERTX_LOG=${NETALERTX_APP}/log
ENV NETALERTX_PLUGINS_LOG=${NETALERTX_LOG}/plugins ENV NETALERTX_PLUGINS_LOG=${NETALERTX_LOG}/plugins
ENV NETALERTX_CONFIG_FILE=${NETALERTX_CONFIG}/app.conf
# NetAlertX log files # NetAlertX log files
ENV LOG_IP_CHANGES=${NETALERTX_LOG}/IP_changes.log ENV LOG_IP_CHANGES=${NETALERTX_LOG}/IP_changes.log
@@ -53,7 +53,6 @@ ENV SYSTEM_SERVICES=/services
ENV SYSTEM_SERVICES_CONFIG=${SYSTEM_SERVICES}/config ENV SYSTEM_SERVICES_CONFIG=${SYSTEM_SERVICES}/config
ENV SYSTEM_NGINIX_CONFIG=${SYSTEM_SERVICES_CONFIG}/nginx ENV SYSTEM_NGINIX_CONFIG=${SYSTEM_SERVICES_CONFIG}/nginx
ENV SYSTEM_NGINX_CONFIG_FILE=${SYSTEM_NGINIX_CONFIG}/nginx.conf ENV SYSTEM_NGINX_CONFIG_FILE=${SYSTEM_NGINIX_CONFIG}/nginx.conf
ENV NETALERTX_CONFIG_FILE=${NETALERTX_CONFIG}/app.conf
ENV SYSTEM_SERVICES_PHP_FOLDER=${SYSTEM_SERVICES_CONFIG}/php ENV SYSTEM_SERVICES_PHP_FOLDER=${SYSTEM_SERVICES_CONFIG}/php
ENV SYSTEM_SERVICES_PHP_FPM_D=${SYSTEM_SERVICES_PHP_FOLDER}/php-fpm.d ENV SYSTEM_SERVICES_PHP_FPM_D=${SYSTEM_SERVICES_PHP_FOLDER}/php-fpm.d
ENV SYSTEM_SERVICES_CROND=${SYSTEM_SERVICES_CONFIG}/crond ENV SYSTEM_SERVICES_CROND=${SYSTEM_SERVICES_CONFIG}/crond
@@ -61,12 +60,18 @@ ENV SYSTEM_SERVICES_RUN=${SYSTEM_SERVICES}/run
ENV SYSTEM_SERVICES_RUN_TMP=${SYSTEM_SERVICES_RUN}/tmp ENV SYSTEM_SERVICES_RUN_TMP=${SYSTEM_SERVICES_RUN}/tmp
ENV SYSTEM_SERVICES_RUN_LOG=${SYSTEM_SERVICES_RUN}/logs ENV SYSTEM_SERVICES_RUN_LOG=${SYSTEM_SERVICES_RUN}/logs
ENV PHP_FPM_CONFIG_FILE=${SYSTEM_SERVICES_PHP_FOLDER}/php-fpm.conf ENV PHP_FPM_CONFIG_FILE=${SYSTEM_SERVICES_PHP_FOLDER}/php-fpm.conf
ENV READ_ONLY_FOLDERS="${NETALERTX_BACK} ${NETALERTX_FRONT} ${NETALERTX_SERVER} ${SYSTEM_SERVICES} \
${SYSTEM_SERVICES_CONFIG} /opt /opt/venv"
ENV READ_WRITE_FOLDERS="${NETALERTX_CONFIG} ${NETALERTX_DB} ${NETALERTX_API} ${NETALERTX_LOG} \
${NETALERTX_PLUGINS_LOG} ${SYSTEM_SERVICES_RUN} ${SYSTEM_SERVICES_RUN_TMP} \
${SYSTEM_SERVICES_RUN_LOG}"
#Python environment #Python environment
ENV PYTHONPATH=${NETALERTX_SERVER}
ENV PYTHONUNBUFFERED=1 ENV PYTHONUNBUFFERED=1
ENV VIRTUAL_ENV=/opt/venv ENV VIRTUAL_ENV=/opt/venv
ENV VIRTUAL_ENV_BIN=/opt/venv/bin ENV VIRTUAL_ENV_BIN=/opt/venv/bin
ENV PYTHONPATH=${NETALERTX_APP}:${NETALERTX_SERVER}:${VIRTUAL_ENV}/lib/python3.12/site-packages
ENV PATH="${SYSTEM_SERVICES}:${VIRTUAL_ENV_BIN}:$PATH"
# App Environment # App Environment
ENV LISTEN_ADDR=0.0.0.0 ENV LISTEN_ADDR=0.0.0.0
@@ -74,8 +79,12 @@ ENV PORT=20211
ENV NETALERTX_DEBUG=0 ENV NETALERTX_DEBUG=0
ENV VENDORSPATH=/app/back/ieee-oui.txt ENV VENDORSPATH=/app/back/ieee-oui.txt
ENV VENDORSPATH_NEWEST=/services/run/tmp/ieee-oui.txt ENV VENDORSPATH_NEWEST=/services/run/tmp/ieee-oui.txt
ENV PATH="${VIRTUAL_ENV}/bin:${PATH}" ENV PYTHONPATHPATH="${NETALERTX_APP}:${VIRTUAL_ENV}/bin:${PATH}"
ENV ENVIRONMENT=alpine ENV ENVIRONMENT=alpine
ENV READ_ONLY_USER=readonly READ_ONLY_GROUP=readonly
ENV NETALERTX_USER=netalertx NETALERTX_GROUP=netalertx
RUN apk add --no-cache bash mtr libbsd zip lsblk sudo tzdata curl arp-scan iproute2 \ RUN apk add --no-cache bash mtr libbsd zip lsblk sudo tzdata curl arp-scan iproute2 \
iproute2-ss nmap nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake \ iproute2-ss nmap nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake \
@@ -83,40 +92,43 @@ RUN apk add --no-cache bash mtr libbsd zip lsblk sudo tzdata curl arp-scan iprou
envsubst nginx sudo shadow && \ envsubst nginx sudo shadow && \
rm -Rf /var/cache/apk/* && \ rm -Rf /var/cache/apk/* && \
rm -Rf /etc/nginx && \ rm -Rf /etc/nginx && \
addgroup -g 20211 netalertx && \ addgroup -g 20211 ${NETALERTX_GROUP} && \
adduser -u 20211 -D -h ${NETALERTX_APP} -G netalertx netalertx && \ adduser -u 20211 -D -h ${NETALERTX_APP} -G ${NETALERTX_GROUP} ${NETALERTX_USER} && \
apk del shadow apk del shadow
# Install application, copy files, set permissions # Install application, copy files, set permissions
COPY --from=builder --chown=20212:20212 ${VIRTUAL_ENV} ${VIRTUAL_ENV}} COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} install/production-filesystem/ /
COPY --from=builder /usr/sbin/usermod /usr/sbin/groupmod /usr/sbin/ COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} --chmod=755 back ${NETALERTX_BACK}
COPY --chown=netalertx:netalertx install/production-filesystem/ / COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} --chmod=755 front ${NETALERTX_FRONT}
COPY --chown=netalertx:netalertx --chmod=755 back ${NETALERTX_BACK} COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} --chmod=755 server ${NETALERTX_SERVER}
COPY --chown=netalertx:netalertx --chmod=755 front ${NETALERTX_FRONT} RUN install -d -o ${NETALERTX_USER} -g ${NETALERTX_GROUP} -m 755 ${NETALERTX_API} \
COPY --chown=netalertx:netalertx --chmod=755 server ${NETALERTX_SERVER}
RUN install -d -o netalertx -g netalertx -m 755 ${NETALERTX_API} \
${NETALERTX_LOG} ${SYSTEM_SERVICES_RUN_TMP} ${SYSTEM_SERVICES_RUN_LOG} && \ ${NETALERTX_LOG} ${SYSTEM_SERVICES_RUN_TMP} ${SYSTEM_SERVICES_RUN_LOG} && \
sh -c "find ${NETALERTX_APP} -type f \( -name '*.sh' -o -name 'speedtest-cli' \) \ sh -c "find ${NETALERTX_APP} -type f \( -name '*.sh' -o -name 'speedtest-cli' \) \
-exec chmod 750 {} \;" -exec chmod 750 {} \;"
# Copy the virtualenv from the builder stage
COPY --from=builder --chown=20212:20212 ${VIRTUAL_ENV} ${VIRTUAL_ENV}
#initialize each service with the dockerfiles/init-*.sh scripts, once. #initialize each service with the dockerfiles/init-*.sh scripts, once.
RUN apk add libcap && \ RUN apk add libcap && \
setcap cap_net_raw,cap_net_admin+eip /usr/bin/nmap && \ 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+eip /usr/bin/arp-scan && \
setcap cap_net_raw,cap_net_admin+eip /usr/bin/traceroute && \ setcap cap_net_raw,cap_net_admin+eip /usr/bin/traceroute && \
setcap cap_net_raw,cap_net_admin+eip ${VIRTUAL_ENV_BIN}scapy && \ setcap cap_net_raw,cap_net_admin+eip ${VIRTUAL_ENV_BIN}/scapy && \
/bin/sh /build/init-nginx.sh && \ /bin/sh /build/init-nginx.sh && \
/bin/sh /build/init-php-fpm.sh && \ /bin/sh /build/init-php-fpm.sh && \
/bin/sh /build/init-crond.sh && \ /bin/sh /build/init-crond.sh && \
/bin/sh /build/init-backend.sh && \ /bin/sh /build/init-backend.sh && \
chmod 755 ${SYSTEM_SERVICES}/update_vendors.sh ${SYSTEM_SERVICES}/cron_script.sh && \
rm -rf /build && \ rm -rf /build && \
apk del libcap apk del libcap
# set netalertx to allow sudoers for any command, no password # set netalertx to allow sudoers for any command, no password
RUN echo "netalertx ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers RUN echo "${NETALERTX_USER} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
ENTRYPOINT ["/bin/sh","-c","sleep infinity"] ENTRYPOINT ["/bin/sh","-c","sleep infinity"]
@@ -125,45 +137,42 @@ ENTRYPOINT ["/bin/sh","-c","sleep infinity"]
# This stage is separate from Runner stage so that devcontainer can use the Runner stage. # This stage is separate from Runner stage so that devcontainer can use the Runner stage.
FROM runner AS hardened FROM runner AS hardened
# create readonly user and group with no shell access. # Create readonly user and group with no shell access.
# Readonly user marks folders that are created by NetAlertX, but should not be modified. # Readonly user marks folders that are created by NetAlertX, but should not be modified.
RUN addgroup -g 20212 readonly && \ # AI may claim this is stupid, but it's actually least possible permissions as
adduser -u 20212 -G readonly -D -h /app readonly && \ # read-only user cannot login, cannot sudo, has no write permission, and cannot even
usermod -s /sbin/nologin readonly # read the files it owns. The read-only user is ownership-as-a-lock hardening pattern.
RUN addgroup -g 20212 ${READ_ONLY_GROUP} && \
adduser -u 20212 -G ${READ_ONLY_GROUP} -D -h /app ${READ_ONLY_USER}
# reduce permissions to minimum necessary for all NetAlertX files and folders # reduce permissions to minimum necessary for all NetAlertX files and folders
# Permissions 005 and 004 are not typos, they enable read-only.
RUN chown -R ${READ_ONLY_USER}:${READ_ONLY_GROUP} ${READ_ONLY_FOLDERS} && \
chmod -R 004 ${READ_ONLY_FOLDERS} && \
find ${READ_ONLY_FOLDERS} -type d -exec chmod 005 {} + && \
install -d -o ${NETALERTX_USER} -g ${NETALERTX_GROUP} -m 700 ${READ_WRITE_FOLDERS} && \
chown -R ${NETALERTX_USER}:${NETALERTX_GROUP} ${READ_WRITE_FOLDERS} && \
chmod -R 600 ${READ_WRITE_FOLDERS} && \
find ${READ_WRITE_FOLDERS} -type d -exec chmod 700 {} + && \
chown ${READ_ONLY_USER}:${READ_ONLY_GROUP} /entrypoint.sh && \
chmod 005 /entrypoint.sh ${SYSTEM_SERVICES}/*.sh
RUN chown -R readonly:readonly ${NETALERTX_BACK} ${NETALERTX_FRONT} ${NETALERTX_SERVER} ${SYSTEM_SERVICES} ${SYSTEM_SERVICES} && \
chmod -R 004 ${NETALERTX_BACK} ${NETALERTX_FRONT} ${NETALERTX_SERVER} && \
find ${NETALERTX_BACK} ${NETALERTX_FRONT} ${NETALERTX_SERVER} -type d -exec chmod 005 {} + && \
chmod -R 005 ${SYSTEM_SERVICES} ${SYSTEM_SERVICES}/* && \
chown -R netalertx:netalertx ${NETALERTX_CONFIG} ${NETALERTX_DB} ${NETALERTX_API} ${NETALERTX_LOG} && \
chmod -R 600 ${NETALERTX_CONFIG} ${NETALERTX_DB} ${NETALERTX_API} ${NETALERTX_LOG} && \
chmod 700 ${NETALERTX_CONFIG} ${NETALERTX_DB} ${NETALERTX_API} ${NETALERTX_LOG} ${NETALERTX_PLUGINS_LOG} ${SYSTEM_SERVICES_RUN_TMP} && \
chown readonly:readonly /entrypoint.sh && \
install -d -o netalertx -g netalertx -m 700 ${SYSTEM_SERVICES_RUN} ${SYSTEM_SERVICES_RUN_TMP} ${SYSTEM_SERVICES_RUN_LOG} && \
chmod 005 /entrypoint.sh ${SYSTEM_SERVICES}/update_vendors.sh ${SYSTEM_SERVICES}/cron_script.sh ${SYSTEM_SERVICES}/speedtest-cli
# # remove sudoers, sudo, alpine installers pacakges, and all users and groups except
# remove sudo and alpine installers pacakges # readonly and netalertx
RUN apk del sudo apk-tools && \ RUN apk del sudo apk-tools && \
rm -rf /var/cache/apk/* rm -rf /var/cache/apk/* && \
# remove all users and groups except readonly and netalertx & remove all sudoers rm -Rf /etc/sudoers.d/* /etc/shadow /etc/gshadow /etc/sudoers \
RUN rm -Rf /etc/sudoers.d/* /etc/shadow /etc/gshadow /etc/sudoers \ /lib/apk /lib/firmware /lib/modules-load.d /lib/sysctl.d /mnt /home/ /root \
/lib/apk /lib/firmware /lib/modules-load.d /lib/sysctl.d /mnt /home/ /root \
/srv /media && \ /srv /media && \
sed -i -n -e '/^readonly:/p' -e '/^netalertx:/p' /etc/passwd && \ sed -i "/^\(${READ_ONLY_USER}\|${NETALERTX_USER}\):/!d" /etc/passwd && \
sed -i -n -e '/^readonly:/p' -e '/^netalertx:/p' /etc/group && \ sed -i "/^\(${READ_ONLY_GROUP}\|${NETALERTX_GROUP}\):/!d" /etc/group && \
echo -ne '#!/bin/sh\n"$@"\n' > /usr/bin/sudo && chmod +x /usr/bin/sudo echo -ne '#!/bin/sh\n"$@"\n' > /usr/bin/sudo && chmod +x /usr/bin/sudo
USER netalertx USER netalertx
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD /services/healthcheck.sh CMD /services/healthcheck.sh
#ENTRYPOINT [ "/bin/sh" ]
ENTRYPOINT [ "/bin/sh", "/entrypoint.sh" ] ENTRYPOINT [ "/bin/sh", "/entrypoint.sh" ]
+51 -12
View File
@@ -1,7 +1,46 @@
# Warning - use of this unhardened image is not recommended for production use.
# This image is provided for backward compatibility, development and testing purposes only.
# For production use, please use the hardened image built with Alpine. This image attempts to
# treat a container as an operating system, which is an anti-pattern and a common source of
# security issues.
#
# The default Dockerfile/docker-compose image contains the following security improvements
# over the Debian image:
# - read-only filesystem
# - no sudo access
# - least possible permissions on all files and folders
# - no shell access for non-privileged users
# - no unnecessary packages or services
# - reduced capabilities
# - tmpfs for writable folders
# - healthcheck
# - no package managers
# - no compilers or build tools
# - no systemd, uses lightweight init system
# - no persistent storage except for config and db volumes
# - minimal image size due to segmented build stages
# - minimal base image (Alpine Linux)
# - minimal python environment (venv, no pip)
# - minimal stripped web server
# - minimal stripped php environment
# - minimal services (nginx, php-fpm, crond, no unnecessary services or service managers)
# - minimal users and groups (netalertx and readonly only, no others)
# - minimal permissions (read-only for most files and folders, write-only for necessary folders)
# - minimal capabilities (NET_ADMIN and NET_RAW only, no others)
# - minimal environment variables (only necessary ones, no others)
# - minimal entrypoint (only necessary commands, no others)
# - Uses the same base image as the development environmnment (Alpine Linux)
# - Uses the same services as the development environment (nginx, php-fpm, crond)
# - Uses the same environment variables as the development environment (only necessary ones, no others)
# - Uses the same file and folder structure as the development environment (only necessary ones, no others)
# NetAlertX is designed to be run as an unattended network security monitoring appliance, which means it
# should be able to operate without human intervention. Overall, the hardened image is designed to be as
# secure as possible while still being functional and is recommended because you cannot attack a surface
# that isn't there.
FROM debian:bookworm-slim FROM debian:bookworm-slim
#TZ=Europe/London #TZ=Europe/London
# NetAlertX app directories # NetAlertX app directories
@@ -74,11 +113,11 @@ ENV USER_GID=1000
# add root and www-data to pi group so they can r/w files and db # add root and www-data to pi group so they can r/w files and db
RUN groupadd --gid "${USER_GID}" "${USER}" && \ RUN groupadd --gid "${USER_GID}" "${USER}" && \
useradd \ useradd \
--uid ${USER_ID} \ --uid ${USER_ID} \
--gid ${USER_GID} \ --gid ${USER_GID} \
--create-home \ --create-home \
--shell /bin/bash \ --shell /bin/bash \
${USER} && \ ${USER} && \
usermod -a -G ${USER_GID} root && \ usermod -a -G ${USER_GID} root && \
usermod -a -G ${USER_GID} www-data usermod -a -G ${USER_GID} www-data
@@ -97,10 +136,10 @@ RUN apt update && apt-get install -y \
# (Ondřej Surý maintains php packages for debian. This is temp until debian includes php-fpm in their # (Ondřej Surý maintains php packages for debian. This is temp until debian includes php-fpm in their
# repos. Likely it will be in Debian Trixie.). This keeps the image up-to-date with the alpine version. # repos. Likely it will be in Debian Trixie.). This keeps the image up-to-date with the alpine version.
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
apt-transport-https \ apt-transport-https \
ca-certificates \ ca-certificates \
lsb-release \ lsb-release \
wget && \ wget && \
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg && \ wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg && \
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list && \ echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list && \
apt-get update && \ apt-get update && \
@@ -109,7 +148,7 @@ RUN apt-get install -y --no-install-recommends \
# Setup virtual python environment and use pip3 to install packages # Setup virtual python environment and use pip3 to install packages
RUN python3 -m venv ${VIRTUAL_ENV} && \ RUN python3 -m venv ${VIRTUAL_ENV} && \
/bin/bash -c "source ${VIRTUAL_ENV_BIN}/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors unifi-sm-api tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag " /bin/bash -c "source ${VIRTUAL_ENV_BIN}/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install -r ${INSTALL_DIR}/requirements.txt"
# Configure php-fpm # Configure php-fpm
RUN chmod -R 755 /services && \ RUN chmod -R 755 /services && \
+32 -30
View File
@@ -1,39 +1,41 @@
version: '3.8'
services: services:
netalertx: netalertx:
network_mode: host # Use host networking for ARP scanning and other services
build: build:
context: . context: . # Build context is the current directory
dockerfile: Dockerfile dockerfile: Dockerfile # Specify the Dockerfile to use
image: netalertx:latest image: netalertx:latest
container_name: netalertx_internal container_name: netalertx # The name when you docker contiainer ls
read_only: true read_only: true # Make the container filesystem read-only
# cap_drop: # Drop all capabilities for enhanced security
# - ALL
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
- seccomp:unconfined # Use unconfined seccomp profile (adjust as needed)
volumes:
- netalertx_config:/app/config
- netalertx_db:/app/db
- /etc/localtime:/etc/localtime:ro
tmpfs: tmpfs:
- /etc/nginx/conf.d - "/app/api:uid=20211,gid=20211,mode=700"
- /var/cache/nginx - "/app/log:uid=20211,gid=20211,mode=700"
- /var/run - "/services/config/nginx/conf.active:uid=20211,gid=20211,mode=700"
- /app/log - "/services/run:uid=20211,gid=20211,mode=700"
- /tmp - "/tmp:mode=700"
networks:
- netalertx_net
environment: environment:
- NETALERTX_MODE=hardened NETALERTX_MODE: hardened
- GRAPHQL_PORT=25378 PORT: 20211
GRAPHQL_PORT: 25378
ALWAYS_FRESH_INSTALL: false
restart: unless-stopped restart: unless-stopped
proxy: volumes:
image: nginx:alpine netalertx_config:
container_name: netalertx_proxy netalertx_db:
ports:
- "20211:25377"
- "20212:25378"
networks:
- netalertx_net
depends_on:
- netalertx
restart: unless-stopped
networks:
netalertx_net:
+37 -76
View File
@@ -1,82 +1,43 @@
services: services:
netalertx: netalertx:
privileged: true network_mode: host # Use host networking for ARP scanning and other services
build: build:
dockerfile: Dockerfile context: . # Build context is the current directory
context: . dockerfile: Dockerfile # Specify the Dockerfile to use
cache_from: image: netalertx:latest
- type=registry,ref=docker.io/jokob-sk/netalertx:buildcache container_name: netalertx # The name when you docker contiainer ls
container_name: netalertx read_only: true # Make the container filesystem read-only
network_mode: host cap_drop: # Drop all capabilities for enhanced security
# restart: unless-stopped - ALL
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
- seccomp:unconfined # Use unconfined seccomp profile (adjust as needed)
volumes: volumes:
# - ${APP_DATA_LOCATION}/netalertx_dev/config:/app/config - netalertx_config:/app/config # Store your NetAlertX config
- ${APP_DATA_LOCATION}/netalertx/config:/app/config - netalertx_db:/app/db # Store your NetAlertX devices and settings
# - ${APP_DATA_LOCATION}/netalertx_dev/db:/app/db - /etc/localtime:/etc/localtime:ro # Use your system clock inside the container (read-only)
- ${APP_DATA_LOCATION}/netalertx/db:/app/db #- /path/on/host:/app/front/plugins/custom # Test your plugin on the production container
# (optional) useful for debugging if you have issues setting up the container
- ${APP_DATA_LOCATION}/netalertx/log:/app/log # Tempfs mounts for writable directories in a read-only container and improve system performance
# (API: OPTION 1) use for performance # by providing a clean R/W filesystem each container start and reducing disk I/O.
- type: tmpfs tmpfs:
target: /app/api - "/app/api:uid=20211,gid=20211,mode=700"
# (API: OPTION 2) use when debugging issues - "/app/log:uid=20211,gid=20211,mode=700"
# - ${DEV_LOCATION}/api:/app/api - "/services/config/nginx/conf.active:uid=20211,gid=20211,mode=700"
# --------------------------------------------------------------------------- - "/services/run:uid=20211,gid=20211,mode=700"
# DELETE START anyone trying to use this file: comment out / delete BELOW lines, they are only for development purposes
- ${APP_DATA_LOCATION}/netalertx/dhcp_samples/dhcp1.leases:/mnt/dhcp1.leases # test data for DCPLSS plugin
- ${APP_DATA_LOCATION}/netalertx/dhcp_samples/dhcp2.leases:/mnt/dhcp2.leases # test data for DCPLSS plugin
- ${APP_DATA_LOCATION}/netalertx/dhcp_samples/pihole_dhcp_full.leases:/etc/pihole/dhcp.leases # test data for DCPLSS plugin
- ${APP_DATA_LOCATION}/netalertx/dhcp_samples/pihole_dhcp_2.leases:/etc/pihole/dhcp2.leases # test data for DCPLSS plugin
- ${APP_DATA_LOCATION}/pihole/etc-pihole/pihole-FTL.db:/etc/pihole/pihole-FTL.db # test data for PIHOLE plugin
- ${DEV_LOCATION}/mkdocs.yml:/app/mkdocs.yml
- ${DEV_LOCATION}/docs:/app/docs
- ${DEV_LOCATION}/server:/app/server
- ${DEV_LOCATION}/test:/app/test
- ${DEV_LOCATION}/dockerfiles:/app/dockerfiles
# - ${APP_DATA_LOCATION}/netalertx/php.ini:/etc/php/8.2/fpm/php.ini
- ${DEV_LOCATION}/install:/app/install
- ${DEV_LOCATION}/front/css:/app/front/css
- ${DEV_LOCATION}/front/img:/app/front/img
- ${DEV_LOCATION}/back/update_vendors.sh:/app/back/update_vendors.sh
- ${DEV_LOCATION}/front/lib:/app/front/lib
- ${DEV_LOCATION}/front/js:/app/front/js
- ${DEV_LOCATION}/front/php:/app/front/php
- ${DEV_LOCATION}/front/deviceDetails.php:/app/front/deviceDetails.php
- ${DEV_LOCATION}/front/deviceDetailsEdit.php:/app/front/deviceDetailsEdit.php
- ${DEV_LOCATION}/front/userNotifications.php:/app/front/userNotifications.php
- ${DEV_LOCATION}/front/deviceDetailsTools.php:/app/front/deviceDetailsTools.php
- ${DEV_LOCATION}/front/deviceDetailsPresence.php:/app/front/deviceDetailsPresence.php
- ${DEV_LOCATION}/front/deviceDetailsSessions.php:/app/front/deviceDetailsSessions.php
- ${DEV_LOCATION}/front/deviceDetailsEvents.php:/app/front/deviceDetailsEvents.php
- ${DEV_LOCATION}/front/devices.php:/app/front/devices.php
- ${DEV_LOCATION}/front/events.php:/app/front/events.php
- ${DEV_LOCATION}/front/plugins.php:/app/front/plugins.php
- ${DEV_LOCATION}/front/pluginsCore.php:/app/front/pluginsCore.php
- ${DEV_LOCATION}/front/index.php:/app/front/index.php
- ${DEV_LOCATION}/front/initCheck.php:/app/front/initCheck.php
- ${DEV_LOCATION}/front/maintenance.php:/app/front/maintenance.php
- ${DEV_LOCATION}/front/network.php:/app/front/network.php
- ${DEV_LOCATION}/front/presence.php:/app/front/presence.php
- ${DEV_LOCATION}/front/settings.php:/app/front/settings.php
- ${DEV_LOCATION}/front/systeminfo.php:/app/front/systeminfo.php
- ${DEV_LOCATION}/front/systeminfoNetwork.php:/app/front/systeminfoNetwork.php
- ${DEV_LOCATION}/front/systeminfoServer.php:/app/front/systeminfoServer.php
- ${DEV_LOCATION}/front/systeminfoStorage.php:/app/front/systeminfoStorage.php
- ${DEV_LOCATION}/front/cloud_services.php:/app/front/cloud_services.php
- ${DEV_LOCATION}/front/report.php:/app/front/report.php
- ${DEV_LOCATION}/front/workflows.php:/app/front/workflows.php
- ${DEV_LOCATION}/front/workflowsCore.php:/app/front/workflowsCore.php
- ${DEV_LOCATION}/front/appEvents.php:/app/front/appEvents.php
- ${DEV_LOCATION}/front/appEventsCore.php:/app/front/appEventsCore.php
- ${DEV_LOCATION}/front/multiEditCore.php:/app/front/multiEditCore.php
- ${DEV_LOCATION}/front/plugins:/app/front/plugins
# DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes
# ---------------------------------------------------------------------------
environment: environment:
# - APP_CONF_OVERRIDE={"SCAN_SUBNETS":"['192.168.1.0/24 --interface=eth1']","GRAPHQL_PORT":"20223","UI_theme":"Light"} LISTEN_ADDR: 0.0.0.0
- TZ=${TZ} PORT: 20211
- PORT=${PORT} GRAPHQL_PORT: 20212
# ❗ DANGER ZONE BELOW - Setting ALWAYS_FRESH_INSTALL=true will delete the content of the /db & /config folders NETALERTX_MODE: hardened
- ALWAYS_FRESH_INSTALL=${ALWAYS_FRESH_INSTALL} ALWAYS_FRESH_INSTALL: false
# - LOADED_PLUGINS=["DHCPLSS","PIHOLE","ASUSWRT","FREEBOX"] NETALERTX_DEBUG: 0
restart: unless-stopped
volumes:
netalertx_config:
netalertx_db:
@@ -6,6 +6,15 @@ echo "---------------------------------------------------------"
# ❗ IMPORTANT - if you modify this file modify the root Dockerfile as well ❗ # ❗ IMPORTANT - if you modify this file modify the root Dockerfile as well ❗
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
REQUIREMENTS_FILE="${REPO_ROOT}/requirements.txt"
if [[ ! -f "${REQUIREMENTS_FILE}" ]]; then
echo "requirements.txt not found at ${REQUIREMENTS_FILE}. Please ensure the repository root is available." >&2
exit 1
fi
# Check if script is run as root # Check if script is run as root
if [[ $EUID -ne 0 ]]; then if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Please use 'sudo'." echo "This script must be run as root. Please use 'sudo'."
@@ -30,4 +39,4 @@ source /opt/venv/bin/activate
update-alternatives --install /usr/bin/python python /usr/bin/python3 10 update-alternatives --install /usr/bin/python python /usr/bin/python3 10
# install packages thru pip3 # install packages thru pip3
pip3 install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors unifi-sm-api tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag git+https://github.com/foreign-sub/aiofreepybox.git pip3 install -r "${REQUIREMENTS_FILE}"
@@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
echo "Initializing nginx..." echo "Initializing nginx..."
install -d -o netalertx -g netalertx -m 700 /app/run/tmp/client_body; install -d -o netalertx -g netalertx -m 700 ${SYSTEM_SERVICES_RUN_TMP}/client_body;
echo "nginx initialized." echo "nginx initialized."
@@ -3,6 +3,9 @@
set -u set -u
bash /services/capcheck.sh bash /services/capcheck.sh
bash /services/ramdisk-check.sh
SERVICES="" SERVICES=""
FAILED_NAME="" FAILED_NAME=""
@@ -107,7 +107,7 @@ http {
# Set Cache-Control header to prevent caching on the first load # Set Cache-Control header to prevent caching on the first load
add_header Cache-Control "no-store"; add_header Cache-Control "no-store";
fastcgi_pass unix:/services/run/php.sock; fastcgi_pass unix:/services/run/php.sock;
include fastcgi_params; include /services/config/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_connect_timeout 75; fastcgi_connect_timeout 75;
@@ -0,0 +1,32 @@
#!/bin/sh
# ramdisk-check.sh - Verify critical paths are backed by ramdisk and warn on fallback storage.
warn_if_not_ramdisk() {
path="$1"
if cat /proc/mounts| grep ${path} | grep -qE 'tmpfs|ramfs'; then
return 0
fi
cat >&2 <<EOF
⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
ATTENTION: ${path} is not on a ramdisk.
Mount this folder inside the container as tmpfs or ramfs.
NetAlertX expects this location to live in memory for fast reads and writes.
Running it on disk will severely degrade performance for every user.
Fix: Please mount ${path} as tmpfs/ramfs.
eg. --mount type=tmpfs,destination=${path}
Restart the container after adding the ramdisk mount.
⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
EOF
exit 1
}
warn_if_not_ramdisk "${NETALERTX_API}"
warn_if_not_ramdisk "${NETALERTX_LOG}"
if [ ! -f "${SYSTEM_NGINIX_CONFIG}/conf.active" ]; then
echo "Note: Using default listen address ${LISTEN_ADDR}:${PORT} (no ${SYSTEM_NGINIX_CONFIG}/conf.active override)."
fi
@@ -1,4 +1,5 @@
#!/bin/bash #! /bin/sh
set -euo pipefail set -euo pipefail
LOG_DIR=${NETALERTX_APP} LOG_DIR=${NETALERTX_APP}
@@ -34,10 +35,10 @@ done
TEMP_CONFIG_FILE=$(mktemp "${TMP_DIR}/netalertx.conf.XXXXXX") TEMP_CONFIG_FILE=$(mktemp "${TMP_DIR}/netalertx.conf.XXXXXX")
if envsubst '${LISTEN_ADDR} ${PORT}' < "${SYSTEM_NGINX_CONFIG_TEMPLATE}" > "${TEMP_CONFIG_FILE}" 2>/dev/null; then if envsubst '${LISTEN_ADDR} ${PORT}' < "${SYSTEM_NGINX_CONFIG_TEMPLATE}" > "${TEMP_CONFIG_FILE}" 2>/dev/null; then
mv "${TEMP_CONFIG_FILE}" "${SYSTEM_NGINX_CONFIG_FILE}" mv "${TEMP_CONFIG_FILE}" "${SYSTEM_NGINX_CONFIG_FILE}" 2>/dev/null || true
else else
echo "Note: Unable to write to ${SYSTEM_NGINX_CONFIG_FILE}. Using default configuration." echo "Note: Unable to write to ${SYSTEM_NGINX_CONFIG_FILE}. Using default configuration."
rm -f "${TEMP_CONFIG_FILE}" rm -f "${TEMP_CONFIG_FILE}" 2>/dev/null || true
fi fi
trap cleanup EXIT trap cleanup EXIT
+7 -1
View File
@@ -15,6 +15,7 @@ echo "---------------------------------------------------------"
INSTALL_DIR=/app INSTALL_DIR=/app
INSTALL_SYSTEM_NAME=ubuntu24 INSTALL_SYSTEM_NAME=ubuntu24
INSTALLER_DIR=${INSTALL_DIR}/install/$INSTALL_SYSTEM_NAME INSTALLER_DIR=${INSTALL_DIR}/install/$INSTALL_SYSTEM_NAME
REQUIREMENTS_FILE=${INSTALL_DIR}/requirements.txt
CONF_FILE=app.conf CONF_FILE=app.conf
DB_FILE=app.db DB_FILE=app.db
NGINX_CONF_FILE=netalertx.conf NGINX_CONF_FILE=netalertx.conf
@@ -153,7 +154,12 @@ echo
python3 -m venv "${VENV_DIR}" python3 -m venv "${VENV_DIR}"
source "${VENV_DIR}/bin/activate" source "${VENV_DIR}/bin/activate"
pip3 install -r "${INSTALLER_DIR}/requirements.txt" || { if [[ ! -f "${REQUIREMENTS_FILE}" ]]; then
echo "[INSTALL] requirements.txt not found at ${REQUIREMENTS_FILE}"
exit 1
fi
pip3 install -r "${REQUIREMENTS_FILE}" || {
echo "[INSTALL] Failed to install Python dependencies" echo "[INSTALL] Failed to install Python dependencies"
exit 1 exit 1
} }
+33
View File
@@ -0,0 +1,33 @@
openwrt-luci-rpc
asusrouter
asyncio
aiohttp
graphene
flask
flask-cors
unifi-sm-api
tplink-omada-client
wakeonlan
pycryptodome
requests
paho-mqtt
scapy
cron-converter
pytz
json2table
dhcp-leases
pyunifi
speedtest-cli
chardet
python-nmap
dnspython
librouteros
yattag
zeroconf
simplejson
future
six
urllib3
httplib2
gunicorn
git+https://github.com/foreign-sub/aiofreepybox.git