init
Some checks failed
release-tag / release-image (push) Failing after 1m39s

This commit is contained in:
2026-04-23 21:56:44 +02:00
parent 329faadf8f
commit 2b08d518ad
14 changed files with 2823 additions and 0 deletions

38
.env Normal file
View File

@@ -0,0 +1,38 @@
TZ=Europe/Berlin
LISTEN_ADDR=:8080
DB_DSN=eventuser:DEINPASSWORT@tcp(mariadb:3306)/eventcollector?parseTime=true&charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&loc=UTC
DB_MAX_OPEN_CONNS=50
DB_MAX_IDLE_CONNS=25
DB_CONN_MAX_LIFETIME=3m
DB_CONN_MAX_IDLE_TIME=1m
MAX_BODY_BYTES=10485760
HTTP_READ_TIMEOUT=15s
HTTP_WRITE_TIMEOUT=30s
HTTP_IDLE_TIMEOUT=60s
DETECTION_INTERVAL=1m
OFFLINE_AFTER=10m
FAILED_LOGON_WINDOW=5m
FAILED_LOGON_THRESHOLD=25
REBOOT_WINDOW=15m
REBOOT_THRESHOLD=3
PASSWORD_SPRAY_WINDOW=5m
PASSWORD_SPRAY_MIN_USERS=5
PASSWORD_SPRAY_MIN_ATTEMPTS=15
SUCCESS_AFTER_FAILURE_WINDOW=10m
NEW_SOURCE_IP_LOOKBACK=720h
NEW_SOURCE_IP_WINDOW=10m
DETECTIONS_LIMIT=100
MARIADB_DATABASE=eventcollector
MARIADB_USER=eventuser
MARIADB_PASSWORD=DEINPASSWORT
MARIADB_ROOT_PASSWORD=ROOTPASSWORT
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=BITTE_AENDERN
ENROLLMENT_KEY=BITTE_SEHR_LANG_UND_ZUFAELLIG

View File

@@ -0,0 +1,51 @@
name: release-tag
on:
push:
branches:
- 'main'
jobs:
release-image:
runs-on: ubuntu-latest
env:
DOCKER_ORG: sendnrw
DOCKER_LATEST: latest
RUNNER_TOOL_CACHE: /toolcache
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v2
with: # replace it with your local IP
config-inline: |
[registry."git.send.nrw"]
http = true
insecure = true
- name: Login to DockerHub
uses: docker/login-action@v2
with:
registry: git.send.nrw # replace it with your local IP
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get Meta
id: meta
run: |
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile
platforms: |
linux/amd64
push: true
tags: | # replace it with your local IP and tags
git.send.nrw/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
git.send.nrw/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}

32
Dockerfile Normal file
View File

@@ -0,0 +1,32 @@
FROM golang:1.24 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -trimpath -ldflags="-s -w" -o /out/eventcollector .
FROM debian:trixie-slim
ENV LISTEN_ADDR=:8080
ENV TZ=Europe/Berlin
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates tzdata wget \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid 10001 app \
&& useradd --system --uid 10001 --gid 10001 --no-create-home --home-dir /nonexistent --shell /usr/sbin/nologin app
WORKDIR /app
COPY --from=builder /out/eventcollector /app/eventcollector
USER 10001:10001
EXPOSE 8080
ENTRYPOINT ["/app/eventcollector"]

118
compose.yml Normal file
View File

@@ -0,0 +1,118 @@
services:
mariadb:
image: mariadb:11.8
container_name: siem-mariadb
restart: unless-stopped
env_file:
- .env
environment:
MARIADB_DATABASE: ${MARIADB_DATABASE}
MARIADB_USER: ${MARIADB_USER}
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
TZ: ${TZ}
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --innodb-buffer-pool-size=512M
- --max-connections=300
volumes:
- mariadb_data:/var/lib/mysql
- ./deploy/mariadb/init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "mariadb-admin ping -h 127.0.0.1 -u root -p$$MARIADB_ROOT_PASSWORD --silent"]
interval: 20s
timeout: 5s
retries: 10
start_period: 30s
siem-backend:
build:
context: .
dockerfile: Dockerfile
image: siem-backend:latest
container_name: siem-backend
restart: unless-stopped
env_file:
- .env
environment:
LISTEN_ADDR: ${LISTEN_ADDR}
DB_DSN: ${DB_DSN}
DB_MAX_OPEN_CONNS: ${DB_MAX_OPEN_CONNS}
DB_MAX_IDLE_CONNS: ${DB_MAX_IDLE_CONNS}
DB_CONN_MAX_LIFETIME: ${DB_CONN_MAX_LIFETIME}
DB_CONN_MAX_IDLE_TIME: ${DB_CONN_MAX_IDLE_TIME}
MAX_BODY_BYTES: ${MAX_BODY_BYTES}
HTTP_READ_TIMEOUT: ${HTTP_READ_TIMEOUT}
HTTP_WRITE_TIMEOUT: ${HTTP_WRITE_TIMEOUT}
HTTP_IDLE_TIMEOUT: ${HTTP_IDLE_TIMEOUT}
DETECTION_INTERVAL: ${DETECTION_INTERVAL}
OFFLINE_AFTER: ${OFFLINE_AFTER}
FAILED_LOGON_WINDOW: ${FAILED_LOGON_WINDOW}
FAILED_LOGON_THRESHOLD: ${FAILED_LOGON_THRESHOLD}
REBOOT_WINDOW: ${REBOOT_WINDOW}
REBOOT_THRESHOLD: ${REBOOT_THRESHOLD}
PASSWORD_SPRAY_WINDOW: ${PASSWORD_SPRAY_WINDOW}
PASSWORD_SPRAY_MIN_USERS: ${PASSWORD_SPRAY_MIN_USERS}
PASSWORD_SPRAY_MIN_ATTEMPTS: ${PASSWORD_SPRAY_MIN_ATTEMPTS}
SUCCESS_AFTER_FAILURE_WINDOW: ${SUCCESS_AFTER_FAILURE_WINDOW}
NEW_SOURCE_IP_LOOKBACK: ${NEW_SOURCE_IP_LOOKBACK}
NEW_SOURCE_IP_WINDOW: ${NEW_SOURCE_IP_WINDOW}
DETECTIONS_LIMIT: ${DETECTIONS_LIMIT}
TZ: ${TZ}
depends_on:
mariadb:
condition: service_healthy
ports:
- "8080:8080"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/healthz >/dev/null 2>&1 || exit 1"]
interval: 30s
timeout: 5s
retries: 5
start_period: 20s
prometheus:
image: prom/prometheus:latest
container_name: siem-prometheus
restart: unless-stopped
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=30d
- --web.enable-lifecycle
depends_on:
siem-backend:
condition: service_healthy
volumes:
- ./deploy/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./deploy/prometheus/rules:/etc/prometheus/rules:ro
- prometheus_data:/prometheus
ports:
- "9090:9090"
grafana:
image: grafana/grafana:latest
container_name: siem-grafana
restart: unless-stopped
env_file:
- .env
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
GF_USERS_ALLOW_SIGN_UP: "false"
GF_SERVER_ROOT_URL: http://localhost:3000
TZ: ${TZ}
depends_on:
- prometheus
volumes:
- grafana_data:/var/lib/grafana
- ./deploy/grafana/provisioning:/etc/grafana/provisioning:ro
- ./deploy/grafana/dashboards:/var/lib/grafana/dashboards:ro
ports:
- "3000:3000"
volumes:
mariadb_data:
prometheus_data:
grafana_data:

View File

@@ -0,0 +1,12 @@
apiVersion: 1
providers:
- name: SIEM Dashboards
orgId: 1
folder: SIEM
type: file
disableDeletion: false
editable: true
updateIntervalSeconds: 30
options:
path: /var/lib/grafana/dashboards

View File

@@ -0,0 +1,76 @@
{
"annotations": {
"list": []
},
"editable": true,
"panels": [
{
"type": "stat",
"title": "Active Agents",
"gridPos": { "h": 4, "w": 6, "x": 0, "y": 0 },
"targets": [
{
"expr": "eventcollector_active_agents",
"refId": "A"
}
]
},
{
"type": "stat",
"title": "High Detections (5m)",
"gridPos": { "h": 4, "w": 6, "x": 6, "y": 0 },
"targets": [
{
"expr": "increase(eventcollector_detection_hits_total{severity=\"high\"}[5m])",
"refId": "A"
}
]
},
{
"type": "timeseries",
"title": "HTTP Requests",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 4 },
"targets": [
{
"expr": "rate(eventcollector_http_requests_total[5m])",
"legendFormat": "{{path}} {{status}}",
"refId": "A"
}
]
},
{
"type": "timeseries",
"title": "Detection Hits",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 4 },
"targets": [
{
"expr": "increase(eventcollector_detection_hits_total[5m])",
"legendFormat": "{{rule}} {{severity}}",
"refId": "A"
}
]
},
{
"type": "timeseries",
"title": "Ingested Events",
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 12 },
"targets": [
{
"expr": "rate(eventcollector_ingest_events_total[5m])",
"legendFormat": "{{channel}} {{event_id}}",
"refId": "A"
}
]
}
],
"schemaVersion": 39,
"style": "dark",
"tags": ["siem"],
"templating": { "list": [] },
"time": {
"from": "now-6h",
"to": "now"
},
"title": "SIEM Overview",
"version": 1
}

View File

@@ -0,0 +1,10 @@
apiVersion: 1
datasources:
- name: Prometheus
uid: prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: true

View File

@@ -0,0 +1,88 @@
CREATE DATABASE IF NOT EXISTS eventcollector
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE eventcollector;
CREATE TABLE IF NOT EXISTS agents (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
hostname VARCHAR(255) NOT NULL,
api_key_hash CHAR(64) NOT NULL,
first_seen DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
last_seen DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
last_ip VARCHAR(64) NOT NULL DEFAULT '',
is_enabled TINYINT(1) NOT NULL DEFAULT 1,
PRIMARY KEY (id),
UNIQUE KEY ux_agents_hostname (hostname),
KEY ix_agents_last_seen (last_seen)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS event_logs (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
agent_id BIGINT UNSIGNED NOT NULL,
hostname VARCHAR(255) NOT NULL,
channel_name VARCHAR(128) NOT NULL,
event_id INT UNSIGNED NOT NULL,
source VARCHAR(255) NOT NULL,
computer VARCHAR(255) NOT NULL DEFAULT '',
provider_name VARCHAR(255) NOT NULL DEFAULT '',
level_value INT UNSIGNED NOT NULL DEFAULT 0,
task_value INT UNSIGNED NOT NULL DEFAULT 0,
opcode_value INT UNSIGNED NOT NULL DEFAULT 0,
keywords VARCHAR(255) NOT NULL DEFAULT '',
target_user VARCHAR(255) NOT NULL DEFAULT '',
target_domain VARCHAR(255) NOT NULL DEFAULT '',
subject_user VARCHAR(255) NOT NULL DEFAULT '',
subject_domain VARCHAR(255) NOT NULL DEFAULT '',
workstation VARCHAR(255) NOT NULL DEFAULT '',
src_ip VARCHAR(64) NOT NULL DEFAULT '',
src_port VARCHAR(32) NOT NULL DEFAULT '',
logon_type VARCHAR(32) NOT NULL DEFAULT '',
process_name VARCHAR(512) NOT NULL DEFAULT '',
authentication_package VARCHAR(128) NOT NULL DEFAULT '',
logon_process VARCHAR(128) NOT NULL DEFAULT '',
status_text VARCHAR(64) NOT NULL DEFAULT '',
sub_status_text VARCHAR(64) NOT NULL DEFAULT '',
failure_reason VARCHAR(512) NOT NULL DEFAULT '',
ts DATETIME(6) NOT NULL,
received_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
msg LONGTEXT NOT NULL,
msg_sha256 CHAR(64) NOT NULL,
PRIMARY KEY (id),
KEY ix_event_logs_ts (ts),
KEY ix_event_logs_received_at (received_at),
KEY ix_event_logs_agent_ts (agent_id, ts),
KEY ix_event_logs_eventid_ts (event_id, ts),
KEY ix_event_logs_hostname_ts (hostname, ts),
KEY ix_event_logs_channel_event_ts (channel_name, event_id, ts),
KEY ix_event_logs_target_user_ts (target_user, ts),
KEY ix_event_logs_src_ip_ts (src_ip, ts),
KEY ix_event_logs_target_user_src_ip_ts (target_user, src_ip, ts),
KEY ix_event_logs_eventid_srcip_ts (event_id, src_ip, ts),
KEY ix_event_logs_eventid_targetuser_ts (event_id, target_user, ts),
KEY ix_event_logs_eventid_logontype_ts (event_id, logon_type, ts),
CONSTRAINT fk_event_logs_agent
FOREIGN KEY (agent_id) REFERENCES agents(id)
ON DELETE RESTRICT
ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS detections (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
rule_name VARCHAR(128) NOT NULL,
severity VARCHAR(32) NOT NULL,
hostname VARCHAR(255) NOT NULL,
channel_name VARCHAR(128) NOT NULL DEFAULT '',
event_id INT UNSIGNED NOT NULL DEFAULT 0,
score DOUBLE NOT NULL DEFAULT 0,
window_start DATETIME(6) NOT NULL,
window_end DATETIME(6) NOT NULL,
summary VARCHAR(512) NOT NULL,
details_json JSON NOT NULL,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
PRIMARY KEY (id),
UNIQUE KEY ux_detection_dedupe (rule_name, hostname, channel_name, event_id, window_start, window_end),
KEY ix_detections_created (created_at),
KEY ix_detections_rule_host_time (rule_name, hostname, created_at),
KEY ix_detections_severity_time (severity, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -0,0 +1,18 @@
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- /etc/prometheus/rules/*.yml
scrape_configs:
- job_name: siem-backend
metrics_path: /metrics
static_configs:
- targets:
- siem-backend:8080
- job_name: prometheus
static_configs:
- targets:
- localhost:9090

View File

@@ -0,0 +1,38 @@
groups:
- name: siem-backend
rules:
- alert: SiemBackendDown
expr: up{job="siem-backend"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "SIEM backend nicht erreichbar"
description: "Prometheus kann das SIEM-Backend seit mindestens 2 Minuten nicht scrapen."
- alert: SiemHighDetections
expr: increase(eventcollector_detection_hits_total{severity="high"}[5m]) > 0
for: 1m
labels:
severity: high
annotations:
summary: "Neue High-Severity Detection"
description: "Es wurde mindestens eine neue High-Severity-Detection in den letzten 5 Minuten erzeugt."
- alert: SiemRuleErrors
expr: increase(eventcollector_rule_errors_total[5m]) > 0
for: 1m
labels:
severity: warning
annotations:
summary: "Fehler in Detection-Regeln"
description: "Mindestens eine Detection-Regel hat in den letzten 5 Minuten einen Fehler erzeugt."
- alert: SiemTooFewActiveAgents
expr: eventcollector_active_agents < 1
for: 5m
labels:
severity: warning
annotations:
summary: "Zu wenige aktive Agents"
description: "Es wurden weniger aktive Agents erkannt als erwartet."

22
go.mod Normal file
View File

@@ -0,0 +1,22 @@
module git.send.nrw/sendnrw/siem-backend
go 1.26.1
require github.com/go-sql-driver/mysql v1.9.3
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/sys v0.35.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/prometheus/client_golang v1.23.2
)

25
go.sum Normal file
View File

@@ -0,0 +1,25 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

2194
main.go Normal file

File diff suppressed because it is too large Load Diff

101
schema.sql Normal file
View File

@@ -0,0 +1,101 @@
CREATE DATABASE IF NOT EXISTS eventcollector
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE eventcollector;
CREATE TABLE IF NOT EXISTS agents (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
hostname VARCHAR(255) NOT NULL,
api_key_hash CHAR(64) NOT NULL,
first_seen DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
last_seen DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
last_ip VARCHAR(64) NOT NULL DEFAULT '',
is_enabled TINYINT(1) NOT NULL DEFAULT 1,
PRIMARY KEY (id),
UNIQUE KEY ux_agents_hostname (hostname),
KEY ix_agents_last_seen (last_seen)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS event_logs (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
agent_id BIGINT UNSIGNED NOT NULL,
hostname VARCHAR(255) NOT NULL,
channel_name VARCHAR(128) NOT NULL,
event_id INT UNSIGNED NOT NULL,
source VARCHAR(255) NOT NULL,
ts DATETIME(6) NOT NULL,
received_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
msg LONGTEXT NOT NULL,
msg_sha256 CHAR(64) NOT NULL,
PRIMARY KEY (id),
KEY ix_event_logs_ts (ts),
KEY ix_event_logs_received_at (received_at),
KEY ix_event_logs_agent_ts (agent_id, ts),
KEY ix_event_logs_eventid_ts (event_id, ts),
KEY ix_event_logs_hostname_ts (hostname, ts),
KEY ix_event_logs_channel_event_ts (channel_name, event_id, ts),
CONSTRAINT fk_event_logs_agent
FOREIGN KEY (agent_id) REFERENCES agents(id)
ON DELETE RESTRICT
ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS detections (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
rule_name VARCHAR(128) NOT NULL,
severity VARCHAR(32) NOT NULL,
hostname VARCHAR(255) NOT NULL,
channel_name VARCHAR(128) NOT NULL DEFAULT '',
event_id INT UNSIGNED NOT NULL DEFAULT 0,
score DOUBLE NOT NULL DEFAULT 0,
window_start DATETIME(6) NOT NULL,
window_end DATETIME(6) NOT NULL,
summary VARCHAR(512) NOT NULL,
details_json JSON NOT NULL,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
PRIMARY KEY (id),
UNIQUE KEY ux_detection_dedupe (rule_name, hostname, channel_name, event_id, window_start, window_end),
KEY ix_detections_created (created_at),
KEY ix_detections_rule_host_time (rule_name, hostname, created_at),
KEY ix_detections_severity_time (severity, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
USE eventcollector;
INSERT INTO agents (hostname, api_key_hash)
VALUES
('client01.domain.local', SHA2('SUPER-LANGER-AGENT-KEY-01', 256)),
('client02.domain.local', SHA2('SUPER-LANGER-AGENT-KEY-02', 256));
#V2
ALTER TABLE event_logs
ADD COLUMN computer VARCHAR(255) NOT NULL DEFAULT '' AFTER source,
ADD COLUMN provider_name VARCHAR(255) NOT NULL DEFAULT '' AFTER computer,
ADD COLUMN level_value INT UNSIGNED NOT NULL DEFAULT 0 AFTER provider_name,
ADD COLUMN task_value INT UNSIGNED NOT NULL DEFAULT 0 AFTER level_value,
ADD COLUMN opcode_value INT UNSIGNED NOT NULL DEFAULT 0 AFTER task_value,
ADD COLUMN keywords VARCHAR(255) NOT NULL DEFAULT '' AFTER opcode_value,
ADD COLUMN target_user VARCHAR(255) NOT NULL DEFAULT '' AFTER keywords,
ADD COLUMN target_domain VARCHAR(255) NOT NULL DEFAULT '' AFTER target_user,
ADD COLUMN subject_user VARCHAR(255) NOT NULL DEFAULT '' AFTER target_domain,
ADD COLUMN subject_domain VARCHAR(255) NOT NULL DEFAULT '' AFTER subject_user,
ADD COLUMN workstation VARCHAR(255) NOT NULL DEFAULT '' AFTER subject_domain,
ADD COLUMN src_ip VARCHAR(64) NOT NULL DEFAULT '' AFTER workstation,
ADD COLUMN src_port VARCHAR(32) NOT NULL DEFAULT '' AFTER src_ip,
ADD COLUMN logon_type VARCHAR(32) NOT NULL DEFAULT '' AFTER src_port,
ADD COLUMN process_name VARCHAR(512) NOT NULL DEFAULT '' AFTER logon_type,
ADD COLUMN authentication_package VARCHAR(128) NOT NULL DEFAULT '' AFTER process_name,
ADD COLUMN logon_process VARCHAR(128) NOT NULL DEFAULT '' AFTER authentication_package,
ADD COLUMN status_text VARCHAR(64) NOT NULL DEFAULT '' AFTER logon_process,
ADD COLUMN sub_status_text VARCHAR(64) NOT NULL DEFAULT '' AFTER status_text,
ADD COLUMN failure_reason VARCHAR(512) NOT NULL DEFAULT '' AFTER sub_status_text;
ALTER TABLE event_logs
ADD KEY ix_event_logs_target_user_ts (target_user, ts),
ADD KEY ix_event_logs_src_ip_ts (src_ip, ts),
ADD KEY ix_event_logs_target_user_src_ip_ts (target_user, src_ip, ts),
ADD KEY ix_event_logs_eventid_srcip_ts (event_id, src_ip, ts),
ADD KEY ix_event_logs_eventid_targetuser_ts (event_id, target_user, ts),
ADD KEY ix_event_logs_eventid_logontype_ts (event_id, logon_type, ts);