diff --git a/README.md b/README.md index 48e66c1..b3c2252 100644 --- a/README.md +++ b/README.md @@ -194,34 +194,31 @@ Tous les champs des sources A et B sont fusionnés au même niveau. Les champs d ## Schema ClickHouse -Le service utilise deux tables ClickHouse : +Le service utilise deux tables ClickHouse dans la base `mabase_prod` : -### Table brute (`http_logs_raw`) - -Table d'ingestion qui stocke le log corrélé brut au format JSON : +### Setup complet ```sql -CREATE TABLE http_logs_raw +-- 1. Créer la base de données +CREATE DATABASE IF NOT EXISTS mabase_prod; + +-- 2. Table brute avec TTL (1 jour de rétention) +DROP TABLE IF EXISTS mabase_prod.http_logs_raw; + +CREATE TABLE mabase_prod.http_logs_raw ( - raw_json String + raw_json String, + ingest_time DateTime DEFAULT now() ) ENGINE = MergeTree -ORDER BY tuple(); -``` +ORDER BY tuple() +TTL ingest_time + INTERVAL 1 DAY +SETTINGS ttl_only_drop_parts = 1; -**Format d'insertion :** Le service envoie chaque log corrélé sérialisé en JSON dans la colonne `raw_json` : +-- 3. Table parsée +DROP TABLE IF EXISTS mabase_prod.http_logs; -```sql -INSERT INTO http_logs_raw (raw_json) FORMAT JSONEachRow -{"raw_json":"{\"timestamp\":\"2024-01-01T12:00:00Z\",\"src_ip\":\"192.168.1.1\",\"correlated\":true,...}"} -``` - -### Table enrichie (`http_logs`) - -Vue matérialisée qui extrait les champs du JSON pour l'analyse : - -```sql -CREATE TABLE http_logs +CREATE TABLE mabase_prod.http_logs ( raw_json String, @@ -246,7 +243,6 @@ CREATE TABLE http_logs http_version LowCardinality(String) DEFAULT JSONExtractString(raw_json, 'http_version'), orphan_side LowCardinality(String) DEFAULT JSONExtractString(raw_json, 'orphan_side'), - -- champs « presque toujours là » a_timestamp UInt64 DEFAULT JSONExtractUInt(raw_json, 'a_timestamp'), b_timestamp UInt64 DEFAULT JSONExtractUInt(raw_json, 'b_timestamp'), conn_id String DEFAULT JSONExtractString(raw_json, 'conn_id'), @@ -263,12 +259,54 @@ CREATE TABLE http_logs ja3_hash String DEFAULT JSONExtractString(raw_json, 'ja3_hash'), ja4 String DEFAULT JSONExtractString(raw_json, 'ja4'), - -- tous les autres champs JSON (headers dynamiques etc.) extra JSON DEFAULT raw_json ) ENGINE = MergeTree PARTITION BY toYYYYMM(log_date) ORDER BY (log_date, dst_ip, src_ip, time); + +-- 4. Vue matérialisée (RAW → logs) +DROP VIEW IF EXISTS mabase_prod.mv_http_logs; + +CREATE MATERIALIZED VIEW mabase_prod.mv_http_logs +TO mabase_prod.http_logs +AS +SELECT raw_json +FROM mabase_prod.http_logs_raw; +``` + +### Utilisateurs et permissions + +```sql +-- Créer les utilisateurs +CREATE USER IF NOT EXISTS data_writer IDENTIFIED WITH TonMotDePasseInsert; +CREATE USER IF NOT EXISTS analyst IDENTIFIED WITH TonMotDePasseAnalyst; + +-- Droits pour data_writer (INSERT + SELECT pour la MV) +GRANT INSERT(raw_json) ON mabase_prod.http_logs_raw TO data_writer; +GRANT SELECT(raw_json) ON mabase_prod.http_logs_raw TO data_writer; + +-- Droits pour analyst (lecture seule sur les logs parsés) +GRANT SELECT ON mabase_prod.http_logs TO analyst; +``` + +### Format d'insertion + +Le service envoie chaque log corrélé sérialisé en JSON dans la colonne `raw_json` : + +```sql +INSERT INTO mabase_prod.http_logs_raw (raw_json) FORMAT JSONEachRow +{"raw_json":"{\"timestamp\":\"2024-01-01T12:00:00Z\",\"src_ip\":\"192.168.1.1\",\"correlated\":true,...}"} +``` + +### Migration des données existantes + +Si vous avez déjà des données dans l'ancienne table `http_logs_raw` : + +```sql +INSERT INTO mabase_prod.http_logs (raw_json) +SELECT raw_json +FROM mabase_prod.http_logs_raw; ``` ## Tests diff --git a/architecture.yml b/architecture.yml index 9f7024a..303155d 100644 --- a/architecture.yml +++ b/architecture.yml @@ -401,22 +401,30 @@ schema: clickhouse_schema: strategy: external_ddls + database: mabase_prod description: > La table ClickHouse est gérée en dehors du service. Deux tables sont utilisées : - http_logs_raw (table d'ingestion avec le JSON brut) et http_logs (table enrichie - avec extraction des champs via des colonnes matérialisées). + http_logs_raw (table d'ingestion avec TTL 1 jour) et http_logs (table enrichie + avec extraction des champs via des colonnes matérialisées). Une vue matérialisée + transfère automatiquement les données de RAW vers parsée. tables: - name: http_logs_raw description: > - Table d'ingestion brute. Une seule colonne raw_json contient le log corrélé - complet sérialisé en JSON. Le service insère via INSERT INTO http_logs_raw (raw_json). + Table d'ingestion brute avec TTL. Une seule colonne raw_json contient le log + corrélé complet sérialisé en JSON. TTL de 1 jour pour limiter le stockage. engine: MergeTree order_by: tuple() + ttl: ingest_time + INTERVAL 1 DAY + settings: + ttl_only_drop_parts: 1 columns: - name: raw_json type: String - insert_format: > - INSERT INTO http_logs_raw (raw_json) FORMAT JSONEachRow + - name: ingest_time + type: DateTime + default: now() + insert_format: | + INSERT INTO mabase_prod.http_logs_raw (raw_json) FORMAT JSONEachRow {"raw_json":"{...log corrélé sérialisé en JSON...}"} - name: http_logs @@ -529,6 +537,36 @@ clickhouse_schema: type: JSON default: raw_json + - name: mv_http_logs + type: materialized_view + description: > + Vue matérialisée qui transfère automatiquement les données de http_logs_raw + vers http_logs lors de chaque INSERT. + target: mabase_prod.http_logs + query: | + SELECT raw_json FROM mabase_prod.http_logs_raw + + users: + - name: data_writer + description: Utilisateur pour l'insertion des logs (utilisé par logcorrelator) + grants: + - INSERT(raw_json) ON mabase_prod.http_logs_raw + - SELECT(raw_json) ON mabase_prod.http_logs_raw + + - name: analyst + description: Utilisateur pour la lecture des logs parsés (BI, requêtes) + grants: + - SELECT ON mabase_prod.http_logs + + migration: + description: > + Script de migration pour transférer les données existantes de l'ancienne + table http_logs_raw vers la nouvelle structure avec vue matérialisée. + sql: | + INSERT INTO mabase_prod.http_logs (raw_json) + SELECT raw_json + FROM mabase_prod.http_logs_raw; + architecture: description: > Architecture hexagonale : domaine de corrélation indépendant, ports abstraits