v2.0.0: adaptive eBPF firewall with AI honeypot and P2P threat mesh

This commit is contained in:
Vladyslav Soliannikov 2026-04-07 22:28:11 +00:00
commit 37c6bbf5a1
133 changed files with 28073 additions and 0 deletions

View file

@ -0,0 +1,20 @@
# Blackwall userspace daemon — multi-stage build
# Stage 1: Build the Rust binary
FROM rust:1.87-bookworm AS builder
WORKDIR /build
COPY . .
RUN cargo build --release --bin blackwall \
&& strip target/release/blackwall
# Stage 2: Minimal runtime image
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
iproute2 \
libelf1 \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /build/target/release/blackwall /usr/local/bin/blackwall
RUN useradd -r -s /usr/sbin/nologin blackwall
# eBPF requires root/CAP_BPF — runs as root in container, limited by securityContext
ENTRYPOINT ["/usr/local/bin/blackwall"]
CMD ["/etc/blackwall/config.toml"]

16
deploy/docker/Dockerfile.ebpf Executable file
View file

@ -0,0 +1,16 @@
# Blackwall eBPF programs — init container
# Builds the BPF object file with nightly + bpfel target
FROM rust:1.87-bookworm AS builder
RUN rustup toolchain install nightly \
&& rustup component add rust-src --toolchain nightly
WORKDIR /build
COPY . .
RUN cd blackwall-ebpf && \
cargo +nightly build \
--target bpfel-unknown-none \
-Z build-std=core \
--release
# Stage 2: Tiny image with just the BPF binary
FROM busybox:1.37
COPY --from=builder /build/target/bpfel-unknown-none/release/blackwall-ebpf /opt/blackwall/blackwall-ebpf

View file

@ -0,0 +1,34 @@
# Example BlackwallPolicy — drop known bad IPs, tarpit scanners
apiVersion: security.blackwall.io/v1alpha1
kind: BlackwallPolicy
metadata:
name: default-policy
namespace: blackwall-system
spec:
rules:
blocklist:
- ip: "192.168.1.100"
action: drop
duration: "1h"
- ip: "10.0.0.0/8"
action: tarpit
- ip: "203.0.113.0/24"
action: drop
allowlist:
- ip: "192.168.0.0/16"
reason: "internal network"
thresholds:
entropyAnomaly: 6500
synFloodRate: 1000
tarpit:
enabled: true
port: 2222
baseDelayMs: 100
maxDelayMs: 30000
ai:
enabled: true
model: "qwen3:1.7b"
fallbackModel: "qwen3:0.6b"
network:
interface: "auto"
xdpMode: "native"

61
deploy/healthcheck.sh Executable file
View file

@ -0,0 +1,61 @@
#!/bin/bash
# Blackwall Health Check — returns non-zero if any component is down
FAILED=0
REPORT=""
# Check blackwall daemon
if ! pidof blackwall > /dev/null 2>&1; then
REPORT+="CRIT: blackwall not running\n"
FAILED=1
fi
# Check XDP attached
if ! ip link show | grep -q xdp; then
REPORT+="CRIT: XDP not attached to any interface\n"
FAILED=1
fi
# Check tarpit
if ! pidof tarpit > /dev/null 2>&1; then
REPORT+="WARN: tarpit not running\n"
fi
# Check hivemind
if ! pidof hivemind > /dev/null 2>&1; then
REPORT+="WARN: hivemind not running\n"
fi
# Check hivemind-api
if ! ss -tlnp | grep -q 8090; then
REPORT+="WARN: hivemind-api not listening on 8090\n"
fi
# Check peer connectivity (if hivemind-api responds)
STATS=$(curl -s --max-time 3 http://127.0.0.1:8090/stats 2>/dev/null)
if [ -n "$STATS" ]; then
PEERS=$(echo "$STATS" | grep -o '"peer_count":[0-9]*' | cut -d: -f2)
if [ "${PEERS:-0}" -eq 0 ]; then
REPORT+="WARN: hivemind has 0 peers\n"
fi
fi
# Check Docker (if applicable)
if command -v docker &> /dev/null; then
DOCKER_COUNT=$(docker ps -q 2>/dev/null | wc -l)
if [ "$DOCKER_COUNT" -eq 0 ]; then
REPORT+="CRIT: No Docker containers running (expected >0)\n"
FAILED=1
fi
fi
if [ $FAILED -eq 1 ]; then
echo -e "BLACKWALL HEALTH: CRITICAL\n$REPORT"
exit 1
elif [ -n "$REPORT" ]; then
echo -e "BLACKWALL HEALTH: DEGRADED\n$REPORT"
exit 0
else
echo "BLACKWALL HEALTH: OK"
exit 0
fi

View file

@ -0,0 +1,16 @@
apiVersion: v2
name: blackwall
description: eBPF-powered AI firewall with XDP native DNAT, TCP tarpit deception, and P2P threat intelligence
type: application
version: 0.1.0
appVersion: "2.0.0"
keywords:
- ebpf
- xdp
- firewall
- honeypot
- ai
- security
maintainers:
- name: Blackwall Team
home: https://github.com/blackwall-fw/blackwall

View file

@ -0,0 +1,36 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: blackwall
app.kubernetes.io/instance: {{ .Release.Name }}
data:
config.toml: |
[network]
interface = {{ .Values.network.interface | quote }}
xdp_mode = {{ .Values.network.xdpMode | quote }}
[tarpit]
enabled = {{ .Values.tarpit.enabled }}
port = {{ .Values.tarpit.port }}
base_delay_ms = {{ .Values.tarpit.baseDelayMs }}
max_delay_ms = {{ .Values.tarpit.maxDelayMs }}
jitter_ms = {{ .Values.tarpit.jitterMs }}
[ai]
enabled = {{ .Values.ai.enabled }}
ollama_url = {{ .Values.ai.ollamaUrl | quote }}
model = {{ .Values.ai.model | quote }}
fallback_model = {{ .Values.ai.fallbackModel | quote }}
max_tokens = {{ .Values.ai.maxTokens }}
timeout_ms = {{ .Values.ai.timeoutMs }}
[feeds]
enabled = {{ .Values.feeds.enabled }}
refresh_interval_secs = {{ .Values.feeds.refreshIntervalSecs }}
[metrics]
enabled = {{ .Values.metrics.enabled }}
port = {{ .Values.metrics.port }}

View file

@ -0,0 +1,137 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: blackwallpolicies.security.blackwall.io
labels:
app.kubernetes.io/name: blackwall
spec:
group: security.blackwall.io
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
# IP-based rules
rules:
type: object
properties:
blocklist:
type: array
items:
type: object
properties:
ip:
type: string
pattern: '^(\d{1,3}\.){3}\d{1,3}(/\d{1,2})?$'
action:
type: string
enum: ["drop", "tarpit", "pass"]
duration:
type: string
pattern: '^\d+[smh]$'
description: "Block duration (e.g., 10m, 1h, 30s)"
required: ["ip", "action"]
allowlist:
type: array
items:
type: object
properties:
ip:
type: string
reason:
type: string
required: ["ip"]
# Anomaly detection thresholds
thresholds:
type: object
properties:
entropyAnomaly:
type: integer
minimum: 0
maximum: 8000
description: "Byte diversity score above which packets are flagged"
synFloodRate:
type: integer
minimum: 0
description: "SYN packets per second before triggering protection"
# Tarpit configuration
tarpit:
type: object
properties:
enabled:
type: boolean
port:
type: integer
minimum: 1
maximum: 65535
baseDelayMs:
type: integer
maxDelayMs:
type: integer
# AI classification
ai:
type: object
properties:
enabled:
type: boolean
model:
type: string
fallbackModel:
type: string
# Interface selection (per-node override via nodeSelector)
network:
type: object
properties:
interface:
type: string
xdpMode:
type: string
enum: ["generic", "native", "offload"]
status:
type: object
properties:
conditions:
type: array
items:
type: object
properties:
type:
type: string
status:
type: string
lastTransitionTime:
type: string
format: date-time
message:
type: string
appliedNodes:
type: integer
description: "Number of nodes where policy is active"
blockedIPs:
type: integer
description: "Total IPs currently in blocklist across cluster"
subresources:
status: {}
additionalPrinterColumns:
- name: Rules
type: integer
jsonPath: .status.blockedIPs
- name: Nodes
type: integer
jsonPath: .status.appliedNodes
- name: Age
type: date
jsonPath: .metadata.creationTimestamp
scope: Namespaced
names:
plural: blackwallpolicies
singular: blackwallpolicy
kind: BlackwallPolicy
shortNames:
- bwp

View file

@ -0,0 +1,119 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: {{ .Release.Name }}-blackwall
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: blackwall
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/component: dataplane
spec:
selector:
matchLabels:
app.kubernetes.io/name: blackwall
app.kubernetes.io/instance: {{ .Release.Name }}
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
template:
metadata:
labels:
app.kubernetes.io/name: blackwall
app.kubernetes.io/instance: {{ .Release.Name }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
spec:
{{- if .Values.serviceAccount.create }}
serviceAccountName: {{ .Values.serviceAccount.name }}
{{- end }}
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
initContainers:
# Copy pre-built eBPF object into shared volume
- name: ebpf-loader
image: "{{ .Values.ebpfImage.repository }}:{{ .Values.ebpfImage.tag }}"
imagePullPolicy: {{ .Values.ebpfImage.pullPolicy }}
command: ["cp", "/opt/blackwall/blackwall-ebpf", "/bpf/blackwall-ebpf"]
volumeMounts:
- name: bpf-objects
mountPath: /bpf
containers:
- name: blackwall
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
args:
- "/etc/blackwall/config.toml"
env:
- name: BLACKWALL_EBPF_PATH
value: "/bpf/blackwall-ebpf"
- name: RUST_LOG
value: "blackwall=info"
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: bpf-objects
mountPath: /bpf
readOnly: true
- name: config
mountPath: /etc/blackwall
readOnly: true
- name: bpf-fs
mountPath: /sys/fs/bpf
{{- if .Values.pcap.enabled }}
- name: pcap-storage
mountPath: /var/lib/blackwall/pcap
{{- end }}
ports:
{{- if .Values.tarpit.enabled }}
- name: tarpit
containerPort: {{ .Values.tarpit.port }}
protocol: TCP
hostPort: {{ .Values.tarpit.port }}
{{- end }}
{{- if .Values.metrics.enabled }}
- name: metrics
containerPort: {{ .Values.metrics.port }}
protocol: TCP
{{- end }}
livenessProbe:
exec:
command: ["cat", "/proc/1/status"]
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
exec:
command: ["test", "-f", "/sys/fs/bpf/blackwall_xdp"]
initialDelaySeconds: 5
periodSeconds: 10
volumes:
- name: bpf-objects
emptyDir: {}
- name: config
configMap:
name: {{ .Release.Name }}-config
- name: bpf-fs
hostPath:
path: /sys/fs/bpf
type: DirectoryOrCreate
{{- if .Values.pcap.enabled }}
- name: pcap-storage
persistentVolumeClaim:
claimName: {{ .Release.Name }}-pcap
{{- end }}

View file

@ -0,0 +1,39 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ .Release.Name }}-blackwall
labels:
app.kubernetes.io/name: blackwall
app.kubernetes.io/instance: {{ .Release.Name }}
rules:
# Watch BlackwallPolicy CRDs
- apiGroups: ["security.blackwall.io"]
resources: ["blackwallpolicies"]
verbs: ["get", "list", "watch"]
- apiGroups: ["security.blackwall.io"]
resources: ["blackwallpolicies/status"]
verbs: ["patch", "update"]
# Read node info for interface auto-detection
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list"]
# ConfigMaps for config
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ .Release.Name }}-blackwall
labels:
app.kubernetes.io/name: blackwall
app.kubernetes.io/instance: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ .Release.Name }}-blackwall
subjects:
- kind: ServiceAccount
name: {{ .Values.serviceAccount.name }}
namespace: {{ .Release.Namespace }}

View file

@ -0,0 +1,14 @@
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Values.serviceAccount.name }}
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: blackwall
app.kubernetes.io/instance: {{ .Release.Name }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,92 @@
# Blackwall Helm Chart — Default Values
# Override per environment via -f values-production.yaml
# Container image
image:
repository: ghcr.io/blackwall-fw/blackwall
tag: "2.0.0"
pullPolicy: IfNotPresent
# eBPF image (init container builds/copies the BPF object)
ebpfImage:
repository: ghcr.io/blackwall-fw/blackwall-ebpf
tag: "2.0.0"
pullPolicy: IfNotPresent
# DaemonSet scheduling
nodeSelector: {}
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
affinity: {}
# Resource limits
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"
# Network configuration
network:
# Interface to attach XDP program to.
# "auto" = detect primary interface via default route.
interface: "auto"
# XDP attach mode: generic, native, offload
xdpMode: "generic"
# Tarpit honeypot
tarpit:
enabled: true
port: 2222
baseDelayMs: 100
maxDelayMs: 30000
jitterMs: 500
# AI/LLM classification
ai:
enabled: true
ollamaUrl: "http://ollama.default.svc.cluster.local:11434"
model: "qwen3:1.7b"
fallbackModel: "qwen3:0.6b"
maxTokens: 512
timeoutMs: 30000
# Threat feeds
feeds:
enabled: true
refreshIntervalSecs: 3600
# HiveMind P2P mesh
hivemind:
enabled: false
bootstrapPeers: []
# PCAP forensic capture
pcap:
enabled: false
storageClass: ""
storageSize: "10Gi"
# Metrics (Prometheus)
metrics:
enabled: true
port: 9090
# ServiceAccount
serviceAccount:
create: true
name: "blackwall"
annotations: {}
# Security context (eBPF requires CAP_BPF + CAP_NET_ADMIN)
securityContext:
privileged: false
capabilities:
add:
- BPF
- NET_ADMIN
- SYS_ADMIN
- PERFMON

View file

@ -0,0 +1,14 @@
[Unit]
Description=Blackwall HiveMind API
After=blackwall-hivemind.service
[Service]
Type=simple
WorkingDirectory=/opt/blackwall
ExecStart=/opt/blackwall/bin/hivemind-api
Environment=RUST_LOG=info
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,8 @@
[Unit]
Description=Blackwall health check
[Service]
Type=oneshot
ExecStart=/opt/blackwall/healthcheck.sh
StandardOutput=append:/var/log/blackwall-health.log
StandardError=append:/var/log/blackwall-health.log

View file

@ -0,0 +1,10 @@
[Unit]
Description=Blackwall health check timer (every 5 min)
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Persistent=true
[Install]
WantedBy=timers.target

View file

@ -0,0 +1,14 @@
[Unit]
Description=Blackwall HiveMind P2P Mesh
After=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/blackwall
ExecStart=/opt/blackwall/bin/hivemind
Environment=RUST_LOG=info
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,14 @@
[Unit]
Description=Blackwall Tarpit Honeypot
After=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/blackwall
ExecStart=/opt/blackwall/bin/tarpit
Environment=RUST_LOG=info
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,18 @@
[Unit]
Description=Blackwall Adaptive eBPF Firewall
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/blackwall
ExecStart=/opt/blackwall/bin/blackwall /opt/blackwall/config.toml
Environment=BLACKWALL_EBPF_PATH=/opt/blackwall/bin/blackwall-ebpf
Environment=RUST_LOG=info
Restart=on-failure
RestartSec=5
LimitMEMLOCK=infinity
AmbientCapabilities=CAP_BPF CAP_NET_ADMIN CAP_PERFMON CAP_SYS_PTRACE
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,14 @@
[Unit]
Description=Blackwall HiveMind API
After=blackwall-hivemind.service
[Service]
Type=simple
WorkingDirectory=/opt/blackwall
ExecStart=/opt/blackwall/hivemind-api
Environment=RUST_LOG=info
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,14 @@
[Unit]
Description=Blackwall HiveMind P2P Mesh
After=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/blackwall
ExecStart=/usr/local/bin/hivemind
Environment=RUST_LOG=info
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,14 @@
[Unit]
Description=Blackwall Tarpit Honeypot
After=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/blackwall
ExecStart=/opt/blackwall/tarpit
Environment=RUST_LOG=info
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,18 @@
[Unit]
Description=Blackwall Adaptive eBPF Firewall
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/blackwall
ExecStart=/opt/blackwall/blackwall /opt/blackwall/config.toml
Environment=BLACKWALL_EBPF_PATH=/opt/blackwall/blackwall-ebpf
Environment=RUST_LOG=info
Restart=on-failure
RestartSec=5
LimitMEMLOCK=infinity
AmbientCapabilities=CAP_BPF CAP_NET_ADMIN CAP_PERFMON CAP_SYS_PTRACE
[Install]
WantedBy=multi-user.target