← Tous les guides

Guide · Sécurité

Signez vos check-ins avec HMAC

Une URL de ping en clair est un secret au porteur : quiconque la voit, dans un log, une crontab fuitée, ou sur le réseau, peut envoyer un faux « actif ». Les check-ins signés lient chaque ping à un secret partagé et à un horodatage, donc un ping rejoué ou forgé est rejeté, même en HTTP simple.

Pourquoi signer vos check-ins

Une URL de ping en clair est un mot de passe que n'importe qui peut réutiliser. Si elle fuite, via un log, une crontab exposée, ou une interception réseau, un attaquant peut envoyer un faux signal tout va bien pour masquer une panne réelle. Le check reste au vert pendant que votre job est à terre.

Prenez un job nocturne qui fait tourner vos clés TLS, et qui se met en échec. Si quelqu'un peut forger son check-in, il maintient le check sur un faux actif pendant que vos clés expirent en silence, laissant des accès vulnérables ouverts, et l'alerte sur laquelle vous comptiez ne part jamais. Ou prenez un backup qui cesse de tourner : une seule ligne de log fuitée suffit à simuler le ping terminé, la panne reste cachée, et vous découvrez le trou seulement au moment de restaurer.

Les pings signés ferment cette brèche. Chaque check-in est lié à un secret et à un horodatage, donc un ping forgé ou rejoué ne correspond plus et il est refusé. La seule chose qui puisse parler pour votre job, c'est votre job lui-même.

1. Activez les pings signés

Les pings signés sont disponibles sur toutes les offres payantes (Solo et au-dessus) ; ils ne font pas partie de l'offre gratuite. Sur la page du check, cochez Exiger des pings signés et enregistrez. Mortemain affiche juste en dessous un secret de ping par check (une clé HMAC en hexadécimal), copiez-le.

Activez-la après que votre job signe, pas avant. Une fois Exiger des pings signés actif, un ping non signé vers l'URL est rejeté et ne compte plus comme check-in. Mettez d'abord le job à jour pour qu'il signe, puis basculez l'option, sinon vous déclencherez votre propre alerte.

Traitez le secret de ping comme un mot de passe : il est propre à chaque check, et quiconque le détient peut signer pour ce check. Gardez-le hors de Git, hors des logs, et hors des captures d'écran.

2. Signer un check-in (shell, openssl)

Le secret est la clé HMAC en octets bruts ; openssl la prend via hexkey:. Le message signé fait trois lignes : l'UUID du check, un horodatage Unix, et le type (success).

 checkin-signe.sh
SECRET=votre-secret-de-ping-hex
URL="https://ping.mortemain.com/votre-uuid-de-check"
UUID=$(basename "$URL"); TS=$(date +%s)
SIG=$(printf '%s\n%s\nsuccess' "$UUID" "$TS" | openssl dgst -sha256 -mac HMAC -macopt hexkey:$SECRET -r | cut -d' ' -f1)
curl -H "X-Mortemain-Timestamp: $TS" -H "X-Mortemain-Signature: $SIG" "$URL"

3. Signer un check-in (PowerShell)

 checkin-signe.ps1
$secret = 'votre-secret-de-ping-hex'; $url = 'https://ping.mortemain.com/votre-uuid-de-check'
$key = [byte[]]::new($secret.Length/2); for ($i=0; $i -lt $key.Length; $i++) { $key[$i] = [Convert]::ToByte($secret.Substring($i*2,2),16) }
$uuid = $url.Split('/')[-1]; $ts = [int][double]::Parse((Get-Date -UFormat %s))
$sig = [BitConverter]::ToString(([Security.Cryptography.HMACSHA256]::new($key)).ComputeHash([Text.Encoding]::UTF8.GetBytes("$uuid`n$ts`nsuccess"))).Replace('-','').ToLower()
Invoke-RestMethod $url -Headers @{ 'X-Mortemain-Timestamp' = $ts; 'X-Mortemain-Signature' = $sig }

Votre tableau de bord génère ces deux extraits pour vous, avec le vrai secret et l'URL, sur la page du check une fois la signature activée.

4. Signer un check-in (Python)

Bibliothèque standard uniquement, aucune dépendance. Même message sur trois lignes, mêmes deux en-têtes.

 checkin_signe.py
import hmac, hashlib, time, urllib.request

secret = bytes.fromhex("votre-secret-de-ping-hex")
url    = "https://ping.mortemain.com/votre-uuid-de-check"

uuid = url.rsplit("/", 1)[-1]
ts   = str(int(time.time()))
msg  = f"{uuid}\n{ts}\nsuccess".encode()
sig  = hmac.new(secret, msg, hashlib.sha256).hexdigest()

req = urllib.request.Request(url, headers={
    "X-Mortemain-Timestamp": ts,
    "X-Mortemain-Signature": sig,
})
urllib.request.urlopen(req)

5. La règle (n'importe quel langage)

Pour signer depuis n'importe quel langage, reproduisez exactement ceci :

 la signature
signature = hex( HMAC-SHA256( secret, uuid + "\n" + horodatage + "\n" + type ) )
  • secret — le secret de ping du check, décodé de l'hexadécimal en octets bruts comme clé HMAC.
  • uuid — le dernier segment de l'URL de ping.
  • horodatage — l'heure Unix actuelle en secondes, envoyée telle quelle dans l'en-tête X-Mortemain-Timestamp. Elle doit être à environ cinq minutes près de l'horloge du serveur, gardez donc le client à peu près synchronisé (NTP). C'est ce qui empêche de rejouer plus tard une signature interceptée.
  • typesuccess, start, fail ou log. Signez le type que vous envoyez.
  • Envoyez la signature hex dans l'en-tête X-Mortemain-Signature.

Pour /start ou /fail, ajoutez-le à l'URL et signez le type correspondant, par exemple un échec signé :

 /fail signé
SIG=$(printf '%s\n%s\nfail' "$UUID" "$TS" | openssl dgst -sha256 -mac HMAC -macopt hexkey:$SECRET -r | cut -d' ' -f1)
curl -H "X-Mortemain-Timestamp: $TS" -H "X-Mortemain-Signature: $SIG" "$URL/fail"

Testez

Lancez le curl signé une fois à la main. Le check passe actif en une seconde ou deux. Maintenant, changez un caractère de la signature et réessayez, il doit être rejeté et le check reste en panne. Ce rejet, c'est tout l'intérêt : une URL de ping volée ou rejouée ne peut plus mentir sur la santé de votre job.

FAQ

Puis-je utiliser le même secret pour plusieurs checks ?

Non. Chaque check a son propre secret de ping, affiché sur sa page une fois la signature activée. Un secret ne signe jamais que pour son propre check, donc une fuite reste circonscrite à celui-ci.

Que se passe-t-il si mon horodatage est trop ancien ?

Mortemain rejette le ping et le traite comme un rejeu possible. Les signatures ne sont acceptées qu'à environ cinq minutes près de l'horloge du serveur, gardez donc la machine émettrice synchronisée via NTP.

Puis-je signer /start et /fail aussi ?

Oui. Ajoutez /start ou /fail à l'URL et signez ce même type (start ou fail) dans le message. Le type signé doit correspondre à celui que vous envoyez, sinon le ping est rejeté.

Pour aller plus loin