Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.git
.github
dist/
testdata/
*.pcapng
*.pcap
*.zip
captures*/
__MACOSX/
ja4monitor
49 changes: 48 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,53 @@ jobs:
go build -tags pcaponly -ldflags "-X main.version=$VERSION" \
-o dist/ja4monitor-linux-arm64-pcaponly ./cmd/ja4monitor/

- name: Install nfpm
run: |
NFPM_VERSION=2.40.0
curl -fsSL "https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_Linux_x86_64.tar.gz" \
| sudo tar -xz -C /usr/local/bin nfpm
nfpm --version

- name: Package amd64 (.deb)
run: |
cp dist/ja4monitor-linux-amd64 dist/ja4monitor
ARCH=amd64 VERSION=${VERSION#v} nfpm package \
--config packaging/nfpm.yaml \
--packager deb \
--target dist/ja4monitor_${VERSION#v}_linux_amd64.deb
rm dist/ja4monitor

- name: Package amd64 (.rpm)
run: |
cp dist/ja4monitor-linux-amd64 dist/ja4monitor
ARCH=amd64 VERSION=${VERSION#v} nfpm package \
--config packaging/nfpm.yaml \
--packager rpm \
--target dist/ja4monitor_${VERSION#v}_linux_amd64.rpm
rm dist/ja4monitor

- name: Package arm64 (.deb)
run: |
cp dist/ja4monitor-linux-arm64 dist/ja4monitor
ARCH=arm64 VERSION=${VERSION#v} nfpm package \
--config packaging/nfpm.yaml \
--packager deb \
--target dist/ja4monitor_${VERSION#v}_linux_arm64.deb
rm dist/ja4monitor

- name: Package arm64 (.rpm)
run: |
cp dist/ja4monitor-linux-arm64 dist/ja4monitor
ARCH=arm64 VERSION=${VERSION#v} nfpm package \
--config packaging/nfpm.yaml \
--packager rpm \
--target dist/ja4monitor_${VERSION#v}_linux_arm64.rpm
rm dist/ja4monitor

- name: Checksum
run: |
cd dist
sha256sum ja4monitor-* > sha256sums.txt
sha256sum ja4monitor-* *.deb *.rpm > sha256sums.txt
cat sha256sums.txt

- name: Create GitHub Release
Expand All @@ -100,6 +143,10 @@ jobs:
dist/ja4monitor-linux-amd64-pcaponly
dist/ja4monitor-linux-arm64
dist/ja4monitor-linux-arm64-pcaponly
dist/ja4monitor_*_linux_amd64.deb
dist/ja4monitor_*_linux_amd64.rpm
dist/ja4monitor_*_linux_arm64.deb
dist/ja4monitor_*_linux_arm64.rpm
dist/sha256sums.txt
generate_release_notes: true
draft: false
Expand Down
61 changes: 61 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,67 @@ archives:
- format: tar.gz
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"

# .deb and .rpm packages (Linux only)
nfpms:
- package_name: ja4monitor
vendor: Crank-Git
homepage: https://github.com/Crank-Git/ja4monitor
maintainer: Crank-Git <noreply@github.com>
description: |
Passive JA4 network fingerprint sensor.
Captures TLS, HTTP, SSH, and TCP fingerprints from live traffic or PCAP
files and alerts on anomalies: new fingerprints, known malware signatures,
protocol mismatches, and behavioral novelty.
license: MIT
section: net
priority: optional

# Only build packages for Linux; Darwin .pkg is out of scope.
builds:
- ja4monitor
goos:
- linux
goarch:
- amd64
- arm64

formats:
- deb
- rpm

dependencies:
- libpcap

rpm:
group: Applications/System

contents:
# Example config — installed to /etc; not overwritten on upgrade
- src: configs/ja4monitor.example.toml
dst: /etc/ja4monitor/ja4monitor.toml
type: config|noreplace
file_info:
mode: 0640
owner: root
group: ja4monitor

# Example custom rules — reference only, not loaded by default
- src: configs/custom_rules.example.toml
dst: /etc/ja4monitor/custom_rules.example.toml
file_info:
mode: 0644

# Systemd unit
- src: packaging/ja4monitor.service
dst: /lib/systemd/system/ja4monitor.service
file_info:
mode: 0644

scripts:
postinstall: packaging/scripts/postinst
preremove: packaging/scripts/prerm
postremove: packaging/scripts/postrm

checksum:
name_template: checksums.txt

Expand Down
64 changes: 64 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# ja4monitor Dockerfile
#
# Build:
# docker build -t ja4monitor:latest .
#
# Run (live capture — requires host network and raw-socket capabilities):
# docker run --rm -it \
# --cap-add NET_RAW \
# --cap-add NET_ADMIN \
# --network host \
# -v /var/lib/ja4monitor:/data \
# ja4monitor:latest \
# --interface eth0 --db /data/ja4monitor.db
#
# Run (PCAP replay — no special capabilities needed):
# docker run --rm -it \
# -v /path/to/captures:/pcap:ro \
# ja4monitor:latest \
# /pcap/traffic.pcapng
#
# Kubernetes note:
# Live capture requires a privileged DaemonSet or a custom seccomp profile
# that allows CAP_NET_RAW and CAP_NET_ADMIN. See README for a reference
# DaemonSet manifest.
#
# ─── Build stage ────────────────────────────────────────────────────────────
FROM golang:1.25-bookworm AS builder

WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=1 go build \
-ldflags="-s -w" \
-o /out/ja4monitor \
./cmd/ja4monitor/

# ─── Runtime stage ───────────────────────────────────────────────────────────
FROM debian:bookworm-slim

# libpcap is required for live capture. ca-certificates enables HTTPS webhooks.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
libpcap0.8 \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Non-root user. Capabilities are granted at runtime via --cap-add, NOT
# by making the binary setuid — the container runtime handles privilege.
RUN groupadd --system ja4monitor \
&& useradd --system --gid ja4monitor --no-create-home \
--shell /usr/sbin/nologin ja4monitor

COPY --from=builder /out/ja4monitor /usr/bin/ja4monitor

# Data directory for the SQLite database.
RUN install -d -o ja4monitor -g ja4monitor -m 750 /data

USER ja4monitor
WORKDIR /data

ENTRYPOINT ["/usr/bin/ja4monitor"]
CMD ["--help"]
40 changes: 40 additions & 0 deletions packaging/ja4monitor.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[Unit]
Description=ja4monitor — passive JA4 fingerprint sensor
Documentation=https://github.com/Crank-Git/ja4monitor
After=network.target
Wants=network.target

[Service]
Type=simple
User=ja4monitor
Group=ja4monitor

# The binary has CAP_NET_RAW and CAP_NET_ADMIN set via setcap in postinst.
# AmbientCapabilities ensures those capabilities survive the setuid drop.
AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN

ExecStart=/usr/bin/ja4monitor daemon --config /etc/ja4monitor/ja4monitor.toml
Restart=on-failure
RestartSec=5s

# Harden the service: deny most kernel interfaces that a passive sensor
# doesn't need.
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/ja4monitor /var/log/ja4monitor
PrivateTmp=yes
PrivateDevices=no # needs /dev/net for packet capture
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
SystemCallFilter=@system-service
SystemCallArchitectures=native

[Install]
WantedBy=multi-user.target
65 changes: 65 additions & 0 deletions packaging/nfpm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# nfpm package configuration for ja4monitor
# Run from repo root: ARCH=amd64 VERSION=0.8.0 nfpm package --config packaging/nfpm.yaml --packager deb
# https://nfpm.goreleaser.com/configuration/

name: ja4monitor
arch: ${ARCH}
platform: linux
version: ${VERSION}
section: net
priority: optional
maintainer: Crank-Git <noreply@github.com>
description: |
Passive JA4 network fingerprint sensor.
Captures TLS, HTTP, SSH, and TCP fingerprints from live traffic or PCAP
files and alerts on anomalies: new fingerprints, known malware signatures,
protocol mismatches, and behavioral novelty.
vendor: Crank-Git
homepage: https://github.com/Crank-Git/ja4monitor
license: MIT

# Per-format dependency names differ; use overrides to avoid deb getting
# the RPM package name and vice versa.
overrides:
deb:
depends:
- libpcap0.8
rpm:
depends:
- libpcap
rpm:
group: Applications/System

contents:
# Binary — the release workflow copies the arch-specific binary to dist/ja4monitor
# before invoking nfpm, so the source path is always ../dist/ja4monitor.
- src: ../dist/ja4monitor
dst: /usr/bin/ja4monitor
file_info:
mode: 0755

# Example config — installed to /etc; not overwritten on upgrade.
- src: ../configs/ja4monitor.example.toml
dst: /etc/ja4monitor/ja4monitor.toml
type: config|noreplace
file_info:
mode: 0640
owner: root
group: ja4monitor

# Example custom rules — reference only, not loaded by default.
- src: ../configs/custom_rules.example.toml
dst: /etc/ja4monitor/custom_rules.example.toml
file_info:
mode: 0644

# Systemd unit.
- src: ja4monitor.service
dst: /lib/systemd/system/ja4monitor.service
file_info:
mode: 0644

scripts:
postinstall: scripts/postinst
preremove: scripts/prerm
postremove: scripts/postrm
48 changes: 48 additions & 0 deletions packaging/scripts/postinst
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/sh
# ja4monitor postinst — runs after package install/upgrade
set -e

# Create system user and group (no login shell, no home directory).
# getent check makes this idempotent across upgrades.
if ! getent group ja4monitor >/dev/null 2>&1; then
groupadd --system ja4monitor
fi
if ! getent passwd ja4monitor >/dev/null 2>&1; then
useradd --system \
--gid ja4monitor \
--no-create-home \
--shell /usr/sbin/nologin \
--comment "ja4monitor network monitor" \
ja4monitor
fi

# Create data directory owned by the service user.
install -d -o ja4monitor -g ja4monitor -m 750 /var/lib/ja4monitor

# Create log directory.
install -d -o ja4monitor -g ja4monitor -m 750 /var/log/ja4monitor

# Grant raw-socket capture capability so the daemon runs without root.
# setcap is preferred over adding the user to a privileged group because
# the capability is scoped to this binary only.
#
# Required capabilities:
# CAP_NET_RAW — raw packet capture (libpcap / AF_PACKET)
# CAP_NET_ADMIN — required by some kernel versions for promiscuous mode
if command -v setcap >/dev/null 2>&1; then
setcap cap_net_raw,cap_net_admin=eip /usr/bin/ja4monitor
else
echo "WARNING: setcap not found. ja4monitor must run as root or with" >&2
echo " CAP_NET_RAW and CAP_NET_ADMIN capabilities set manually." >&2
fi

# Install and enable the systemd unit if systemd is available.
if command -v systemctl >/dev/null 2>&1 && systemctl is-system-running --quiet 2>/dev/null; then
systemctl daemon-reload
# Enable but do not start — operator must configure /etc/ja4monitor/ja4monitor.toml first.
systemctl enable ja4monitor.service 2>/dev/null || true
echo "ja4monitor installed. Configure /etc/ja4monitor/ja4monitor.toml then:"
echo " systemctl start ja4monitor"
fi

exit 0
22 changes: 22 additions & 0 deletions packaging/scripts/postrm
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh
# ja4monitor postrm — runs after package removal
set -e

case "$1" in
purge)
# Full purge: remove data, logs, config, and system user.
rm -rf /var/lib/ja4monitor /var/log/ja4monitor /etc/ja4monitor

if getent passwd ja4monitor >/dev/null 2>&1; then
userdel ja4monitor 2>/dev/null || true
fi
if getent group ja4monitor >/dev/null 2>&1; then
groupdel ja4monitor 2>/dev/null || true
fi
;;
remove)
# Plain remove: keep data and config (operator may reinstall).
;;
esac

exit 0
Loading
Loading