Additional hardening

This commit is contained in:
Adam Outler
2025-10-12 21:00:27 -04:00
parent 1be91559d2
commit 5109a0881d
6 changed files with 64 additions and 101 deletions

View File

@@ -6,6 +6,8 @@
FROM runner AS netalertx-devcontainer
ENV INSTALL_DIR=/app
ENV PYTHONPATH=/workspaces/NetAlertX/test:/workspaces/NetAlertX/server:/app:/app/server:/opt/venv/lib/python3.12/site-packages
ENV PATH=/services:${PATH}
ENV PHP_INI_SCAN_DIR=/services/config/php/conf.d:/etc/php83/conf.d
@@ -15,10 +17,11 @@ ENV NETALERTX_DEBUG=1
COPY .devcontainer/resources/devcontainer-overlay/ /
# Install common tools, create user, and set up sudo
RUN apk add --no-cache git nano vim jq php83-pecl-xdebug py3-pip nodejs sudo gpgconf pytest pytest-cov fish shfmt
RUN apk add --no-cache git nano vim jq php83-pecl-xdebug py3-pip nodejs sudo gpgconf pytest pytest-cov fish shfmt sudo
RUN install -d -o netalertx -g netalertx -m 755 /services/php/modules && \
cp -a /usr/lib/php83/modules/. /services/php/modules/
cp -a /usr/lib/php83/modules/. /services/php/modules/ && \
echo "${NETALERTX_USER} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
# Install debugpy in the virtualenv if present, otherwise into system python3
RUN /bin/sh -c '(/opt/venv/bin/python3 -m pip install --no-cache-dir debugpy) || (python3 -m pip install --no-cache-dir debugpy) || true' && \
mkdir /workspaces && \

View File

@@ -83,13 +83,13 @@ ENV PYTHONPATHPATH="${NETALERTX_APP}:${VIRTUAL_ENV}/bin:${PATH}"
ENV ENVIRONMENT=alpine
ENV READ_ONLY_USER=readonly READ_ONLY_GROUP=readonly
ENV NETALERTX_USER=netalertx NETALERTX_GROUP=netalertx
ENV LANG=C.UTF-8
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 \
ca-certificates sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 \
envsubst nginx sudo shadow && \
RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss nmap \
nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \
sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 envsubst \
nginx shadow && \
rm -Rf /var/cache/apk/* && \
rm -Rf /etc/nginx && \
addgroup -g 20211 ${NETALERTX_GROUP} && \
@@ -124,19 +124,17 @@ RUN apk add libcap && \
/bin/sh /build/init-backend.sh && \
rm -rf /build && \
apk del libcap
# set netalertx to allow sudoers for any command, no password
RUN echo "${NETALERTX_USER} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
ENTRYPOINT ["/bin/sh","-c","sleep infinity"]
ENTRYPOINT ["/bin/sh","/entrypoint.sh"]
# Final hardened stage to improve security by setting least possible permissions and removing sudo access.
# When complete, if the image is compromised, there's not much that can be done with it.
# This stage is separate from Runner stage so that devcontainer can use the Runner stage.
FROM runner AS hardened
ENV UMASK=0077
# Create readonly user and group with no shell access.
# Readonly user marks folders that are created by NetAlertX, but should not be modified.
# AI may claim this is stupid, but it's actually least possible permissions as
@@ -159,9 +157,9 @@ RUN chown -R ${READ_ONLY_USER}:${READ_ONLY_GROUP} ${READ_ONLY_FOLDERS} && \
chmod 005 /entrypoint.sh ${SYSTEM_SERVICES}/*.sh
# remove sudoers, sudo, alpine installers pacakges, and all users and groups except
# remove sudoers, alpine installers pacakges, and all users and groups except
# readonly and netalertx
RUN apk del sudo apk-tools && \
RUN apk del apk-tools && \
rm -rf /var/cache/apk/* && \
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 \
@@ -175,4 +173,3 @@ USER netalertx
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD /services/healthcheck.sh
ENTRYPOINT [ "/bin/sh", "/entrypoint.sh" ]

View File

@@ -9,6 +9,9 @@
# - read-only filesystem
# - no sudo access
# - least possible permissions on all files and folders
# - Root user has all permissions revoked and is unused
# - Secure umask applied so files are owner-only by default
# - non-privileged user runs the application
# - no shell access for non-privileged users
# - no unnecessary packages or services
# - reduced capabilities

View File

@@ -1,41 +0,0 @@
services:
netalertx:
network_mode: host # Use host networking for ARP scanning and other services
build:
context: . # Build context is the current directory
dockerfile: Dockerfile # Specify the Dockerfile to use
image: netalertx:latest
container_name: netalertx # The name when you docker contiainer ls
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:
- "/app/api:uid=20211,gid=20211,mode=700"
- "/app/log:uid=20211,gid=20211,mode=700"
- "/services/config/nginx/conf.active:uid=20211,gid=20211,mode=700"
- "/services/run:uid=20211,gid=20211,mode=700"
- "/tmp:mode=700"
environment:
NETALERTX_MODE: hardened
PORT: 20211
GRAPHQL_PORT: 25378
ALWAYS_FRESH_INSTALL: false
restart: unless-stopped
volumes:
netalertx_config:
netalertx_db:

View File

@@ -1,21 +0,0 @@
version: '3.8'
services:
netalertx:
build:
context: .
dockerfile: Dockerfile
image: netalertx:latest
container_name: netalertx_unproxied
read_only: true
tmpfs:
- /etc/nginx/conf.d
- /var/cache/nginx
- /var/run
- /app/log
- /tmp
network_mode: "host"
environment:
- NETALERTX_MODE=unproxied
- GRAPHQL_PORT=20212
restart: unless-stopped

View File

@@ -1,40 +1,62 @@
services:
netalertx:
network_mode: host # Use host networking for ARP scanning and other services
network_mode: host # Use host networking for ARP scanning and other services
build:
context: . # Build context is the current directory
dockerfile: Dockerfile # Specify the Dockerfile to use
context: . # Build context is the current directory
dockerfile: Dockerfile # Specify the Dockerfile to use
image: netalertx:latest
container_name: netalertx # The name when you docker contiainer ls
read_only: true # Make the container filesystem read-only
cap_drop: # Drop all capabilities for enhanced security
container_name: netalertx # The name when you docker contiainer ls
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)
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
volumes:
- netalertx_config:/app/config # Store your NetAlertX config
- netalertx_db:/app/db # Store your NetAlertX devices and settings
- /etc/localtime:/etc/localtime:ro # Use your system clock inside the container (read-only)
#- /path/on/host:/app/front/plugins/custom # Test your plugin on the production container
# Additional Volume Examples below
# Use a custom Enterprise-configured nginx config for ldap or other settings
# - /custom-enterprise.conf:/services/config/nginx/conf.active/netalertx.conf:ro
# Test your plugin on the production container
# - /path/on/host:/app/front/plugins/custom
# Retain logs - comment out tmpfs /app/log if you want to retain logs between container restarts
# - /path/on/host/log:/app/log
# Tempfs mounts for writable directories in a read-only container and improve system performance
# by providing a clean R/W filesystem each container start and reducing disk I/O.
# Temp mounts are noexec, nosuid, and nodev for security.
tmpfs:
- "/app/api:uid=20211,gid=20211,mode=700"
- "/app/log:uid=20211,gid=20211,mode=700"
- "/services/config/nginx/conf.active:uid=20211,gid=20211,mode=700"
- "/services/run:uid=20211,gid=20211,mode=700"
- "/app/api:uid=20211,gid=20211,mode=700,noexec,nosuid,nodev"
- "/app/log:uid=20211,gid=20211,mode=700,noexec,nosuid,nodev"
- "/services/config/nginx/conf.active:uid=20211,gid=20211,mode=700,noexec,nosuid,nodev"
- "/services/run:uid=20211,gid=20211,mode=700,noexec,nosuid,nodev"
environment:
LISTEN_ADDR: 0.0.0.0
PORT: 20211
GRAPHQL_PORT: 20212
NETALERTX_MODE: hardened
ALWAYS_FRESH_INSTALL: false
NETALERTX_DEBUG: 0
LISTEN_ADDR: 0.0.0.0 # Listen for connections on all interfaces
PORT: 20211 # Application port
GRAPHQL_PORT: 20212 # GraphQL API port
ALWAYS_FRESH_INSTALL: false # Set to true to reset your config and database on each container start
NETALERTX_DEBUG: 0 # 0=kill all services and restart if any dies. 1 keeps running dead services.
# Resource limits to prevent resource exhaustion
mem_limit: 2048m
mem_reservation: 1024m
cpus: 4
pids_limit: 512
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
restart: unless-stopped
volumes: