Files
logcorrelator/architecture.yml
Jacquin Antoine d3436f6245
Some checks failed
Build and Test / test (push) Has been cancelled
Build and Test / build (push) Has been cancelled
Build and Test / docker (push) Has been cancelled
1.0.8
2026-03-01 11:30:55 +01:00

545 lines
18 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

service:
name: logcorrelator
context: http-network-correlation
language: go
pattern: hexagonal
description: >
logcorrelator est un service système (lancé par systemd) écrit en Go, chargé
de recevoir deux flux de logs JSON via des sockets Unix, de corréler les
événements HTTP applicatifs (source A, typiquement Apache ou reverse proxy)
avec des événements réseau (source B, métadonnées IP/TCP, JA3/JA4, etc.)
sur la base de la combinaison strictement définie src_ip + src_port, avec
une fenêtre temporelle configurable. Le service produit un log corrélé
unique pour chaque paire correspondante, émet toujours les événements A
même lorsquaucun événement B corrélé nest disponible, német jamais de
logs B seuls, et pousse les logs agrégés en temps quasi réel vers
ClickHouse et/ou un fichier local, en minimisant la rétention en mémoire
et sur disque.
runtime:
deployment:
unit_type: systemd
description: >
logcorrelator est livré sous forme de binaire autonome, exécuté comme un
service systemd. L'unité systemd assure le démarrage automatique au boot,
le redémarrage en cas de crash, et une intégration standard dans l'écosystème
Linux (notamment sur CentOS 7 et Rocky Linux 8+).
binary_path: /usr/bin/logcorrelator
config_path: /etc/logcorrelator/logcorrelator.yml
user: logcorrelator
group: logcorrelator
restart: on-failure
systemd_unit:
path: /etc/systemd/system/logcorrelator.service
content_example: |
[Unit]
Description=logcorrelator service
After=network.target
[Service]
Type=simple
User=logcorrelator
Group=logcorrelator
ExecStart=/usr/bin/logcorrelator -config /etc/logcorrelator/logcorrelator.yml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
os:
supported:
- rocky-linux-8
- rocky-linux-9
- almalinux-10
- autres-linux-recentes
logs:
stdout_stderr: journald
structured: true
description: >
Les logs internes du service (erreurs, messages dinformation) sont envoyés
vers stdout/stderr et collectés par journald. Ils sont structurés et ne
contiennent pas de données personnelles.
signals:
graceful_shutdown:
- SIGINT
- SIGTERM
description: >
En réception de SIGINT ou SIGTERM, le service arrête proprement la lecture
des sockets Unix, vide les buffers denvoi (dans les limites de la politique
de drop), ferme les connexions ClickHouse puis sarrête.
config:
format: yaml
location: /etc/logcorrelator/logcorrelator.yml
description: >
Toute la configuration est centralisée dans un fichier YAML lisible,
stocké dans /etc/logcorrelator.
reload_strategy: restart_service
example: |
# Logging configuration
log:
level: INFO # DEBUG, INFO, WARN, ERROR
# Inputs - at least 2 unix sockets required
inputs:
unix_sockets:
- name: http
path: /var/run/logcorrelator/http.socket
socket_permissions: "0660"
- name: network
path: /var/run/logcorrelator/network.socket
# Outputs
outputs:
file:
path: /var/log/logcorrelator/correlated.log
clickhouse:
dsn: clickhouse://user:pass@localhost:9000/db
table: correlated_logs
stdout: false
# Correlation (optional)
correlation:
time_window_s: 1
emit_orphans: true
inputs:
description: >
Le service consomme deux flux de logs JSON via des sockets Unix. Le schéma
exact des logs pour chaque source est flexible et peut évoluer. Seuls
quelques champs sont nécessaires pour la corrélation.
unix_sockets:
- name: apache_source
id: A
description: >
Source A, destinée aux logs HTTP applicatifs (Apache, reverse proxy, etc.).
Le schéma JSON est variable, avec un champ timestamp numérique obligatoire
et des champs header_* dynamiques.
path: /var/run/logcorrelator/apache.sock
protocol: unix
mode: stream
format: json
framing: line
retry_on_error: true
- name: network_source
id: B
description: >
Source B, destinée aux logs réseau (métadonnées IP/TCP, JA3/JA4, etc.).
Le schéma JSON est variable ; seuls src_ip et src_port sont requis.
path: /var/run/logcorrelator/network.sock
protocol: unix
mode: stream
format: json
framing: line
retry_on_error: true
outputs:
description: >
Les logs corrélés sont envoyés vers un ou plusieurs sinks. MultiSink permet
de diffuser chaque log corrélé vers plusieurs destinations (fichier,
ClickHouse, stdout…).
sinks:
file:
enabled: true
description: >
Sink vers fichier local, utile pour debug ou archivage local. Écrit un
JSON par ligne dans le chemin configuré. Rotation gérée par logrotate
ou équivalent.
path: /var/log/logcorrelator/correlated.log
format: json_lines
rotate_managed_by: external
clickhouse:
enabled: true
description: >
Sink principal pour larchivage et lanalyse en temps quasi réel. Les
logs corrélés sont insérés en batch dans ClickHouse avec un small buffer
et des inserts asynchrones. En cas de saturation ou dindisponibilité
ClickHouse, les logs sont drop pour éviter de saturer la machine locale.
dsn: clickhouse://user:pass@host:9000/db
table: correlated_logs_http_network
batch_size: 500
flush_interval_ms: 200
max_buffer_size: 5000
drop_on_overflow: true
async_insert: true
timeout_ms: 1000
stdout:
enabled: false
description: >
Sink optionnel vers stdout pour les tests et le développement.
correlation:
description: >
Corrélation strictement basée sur src_ip + src_port et une fenêtre temporelle
configurable. Aucun autre champ (dst_ip, dst_port, JA3/JA4, headers HTTP...)
nest utilisé pour la décision de corrélation.
key:
- src_ip
- src_port
time_window:
value: 1
unit: s
description: >
Fenêtre de temps symétrique appliquée aux timestamps de A et B. Deux
événements sont corrélés si |tA - tB| <= time_window. La valeur et l'unité
sont définies dans le YAML.
timestamp_source:
apache: field_timestamp
network: reception_time
description: >
Pour A, utilisation du champ numérique "timestamp" (epoch ns). Pour B,
utilisation du temps de réception local.
orphan_policy:
apache_always_emit: true
network_emit: false
description: >
A est toujours émis (même sans B) avec correlated=false et orphan_side="A".
B nest jamais émis seul.
matching:
mode: one_to_one_first_match
description: >
Stratégie 1à1, premier match : lors de larrivée dun événement, on
cherche le premier événement compatible dans le buffer de lautre source.
Les autres restent en attente ou expirent.
schema:
description: >
Les schémas des sources A et B sont variables. Le service impose seulement
quelques champs obligatoires nécessaires à la corrélation et accepte des
champs supplémentaires sans modification de code.
source_A:
description: >
Logs HTTP applicatifs (Apache/reverse proxy) au format JSON. Schéma
variable, avec champs obligatoires pour corrélation (src_ip, src_port,
timestamp) et collecte des autres champs dans des maps.
required_fields:
- name: src_ip
type: string
description: Adresse IP source client.
- name: src_port
type: int
description: Port source client.
- name: timestamp
type: int64
unit: ns
description: Timestamp de référence pour la corrélation.
optional_fields:
- name: time
type: string
format: rfc3339
- name: dst_ip
type: string
- name: dst_port
type: int
- name: method
type: string
- name: path
type: string
- name: host
type: string
- name: http_version
type: string
dynamic_fields:
- pattern: header_*
target_map: headers
description: >
Tous les champs header_* sont collectés dans headers[clé] = valeur.
- pattern: "*"
target_map: extra
description: >
Tous les champs non reconnus explicitement vont dans extra.
source_B:
description: >
Logs réseau JSON (IP/TCP, JA3/JA4...). Schéma variable. src_ip et src_port
sont obligatoires pour la corrélation, le reste est libre.
required_fields:
- name: src_ip
type: string
- name: src_port
type: int
optional_fields:
- name: dst_ip
type: string
- name: dst_port
type: int
dynamic_fields:
- pattern: "*"
target_map: extra
description: >
Tous les autres champs (ip_meta_*, tcp_meta_*, ja3, ja4, etc.) sont
rangés dans extra.
normalized_event:
description: >
Représentation interne unifiée des événements A/B sur laquelle opère la
logique de corrélation.
fields:
- name: source
type: enum("A","B")
- name: timestamp
type: time.Time
- name: src_ip
type: string
- name: src_port
type: int
- name: dst_ip
type: string
optional: true
- name: dst_port
type: int
optional: true
- name: headers
type: map[string]string
optional: true
- name: extra
type: map[string]any
description: Champs additionnels provenant de A ou B.
correlated_log:
description: >
Structure du log corrélé émis vers les sinks (fichier, ClickHouse). Contient
les informations de corrélation et tous les champs des sources A et B fusionnés
dans une structure JSON plate (flat).
fields:
- name: timestamp
type: time.Time
- name: src_ip
type: string
- name: src_port
type: int
- name: dst_ip
type: string
optional: true
- name: dst_port
type: int
optional: true
- name: correlated
type: bool
- name: orphan_side
type: string
- name: "*"
type: map[string]any
description: >
Tous les champs additionnels provenant de A et B sont fusionnés
directement à la racine du JSON (structure plate, sans subdivisions).
clickhouse_schema:
strategy: external_ddls
description: >
logcorrelator ne gère pas les ALTER TABLE. La table ClickHouse doit être
créée/modifiée en dehors du service. logcorrelator remplit les colonnes
existantes qu'il connaît et met NULL si un champ manque.
Depuis la version 1.0.3, les champs apache et network sont remplacés par
une colonne unique fields JSON contenant tous les champs fusionnés.
base_columns:
- name: timestamp
type: DateTime64(9)
- name: src_ip
type: String
- name: src_port
type: UInt32
- name: dst_ip
type: String
- name: dst_port
type: UInt32
- name: correlated
type: UInt8
- name: orphan_side
type: String
- name: fields
type: JSON
dynamic_fields:
mode: map_or_additional_columns
description: >
Les champs dynamiques peuvent être exposés via colonnes dédiées créées par
migration, ou via Map/JSON.
architecture:
description: >
Architecture hexagonale : domaine de corrélation indépendant, ports
abstraits pour les sources/sinks, adaptateurs pour sockets Unix, fichier et
ClickHouse, couche application dorchestration, et modules infra pour
config/observabilité.
modules:
- name: cmd/logcorrelator
type: entrypoint
responsibilities:
- Chargement configuration YAML.
- Initialisation des adaptateurs d'entrée/sortie.
- Création du CorrelationService.
- Démarrage de l'orchestrateur.
- Gestion du cycle de vie (signaux systemd).
- name: internal/domain
type: domain
responsibilities:
- Modèles NormalizedEvent et CorrelatedLog.
- Implémentation de CorrelationService (buffers, fenêtre,
orphelins).
- name: internal/ports
type: ports
responsibilities:
- EventSource, CorrelatedLogSink, CorrelationProcessor.
- name: internal/app
type: application
responsibilities:
- Orchestrator : relier EventSource → CorrelationService → MultiSink.
- name: internal/adapters/inbound/unixsocket
type: adapter_inbound
responsibilities:
- Lecture sockets Unix + parsing JSON → NormalizedEvent.
- name: internal/adapters/outbound/file
type: adapter_outbound
responsibilities:
- Écriture fichier JSON lines.
- name: internal/adapters/outbound/clickhouse
type: adapter_outbound
responsibilities:
- Bufferisation + inserts batch vers ClickHouse.
- Application de drop_on_overflow.
- name: internal/adapters/outbound/multi
type: adapter_outbound
responsibilities:
- Fan-out vers plusieurs sinks.
- name: internal/config
type: infrastructure
responsibilities:
- Chargement/validation config YAML.
- name: internal/observability
type: infrastructure
responsibilities:
- Logging et métriques internes.
testing:
unit:
description: >
Tests unitaires table-driven avec couverture cible ≥ 80 %. Focalisés sur
la logique de corrélation, parsing et sink ClickHouse.[web:94][web:98][web:102]
coverage_minimum: 0.8
focus:
- CorrelationService
- Parsing A/B → NormalizedEvent
- ClickHouseSink (batching, overflow)
- MultiSink
integration:
description: >
Tests dintégration validant le flux complet A+B → corrélation → sinks,
avec sockets simulés et ClickHouse mocké.
docker:
description: >
Build et tests entièrement encapsulés dans Docker, avec multistage build :
un stage builder pour compiler et tester, un stage runtime minimal pour
exécuter le service.[web:95][web:103]
images:
builder:
base: golang:latest
purpose: build_and_test
runtime:
base: scratch
purpose: run_binary_only
build:
multi_stage: true
steps:
- name: unit_tests
description: >
go test ./... avec génération de couverture. Le build échoue si la
couverture est < 80 %.
- name: compile_binary
description: >
Compilation CGO_ENABLED=0, GOOS=linux, GOARCH=amd64 pour un binaire
statique /usr/bin/logcorrelator.
- name: assemble_runtime_image
description: >
Copie du binaire dans limage runtime et définition de lENTRYPOINT.
packaging:
description: >
logcorrelator est distribué sous forme de packages .rpm (Rocky Linux 8, 9 et AlmaLinux 10),
construits intégralement dans Docker avec fpm.
formats:
- rpm
target_distros:
rpm:
- rocky-linux-8
- rocky-linux-9
- almalinux-10
- rhel-8+
- rhel-9+
- rhel-10+
tool: fpm
build_pipeline:
dockerfile: Dockerfile.package
stages:
- name: builder
description: >
Compilation du binaire Go avec CGO_ENABLED=0 pour un binaire statique.
GOOS=linux GOARCH=amd64.
- name: rpm_rocky8_builder
description: >
Construction du package RPM pour Rocky Linux 8 (el8) avec fpm.
- name: rpm_rocky9_builder
description: >
Construction du package RPM pour Rocky Linux 9 (el9) avec fpm.
- name: rpm_almalinux10_builder
description: >
Construction du package RPM pour AlmaLinux 10 (el10) avec fpm.
- name: output
description: >
Image Alpine minimale contenant les packages dans
/packages/rpm/{rocky8,rocky9,almalinux10}.
files:
binary:
source: dist/logcorrelator
dest: /usr/bin/logcorrelator
mode: "0755"
config:
- source: config.example.yml
dest: /etc/logcorrelator/logcorrelator.yml
mode: "0640"
config_file: true
- source: config.example.yml
dest: /usr/share/logcorrelator/logcorrelator.yml.example
mode: "0640"
directories:
- path: /var/log/logcorrelator
mode: "0755"
- path: /var/run/logcorrelator
mode: "0755"
- path: /etc/logcorrelator
mode: "0750"
maintainer_scripts:
rpm:
post: packaging/rpm/post
preun: packaging/rpm/preun
postun: packaging/rpm/postun
dependencies:
rpm:
- systemd
verify:
rpm:
rocky8:
command: docker run --rm -v $(pwd)/dist/rpm/rocky8:/packages rockylinux:8 sh -c "dnf install -y /packages/*.rpm"
rocky9:
command: docker run --rm -v $(pwd)/dist/rpm/rocky9:/packages rockylinux:9 sh -c "dnf install -y /packages/*.rpm"
almalinux10:
command: docker run --rm -v $(pwd)/dist/rpm/almalinux10:/packages almalinux:10 sh -c "dnf install -y /packages/*.rpm"
non_functional:
performance:
target_latency_ms: 1000
description: >
Latence visée < 1 s entre réception et insertion ClickHouse, avec
batching léger.
reliability:
drop_on_clickhouse_failure: true
description: >
En cas de ClickHouse lent/HS, les logs sont drop audelà du buffer pour
protéger la machine.
security:
user_separation: true
privileges: least
description: >
Service sous utilisateur dédié, pas de secrets en clair dans les logs,
principe de moindre privilège.