ssh-guard-evenements.md 10389 octets

É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 :

ChampTypeDescription
eventstringNom snake_case du type d'événement (clé de filtrage).
tsstring ISO 8601 UTCHorodatage UTC de l'événement (ex. 2026-04-19T14:32:11.482Z).
ipstringAdresse 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

eventCatégorieÉmis parCas d'usage admin
connection_acceptedTraficSecureListenerAudit volume
connection_droppedDécisionSecureListener ou ConnectionFloodDetectorVolumétrie des refus
auth_failedAuthentificationAuthTrackerSource principale fail2ban
auth_succeededAuthentificationAuthTrackerAudit accès légitimes
brute_force_detectedDétectionBruteForceDetectorSignal fort fail2ban
user_enumeration_detectedDétectionUserEnumerationDetectorSignal fort fail2ban
key_scanning_detectedDétectionKeyScanningDetectorSignal fort fail2ban
connection_flood_detectedDétectionConnectionFloodDetectorSignal fort fail2ban
ip_bannedActionBanManagerBan à appliquer côté firewall (fail2ban)
ip_unbannedActionBanManagerLevé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.

ChampTypeDescription
event"connection_accepted"
tsstringHorodatage UTC
session_idstring UUID v4Identifiant unique de session, présent ensuite dans tous les événements liés (auth_failed, auth_succeeded)
ipstringIP 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.

ChampTypeDescription
event"connection_dropped"
tsstringHorodatage UTC
ipstringIP source (réelle si PROXY parsé, sinon peer_addr)
reasonenum stringVoir tableau des raisons ci-dessous

Valeurs de reason :

reasonSignification
bannedIP couverte par un ban actif (auto ou denylist admin)
flood_limitCap de connexions/seconde par IP atteint
proxy_header_missingPROXY protocol obligatoire mais en-tête absent (timeout)
untrusted_proxyEn-tête PROXY reçu d'un socket pas dans trusted_proxies
proxy_header_invalidEn-tête PROXY malformé ou version non autorisée
concurrent_limitLimite 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.

ChampTypeDescription
event"auth_failed"
tsstringHorodatage UTC
session_idstring UUIDLien avec le connection_accepted
ipstringIP cliente réelle
userstring ou nullNom d'utilisateur tenté (si fourni par le client)
methodenum stringMéthode SSH : none, password, public_key, keyboard_interactive, host_based
fingerprintstring ou nullFingerprint 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.

ChampTypeDescription
event"auth_succeeded"
tsstringHorodatage UTC
session_idstring UUID
ipstring
userstringNom d'utilisateur authentifié
fingerprintstring ou nullFingerprint 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.

ChampTypeDescription
event"brute_force_detected"
tsstringHorodatage UTC
ipstringIP fautive
countnumberNombre d'auth_failed comptés dans la fenêtre
window_secsnumberLargeur 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.

ChampTypeDescription
event"user_enumeration_detected"
tsstringHorodatage UTC
ipstring
distinct_usersnumberNombre d'usernames distincts dans la fenêtre
window_secsnumber
{"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.

ChampTypeDescription
event"key_scanning_detected"
tsstringHorodatage UTC
ipstring
distinct_keysnumberNombre de fingerprints distincts dans la fenêtre
window_secsnumber
{"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.

ChampTypeDescription
event"connection_flood_detected"
tsstringHorodatage UTC
ipstring
rate_per_secnumberCap 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).

ChampTypeDescription
event"ip_banned"
tsstringHorodatage UTC
ipstringIP bannie (pour un CIDR > /32, l'adresse réseau)
reasonenum stringVoir tableau ci-dessous
expires_atstring ou nullHorodatage UTC d'expiration. null = ban permanent

Valeurs de reason :

reasonOrigine
brute_forceBruteForceDetector
user_enumerationUserEnumerationDetector
key_scanningKeyScanningDetector
connection_floodConnectionFloodDetector (rare : le flood drop ne pose pas de ban persistant par défaut)
admin_deny_listAjout admin dans l'ACL deny
manualBan 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 : un ip_banned est é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).

ChampTypeDescription
event"ip_unbanned"
tsstringHorodatage UTC
ipstring
manualbooleantrue = action admin, false = expiration auto
{"event":"ip_unbanned","ts":"2026-04-19T15:36:43.001Z","ip":"203.0.113.42","manual":false}

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

5. Pour aller plus loin