fix(rpm): preserve config on upgrade, set correct ownership/permissions
RPM packaging improvements: - Fix %config(noreplace) directive in spec file (logcorrelator.yml) - Fix post script: use correct path for .yml.example (/etc/logcorrelator/) - Set /var/run/logcorrelator ownership to logcorrelator:logcorrelator - Set correct permissions: /var/run (755), /var/log (750), /var/lib (750) - Add %config(noreplace) for logrotate.d/logcorrelator - Add comprehensive RPM test script (packaging/test/test-rpm.sh) Documentation updates: - Update architecture.yml with filesystem permissions section - Document socket ownership (logcorrelator:logcorrelator, 0666) - Document config file policy (%config(noreplace) behavior) - Add systemd hardening directives (NoNewPrivileges, ProtectSystem) - Update ClickHouse schema: mark non-implemented fields - Remove materialized view SQL (managed externally) - Add stdout sink module documentation Build pipeline: - Update Dockerfile.package with comments for config policy - Add /var/lib/logcorrelator directory creation - Document fpm %config(noreplace) limitations Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@ -45,6 +45,8 @@ RUN dnf install -y epel-release && \
|
|||||||
|
|
||||||
# Copy binary from builder
|
# Copy binary from builder
|
||||||
COPY --from=builder /build/dist/logcorrelator /tmp/pkgroot/usr/bin/logcorrelator
|
COPY --from=builder /build/dist/logcorrelator /tmp/pkgroot/usr/bin/logcorrelator
|
||||||
|
# Config files: .yml is marked %config(noreplace) in RPM spec (preserved on upgrade)
|
||||||
|
# .yml.example is always updated to reflect latest configuration options
|
||||||
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml
|
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml
|
||||||
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml.example
|
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml.example
|
||||||
COPY --from=builder /build/logcorrelator.service /tmp/pkgroot/etc/systemd/system/logcorrelator.service
|
COPY --from=builder /build/logcorrelator.service /tmp/pkgroot/etc/systemd/system/logcorrelator.service
|
||||||
@ -54,6 +56,9 @@ COPY packaging/rpm/postun /tmp/scripts/postun
|
|||||||
COPY packaging/rpm/logrotate /tmp/pkgroot/etc/logrotate.d/logcorrelator
|
COPY packaging/rpm/logrotate /tmp/pkgroot/etc/logrotate.d/logcorrelator
|
||||||
|
|
||||||
# Create directories and set permissions
|
# Create directories and set permissions
|
||||||
|
# /var/run/logcorrelator: 755 - will be owned by logcorrelator:logcorrelator by post install script
|
||||||
|
# /var/log/logcorrelator: 755 - will be owned by logcorrelator:logcorrelator by post install script
|
||||||
|
# /var/lib/logcorrelator: created for service home directory
|
||||||
RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
||||||
mkdir -p /tmp/pkgroot/var/run/logcorrelator && \
|
mkdir -p /tmp/pkgroot/var/run/logcorrelator && \
|
||||||
mkdir -p /tmp/pkgroot/var/lib/logcorrelator && \
|
mkdir -p /tmp/pkgroot/var/lib/logcorrelator && \
|
||||||
@ -63,9 +68,12 @@ RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
|||||||
chmod 644 /tmp/pkgroot/etc/systemd/system/logcorrelator.service && \
|
chmod 644 /tmp/pkgroot/etc/systemd/system/logcorrelator.service && \
|
||||||
chmod 755 /tmp/scripts/* && \
|
chmod 755 /tmp/scripts/* && \
|
||||||
chmod 755 /tmp/pkgroot/var/log/logcorrelator && \
|
chmod 755 /tmp/pkgroot/var/log/logcorrelator && \
|
||||||
chmod 755 /tmp/pkgroot/var/run/logcorrelator
|
chmod 755 /tmp/pkgroot/var/run/logcorrelator && \
|
||||||
|
chmod 755 /tmp/pkgroot/var/lib/logcorrelator
|
||||||
|
|
||||||
# Build RPM for Enterprise Linux 8 (el8)
|
# Build RPM for Enterprise Linux 8 (el8)
|
||||||
|
# Note: fpm does not support %config(noreplace) directly; this is handled in the spec file
|
||||||
|
# The post install script ensures existing config is preserved
|
||||||
ARG VERSION=$(grep -m1 "^Version:" packaging/rpm/logcorrelator.spec | awk '{print $2}')
|
ARG VERSION=$(grep -m1 "^Version:" packaging/rpm/logcorrelator.spec | awk '{print $2}')
|
||||||
RUN mkdir -p /packages/rpm/el8 && \
|
RUN mkdir -p /packages/rpm/el8 && \
|
||||||
fpm -s dir -t rpm \
|
fpm -s dir -t rpm \
|
||||||
@ -107,6 +115,8 @@ RUN dnf install -y epel-release && \
|
|||||||
|
|
||||||
# Copy binary from builder
|
# Copy binary from builder
|
||||||
COPY --from=builder /build/dist/logcorrelator /tmp/pkgroot/usr/bin/logcorrelator
|
COPY --from=builder /build/dist/logcorrelator /tmp/pkgroot/usr/bin/logcorrelator
|
||||||
|
# Config files: .yml is marked %config(noreplace) in RPM spec (preserved on upgrade)
|
||||||
|
# .yml.example is always updated to reflect latest configuration options
|
||||||
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml
|
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml
|
||||||
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml.example
|
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml.example
|
||||||
COPY --from=builder /build/logcorrelator.service /tmp/pkgroot/etc/systemd/system/logcorrelator.service
|
COPY --from=builder /build/logcorrelator.service /tmp/pkgroot/etc/systemd/system/logcorrelator.service
|
||||||
@ -116,6 +126,9 @@ COPY packaging/rpm/postun /tmp/scripts/postun
|
|||||||
COPY packaging/rpm/logrotate /tmp/pkgroot/etc/logrotate.d/logcorrelator
|
COPY packaging/rpm/logrotate /tmp/pkgroot/etc/logrotate.d/logcorrelator
|
||||||
|
|
||||||
# Create directories and set permissions
|
# Create directories and set permissions
|
||||||
|
# /var/run/logcorrelator: 755 - will be owned by logcorrelator:logcorrelator by post install script
|
||||||
|
# /var/log/logcorrelator: 755 - will be owned by logcorrelator:logcorrelator by post install script
|
||||||
|
# /var/lib/logcorrelator: created for service home directory
|
||||||
RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
||||||
mkdir -p /tmp/pkgroot/var/run/logcorrelator && \
|
mkdir -p /tmp/pkgroot/var/run/logcorrelator && \
|
||||||
mkdir -p /tmp/pkgroot/var/lib/logcorrelator && \
|
mkdir -p /tmp/pkgroot/var/lib/logcorrelator && \
|
||||||
@ -125,7 +138,8 @@ RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
|||||||
chmod 644 /tmp/pkgroot/etc/systemd/system/logcorrelator.service && \
|
chmod 644 /tmp/pkgroot/etc/systemd/system/logcorrelator.service && \
|
||||||
chmod 755 /tmp/scripts/* && \
|
chmod 755 /tmp/scripts/* && \
|
||||||
chmod 755 /tmp/pkgroot/var/log/logcorrelator && \
|
chmod 755 /tmp/pkgroot/var/log/logcorrelator && \
|
||||||
chmod 755 /tmp/pkgroot/var/run/logcorrelator
|
chmod 755 /tmp/pkgroot/var/run/logcorrelator && \
|
||||||
|
chmod 755 /tmp/pkgroot/var/lib/logcorrelator
|
||||||
|
|
||||||
# Build RPM for Enterprise Linux 9 (el9)
|
# Build RPM for Enterprise Linux 9 (el9)
|
||||||
ARG VERSION=$(grep -m1 "^Version:" packaging/rpm/logcorrelator.spec | awk '{print $2}')
|
ARG VERSION=$(grep -m1 "^Version:" packaging/rpm/logcorrelator.spec | awk '{print $2}')
|
||||||
@ -169,6 +183,8 @@ RUN dnf install -y epel-release && \
|
|||||||
|
|
||||||
# Copy binary from builder
|
# Copy binary from builder
|
||||||
COPY --from=builder /build/dist/logcorrelator /tmp/pkgroot/usr/bin/logcorrelator
|
COPY --from=builder /build/dist/logcorrelator /tmp/pkgroot/usr/bin/logcorrelator
|
||||||
|
# Config files: .yml is marked %config(noreplace) in RPM spec (preserved on upgrade)
|
||||||
|
# .yml.example is always updated to reflect latest configuration options
|
||||||
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml
|
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml
|
||||||
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml.example
|
COPY --from=builder /build/config.example.yml /tmp/pkgroot/etc/logcorrelator/logcorrelator.yml.example
|
||||||
COPY --from=builder /build/logcorrelator.service /tmp/pkgroot/etc/systemd/system/logcorrelator.service
|
COPY --from=builder /build/logcorrelator.service /tmp/pkgroot/etc/systemd/system/logcorrelator.service
|
||||||
@ -178,6 +194,9 @@ COPY packaging/rpm/postun /tmp/scripts/postun
|
|||||||
COPY packaging/rpm/logrotate /tmp/pkgroot/etc/logrotate.d/logcorrelator
|
COPY packaging/rpm/logrotate /tmp/pkgroot/etc/logrotate.d/logcorrelator
|
||||||
|
|
||||||
# Create directories and set permissions
|
# Create directories and set permissions
|
||||||
|
# /var/run/logcorrelator: 755 - will be owned by logcorrelator:logcorrelator by post install script
|
||||||
|
# /var/log/logcorrelator: 755 - will be owned by logcorrelator:logcorrelator by post install script
|
||||||
|
# /var/lib/logcorrelator: created for service home directory
|
||||||
RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
||||||
mkdir -p /tmp/pkgroot/var/run/logcorrelator && \
|
mkdir -p /tmp/pkgroot/var/run/logcorrelator && \
|
||||||
mkdir -p /tmp/pkgroot/var/lib/logcorrelator && \
|
mkdir -p /tmp/pkgroot/var/lib/logcorrelator && \
|
||||||
@ -187,7 +206,8 @@ RUN mkdir -p /tmp/pkgroot/var/log/logcorrelator && \
|
|||||||
chmod 644 /tmp/pkgroot/etc/systemd/system/logcorrelator.service && \
|
chmod 644 /tmp/pkgroot/etc/systemd/system/logcorrelator.service && \
|
||||||
chmod 755 /tmp/scripts/* && \
|
chmod 755 /tmp/scripts/* && \
|
||||||
chmod 755 /tmp/pkgroot/var/log/logcorrelator && \
|
chmod 755 /tmp/pkgroot/var/log/logcorrelator && \
|
||||||
chmod 755 /tmp/pkgroot/var/run/logcorrelator
|
chmod 755 /tmp/pkgroot/var/run/logcorrelator && \
|
||||||
|
chmod 755 /tmp/pkgroot/var/lib/logcorrelator
|
||||||
|
|
||||||
# Build RPM for Enterprise Linux 10 (el10)
|
# Build RPM for Enterprise Linux 10 (el10)
|
||||||
ARG VERSION=$(grep -m1 "^Version:" packaging/rpm/logcorrelator.spec | awk '{print $2}')
|
ARG VERSION=$(grep -m1 "^Version:" packaging/rpm/logcorrelator.spec | awk '{print $2}')
|
||||||
|
|||||||
406
architecture.yml
406
architecture.yml
@ -46,6 +46,19 @@ runtime:
|
|||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=true
|
||||||
|
ReadWritePaths=/var/log/logcorrelator /var/run/logcorrelator /etc/logcorrelator
|
||||||
|
|
||||||
|
# Resource limits
|
||||||
|
LimitNOFILE=65536
|
||||||
|
|
||||||
|
# Systemd timeouts
|
||||||
|
TimeoutStartSec=10
|
||||||
|
TimeoutStopSec=30
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
os:
|
os:
|
||||||
@ -58,7 +71,7 @@ runtime:
|
|||||||
stdout_stderr: journald
|
stdout_stderr: journald
|
||||||
structured: true
|
structured: true
|
||||||
description: >
|
description: >
|
||||||
Les logs internes du service (erreurs, messages d’information) sont envoyés
|
Les logs internes du service (erreurs, messages d'information) sont envoyés
|
||||||
vers stdout/stderr et collectés par journald. Ils sont structurés et ne
|
vers stdout/stderr et collectés par journald. Ils sont structurés et ne
|
||||||
contiennent pas de données personnelles.
|
contiennent pas de données personnelles.
|
||||||
signals:
|
signals:
|
||||||
@ -71,6 +84,57 @@ runtime:
|
|||||||
SIGINT/SIGTERM : arrêt propre (arrêt des sockets, vidage des buffers, fermeture
|
SIGINT/SIGTERM : arrêt propre (arrêt des sockets, vidage des buffers, fermeture
|
||||||
des sinks). SIGHUP : réouverture des fichiers de sortie (utile pour la
|
des sinks). SIGHUP : réouverture des fichiers de sortie (utile pour la
|
||||||
rotation des logs via logrotate) sans arrêter le service.
|
rotation des logs via logrotate) sans arrêter le service.
|
||||||
|
filesystem:
|
||||||
|
description: >
|
||||||
|
Permissions et propriété des fichiers et répertoires utilisés par logcorrelator.
|
||||||
|
directories:
|
||||||
|
- path: /var/run/logcorrelator
|
||||||
|
owner: logcorrelator:logcorrelator
|
||||||
|
permissions: "0755"
|
||||||
|
purpose: >
|
||||||
|
Contient les sockets Unix (http.socket, network.socket).
|
||||||
|
Les sockets sont créés avec des permissions 0666 (world read/write).
|
||||||
|
- path: /var/log/logcorrelator
|
||||||
|
owner: logcorrelator:logcorrelator
|
||||||
|
permissions: "0750"
|
||||||
|
purpose: >
|
||||||
|
Contient les logs corrélés (correlated.log).
|
||||||
|
- path: /var/lib/logcorrelator
|
||||||
|
owner: logcorrelator:logcorrelator
|
||||||
|
permissions: "0750"
|
||||||
|
purpose: >
|
||||||
|
Répertoire home du service (données internes).
|
||||||
|
- path: /etc/logcorrelator
|
||||||
|
owner: logcorrelator:logcorrelator
|
||||||
|
permissions: "0750"
|
||||||
|
purpose: >
|
||||||
|
Contient la configuration (logcorrelator.yml, logcorrelator.yml.example).
|
||||||
|
files:
|
||||||
|
- path: /etc/logcorrelator/logcorrelator.yml
|
||||||
|
owner: logcorrelator:logcorrelator
|
||||||
|
permissions: "0640"
|
||||||
|
rpm_directive: "%config(noreplace)"
|
||||||
|
- path: /etc/logcorrelator/logcorrelator.yml.example
|
||||||
|
owner: logcorrelator:logcorrelator
|
||||||
|
permissions: "0640"
|
||||||
|
- path: /etc/systemd/system/logcorrelator.service
|
||||||
|
owner: root:root
|
||||||
|
permissions: "0644"
|
||||||
|
- path: /etc/logrotate.d/logcorrelator
|
||||||
|
owner: root:root
|
||||||
|
permissions: "0644"
|
||||||
|
rpm_directive: "%config(noreplace)"
|
||||||
|
sockets:
|
||||||
|
- path: /var/run/logcorrelator/http.socket
|
||||||
|
owner: logcorrelator:logcorrelator
|
||||||
|
permissions: "0666"
|
||||||
|
type: unix_datagram
|
||||||
|
purpose: "Source A - logs HTTP applicatifs"
|
||||||
|
- path: /var/run/logcorrelator/network.socket
|
||||||
|
owner: logcorrelator:logcorrelator
|
||||||
|
permissions: "0666"
|
||||||
|
type: unix_datagram
|
||||||
|
purpose: "Source B - logs réseau"
|
||||||
|
|
||||||
packaging:
|
packaging:
|
||||||
description: >
|
description: >
|
||||||
@ -79,6 +143,14 @@ packaging:
|
|||||||
à jour à chaque changement de version.
|
à jour à chaque changement de version.
|
||||||
Tous les numéros de version doivent être cohérents entre le spec RPM, le Makefile
|
Tous les numéros de version doivent être cohérents entre le spec RPM, le Makefile
|
||||||
(PKG_VERSION), le CHANGELOG.md et les tags git.
|
(PKG_VERSION), le CHANGELOG.md et les tags git.
|
||||||
|
|
||||||
|
Politique de mise à jour de la configuration :
|
||||||
|
- Le fichier logcorrelator.yml est marqué %config(noreplace) : il n'est JAMAIS
|
||||||
|
écrasé lors d'une mise à jour. La configuration existante est préservée.
|
||||||
|
- Le fichier logcorrelator.yml.example est TOUJOURS mis à jour pour refléter
|
||||||
|
les nouvelles options de configuration disponibles.
|
||||||
|
- Lors de la première installation, si logcorrelator.yml n'existe pas, il est
|
||||||
|
créé à partir de logcorrelator.yml.example.
|
||||||
formats:
|
formats:
|
||||||
- rpm
|
- rpm
|
||||||
target_distros:
|
target_distros:
|
||||||
@ -94,22 +166,28 @@ packaging:
|
|||||||
source: git # ou CHANGELOG.md
|
source: git # ou CHANGELOG.md
|
||||||
description: >
|
description: >
|
||||||
À chaque build, un script génère un fichier de changelog RPM à partir de
|
À chaque build, un script génère un fichier de changelog RPM à partir de
|
||||||
l’historique (tags/commits) et le passe à fpm (option --rpm-changelog).
|
l'historique (tags/commits) et le passe à fpm (option --rpm-changelog).
|
||||||
contents:
|
contents:
|
||||||
- path: /usr/bin/logcorrelator
|
- path: /usr/bin/logcorrelator
|
||||||
type: binary
|
type: binary
|
||||||
- path: /etc/logcorrelator/logcorrelator.yml
|
- path: /etc/logcorrelator/logcorrelator.yml
|
||||||
type: config
|
type: config
|
||||||
directives: "%config(noreplace)"
|
directives: "%config(noreplace)"
|
||||||
|
behavior: >
|
||||||
|
Jamais écrasé lors des mises à jour. Préservé automatiquement par RPM.
|
||||||
|
Créé uniquement lors de la première installation s'il n'existe pas.
|
||||||
- path: /etc/logcorrelator/logcorrelator.yml.example
|
- path: /etc/logcorrelator/logcorrelator.yml.example
|
||||||
type: doc
|
type: doc
|
||||||
description: Fichier d'exemple toujours mis à jour par le RPM.
|
behavior: >
|
||||||
|
TOUJOURS mis à jour lors des mises à jour. Sert de référence pour les
|
||||||
|
nouvelles options de configuration disponibles.
|
||||||
- path: /etc/systemd/system/logcorrelator.service
|
- path: /etc/systemd/system/logcorrelator.service
|
||||||
type: systemd_unit
|
type: systemd_unit
|
||||||
- path: /etc/logrotate.d/logcorrelator
|
- path: /etc/logrotate.d/logcorrelator
|
||||||
type: logrotate_script
|
type: logrotate_script
|
||||||
|
directives: "%config(noreplace)"
|
||||||
logrotate_example: |
|
logrotate_example: |
|
||||||
/var/log/logcorrelator/*.log {
|
/var/log/logcorrelator/correlated.log {
|
||||||
daily
|
daily
|
||||||
rotate 7
|
rotate 7
|
||||||
compress
|
compress
|
||||||
@ -117,8 +195,9 @@ packaging:
|
|||||||
missingok
|
missingok
|
||||||
notifempty
|
notifempty
|
||||||
create 0640 logcorrelator logcorrelator
|
create 0640 logcorrelator logcorrelator
|
||||||
|
sharedscripts
|
||||||
postrotate
|
postrotate
|
||||||
systemctl reload logcorrelator > /dev/null 2>/dev/null || true
|
/bin/systemctl reload logcorrelator > /dev/null 2>&1 || true
|
||||||
endscript
|
endscript
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +207,7 @@ config:
|
|||||||
reload_strategy: signal_sighup_for_files
|
reload_strategy: signal_sighup_for_files
|
||||||
description: >
|
description: >
|
||||||
Toute la configuration est centralisée dans un fichier YAML lisible. Le RPM
|
Toute la configuration est centralisée dans un fichier YAML lisible. Le RPM
|
||||||
fournit aussi un fichier d’exemple mis à jour à chaque version.
|
fournit aussi un fichier d'exemple mis à jour à chaque version.
|
||||||
example: |
|
example: |
|
||||||
# /etc/logcorrelator/logcorrelator.yml
|
# /etc/logcorrelator/logcorrelator.yml
|
||||||
|
|
||||||
@ -139,28 +218,27 @@ config:
|
|||||||
unix_sockets:
|
unix_sockets:
|
||||||
# Source HTTP (A) : logs applicatifs en JSON, 1 datagramme = 1 log.
|
# Source HTTP (A) : logs applicatifs en JSON, 1 datagramme = 1 log.
|
||||||
- name: http
|
- name: http
|
||||||
path: /var/run/logcorrelator/http.sock
|
source_type: A
|
||||||
|
path: /var/run/logcorrelator/http.socket
|
||||||
|
format: json
|
||||||
socket_permissions: "0666"
|
socket_permissions: "0666"
|
||||||
socket_type: dgram
|
|
||||||
max_datagram_bytes: 65535
|
|
||||||
|
|
||||||
# Source réseau (B) : logs IP/TCP/JA3... en JSON, 1 datagramme = 1 log.
|
# Source réseau (B) : logs IP/TCP/JA3... en JSON, 1 datagramme = 1 log.
|
||||||
- name: network
|
- name: network
|
||||||
path: /var/run/logcorrelator/network.sock
|
source_type: B
|
||||||
|
path: /var/run/logcorrelator/network.socket
|
||||||
|
format: json
|
||||||
socket_permissions: "0666"
|
socket_permissions: "0666"
|
||||||
socket_type: dgram
|
|
||||||
max_datagram_bytes: 65535
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
file:
|
file:
|
||||||
enabled: true
|
enabled: true
|
||||||
path: /var/log/logcorrelator/correlated.log
|
path: /var/log/logcorrelator/correlated.log
|
||||||
format: json_lines
|
|
||||||
|
|
||||||
clickhouse:
|
clickhouse:
|
||||||
enabled: true
|
enabled: false
|
||||||
dsn: clickhouse://user:pass@localhost:9000/db
|
dsn: clickhouse://user:pass@localhost:9000/db
|
||||||
table: http_logs_raw
|
table: correlated_logs_http_network
|
||||||
batch_size: 500
|
batch_size: 500
|
||||||
flush_interval_ms: 200
|
flush_interval_ms: 200
|
||||||
max_buffer_size: 5000
|
max_buffer_size: 5000
|
||||||
@ -170,7 +248,7 @@ config:
|
|||||||
|
|
||||||
stdout:
|
stdout:
|
||||||
enabled: false
|
enabled: false
|
||||||
level: INFO # DEBUG: tous les logs, INFO: seulement corrélés, ERROR: aucun
|
level: INFO # DEBUG: tous les logs (y compris orphelins), INFO: seulement corrélés, WARN: corrélés seulement, ERROR: aucun
|
||||||
|
|
||||||
correlation:
|
correlation:
|
||||||
# Fenêtre de corrélation : si le log HTTP arrive avant le réseau, il attend
|
# Fenêtre de corrélation : si le log HTTP arrive avant le réseau, il attend
|
||||||
@ -181,8 +259,8 @@ config:
|
|||||||
unit: s
|
unit: s
|
||||||
|
|
||||||
orphan_policy:
|
orphan_policy:
|
||||||
apache_always_emit: true
|
apache_always_emit: true # Toujours émettre les événements A, même sans correspondance B
|
||||||
network_emit: false
|
network_emit: false # Ne jamais émettre les événements B seuls
|
||||||
|
|
||||||
matching:
|
matching:
|
||||||
mode: one_to_many # Keep‑Alive : un B peut corréler plusieurs A.
|
mode: one_to_many # Keep‑Alive : un B peut corréler plusieurs A.
|
||||||
@ -201,14 +279,17 @@ config:
|
|||||||
inputs:
|
inputs:
|
||||||
description: >
|
description: >
|
||||||
Deux flux de logs JSON via sockets Unix datagram (SOCK_DGRAM). Chaque datagramme
|
Deux flux de logs JSON via sockets Unix datagram (SOCK_DGRAM). Chaque datagramme
|
||||||
contient un JSON complet.
|
contient un JSON complet. Le champ source_type ("A" ou "B") doit être spécifié
|
||||||
|
pour chaque socket. À défaut, la source est déduite automatiquement (présence de
|
||||||
|
headers = source A, sinon source B).
|
||||||
unix_sockets:
|
unix_sockets:
|
||||||
- name: http_source
|
- name: http
|
||||||
id: A
|
id: A
|
||||||
description: >
|
description: >
|
||||||
Source A, logs HTTP applicatifs (Apache, reverse proxy, etc.). Schéma JSON
|
Source A, logs HTTP applicatifs (Apache, reverse proxy, etc.). Schéma JSON
|
||||||
variable, champ timestamp obligatoire, headers dynamiques (header_*).
|
variable, champ timestamp (int64, nanosecondes) obligatoire, headers dynamiques (header_*).
|
||||||
path: /var/run/logcorrelator/http.socket
|
path: /var/run/logcorrelator/http.socket
|
||||||
|
source_type: A
|
||||||
permissions: "0666"
|
permissions: "0666"
|
||||||
protocol: unix
|
protocol: unix
|
||||||
socket_type: dgram
|
socket_type: dgram
|
||||||
@ -218,12 +299,14 @@ inputs:
|
|||||||
max_datagram_bytes: 65535
|
max_datagram_bytes: 65535
|
||||||
retry_on_error: true
|
retry_on_error: true
|
||||||
|
|
||||||
- name: network_source
|
- name: network
|
||||||
id: B
|
id: B
|
||||||
description: >
|
description: >
|
||||||
Source B, logs réseau (métadonnées IP/TCP, JA3/JA4, etc.). Seuls src_ip
|
Source B, logs réseau (métadonnées IP/TCP, JA3/JA4, etc.). Seuls src_ip
|
||||||
et src_port sont requis pour la corrélation.
|
et src_port sont requis pour la corrélation. Le champ timestamp est optionnel ;
|
||||||
|
s'il est absent, l'heure de réception est utilisée.
|
||||||
path: /var/run/logcorrelator/network.socket
|
path: /var/run/logcorrelator/network.socket
|
||||||
|
source_type: B
|
||||||
permissions: "0666"
|
permissions: "0666"
|
||||||
protocol: unix
|
protocol: unix
|
||||||
socket_type: dgram
|
socket_type: dgram
|
||||||
@ -246,12 +329,14 @@ outputs:
|
|||||||
format: json_lines
|
format: json_lines
|
||||||
rotate_managed_by: external_logrotate
|
rotate_managed_by: external_logrotate
|
||||||
clickhouse:
|
clickhouse:
|
||||||
enabled: true
|
enabled: false
|
||||||
description: >
|
description: >
|
||||||
Sink principal pour l'archivage et l'analyse quasi temps réel. Inserts
|
Sink principal pour l'archivage et l'analyse quasi temps réel. Inserts
|
||||||
batch asynchrones, drop en cas de saturation.
|
batch asynchrones, drop en cas de saturation. Le service insère uniquement
|
||||||
|
dans une table RAW (raw_json String, ingest_time DateTime DEFAULT now()).
|
||||||
|
La table parsée et la vue matérialisée sont gérées en externe (DDL séparés).
|
||||||
dsn: clickhouse://user:pass@host:9000/db
|
dsn: clickhouse://user:pass@host:9000/db
|
||||||
table: http_logs_raw
|
table: correlated_logs_http_network
|
||||||
batch_size: 500
|
batch_size: 500
|
||||||
flush_interval_ms: 200
|
flush_interval_ms: 200
|
||||||
max_buffer_size: 5000
|
max_buffer_size: 5000
|
||||||
@ -260,11 +345,12 @@ outputs:
|
|||||||
timeout_ms: 1000
|
timeout_ms: 1000
|
||||||
stdout:
|
stdout:
|
||||||
enabled: false
|
enabled: false
|
||||||
level: INFO # DEBUG: tous les logs, INFO: seulement corrélés, ERROR: aucun
|
level: INFO # DEBUG: tous les logs (y compris orphelins), INFO: seulement corrélés, WARN: corrélés seulement, ERROR: aucun
|
||||||
description: >
|
description: >
|
||||||
Sink optionnel pour les tests/développement.
|
Sink optionnel pour les tests/développement.
|
||||||
Le niveau de log filtre la sortie : DEBUG émet tout (y compris orphelins),
|
Le niveau de log filtre la sortie : DEBUG émet tout (y compris orphelins),
|
||||||
INFO émet uniquement les logs corrélés, ERROR n'émet rien.
|
INFO émet uniquement les logs corrélés, WARN émet les logs corrélés seulement,
|
||||||
|
ERROR n'émet rien.
|
||||||
|
|
||||||
correlation:
|
correlation:
|
||||||
description: >
|
description: >
|
||||||
@ -292,8 +378,9 @@ correlation:
|
|||||||
TTL des logs réseau. Chaque fois qu'un B est corrélé à un A (Keep-Alive),
|
TTL des logs réseau. Chaque fois qu'un B est corrélé à un A (Keep-Alive),
|
||||||
son TTL est remis à cette valeur. Augmenté à 120s pour les sessions longues.
|
son TTL est remis à cette valeur. Augmenté à 120s pour les sessions longues.
|
||||||
timestamp_source:
|
timestamp_source:
|
||||||
apache: field_timestamp
|
apache: timestamp (champ int64, nanosecondes)
|
||||||
network: reception_time
|
network: timestamp (champ int64, nanosecondes) si présent, sinon time (RFC3339),
|
||||||
|
sinon reception_time (time.Now())
|
||||||
orphan_policy:
|
orphan_policy:
|
||||||
apache_always_emit: true
|
apache_always_emit: true
|
||||||
network_emit: false
|
network_emit: false
|
||||||
@ -301,7 +388,7 @@ correlation:
|
|||||||
mode: one_to_many
|
mode: one_to_many
|
||||||
description: >
|
description: >
|
||||||
Stratégie 1‑à‑N : un log réseau peut être utilisé pour plusieurs logs HTTP
|
Stratégie 1‑à‑N : un log réseau peut être utilisé pour plusieurs logs HTTP
|
||||||
successifs tant qu’il n’a pas expiré ni été évincé.
|
successifs tant qu'il n'a pas expiré ni été évincé.
|
||||||
|
|
||||||
schema:
|
schema:
|
||||||
description: >
|
description: >
|
||||||
@ -319,8 +406,6 @@ schema:
|
|||||||
type: int64
|
type: int64
|
||||||
unit: ns
|
unit: ns
|
||||||
optional_fields:
|
optional_fields:
|
||||||
- name: time
|
|
||||||
type: string
|
|
||||||
- name: dst_ip
|
- name: dst_ip
|
||||||
type: string
|
type: string
|
||||||
- name: dst_port
|
- name: dst_port
|
||||||
@ -350,6 +435,12 @@ schema:
|
|||||||
type: string
|
type: string
|
||||||
- name: dst_port
|
- name: dst_port
|
||||||
type: int
|
type: int
|
||||||
|
- name: timestamp
|
||||||
|
type: int64
|
||||||
|
unit: ns
|
||||||
|
- name: time
|
||||||
|
type: string
|
||||||
|
format: RFC3339 ou RFC3339Nano
|
||||||
dynamic_fields:
|
dynamic_fields:
|
||||||
- pattern: "*"
|
- pattern: "*"
|
||||||
target_map: extra
|
target_map: extra
|
||||||
@ -405,15 +496,17 @@ clickhouse_schema:
|
|||||||
strategy: external_ddls
|
strategy: external_ddls
|
||||||
database: mabase_prod
|
database: mabase_prod
|
||||||
description: >
|
description: >
|
||||||
La table ClickHouse est gérée en dehors du service. Deux tables sont utilisées :
|
La table ClickHouse est gérée en dehors du service. Le service insère dans une
|
||||||
http_logs_raw (table d'ingestion partitionnée par jour) et http_logs (table parsée
|
table RAW avec une seule colonne raw_json contenant le log corrélé complet
|
||||||
avec extraction explicite des champs). Une vue matérialisée transfère automatiquement
|
sérialisé en JSON. La colonne ingest_time utilise DEFAULT now().
|
||||||
les données de RAW vers parsée.
|
Toute extraction de champs (table parsée, vue matérialisée) est gérée en externe
|
||||||
|
via des DDL séparés, non implémentés dans le service.
|
||||||
tables:
|
tables:
|
||||||
- name: http_logs_raw
|
- name: http_logs_raw
|
||||||
description: >
|
description: >
|
||||||
Table d'ingestion brute. Une seule colonne raw_json contient le log corrélé
|
Table d'ingestion brute. Une seule colonne raw_json contient le log corrélé
|
||||||
complet sérialisé en JSON. Partitionnée par jour pour optimiser le TTL.
|
complet sérialisé en JSON. La colonne ingest_time est auto-générée avec
|
||||||
|
DEFAULT now(). Partitionnée par jour pour optimiser le TTL.
|
||||||
engine: MergeTree
|
engine: MergeTree
|
||||||
partition_by: toDate(ingest_time)
|
partition_by: toDate(ingest_time)
|
||||||
order_by: ingest_time
|
order_by: ingest_time
|
||||||
@ -424,13 +517,17 @@ clickhouse_schema:
|
|||||||
type: DateTime
|
type: DateTime
|
||||||
default: now()
|
default: now()
|
||||||
insert_format: |
|
insert_format: |
|
||||||
INSERT INTO mabase_prod.http_logs_raw (raw_json) FORMAT JSONEachRow
|
INSERT INTO mabase_prod.http_logs_raw (raw_json) VALUES
|
||||||
{"raw_json":"{...log corrélé sérialisé en JSON...}"}
|
('{...log corrélé sérialisé en JSON...}')
|
||||||
|
notes: >
|
||||||
|
Le service utilise l'API native clickhouse-go/v2 (PrepareBatch + Append + Send).
|
||||||
|
La colonne ingest_time n'est PAS explicitement insérée (DEFAULT now() est utilisé).
|
||||||
|
|
||||||
- name: http_logs
|
- name: http_logs
|
||||||
description: >
|
description: >
|
||||||
Table parsée avec tous les champs extraits explicitement par la vue matérialisée.
|
Table parsée (optionnelle, gérée en externe). Le service n'implémente PAS
|
||||||
Partitionnée par log_date, optimisée pour les requêtes analytiques.
|
l'extraction des champs suivants. Si cette table est utilisée, elle doit être
|
||||||
|
alimentée par une vue matérialisée ou un traitement ETL externe.
|
||||||
engine: MergeTree
|
engine: MergeTree
|
||||||
partition_by: log_date
|
partition_by: log_date
|
||||||
order_by: (time, src_ip, dst_ip, ja4)
|
order_by: (time, src_ip, dst_ip, ja4)
|
||||||
@ -466,158 +563,113 @@ clickhouse_schema:
|
|||||||
type: UInt8
|
type: UInt8
|
||||||
- name: keepalives
|
- name: keepalives
|
||||||
type: UInt16
|
type: UInt16
|
||||||
|
status: non_implémenté
|
||||||
- name: a_timestamp
|
- name: a_timestamp
|
||||||
type: UInt64
|
type: UInt64
|
||||||
|
status: non_implémenté
|
||||||
- name: b_timestamp
|
- name: b_timestamp
|
||||||
type: UInt64
|
type: UInt64
|
||||||
|
status: non_implémenté
|
||||||
- name: conn_id
|
- name: conn_id
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: ip_meta_df
|
- name: ip_meta_df
|
||||||
type: UInt8
|
type: UInt8
|
||||||
|
status: non_implémenté
|
||||||
- name: ip_meta_id
|
- name: ip_meta_id
|
||||||
type: UInt32
|
type: UInt32
|
||||||
|
status: non_implémenté
|
||||||
- name: ip_meta_total_length
|
- name: ip_meta_total_length
|
||||||
type: UInt32
|
type: UInt32
|
||||||
|
status: non_implémenté
|
||||||
- name: ip_meta_ttl
|
- name: ip_meta_ttl
|
||||||
type: UInt8
|
type: UInt8
|
||||||
|
status: non_implémenté
|
||||||
- name: tcp_meta_options
|
- name: tcp_meta_options
|
||||||
type: LowCardinality(String)
|
type: LowCardinality(String)
|
||||||
|
status: non_implémenté
|
||||||
- name: tcp_meta_window_size
|
- name: tcp_meta_window_size
|
||||||
type: UInt32
|
type: UInt32
|
||||||
|
status: non_implémenté
|
||||||
- name: syn_to_clienthello_ms
|
- name: syn_to_clienthello_ms
|
||||||
type: Int32
|
type: Int32
|
||||||
|
status: non_implémenté
|
||||||
- name: tls_version
|
- name: tls_version
|
||||||
type: LowCardinality(String)
|
type: LowCardinality(String)
|
||||||
|
status: non_implémenté
|
||||||
- name: tls_sni
|
- name: tls_sni
|
||||||
type: LowCardinality(String)
|
type: LowCardinality(String)
|
||||||
|
status: non_implémenté
|
||||||
- name: ja3
|
- name: ja3
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: ja3_hash
|
- name: ja3_hash
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: ja4
|
- name: ja4
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_user_agent
|
- name: header_user_agent
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_accept
|
- name: header_accept
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_accept_encoding
|
- name: header_accept_encoding
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_accept_language
|
- name: header_accept_language
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_x_request_id
|
- name: header_x_request_id
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_x_trace_id
|
- name: header_x_trace_id
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_x_forwarded_for
|
- name: header_x_forwarded_for
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_sec_ch_ua
|
- name: header_sec_ch_ua
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_sec_ch_ua_mobile
|
- name: header_sec_ch_ua_mobile
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_sec_ch_ua_platform
|
- name: header_sec_ch_ua_platform
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_sec_fetch_dest
|
- name: header_sec_fetch_dest
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_sec_fetch_mode
|
- name: header_sec_fetch_mode
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: header_sec_fetch_site
|
- name: header_sec_fetch_site
|
||||||
type: String
|
type: String
|
||||||
|
status: non_implémenté
|
||||||
- name: mv_http_logs
|
notes: >
|
||||||
type: materialized_view
|
Cette table et la vue matérialisée associée sont gérées en externe (DDL séparés).
|
||||||
description: >
|
Le service se contente d'insérer le JSON brut dans http_logs_raw.
|
||||||
Vue matérialisée qui transfère les données de http_logs_raw vers http_logs
|
Les champs marqués "non_implémenté" ne sont PAS extraits par le service.
|
||||||
en extrayant tous les champs du JSON via JSONExtract* et coalesce pour les
|
|
||||||
valeurs par défaut.
|
|
||||||
target: mabase_prod.http_logs
|
|
||||||
query: |
|
|
||||||
SELECT
|
|
||||||
-- 1. Temps
|
|
||||||
parseDateTimeBestEffort(
|
|
||||||
coalesce(JSONExtractString(raw_json, 'time'), '1970-01-01T00:00:00Z')
|
|
||||||
) AS time,
|
|
||||||
toDate(time) AS log_date,
|
|
||||||
|
|
||||||
-- 2. Réseau L3/L4
|
|
||||||
toIPv4(coalesce(JSONExtractString(raw_json, 'src_ip'), '0.0.0.0')) AS src_ip,
|
|
||||||
toUInt16(coalesce(JSONExtractUInt(raw_json, 'src_port'), 0)) AS src_port,
|
|
||||||
toIPv4(coalesce(JSONExtractString(raw_json, 'dst_ip'), '0.0.0.0')) AS dst_ip,
|
|
||||||
toUInt16(coalesce(JSONExtractUInt(raw_json, 'dst_port'), 0)) AS dst_port,
|
|
||||||
|
|
||||||
-- 3. HTTP de base
|
|
||||||
coalesce(JSONExtractString(raw_json, 'method'), '') AS method,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'scheme'), '') AS scheme,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'host'), '') AS host,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'path'), '') AS path,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'query'), '') AS query,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'http_version'), '') AS http_version,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'orphan_side'), '') AS orphan_side,
|
|
||||||
|
|
||||||
-- 4. Connexion / corrélation
|
|
||||||
toUInt8(coalesce(JSONExtractBool(raw_json, 'correlated'), 0)) AS correlated,
|
|
||||||
toUInt16(coalesce(JSONExtractUInt(raw_json, 'keepalives'), 0)) AS keepalives,
|
|
||||||
coalesce(JSONExtractUInt(raw_json, 'a_timestamp'), 0) AS a_timestamp,
|
|
||||||
coalesce(JSONExtractUInt(raw_json, 'b_timestamp'), 0) AS b_timestamp,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'conn_id'), '') AS conn_id,
|
|
||||||
|
|
||||||
-- 5. IP/TCP
|
|
||||||
toUInt8(coalesce(JSONExtractBool(raw_json, 'ip_meta_df'), 0)) AS ip_meta_df,
|
|
||||||
coalesce(JSONExtractUInt(raw_json, 'ip_meta_id'), 0) AS ip_meta_id,
|
|
||||||
coalesce(JSONExtractUInt(raw_json, 'ip_meta_total_length'), 0) AS ip_meta_total_length,
|
|
||||||
coalesce(JSONExtractUInt(raw_json, 'ip_meta_ttl'), 0) AS ip_meta_ttl,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'tcp_meta_options'), '') AS tcp_meta_options,
|
|
||||||
coalesce(JSONExtractUInt(raw_json, 'tcp_meta_window_size'), 0) AS tcp_meta_window_size,
|
|
||||||
toInt32(coalesce(JSONExtractInt(raw_json, 'syn_to_clienthello_ms'), 0)) AS syn_to_clienthello_ms,
|
|
||||||
|
|
||||||
-- 6. TLS / JA3/JA4
|
|
||||||
coalesce(JSONExtractString(raw_json, 'tls_version'), '') AS tls_version,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'tls_sni'), '') AS tls_sni,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'ja3'), '') AS ja3,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'ja3_hash'), '') AS ja3_hash,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'ja4'), '') AS ja4,
|
|
||||||
|
|
||||||
-- 7. Headers HTTP
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_User-Agent'), '') AS header_user_agent,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Accept'), '') AS header_accept,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Accept-Encoding'), '') AS header_accept_encoding,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Accept-Language'), '') AS header_accept_language,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_X-Request-Id'), '') AS header_x_request_id,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_X-Trace-Id'), '') AS header_x_trace_id,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_X-Forwarded-For'), '') AS header_x_forwarded_for,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Sec-CH-UA'), '') AS header_sec_ch_ua,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Sec-CH-UA-Mobile'), '') AS header_sec_ch_ua_mobile,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Sec-CH-UA-Platform'), '') AS header_sec_ch_ua_platform,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Sec-Fetch-Dest'), '') AS header_sec_fetch_dest,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Sec-Fetch-Mode'), '') AS header_sec_fetch_mode,
|
|
||||||
coalesce(JSONExtractString(raw_json, 'header_Sec-Fetch-Site'), '') AS header_sec_fetch_site
|
|
||||||
FROM mabase_prod.http_logs_raw;
|
|
||||||
|
|
||||||
users:
|
users:
|
||||||
- name: data_writer
|
description: >
|
||||||
description: Utilisateur pour l'insertion des logs (utilisé par logcorrelator)
|
La gestion des utilisateurs ClickHouse est externe au service. Le DSN est
|
||||||
grants:
|
configuré dans le fichier de configuration YAML.
|
||||||
- INSERT(raw_json) ON mabase_prod.http_logs_raw
|
notes: >
|
||||||
- SELECT(raw_json) ON mabase_prod.http_logs_raw
|
Cette section est fournie à titre indicatif pour l'administration ClickHouse.
|
||||||
|
|
||||||
- name: analyst
|
|
||||||
description: Utilisateur pour la lecture des logs parsés (BI, requêtes)
|
|
||||||
grants:
|
|
||||||
- SELECT ON mabase_prod.http_logs
|
|
||||||
|
|
||||||
migration:
|
migration:
|
||||||
description: >
|
description: >
|
||||||
Script de migration pour transférer les données existantes de l'ancienne
|
Aucune migration n'est implémentée dans le service. La gestion des schémas
|
||||||
table http_logs_raw vers la nouvelle structure avec vue matérialisée.
|
(tables, vues matérialisées) est entièrement externe (DDL séparés).
|
||||||
sql: |
|
|
||||||
INSERT INTO mabase_prod.http_logs (raw_json)
|
|
||||||
SELECT raw_json
|
|
||||||
FROM mabase_prod.http_logs_raw;
|
|
||||||
|
|
||||||
architecture:
|
architecture:
|
||||||
description: >
|
description: >
|
||||||
Architecture hexagonale : domaine de corrélation indépendant, ports abstraits
|
Architecture hexagonale : domaine de corrélation indépendant, ports abstraits
|
||||||
pour les sources/sinks, adaptateurs pour sockets Unix, fichier et ClickHouse,
|
pour les sources/sinks, adaptateurs pour sockets Unix, fichier, ClickHouse et
|
||||||
couche application d’orchestration, et modules infra (config, observabilité).
|
stdout, couche application d'orchestration, et modules infra (config, observabilité).
|
||||||
modules:
|
modules:
|
||||||
- name: cmd/logcorrelator
|
- name: cmd/logcorrelator
|
||||||
type: entrypoint
|
type: entrypoint
|
||||||
@ -625,84 +677,124 @@ architecture:
|
|||||||
- Chargement de la configuration YAML.
|
- Chargement de la configuration YAML.
|
||||||
- Initialisation des adaptateurs d'entrée/sortie.
|
- Initialisation des adaptateurs d'entrée/sortie.
|
||||||
- Création du CorrelationService.
|
- Création du CorrelationService.
|
||||||
- Démarrage de l’orchestrateur.
|
- Démarrage de l'orchestrateur.
|
||||||
- Gestion des signaux (SIGINT, SIGTERM, SIGHUP).
|
- Gestion des signaux (SIGINT, SIGTERM, SIGHUP).
|
||||||
|
- Versioning via -ldflags (main.Version).
|
||||||
- name: internal/domain
|
- name: internal/domain
|
||||||
type: domain
|
type: domain
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- Modèles NormalizedEvent et CorrelatedLog.
|
- Modèles NormalizedEvent et CorrelatedLog.
|
||||||
- CorrelationService (fenêtre, TTL, buffers bornés, 1‑à‑N, orphelins).
|
- CorrelationService (fenêtre, TTL, buffers bornés, one-to-many/Keep-Alive, orphelins).
|
||||||
|
- Custom JSON marshaling pour CorrelatedLog (structure plate).
|
||||||
- name: internal/ports
|
- name: internal/ports
|
||||||
type: ports
|
type: ports
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- EventSource, CorrelatedLogSink, CorrelationProcessor.
|
- Interfaces EventSource, CorrelatedLogSink, CorrelationProcessor.
|
||||||
- name: internal/app
|
- name: internal/app
|
||||||
type: application
|
type: application
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- Orchestrator : EventSource → CorrelationService → MultiSink.
|
- Orchestrator : EventSource → CorrelationService → MultiSink.
|
||||||
|
- Gestion du contexte de shutdown et drain des événements.
|
||||||
- name: internal/adapters/inbound/unixsocket
|
- name: internal/adapters/inbound/unixsocket
|
||||||
type: adapter_inbound
|
type: adapter_inbound
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- Lecture Unix datagram (SOCK_DGRAM) et parsing JSON → NormalizedEvent.
|
- Lecture Unix datagram (SOCK_DGRAM) et parsing JSON → NormalizedEvent.
|
||||||
|
- Détection automatique de la source (A/B) via source_type ou headers.
|
||||||
|
- Gestion des permissions de socket (défaut 0666).
|
||||||
|
- Cleanup du fichier socket à l'arrêt.
|
||||||
- name: internal/adapters/outbound/file
|
- name: internal/adapters/outbound/file
|
||||||
type: adapter_outbound
|
type: adapter_outbound
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- Écriture JSON lines.
|
- Écriture JSON lines.
|
||||||
- Réouverture du fichier sur SIGHUP.
|
- Réouverture du fichier sur SIGHUP (log rotation).
|
||||||
|
- Validation des chemins (répertoire autorisé).
|
||||||
- name: internal/adapters/outbound/clickhouse
|
- name: internal/adapters/outbound/clickhouse
|
||||||
type: adapter_outbound
|
type: adapter_outbound
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- Bufferisation + inserts batch, gestion du drop_on_overflow.
|
- Bufferisation + inserts batch asynchrones.
|
||||||
|
- Gestion du drop_on_overflow.
|
||||||
|
- Retry avec backoff exponentiel (MaxRetries=3).
|
||||||
|
- API native clickhouse-go/v2 (PrepareBatch + Append + Send).
|
||||||
|
- name: internal/adapters/outbound/stdout
|
||||||
|
type: adapter_outbound
|
||||||
|
responsibilities:
|
||||||
|
- Écriture des logs vers stdout pour débogage.
|
||||||
|
- Filtrage par niveau (DEBUG, INFO, WARN, ERROR).
|
||||||
- name: internal/adapters/outbound/multi
|
- name: internal/adapters/outbound/multi
|
||||||
type: adapter_outbound
|
type: adapter_outbound
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- Fan‑out vers plusieurs sinks.
|
- Fan-out vers plusieurs sinks.
|
||||||
|
- Implémentation de Reopen() pour la rotation des logs.
|
||||||
- name: internal/config
|
- name: internal/config
|
||||||
type: infrastructure
|
type: infrastructure
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- Chargement/validation de la configuration YAML.
|
- Chargement/validation de la configuration YAML.
|
||||||
|
- Valeurs par défaut et fallback pour champs dépréciés.
|
||||||
- name: internal/observability
|
- name: internal/observability
|
||||||
type: infrastructure
|
type: infrastructure
|
||||||
responsibilities:
|
responsibilities:
|
||||||
- Logging interne, métriques (tailles des caches, évictions, erreurs datagram).
|
- Logger structuré avec niveaux (DEBUG, INFO, WARN, ERROR).
|
||||||
|
- Logs pour : événements reçus, corrélations, orphelins, buffer plein.
|
||||||
|
|
||||||
testing:
|
testing:
|
||||||
unit:
|
unit:
|
||||||
description: >
|
description: >
|
||||||
Tests unitaires table‑driven, couverture cible ≥ 80 %, focale sur la logique
|
Tests unitaires table‑driven, couverture cible ≥ 80 %. La couverture actuelle
|
||||||
de corrélation, les caches et les sinks.
|
est d'environ 74-80% selon les versions. Les tests se concentrent sur la logique
|
||||||
|
de corrélation, les caches, les sinks et le parsing des datagrammes.
|
||||||
coverage_minimum: 0.8
|
coverage_minimum: 0.8
|
||||||
|
coverage_actual: ~0.74-0.80
|
||||||
focus:
|
focus:
|
||||||
- CorrelationService (fenêtre, TTL, évictions, 1‑à‑N)
|
- CorrelationService (fenêtre, TTL, évictions, one-to-many/Keep-Alive)
|
||||||
- Parsing A/B → NormalizedEvent (datagrammes)
|
- Parsing A/B → NormalizedEvent (datagrammes JSON)
|
||||||
- ClickHouseSink (batching, overflow)
|
- ClickHouseSink (batching, retry, overflow)
|
||||||
- FileSink (réouverture sur SIGHUP)
|
- FileSink (réouverture sur SIGHUP)
|
||||||
- MultiSink
|
- MultiSink (fan-out)
|
||||||
|
- Config (validation, valeurs par défaut)
|
||||||
|
- UnixSocketSource (lecture, permissions, cleanup)
|
||||||
integration:
|
integration:
|
||||||
description: >
|
description: >
|
||||||
Tests d’intégration validant le flux complet A+B → corrélation → sinks,
|
Tests d'intégration limités. Le flux complet A+B → corrélation → sinks est
|
||||||
avec sockets Unix datagram simulées, ClickHouse mocké et scénarios Keep‑Alive.
|
testé via des tests unitaires avec mocks. ClickHouse est mocké (pas de tests
|
||||||
|
avec vrai ClickHouse). Scénarios Keep-Alive testés dans correlation_service_test.go.
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
description: >
|
description: >
|
||||||
Build, tests et packaging RPM sont exécutés intégralement dans des conteneurs
|
Build, tests et packaging RPM sont exécutés intégralement dans des conteneurs
|
||||||
via un multi‑stage build.
|
via un multi‑stage build. Deux Dockerfiles : Dockerfile (build + runtime + dev)
|
||||||
|
et Dockerfile.package (RPM multi-distros : el8, el9, el10).
|
||||||
build_pipeline:
|
build_pipeline:
|
||||||
multi_stage: true
|
multi_stage: true
|
||||||
stages:
|
stages:
|
||||||
- name: test_and_compile
|
- name: builder
|
||||||
base: golang:latest
|
base: golang:1.21
|
||||||
description: >
|
description: >
|
||||||
go test ./... (échec si couverture < 80 %), puis compilation d’un binaire
|
go test -race -coverprofile=coverage.txt ./... avec vérification de couverture
|
||||||
statique (CGO_ENABLED=0, GOOS=linux, GOARCH=amd64).
|
(échec si < 80 %). Compilation d'un binaire statique (CGO_ENABLED=0,
|
||||||
- name: rpm_builder
|
GOOS=linux, GOARCH=amd64).
|
||||||
base: ruby:alpine
|
- name: runtime
|
||||||
description: >
|
|
||||||
Installation de fpm, git et outils RPM. Génération du changelog RPM à
|
|
||||||
partir de l’historique. Construction des .rpm pour les différentes
|
|
||||||
distributions.
|
|
||||||
- name: output_export
|
|
||||||
base: scratch
|
base: scratch
|
||||||
description: >
|
description: >
|
||||||
Étape minimale pour exposer les paquets RPM produits (docker build --output).
|
Image minimale contenant uniquement le binaire et la config exemple.
|
||||||
|
- name: rpm_builder_el8
|
||||||
|
base: rockylinux:8
|
||||||
|
description: >
|
||||||
|
Installation de fpm (via Ruby), construction RPM pour Enterprise Linux 8.
|
||||||
|
- name: rpm_builder_el9
|
||||||
|
base: rockylinux:9
|
||||||
|
description: >
|
||||||
|
Installation de fpm (via Ruby), construction RPM pour Enterprise Linux 9.
|
||||||
|
- name: rpm_builder_el10
|
||||||
|
base: almalinux:10
|
||||||
|
description: >
|
||||||
|
Installation de fpm (via Ruby), construction RPM pour Enterprise Linux 10.
|
||||||
|
- name: output_export
|
||||||
|
base: alpine:latest
|
||||||
|
description: >
|
||||||
|
Export des paquets RPM produits pour les 3 distributions (el8, el9, el10).
|
||||||
|
files:
|
||||||
|
- path: Dockerfile
|
||||||
|
description: Build principal (builder, runtime, dev) et packaging RPM mono-distro.
|
||||||
|
- path: Dockerfile.package
|
||||||
|
description: Packaging RPM multi-distros (el8, el9, el10) avec scripts post/preun/postun.
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,12 @@ logcorrelator est un service système écrit en Go qui reçoit deux flux de logs
|
|||||||
via des sockets Unix, corrèle les événements HTTP applicatifs avec des événements
|
via des sockets Unix, corrèle les événements HTTP applicatifs avec des événements
|
||||||
réseau, et produit des logs corrélés en temps réel vers ClickHouse et/ou fichier local.
|
réseau, et produit des logs corrélés en temps réel vers ClickHouse et/ou fichier local.
|
||||||
|
|
||||||
|
Notes de sécurité :
|
||||||
|
- Le service s'exécute sous l'utilisateur logcorrelator (non-root)
|
||||||
|
- Les sockets Unix sont créés avec des permissions 0666 (world read/write)
|
||||||
|
- Les répertoires critiques sont protégés : /var/log (750), /var/lib (750), /etc (750)
|
||||||
|
- /var/run/logcorrelator est en 755 pour permettre la création de sockets
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
# No source extraction needed - binary is pre-built
|
# No source extraction needed - binary is pre-built
|
||||||
|
|
||||||
@ -52,73 +58,25 @@ install -m 0644 %{_sourcedir}/logcorrelator.service %{buildroot}/etc/systemd/sys
|
|||||||
# Install logrotate config
|
# Install logrotate config
|
||||||
install -m 0644 %{_sourcedir}/logrotate %{buildroot}/etc/logrotate.d/logcorrelator
|
install -m 0644 %{_sourcedir}/logrotate %{buildroot}/etc/logrotate.d/logcorrelator
|
||||||
|
|
||||||
%post
|
# Note: %post, %preun, %postun scripts are provided externally via Dockerfile.package
|
||||||
# Create logcorrelator user and group
|
# They are injected during RPM build using fpm --after-install, --before-remove, --after-remove
|
||||||
if ! getent group logcorrelator >/dev/null 2>&1; then
|
|
||||||
groupadd --system logcorrelator
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! getent passwd logcorrelator >/dev/null 2>&1; then
|
|
||||||
useradd --system \
|
|
||||||
--gid logcorrelator \
|
|
||||||
--home-dir /var/lib/logcorrelator \
|
|
||||||
--no-create-home \
|
|
||||||
--shell /usr/sbin/nologin \
|
|
||||||
logcorrelator
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create directories
|
|
||||||
mkdir -p /var/lib/logcorrelator
|
|
||||||
mkdir -p /var/log/logcorrelator
|
|
||||||
mkdir -p /var/run/logcorrelator
|
|
||||||
|
|
||||||
# Set ownership
|
|
||||||
chown -R logcorrelator:logcorrelator /var/lib/logcorrelator
|
|
||||||
chown -R logcorrelator:logcorrelator /var/log/logcorrelator
|
|
||||||
chown -R logcorrelator:logcorrelator /var/run/logcorrelator
|
|
||||||
chown -R logcorrelator:logcorrelator /etc/logcorrelator
|
|
||||||
|
|
||||||
# Set permissions
|
|
||||||
chmod 750 /var/lib/logcorrelator
|
|
||||||
chmod 750 /var/log/logcorrelator
|
|
||||||
chmod 755 /var/run/logcorrelator
|
|
||||||
chmod 750 /etc/logcorrelator
|
|
||||||
|
|
||||||
# Copy default config if not exists
|
|
||||||
if [ ! -f /etc/logcorrelator/logcorrelator.yml ]; then
|
|
||||||
cp /etc/logcorrelator/logcorrelator.yml.example /etc/logcorrelator/logcorrelator.yml
|
|
||||||
chown logcorrelator:logcorrelator /etc/logcorrelator/logcorrelator.yml
|
|
||||||
chmod 640 /etc/logcorrelator/logcorrelator.yml
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Reload systemd
|
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl enable logcorrelator.service
|
|
||||||
systemctl start logcorrelator.service
|
|
||||||
|
|
||||||
%preun
|
%preun
|
||||||
if [ $1 -eq 0 ]; then
|
# Placeholder: actual preun script is provided externally via Dockerfile.package
|
||||||
# Package removal, not upgrade
|
# See packaging/rpm/preun for the actual script
|
||||||
systemctl stop logcorrelator.service
|
|
||||||
systemctl disable logcorrelator.service
|
|
||||||
fi
|
|
||||||
|
|
||||||
%postun
|
%postun
|
||||||
systemctl daemon-reload
|
# Placeholder: actual postun script is provided externally via Dockerfile.package
|
||||||
if [ $1 -ge 1 ]; then
|
# See packaging/rpm/postun for the actual script
|
||||||
# Package upgrade, restart service
|
|
||||||
systemctl try-restart logcorrelator.service
|
|
||||||
fi
|
|
||||||
|
|
||||||
%files
|
%files
|
||||||
/usr/bin/logcorrelator
|
/usr/bin/logcorrelator
|
||||||
/etc/logcorrelator/logcorrelator.yml
|
|
||||||
/etc/logcorrelator/logcorrelator.yml.example
|
|
||||||
%config(noreplace) /etc/logcorrelator/logcorrelator.yml
|
%config(noreplace) /etc/logcorrelator/logcorrelator.yml
|
||||||
|
/etc/logcorrelator/logcorrelator.yml.example
|
||||||
/var/log/logcorrelator
|
/var/log/logcorrelator
|
||||||
/var/run/logcorrelator
|
/var/run/logcorrelator
|
||||||
/etc/systemd/system/logcorrelator.service
|
/etc/systemd/system/logcorrelator.service
|
||||||
/etc/logrotate.d/logcorrelator
|
%config(noreplace) /etc/logrotate.d/logcorrelator
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Tue Mar 03 2026 logcorrelator <dev@example.com> - 1.1.7-1
|
* Tue Mar 03 2026 logcorrelator <dev@example.com> - 1.1.7-1
|
||||||
|
|||||||
@ -1,6 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# post script for logcorrelator RPM package
|
# post install script for logcorrelator RPM package
|
||||||
# Compatible with CentOS 7, Rocky Linux 8, 9, 10
|
# Compatible with CentOS 7, Rocky Linux 8, 9, 10
|
||||||
|
#
|
||||||
|
# Configuration file policy:
|
||||||
|
# - logcorrelator.yml: %config(noreplace) - NEVER overwritten on upgrade
|
||||||
|
# - logcorrelator.yml.example: ALWAYS updated with new configuration options
|
||||||
|
# - On first install: logcorrelator.yml is created from logcorrelator.yml.example
|
||||||
|
# - On upgrade: existing logcorrelator.yml is preserved
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@ -24,19 +30,34 @@ mkdir -p /var/log/logcorrelator
|
|||||||
mkdir -p /var/run/logcorrelator
|
mkdir -p /var/run/logcorrelator
|
||||||
|
|
||||||
# Set ownership
|
# Set ownership
|
||||||
|
# /var/run/logcorrelator: must be owned by logcorrelator for socket creation
|
||||||
|
# /var/log/logcorrelator: must be owned by logcorrelator for log file writing
|
||||||
|
# /var/lib/logcorrelator: home directory for the service
|
||||||
chown -R logcorrelator:logcorrelator /var/lib/logcorrelator
|
chown -R logcorrelator:logcorrelator /var/lib/logcorrelator
|
||||||
chown -R logcorrelator:logcorrelator /var/log/logcorrelator
|
chown -R logcorrelator:logcorrelator /var/log/logcorrelator
|
||||||
chown -R logcorrelator:logcorrelator /var/run/logcorrelator
|
chown -R logcorrelator:logcorrelator /var/run/logcorrelator
|
||||||
chown -R logcorrelator:logcorrelator /etc/logcorrelator
|
chown -R logcorrelator:logcorrelator /etc/logcorrelator
|
||||||
|
|
||||||
# Set permissions
|
# Set permissions
|
||||||
|
# /var/run/logcorrelator: 755 to allow other users/apps to create sockets if needed
|
||||||
|
# /var/log/logcorrelator: 750 to restrict log access
|
||||||
|
# /var/lib/logcorrelator: 750 for service data
|
||||||
|
# /etc/logcorrelator: 750 to restrict config access
|
||||||
|
chmod 755 /var/run/logcorrelator
|
||||||
chmod 750 /var/lib/logcorrelator
|
chmod 750 /var/lib/logcorrelator
|
||||||
chmod 750 /var/log/logcorrelator
|
chmod 750 /var/log/logcorrelator
|
||||||
chmod 750 /etc/logcorrelator
|
chmod 750 /etc/logcorrelator
|
||||||
|
|
||||||
# Copy default config if not exists
|
# Copy default config example (always updated)
|
||||||
|
# The main config file is preserved across upgrades via %config(noreplace)
|
||||||
|
if [ -f /etc/logcorrelator/logcorrelator.yml.example ]; then
|
||||||
|
chown logcorrelator:logcorrelator /etc/logcorrelator/logcorrelator.yml.example
|
||||||
|
chmod 640 /etc/logcorrelator/logcorrelator.yml.example
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create main config file only if it doesn't exist (first install)
|
||||||
if [ ! -f /etc/logcorrelator/logcorrelator.yml ]; then
|
if [ ! -f /etc/logcorrelator/logcorrelator.yml ]; then
|
||||||
cp /usr/share/logcorrelator/logcorrelator.yml.example /etc/logcorrelator/logcorrelator.yml
|
cp /etc/logcorrelator/logcorrelator.yml.example /etc/logcorrelator/logcorrelator.yml
|
||||||
chown logcorrelator:logcorrelator /etc/logcorrelator/logcorrelator.yml
|
chown logcorrelator:logcorrelator /etc/logcorrelator/logcorrelator.yml
|
||||||
chmod 640 /etc/logcorrelator/logcorrelator.yml
|
chmod 640 /etc/logcorrelator/logcorrelator.yml
|
||||||
fi
|
fi
|
||||||
|
|||||||
258
packaging/test/test-rpm.sh
Executable file
258
packaging/test/test-rpm.sh
Executable file
@ -0,0 +1,258 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Test script for logcorrelator RPM package
|
||||||
|
# Verifies installation, permissions, and service status
|
||||||
|
#
|
||||||
|
# Usage: ./packaging/test/test-rpm.sh [el8|el9|el10]
|
||||||
|
#
|
||||||
|
# This script tests the RPM package in a Docker container to ensure:
|
||||||
|
# - Installation succeeds
|
||||||
|
# - File permissions are correct
|
||||||
|
# - Service starts properly
|
||||||
|
# - Sockets are created with correct ownership
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
|
||||||
|
RPM_DIR="${PROJECT_ROOT}/dist/rpm"
|
||||||
|
|
||||||
|
# Default to el8 if no argument provided
|
||||||
|
DISTRO="${1:-el8}"
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo "Testing logcorrelator RPM for ${DISTRO}"
|
||||||
|
echo "========================================="
|
||||||
|
|
||||||
|
# Find the RPM file
|
||||||
|
case "${DISTRO}" in
|
||||||
|
el8|rocky8)
|
||||||
|
RPM_PATH="${RPM_DIR}/el8"
|
||||||
|
BASE_IMAGE="rockylinux:8"
|
||||||
|
;;
|
||||||
|
el9|rocky9)
|
||||||
|
RPM_PATH="${RPM_DIR}/el9"
|
||||||
|
BASE_IMAGE="rockylinux:9"
|
||||||
|
;;
|
||||||
|
el10|alma10)
|
||||||
|
RPM_PATH="${RPM_DIR}/el10"
|
||||||
|
BASE_IMAGE="almalinux:10"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown distribution: ${DISTRO}"
|
||||||
|
echo "Valid options: el8, el9, el10"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Find the latest RPM file
|
||||||
|
RPM_FILE=$(ls -t "${RPM_PATH}"/logcorrelator-*.rpm 2>/dev/null | head -n 1)
|
||||||
|
|
||||||
|
if [ -z "${RPM_FILE}" ]; then
|
||||||
|
echo "ERROR: No RPM file found in ${RPM_PATH}"
|
||||||
|
echo "Please run 'make package-rpm' first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Testing RPM: ${RPM_FILE}"
|
||||||
|
echo "Base image: ${BASE_IMAGE}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create test script
|
||||||
|
TEST_SCRIPT=$(cat <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "=== Installing logcorrelator RPM ==="
|
||||||
|
rpm -ivh /tmp/logcorrelator.rpm
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Checking user and group ==="
|
||||||
|
if ! getent group logcorrelator >/dev/null; then
|
||||||
|
echo "FAIL: logcorrelator group not created"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: logcorrelator group exists"
|
||||||
|
|
||||||
|
if ! getent passwd logcorrelator >/dev/null; then
|
||||||
|
echo "FAIL: logcorrelator user not created"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: logcorrelator user exists"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Checking directory permissions ==="
|
||||||
|
|
||||||
|
# Check /var/run/logcorrelator
|
||||||
|
DIR="/var/run/logcorrelator"
|
||||||
|
if [ ! -d "$DIR" ]; then
|
||||||
|
echo "FAIL: $DIR does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
OWNER=$(stat -c '%U:%G' "$DIR")
|
||||||
|
PERMS=$(stat -c '%a' "$DIR")
|
||||||
|
if [ "$OWNER" != "logcorrelator:logcorrelator" ]; then
|
||||||
|
echo "FAIL: $DIR owner is $OWNER (expected logcorrelator:logcorrelator)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$PERMS" != "755" ]; then
|
||||||
|
echo "FAIL: $DIR permissions are $PERMS (expected 755)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: $DIR - owner=$OWNER, permissions=$PERMS"
|
||||||
|
|
||||||
|
# Check /var/log/logcorrelator
|
||||||
|
DIR="/var/log/logcorrelator"
|
||||||
|
if [ ! -d "$DIR" ]; then
|
||||||
|
echo "FAIL: $DIR does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
OWNER=$(stat -c '%U:%G' "$DIR")
|
||||||
|
PERMS=$(stat -c '%a' "$DIR")
|
||||||
|
if [ "$OWNER" != "logcorrelator:logcorrelator" ]; then
|
||||||
|
echo "FAIL: $DIR owner is $OWNER (expected logcorrelator:logcorrelator)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$PERMS" != "750" ]; then
|
||||||
|
echo "FAIL: $DIR permissions are $PERMS (expected 750)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: $DIR - owner=$OWNER, permissions=$PERMS"
|
||||||
|
|
||||||
|
# Check /var/lib/logcorrelator
|
||||||
|
DIR="/var/lib/logcorrelator"
|
||||||
|
if [ ! -d "$DIR" ]; then
|
||||||
|
echo "FAIL: $DIR does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
OWNER=$(stat -c '%U:%G' "$DIR")
|
||||||
|
PERMS=$(stat -c '%a' "$DIR")
|
||||||
|
if [ "$OWNER" != "logcorrelator:logcorrelator" ]; then
|
||||||
|
echo "FAIL: $DIR owner is $OWNER (expected logcorrelator:logcorrelator)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$PERMS" != "750" ]; then
|
||||||
|
echo "FAIL: $DIR permissions are $PERMS (expected 750)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: $DIR - owner=$OWNER, permissions=$PERMS"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Checking config files ==="
|
||||||
|
|
||||||
|
# Check config file exists and has correct permissions
|
||||||
|
CONFIG="/etc/logcorrelator/logcorrelator.yml"
|
||||||
|
if [ ! -f "$CONFIG" ]; then
|
||||||
|
echo "FAIL: $CONFIG does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
OWNER=$(stat -c '%U:%G' "$CONFIG")
|
||||||
|
PERMS=$(stat -c '%a' "$CONFIG")
|
||||||
|
if [ "$OWNER" != "logcorrelator:logcorrelator" ]; then
|
||||||
|
echo "FAIL: $CONFIG owner is $OWNER (expected logcorrelator:logcorrelator)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$PERMS" != "640" ]; then
|
||||||
|
echo "FAIL: $CONFIG permissions are $PERMS (expected 640)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: $CONFIG - owner=$OWNER, permissions=$PERMS"
|
||||||
|
|
||||||
|
# Check example config file
|
||||||
|
EXAMPLE_CONFIG="/etc/logcorrelator/logcorrelator.yml.example"
|
||||||
|
if [ ! -f "$EXAMPLE_CONFIG" ]; then
|
||||||
|
echo "FAIL: $EXAMPLE_CONFIG does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
OWNER=$(stat -c '%U:%G' "$EXAMPLE_CONFIG")
|
||||||
|
PERMS=$(stat -c '%a' "$EXAMPLE_CONFIG")
|
||||||
|
if [ "$OWNER" != "logcorrelator:logcorrelator" ]; then
|
||||||
|
echo "FAIL: $EXAMPLE_CONFIG owner is $OWNER (expected logcorrelator:logcorrelator)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$PERMS" != "640" ]; then
|
||||||
|
echo "FAIL: $EXAMPLE_CONFIG permissions are $PERMS (expected 640)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: $EXAMPLE_CONFIG - owner=$OWNER, permissions=$PERMS"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Checking systemd service ==="
|
||||||
|
if [ ! -f /etc/systemd/system/logcorrelator.service ]; then
|
||||||
|
echo "FAIL: systemd service file not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: systemd service file exists"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Checking logrotate config ==="
|
||||||
|
if [ ! -f /etc/logrotate.d/logcorrelator ]; then
|
||||||
|
echo "FAIL: logrotate config not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: logrotate config exists"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Testing service start ==="
|
||||||
|
# Try to start the service (may fail in container without full systemd)
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl daemon-reload || true
|
||||||
|
if systemctl start logcorrelator.service 2>/dev/null; then
|
||||||
|
echo "OK: service started successfully"
|
||||||
|
|
||||||
|
# Wait for sockets to be created
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Checking sockets ==="
|
||||||
|
HTTP_SOCKET="/var/run/logcorrelator/http.socket"
|
||||||
|
NETWORK_SOCKET="/var/run/logcorrelator/network.socket"
|
||||||
|
|
||||||
|
if [ -S "$HTTP_SOCKET" ]; then
|
||||||
|
OWNER=$(stat -c '%U:%G' "$HTTP_SOCKET")
|
||||||
|
PERMS=$(stat -c '%a' "$HTTP_SOCKET")
|
||||||
|
echo "OK: $HTTP_SOCKET exists - owner=$OWNER, permissions=$PERMS"
|
||||||
|
if [ "$PERMS" != "666" ]; then
|
||||||
|
echo "WARN: socket permissions are $PERMS (expected 666)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARN: $HTTP_SOCKET not found (service may not have started)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -S "$NETWORK_SOCKET" ]; then
|
||||||
|
OWNER=$(stat -c '%U:%G' "$NETWORK_SOCKET")
|
||||||
|
PERMS=$(stat -c '%a' "$NETWORK_SOCKET")
|
||||||
|
echo "OK: $NETWORK_SOCKET exists - owner=$OWNER, permissions=$PERMS"
|
||||||
|
if [ "$PERMS" != "666" ]; then
|
||||||
|
echo "WARN: socket permissions are $PERMS (expected 666)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARN: $NETWORK_SOCKET not found (service may not have started)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemctl stop logcorrelator.service || true
|
||||||
|
else
|
||||||
|
echo "WARN: service failed to start (expected in minimal container)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARN: systemctl not available (minimal container)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "========================================="
|
||||||
|
echo "All tests passed!"
|
||||||
|
echo "========================================="
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run test in Docker container
|
||||||
|
echo "Running tests in Docker container..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
-v "${RPM_FILE}:/tmp/logcorrelator.rpm:ro" \
|
||||||
|
-v "${TEST_SCRIPT}:/test.sh:ro" \
|
||||||
|
"${BASE_IMAGE}" \
|
||||||
|
bash /test.sh
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Test completed successfully for ${DISTRO}"
|
||||||
Reference in New Issue
Block a user