Sysadmin — au quotidien
1. Lundi matin — qu’est-ce qui a changé pendant le weekend
Dans le tableau de bord
- Sidebar → Audit-log
- Filtre : dernières 72h groupé par event_type
- Cliquez chaque ligne drift_event pour operator + raison
- Drift inexpliquée ? → agent → Inventaire → Restore
Chemin de clic :
/audit-log→ filtrecreated_at >= now() - INTERVAL '72 hours'→ tri parevent_type/agents→ panneau “Drift events” — tous les hashes de config modifiés hors fenêtre EAT- Par agent suspect :
/agents/<id> → onglet Kernel → Historique de redémarrage— qui a redémarré, déclenché par EAT ou manuel
Équivalent en une requête SQL :
Ou via API (avancé — pour automatisation)
SELECT a.hostname, l.event_type, l.event_data->>'reason' AS reason, u.email AS actor, l.created_at FROM audit_log l LEFT JOIN agents a ON a.id = l.agent_id LEFT JOIN users u ON u.id = l.user_id WHERE l.tenant_id = $1::UUID AND l.created_at >= NOW() - INTERVAL '72 hours' ORDER BY l.created_at DESC;Ce que vous faites typiquement ensuite : pour chaque drift_event sans
ligne emergency_token_issued correspondante → vérifier si c’était un
changement légitime. Sinon → /agents/<id> → onglet Inventory → Config hashes → Restore ou mettre l’hôte en quarantaine via EAT
IsolateNetwork.
2. Mise à jour noyau de toute la flotte sans coupure
Dans le tableau de bord
- Sidebar → CVE noyau → onglet Batches actifs
- Bouton ‘Nouveau batch’ → sélecteur tag + noyau cible + reboot-strategy
- Saisir TOTP → Démarrer canary
- Suivre canary → primary → completed dans la même vue
Soit USN-2026-1234 affectant 80 hôtes Ubuntu en production. Noyau
cible : 6.8.0-49.49.
Ou via API (avancé — pour automatisation)
curl -X POST https://app.monsys.ai/api/v1/kernel-updates/batches \ -H "Authorization: Bearer $TOKEN" \ -H "X-TOTP-Code: 123456" \ -H "Content-Type: application/json" \ -d '{ "title": "USN-2026-1234 — kernel 6.8.0-49.49", "target_kernel": "6.8.0-49.49", "package_manager": "apt", "reboot_strategy": "auto-at-window", "selector_kind": "tag", "selector_value": {"tag":"production"}, "maintenance_window_id": "8c34…" }'Ce qui se passe en coulisses :
- Le hub choisit 3 hôtes canary (10 % de 80 = 8, plafonné à 3)
- Pour chaque canary : EAT Ed25519 signé, poussé via WebSocket
- L’agent appelle
/usr/local/sbin/monsys-kernel-update(uniquement via la règle sudoers qui autorise ce wrapper) - Le wrapper installe noyau + headers, exécute
update-grub, écrit/var/run/reboot-requiredet — si dans la fenêtre de maintenance —shutdown -r +5 - Le hub détecte le flip
running_releaseau prochain ingest → marque la phaserebooted_new - Quand les 3 canary atteignent rebooted_new → primary se déclenche (77 EATs en un tick)
- Un canary signalant
phase='failed'→ batch avorté, aucun EAT primary envoyé - Canary bloqué 2 h sans transition → avortement automatique (“canary timeout”)
Suivi : onglet /kernel-cves → Batches actifs. Ou :
curl https://app.monsys.ai/api/v1/kernel-updates/batches/<id> \ -H "Authorization: Bearer $TOKEN" | jq .members3. Une application est lente — où regarder
Dans le tableau de bord
- Sidebar → Apps → cliquer host web-03 → onglet Metrics
- Onglet Processes pour top consommateurs CPU/RAM
- Onglet Topology pour dépendances blast-radius
- Onglet Logs pour WARN/ERROR récents de l’agent
Chemin de clic pour l’hôte web-03 :
/agents/web-03 → onglet Metrics— CPU/mem/load sur 6 h/agents/web-03 → onglet Processes— top 10 consommateurs CPU/RAM/agents/web-03 → onglet Topology— quels autres agents/apps en dépendent/agents/web-03 → onglet Containers—restart_countpar conteneur/agents/web-03 → onglet Logs— derniers 200 WARN/ERROR de l’agent/alertsfiltreagent=web-03 AND is_resolved=false
Causes racines courantes :
| Symptôme | Vérifier d’abord |
|---|---|
| CPU 100 % pendant des heures | Processes tab — quel PID ? Puis /agents/web-03 → Logs |
| Mémoire se remplit lentement | Capacity tab — tendance RAM + utilisation swap |
| App ne répond pas | Containers tab — restart_count + Inventory → systemd_services pour l’état du service |
| Erreurs DB | Topology tab — l’agent DB est-il stale ? Vérifier last_seen_at |
4. Auto-reboot uniquement le weekend
Dans le tableau de bord
- Sidebar → Settings → Fenêtres de maintenance → ‘Nouvelle fenêtre’
- Configurer récurrence : samedi 02:00-06:00 tag-target ‘production’
- À la création du batch noyau : reboot_strategy = auto-at-window
- Le wrapper n’exécute shutdown -r +5 que dans la fenêtre active
Définir d’abord une fenêtre de maintenance :
Ou via API (avancé — pour automatisation)
curl -X POST https://app.monsys.ai/api/v1/maintenance-windows \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Weekend reboot window", "starts_at": "2026-05-23T02:00:00Z", "ends_at": "2026-05-23T06:00:00Z", "recurrence": "weekly", "target_type": "tag", "target_filter": {"tag":"production"}, "silence_categories": [] }'Lors de la création d’un batch de mise à jour noyau : mettre
reboot_strategy=auto-at-window. Le wrapper monsys-kernel-update
n’exécute shutdown -r +5 que quand l’hôte se trouve dans une fenêtre
active ; en dehors, il reste sur “reboot required” et laisse à
l’opérateur le soin de confirmer.
5. Drift de configuration après une migration
Dans le tableau de bord
- Sidebar → Agents → cliquer host → onglet Inventory → section Config hashes
- Table montre sha256 actuel vs baseline par chemin surveillé
- Par drift event : ‘Accept as baseline’ OU ‘Investigate’
- Drift sans linked_eat_id = inexpliqué, action requise
Par agent vous voyez le sha256 de tous les chemins surveillés (par
défaut : /etc/passwd, /etc/shadow, /etc/sudoers,
/etc/ssh/sshd_config + 4 autres).
Ou via API (avancé — pour automatisation)
curl https://app.monsys.ai/api/v1/agents/<id>/drift-events?limit=50 \ -H "Authorization: Bearer $TOKEN"Pour chaque drift event vous voyez :
path— quel fichierprev_sha256/new_sha256detected_atlinked_eat_id—nullsignifie : personne n’a autorisé ceci avec un EAT, c’est du drift inexpliqué
Workflow :
- Changement légitime (patch manuel, migration) :
POST /api/v1/agents/<id>/drift-events/<id>/accept— la baseline est mise à jour - Suspect :
POST /api/v1/agents/<id>/emergencyavec actionIsolateNetwork+ TOTP, puis inspection manuelle
6. Trouver tous les serveurs Ubuntu 20.04 (fin du support standard 2025-04)
Dans le tableau de bord
- Sidebar → Agents → filtre os_name=Ubuntu + os_version~20.04
- Sélection groupée des hosts affichés
- Bouton ‘Add tag’ → tag = ‘eol-2025’
- Sidebar → Settings → Alert rules → nouveau avec seuil-date 2025-04-30
Ou via API (avancé — pour automatisation)
curl 'https://app.monsys.ai/api/v1/agents?os_name=Ubuntu&os_version_like=20.04' \ -H "Authorization: Bearer $TOKEN" | jq '.[] | .hostname'Ou en SQL :
SELECT hostname, ip_addresses, last_seen_at FROM agents WHERE tenant_id = $1::UUID AND os_name = 'Ubuntu' AND os_version LIKE '20.04%' AND is_active = true ORDER BY last_seen_at DESC;Typiquement : taguer ces hôtes avec eol-2025 via bulk-tagging dans
/groups, puis construire une alerte SLA qui se déclenche dès que des
agents portent encore ce tag après 2025-04-30.
7. « Pourquoi ai-je reçu 438 alertes CPU cette nuit ? »
Dans le tableau de bord
- Sidebar → Alertes → onglet ‘Grouped by title’
- Trier descending par count
- Cliquer le plus grand groupe — le titre contient-il une valeur ?
- Settings → Alert rules → éditer la règle pour mettre la valeur en description
Depuis le fix anti-storm, InsertAlert fait du dédup sur 30 minutes
par (tenant, agent, category, title). Si vous voyez quand même un
storm : très probablement un titre changeant (par ex. un compteur
incorporé) qui contourne la clé de dédup.
Vérification rapide :
Ou via API (avancé — pour automatisation)
SELECT title, COUNT(*), MIN(created_at), MAX(created_at) FROM alerts WHERE tenant_id = $1::UUID AND created_at >= NOW() - INTERVAL '24 hours' GROUP BY title ORDER BY 2 DESC LIMIT 10;Si un titre apparaît 100+ fois → bug quelque part. Si 100 titres
uniques 1× chacun → le titre contient une valeur (compteur,
pourcentage, timestamp). Corrigez le worker émetteur pour déplacer la
valeur vers description.
8. Employé parti — à quoi avait-il accès
Dans le tableau de bord
- Sidebar → Identity surface → rechercher alice@
- Voir systèmes liés (hosts, SSH keys, sièges Copilot/OpenAI)
- Par système bouton ‘Revoke’ OU un EAT playbook ‘revoke-user’ sur tous
- Audit-log montre ‘identity_revoked’ par révocation
/identity/surface → recherche "alice@…" affiche :
- Compte du tableau de bord (rôles par tenant)
- Utilisateurs locaux sur quels hôtes (
inventory_users.username='alice') - Clés SSH dont le fingerprint de la pubkey correspond
- Siège GitHub Copilot (si module Copilot Audit activé)
- Membre d’org OpenAI (si module OpenAI Audit activé)
- Droits sudo (
inventory_sudo_rules.who='alice')
Bulk-revoke depuis la page Identity surface : soit par système
(POST /api/v1/identity/persons/<id>/revoke), soit comme un seul EAT
RunPlaybook qui gère tous les hôtes d’un coup.
9. Rotation on-call timezone-aware
Dans le tableau de bord
- Sidebar → Settings → On-call rotations → ‘Nouvelle rotation’
- Pour team eu-ops : shifts lun-ven 09:00-18:00 Europe/Brussels
- Ajouter buddy fallback pour hors heures
- NotifyWorker résout quelle shift est ouverte par alerte → ntfy
Ou via API (avancé — pour automatisation)
-- Pour team eu-ops, 09:00-18:00 heure de Bruxelles, lun-ven, avec buddyINSERT INTO oncall_shifts (tenant_id, group_id, person_id, weekday, start_time, end_time, timezone)VALUES ($1, $2, $alice, 1, '09:00', '18:00', 'Europe/Brussels'), ($1, $2, $alice, 2, '09:00', '18:00', 'Europe/Brussels'), -- … ($1, $2, $bob, 1, '18:00', '09:00', 'Europe/Brussels'); -- buddyNotifyWorker résout par alerte quelle shift est ouverte à
alerts.created_at, puis route vers le bon topic ntfy + email.
10. Les backups des BD production fonctionnent-elles encore ?
Dans le tableau de bord
- Sidebar → Inventaire → onglet Backups → filtre tag ‘production-db’
- Trier ‘Last successful’ ascending
- Par host stale (>25h) : cliquer ‘Create alert rule’
- Seuil = 25h + sévérité = critical
Ou via API (avancé — pour automatisation)
SELECT a.hostname, b.tool AS backup_tool, b.destination AS target, b.last_successful_run AS last_ok, NOW() - b.last_successful_run AS age, b.last_failure_message FROM backup_configs b JOIN agents a ON a.id = b.agent_id WHERE b.tenant_id = $1::UUID AND 'production-db' = ANY(a.tags) ORDER BY b.last_successful_run NULLS FIRST;Règle d’alerte si age > 25h (planning par défaut = quotidien) :
curl -X POST https://app.monsys.ai/api/v1/alert-rules \ -H "Authorization: Bearer $TOKEN" \ -d '{ "name": "Backup stale > 25h on production-db", "tag": "production-db", "category": "backup", "metric": "backup_age_hours", "operator": ">", "threshold": 25, "severity": "critical" }'