Aller au contenu

Sysadmin — au quotidien

1. Lundi matin — qu’est-ce qui a changé pendant le weekend

Dans le tableau de bord

  1. Sidebar → Audit-log
  2. Filtre : dernières 72h groupé par event_type
  3. Cliquez chaque ligne drift_event pour operator + raison
  4. Drift inexpliquée ? → agent → Inventaire → Restore

Chemin de clic :

  1. /audit-log → filtre created_at >= now() - INTERVAL '72 hours' → tri par event_type
  2. /agents → panneau “Drift events” — tous les hashes de config modifiés hors fenêtre EAT
  3. 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

  1. Sidebar → CVE noyau → onglet Batches actifs
  2. Bouton ‘Nouveau batch’ → sélecteur tag + noyau cible + reboot-strategy
  3. Saisir TOTP → Démarrer canary
  4. 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)

Fenêtre de terminal
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-required et — si dans la fenêtre de maintenance — shutdown -r +5
  • Le hub détecte le flip running_release au prochain ingest → marque la phase rebooted_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 :

Fenêtre de terminal
curl https://app.monsys.ai/api/v1/kernel-updates/batches/<id> \
-H "Authorization: Bearer $TOKEN" | jq .members

3. Une application est lente — où regarder

Dans le tableau de bord

  1. Sidebar → Apps → cliquer host web-03 → onglet Metrics
  2. Onglet Processes pour top consommateurs CPU/RAM
  3. Onglet Topology pour dépendances blast-radius
  4. Onglet Logs pour WARN/ERROR récents de l’agent

Chemin de clic pour l’hôte web-03 :

  1. /agents/web-03 → onglet Metrics — CPU/mem/load sur 6 h
  2. /agents/web-03 → onglet Processes — top 10 consommateurs CPU/RAM
  3. /agents/web-03 → onglet Topology — quels autres agents/apps en dépendent
  4. /agents/web-03 → onglet Containersrestart_count par conteneur
  5. /agents/web-03 → onglet Logs — derniers 200 WARN/ERROR de l’agent
  6. /alerts filtre agent=web-03 AND is_resolved=false

Causes racines courantes :

SymptômeVérifier d’abord
CPU 100 % pendant des heuresProcesses tab — quel PID ? Puis /agents/web-03 → Logs
Mémoire se remplit lentementCapacity tab — tendance RAM + utilisation swap
App ne répond pasContainers tab — restart_count + Inventory → systemd_services pour l’état du service
Erreurs DBTopology tab — l’agent DB est-il stale ? Vérifier last_seen_at

4. Auto-reboot uniquement le weekend

Dans le tableau de bord

  1. Sidebar → Settings → Fenêtres de maintenance → ‘Nouvelle fenêtre’
  2. Configurer récurrence : samedi 02:00-06:00 tag-target ‘production’
  3. À la création du batch noyau : reboot_strategy = auto-at-window
  4. 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)

Fenêtre de terminal
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

  1. Sidebar → Agents → cliquer host → onglet Inventory → section Config hashes
  2. Table montre sha256 actuel vs baseline par chemin surveillé
  3. Par drift event : ‘Accept as baseline’ OU ‘Investigate’
  4. 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)

Fenêtre de terminal
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 fichier
  • prev_sha256 / new_sha256
  • detected_at
  • linked_eat_idnull signifie : personne n’a autorisé ceci avec un EAT, c’est du drift inexpliqué

Workflow :

  1. Changement légitime (patch manuel, migration) : POST /api/v1/agents/<id>/drift-events/<id>/accept — la baseline est mise à jour
  2. Suspect : POST /api/v1/agents/<id>/emergency avec action IsolateNetwork + TOTP, puis inspection manuelle

6. Trouver tous les serveurs Ubuntu 20.04 (fin du support standard 2025-04)

Dans le tableau de bord

  1. Sidebar → Agents → filtre os_name=Ubuntu + os_version~20.04
  2. Sélection groupée des hosts affichés
  3. Bouton ‘Add tag’ → tag = ‘eol-2025’
  4. Sidebar → Settings → Alert rules → nouveau avec seuil-date 2025-04-30

Ou via API (avancé — pour automatisation)

Fenêtre de terminal
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

  1. Sidebar → Alertes → onglet ‘Grouped by title’
  2. Trier descending par count
  3. Cliquer le plus grand groupe — le titre contient-il une valeur ?
  4. 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

  1. Sidebar → Identity surface → rechercher alice@
  2. Voir systèmes liés (hosts, SSH keys, sièges Copilot/OpenAI)
  3. Par système bouton ‘Revoke’ OU un EAT playbook ‘revoke-user’ sur tous
  4. 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

  1. Sidebar → Settings → On-call rotations → ‘Nouvelle rotation’
  2. Pour team eu-ops : shifts lun-ven 09:00-18:00 Europe/Brussels
  3. Ajouter buddy fallback pour hors heures
  4. 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 buddy
INSERT 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'); -- buddy

NotifyWorker 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

  1. Sidebar → Inventaire → onglet Backups → filtre tag ‘production-db’
  2. Trier ‘Last successful’ ascending
  3. Par host stale (>25h) : cliquer ‘Create alert rule’
  4. 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) :

Fenêtre de terminal
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"
}'