Événements ssh-guard (JSON)¶
Référence stable du flux d'événements émis par la couche ssh-guard du serveur SSH gitrust. Ce format est garanti stable pour les consommateurs externes (fail2ban, Loki, Vector, SIEM). Tout changement incompatible passe par un nouveau nom d'événement.
Où trouver ces événements : selon
SSH_GUARD_LOG_TARGET, dans le journald du service (stderr), dans/var/log/gitrust-ssh-guard.json(file), ou les deux (both). Voir Variables d'environnement — SSH_GUARD_*.
1. Forme générale¶
Tous les événements partagent trois champs :
| Champ | Type | Description |
|---|---|---|
event |
string | Nom snake_case du type d'événement (clé de filtrage). |
ts |
string ISO 8601 UTC | Horodatage UTC de l'événement (ex. 2026-04-19T14:32:11.482Z). |
ip |
string | Adresse IPv4 ou IPv6 réelle du client (après extraction PROXY si applicable). |
Champs additionnels selon le type d'événement (voir tables ci-dessous).
2. Catalogue des événements¶
event |
Catégorie | Émis par | Cas d'usage admin |
|---|---|---|---|
connection_accepted |
Trafic | SecureListener |
Audit volume |
connection_dropped |
Décision | SecureListener ou ConnectionFloodDetector |
Volumétrie des refus |
auth_failed |
Authentification | AuthTracker |
Source principale fail2ban |
auth_succeeded |
Authentification | AuthTracker |
Audit accès légitimes |
brute_force_detected |
Détection | BruteForceDetector |
Signal fort fail2ban |
user_enumeration_detected |
Détection | UserEnumerationDetector |
Signal fort fail2ban |
key_scanning_detected |
Détection | KeyScanningDetector |
Signal fort fail2ban |
connection_flood_detected |
Détection | ConnectionFloodDetector |
Signal fort fail2ban |
ip_banned |
Action | BanManager |
Ban à appliquer côté firewall (fail2ban) |
ip_unbanned |
Action | BanManager |
Levée de ban (manuelle ou TTL) |
3. Référence par événement¶
3.1 connection_accepted¶
Une connexion TCP a passé tous les contrôles ssh-guard. Le russh handshake va démarrer.
| Champ | Type | Description |
|---|---|---|
event |
"connection_accepted" |
|
ts |
string | Horodatage UTC |
session_id |
string UUID v4 | Identifiant unique de session, présent ensuite dans tous les événements liés (auth_failed, auth_succeeded) |
ip |
string | IP cliente réelle |
{"event":"connection_accepted","ts":"2026-04-19T14:32:11.482Z","session_id":"a4c2b8e1-9f3d-4d7e-8c11-0a5d9b6f4e22","ip":"203.0.113.42"}
3.2 connection_dropped¶
ssh-guard a refusé la connexion avant le handshake SSH.
| Champ | Type | Description |
|---|---|---|
event |
"connection_dropped" |
|
ts |
string | Horodatage UTC |
ip |
string | IP source (réelle si PROXY parsé, sinon peer_addr) |
reason |
enum string | Voir tableau des raisons ci-dessous |
Valeurs de reason :
reason |
Signification |
|---|---|
banned |
IP couverte par un ban actif (auto ou denylist admin) |
flood_limit |
Cap de connexions/seconde par IP atteint |
proxy_header_missing |
PROXY protocol obligatoire mais en-tête absent (timeout) |
untrusted_proxy |
En-tête PROXY reçu d'un socket pas dans trusted_proxies |
proxy_header_invalid |
En-tête PROXY malformé ou version non autorisée |
concurrent_limit |
Limite de sessions concurrentes par IP atteinte (placeholder, non actif) |
{"event":"connection_dropped","ts":"2026-04-19T14:33:02.117Z","ip":"203.0.113.42","reason":"banned"}
3.3 auth_failed¶
Tentative d'authentification SSH refusée. Source principale pour fail2ban.
| Champ | Type | Description |
|---|---|---|
event |
"auth_failed" |
|
ts |
string | Horodatage UTC |
session_id |
string UUID | Lien avec le connection_accepted |
ip |
string | IP cliente réelle |
user |
string ou null |
Nom d'utilisateur tenté (si fourni par le client) |
method |
enum string | Méthode SSH : none, password, public_key, keyboard_interactive, host_based |
fingerprint |
string ou null |
Fingerprint SHA256 de la clé publique tentée (forme SHA256:...) ou null si non public_key |
{"event":"auth_failed","ts":"2026-04-19T14:32:13.221Z","session_id":"a4c2b8e1-9f3d-4d7e-8c11-0a5d9b6f4e22","ip":"203.0.113.42","user":"root","method":"public_key","fingerprint":"SHA256:k1Qp9xJ8r6Z3HfV2Bn7tT5Cw"}
3.4 auth_succeeded¶
Tentative d'authentification SSH validée. Audit des accès légitimes.
| Champ | Type | Description |
|---|---|---|
event |
"auth_succeeded" |
|
ts |
string | Horodatage UTC |
session_id |
string UUID | |
ip |
string | |
user |
string | Nom d'utilisateur authentifié |
fingerprint |
string ou null |
Fingerprint de la clé utilisée (peut être null si méthode sans clé) |
{"event":"auth_succeeded","ts":"2026-04-19T14:32:14.005Z","session_id":"a4c2b8e1-9f3d-4d7e-8c11-0a5d9b6f4e22","ip":"203.0.113.42","user":"alice","fingerprint":"SHA256:p3Lm7nB6xQz9fK1WyT8c"}
3.5 brute_force_detected¶
Le seuil SSH_GUARD_BRUTE_FORCE_THRESHOLD a été atteint. Un événement ip_banned suit immédiatement.
| Champ | Type | Description |
|---|---|---|
event |
"brute_force_detected" |
|
ts |
string | Horodatage UTC |
ip |
string | IP fautive |
count |
number | Nombre d'auth_failed comptés dans la fenêtre |
window_secs |
number | Largeur de la fenêtre (en secondes) |
{"event":"brute_force_detected","ts":"2026-04-19T14:36:42.998Z","ip":"203.0.113.42","count":5,"window_secs":300}
3.6 user_enumeration_detected¶
Le seuil SSH_GUARD_USER_ENUM_THRESHOLD (nombre d'usernames distincts essayés depuis la même IP) a été atteint.
| Champ | Type | Description |
|---|---|---|
event |
"user_enumeration_detected" |
|
ts |
string | Horodatage UTC |
ip |
string | |
distinct_users |
number | Nombre d'usernames distincts dans la fenêtre |
window_secs |
number |
{"event":"user_enumeration_detected","ts":"2026-04-19T14:38:15.402Z","ip":"203.0.113.42","distinct_users":10,"window_secs":300}
3.7 key_scanning_detected¶
Le seuil SSH_GUARD_KEY_SCAN_THRESHOLD (nombre de fingerprints distincts essayés depuis la même IP) a été atteint.
| Champ | Type | Description |
|---|---|---|
event |
"key_scanning_detected" |
|
ts |
string | Horodatage UTC |
ip |
string | |
distinct_keys |
number | Nombre de fingerprints distincts dans la fenêtre |
window_secs |
number |
{"event":"key_scanning_detected","ts":"2026-04-19T14:39:08.117Z","ip":"203.0.113.42","distinct_keys":10,"window_secs":300}
3.8 connection_flood_detected¶
Le cap SSH_GUARD_CONN_FLOOD_PER_SEC a été dépassé pour cette IP. Un connection_dropped avec reason="flood_limit" suit dans le même millième de seconde.
| Champ | Type | Description |
|---|---|---|
event |
"connection_flood_detected" |
|
ts |
string | Horodatage UTC |
ip |
string | |
rate_per_sec |
number | Cap nominal (valeur de SSH_GUARD_CONN_FLOOD_PER_SEC) |
{"event":"connection_flood_detected","ts":"2026-04-19T14:40:01.555Z","ip":"203.0.113.42","rate_per_sec":10}
3.9 ip_banned¶
Un ban a été appliqué (auto par un détecteur, manuel par un admin, ou simulé en dry_run).
| Champ | Type | Description |
|---|---|---|
event |
"ip_banned" |
|
ts |
string | Horodatage UTC |
ip |
string | IP bannie (pour un CIDR > /32, l'adresse réseau) |
reason |
enum string | Voir tableau ci-dessous |
expires_at |
string ou null |
Horodatage UTC d'expiration. null = ban permanent |
Valeurs de reason :
reason |
Origine |
|---|---|
brute_force |
BruteForceDetector |
user_enumeration |
UserEnumerationDetector |
key_scanning |
KeyScanningDetector |
connection_flood |
ConnectionFloodDetector (rare : le flood drop ne pose pas de ban persistant par défaut) |
admin_deny_list |
Ajout admin dans l'ACL deny |
manual |
Ban manuel via UI/API admin |
{"event":"ip_banned","ts":"2026-04-19T14:36:42.999Z","ip":"203.0.113.42","reason":"brute_force","expires_at":"2026-04-19T15:36:42.999Z"}
Mode
dry_run: unip_bannedest émis pour signal externe (fail2ban) sans que ssh-guard inscrive le ban dans son store. Utile pour observer un nouveau seuil sans risque.
3.10 ip_unbanned¶
Un ban a été levé (TTL expiré ou action admin).
| Champ | Type | Description |
|---|---|---|
event |
"ip_unbanned" |
|
ts |
string | Horodatage UTC |
ip |
string | |
manual |
boolean | true = action admin, false = expiration auto |
4. Filtrage côté outils externes¶
4.1 Fail2ban (filtre par regex sur le fichier JSON)¶
[Definition]
# Brute-force détecté → ban dur côté firewall
failregex = ^.*"event":"auth_failed".*"ip":"<HOST>".*$
ignoreregex =
Voir le template clé en main : template/security/fail2ban-gitrust-ssh-guard.conf et le how-to Durcir avec Fail2ban.
4.2 Loki (LogQL)¶
# Toutes les détections fortes (signal pour alerting Grafana)
{job="gitrust-ssh-guard"}
| json
| event=~"brute_force_detected|user_enumeration_detected|key_scanning_detected|connection_flood_detected"
4.3 jq (extraction shell)¶
# 10 IP les plus actives en échec d'auth sur la dernière heure
sudo journalctl -u gitrust --since "1 hour ago" --no-pager \
| jq -r 'select(.event=="auth_failed") | .ip' \
| sort | uniq -c | sort -rn | head -10