Demystifying the Technology Architecture of Open Source WAF, SafeLine
Carrie
Posted on October 14, 2024
What is SafeLine
SafeLine (https://waf.chaitin.com/) is a free and open source docker-based, easy to use, self-hosted web application firewall (WAF) that protects your website from cyber attacks such as SQL injection, XSS, OS command injection, CRLF injection, x path injection, RCE, XXE, SSRF, directory traversal, backdoors, brute force, http-flood, bot abused, among others.
Demystifying the Technology Architecture of SafeLine
Let’s look at the architecture diagram of SafeLine (the diagram is somewhat outdated, so consider it a rough reference). The top section enclosed by a dashed line represents the data flow, specifically the flow of traffic data accessing the business server. The middle section outlines the various services within SafeLine.
Explanation of Various Containers and Services
Functions for Admin Management:
For backend administrators, the node that can be communicated with directly is the management service safeline-mgt, responsible for:
- Pushing custom configurations to the Tengine gateway and utilizing NGINX commands for reload and hot updates.
- Custom detection rules (black/white lists, etc.) pushed to the detection engine safeline-detector.
- Directly reading the PostgreSQL database, returning logs, statistics, current configurations, etc., to backend administrators.
Configuration Files Explanation
.env File
Used to set environment variables referenced in compose.yaml
.
echo "SAFELINE_DIR=$(pwd)" >> .env # Set the current path as the root path of Thunderpool Community Edition.
echo "IMAGE_TAG=latest" >> .env # Set the image tag.
echo "MGT_PORT=9443" >> .env # Port used by the management container service.
echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> .env # Generate a random PostgreSQL password.
echo "SUBNET_PREFIX=172.22.222" >> .env # Define the subnet prefix for the docker virtual network card.
compose.yml File
Used to start multiple containers.
networks:
safeline-ce:
name: safeline-ce
driver: bridge
ipam:
driver: default
config:
- gateway: ${SUBNET_PREFIX:?SUBNET_PREFIX required}.1
subnet: ${SUBNET_PREFIX}.0/24
driver_opts:
com.docker.network.bridge.name: safeline-ce
services:
postgres:
container_name: safeline-postgres
restart: always
image: postgres:15.2
volumes:
- ${SAFELINE_DIR}/resources/postgres/data:/var/lib/postgresql/data
- /etc/localtime:/etc/localtime:ro
environment:
- POSTGRES_USER=safeline-ce
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?postgres password required}
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.2
cap_drop:
- net_raw
command: [postgres, -c, max_connections=200]
management:
container_name: safeline-mgt-api
restart: always
image: chaitin/safeline-mgt-api:${IMAGE_TAG:?image tag required}
volumes:
- ${SAFELINE_DIR?safeline dir required}/resources/management:/resources/management
- ${SAFELINE_DIR}/resources/nginx:/resources/nginx
- ${SAFELINE_DIR}/logs:/logs
- /etc/localtime:/etc/localtime:ro
ports:
- ${MGT_PORT:-9443}:1443
environment:
- MANAGEMENT_RESOURCES_DIR=/resources/management
- NGINX_RESOURCES_DIR=/resources/nginx
- DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@127.0.0.1/safeline-ce
- MANAGEMENT_LOGS_DIR=/logs/management
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.4
cap_drop:
- net_raw
detector:
container_name: safeline-detector
restart: always
image: chaitin/safeline-detector:${IMAGE_TAG}
volumes:
- ${SAFELINE_DIR}/resources/detector:/resources/detector
- ${SAFELINE_DIR}/logs/detector:/logs/detector
- /etc/localtime:/etc/localtime:ro
environment:
- LOG_DIR=/logs/detector
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.5
cap_drop:
- net_raw
mario:
container_name: safeline-mario
restart: always
image: chaitin/safeline-mario:${IMAGE_TAG}
volumes:
- ${SAFELINE_DIR}/resources/mario:/resources/mario
- ${SAFELINE_DIR}/logs/mario:/logs/mario
- /etc/localtime:/etc/localtime:ro
environment:
- LOG_DIR=/logs/mario
- GOGC=100
- DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-postgres/safeline-ce
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.6
cap_drop:
- net_raw
tengine:
container_name: safeline-tengine
restart: always
image: chaitin/safeline-tengine:${IMAGE_TAG}
volumes:
- ${SAFELINE_DIR}/resources/nginx:/etc/nginx
- ${SAFELINE_DIR}/resources/management:/resources/management
- ${SAFELINE_DIR}/resources/detector:/resources/detector
- ${SAFELINE_DIR}/logs/nginx:/var/log/nginx
- /etc/localtime:/etc/localtime:ro
- ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache
- /etc/resolv.conf:/etc/resolv.conf
environment:
- MGT_ADDR=${SUBNET_PREFIX}.4:9002
ulimits:
nofile: 131072
network_mode: host
Running Logs of Each Service
docker ps # Check the status of each container
docker logs -f <container_name> # Output the std logs of the container
Some services’ runtime persistence will also be stored on the disk. The directory structure is as follows:
root@user:/path/to/safeline-ce/logs# tree
.
├── detector
│ └── snserver.log # Output logs of the detection container
├── management
│ ├── nginx.log # NGINX log output in the Tengine container
│ └── webserver.log # Log output of the safeline-mgt-api container
├── mario
│ └── mario.log # Traffic log output
└── nginx
├── error.log # NGINX error log
└── tcd.log # Tcd is the network proxy process used by Tengine to communicate with safeline-mgt-api, this file stores their communication logs.
Posted on October 14, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
October 14, 2024