Aller au contenu principal

ServiceNow

fremforge peut ouvrir un incident ServiceNow pour chaque événement de sécurité : un nouveau résultat critique ou élevé, une correspondance de malware, un pull bloqué, une violation de politique ou une acceptation de risque arrivée à échéance. La destination envoie directement à la Table API (POST /api/now/table/incident) : ServiceNow n’a besoin que d’un utilisateur d’intégration, sans Scripted REST API ni serveur MID.

1. Côté ServiceNow : un utilisateur d’intégration

  1. Créez un utilisateur pour fremforge, par exemple fremforge.integration. Cochez Web service access only.
  2. Attribuez-lui un rôle qui peut créer des incidents via la Table API, en général itil, ou un rôle personnalisé plus restreint avec create sur incident.
  3. Choisissez comment fremforge s’authentifie :
    • Basic : le nom et le mot de passe de l’utilisateur, envoyés sous la forme Authorization: Basic <base64 of user:password>.
    • Jeton porteur OAuth : un jeton OAuth pour cet utilisateur, envoyé sous la forme Authorization: Bearer <token>. Un jeton d’accès OAuth ServiceNow expire : un jeton qui arrive à échéance doit donc être remplacé sur la destination avant son expiration. Basic est le choix le plus simple pour un utilisateur machine.
  4. Facultatif : notez le sys_id du groupe d’affectation qui doit recevoir les incidents, ainsi que celui de l’appelant à enregistrer.

ServiceNow doit accepter les requêtes provenant de l’adresse de sortie de fremforge. Si votre instance restreint les IP sources, demandez l’adresse actuelle au support.

2. Côté fremforge : une destination au format ServiceNow

Avec l’API (scope webhooks:write) :

AUTH="Basic $(printf '%s' 'fremforge.integration:<password>' | base64)"

curl -sS -X POST "https://frem.sh/_app/api/v1/orgs/acme/webhooks/destinations" \
  -H "Authorization: Bearer $FREMFORGE_TOKEN" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "name": "ServiceNow incidents",
  "target_url": "https://acme.service-now.com/api/now/table/incident",
  "events": ["security.finding.created", "security.malware.matched",
             "security.pull.blocked", "security.policy.violation",
             "security.exception.expired"],
  "payload_format": "servicenow",
  "security_min_severity": "critical",
  "security_hourly_cap": 50,
  "servicenow": { "assignment_group": "<sys_id>", "category": "security" },
  "auth_header": { "name": "Authorization", "value": "$AUTH" }
}
EOF

La valeur de auth_header est stockée chiffrée et n’est plus jamais affichée. La réponse indique "auth_header_set": true. Pour remplacer le mot de passe, envoyez un PATCH avec un nouvel auth_header.

Envoyez ensuite un incident de test et lisez son résultat :

curl -sS -X POST "https://frem.sh/_app/api/v1/orgs/acme/webhooks/destinations/$ID/test" \
  -H "Authorization: Bearer $FREMFORGE_TOKEN"
curl -sS "https://frem.sh/_app/api/v1/orgs/acme/webhooks/deliveries?destination_id=$ID&limit=1" \
  -H "Authorization: Bearer $FREMFORGE_TOKEN"

Un 201 dans response_status signifie que ServiceNow a créé l’incident. Un 401 signifie que l’identifiant est incorrect. Un 403 signifie que l’utilisateur n’a pas le rôle permettant de créer des incidents.

Contenu de l’incident

Champ de l’incidentValeur
short_description[fremforge] suivi du titre de l’événement, par exemple [fremforge] CVE-2026-12345 in lodash 4.17.20 (160 caractères au plus)
descriptionNom de l’événement, organisation, dépôt, sévérité, heure, clé de corrélation, un lien vers la console fremforge, et le détail de l’événement en JSON
urgency, impact1 pour critique, 2 pour élevé, 3 sinon
correlation_idfremforge: suivi de la clé de corrélation du résultat. Une clé trop longue pour le champ est remplacée par son empreinte SHA-256, qui reste stable
correlation_displayfremforge
assignment_group, caller_id, category, subcategoryUniquement s’ils sont définis sur la destination (objet servicenow)

ServiceNow calcule la priorité de l’incident à partir de l’urgence et de l’impact, comme d’habitude.

Chaque événement crée un nouvel incident. La Table API ne met pas à jour un enregistrement existant. Les événements concernant un même résultat portent le même correlation_id, par exemple un résultat suivi plus tard de l’échéance d’une acceptation de risque qui le concerne. Utilisez cette valeur dans une business rule ou un filtre de liste ServiceNow pour les regrouper. Le plafond horaire limite le nombre d’incidents qu’une destination peut ouvrir par heure. Au-delà du plafond, un incident récapitulatif est créé après l’heure écoulée.

La requête est également signée (X-Fremforge-Signature). La Table API ignore la signature ; c’est l’en-tête d’authentification qui authentifie la requête.

Autre solution : votre propre logique dans une Scripted REST API

Pour mettre à jour un incident existant au lieu d’en créer un, ou pour faire correspondre les champs autrement, laissez la destination au format JSON générique (signé) et faites-la pointer vers une ressource Scripted REST API. Le script reçoit le corps générique. Recherchez un incident ouvert par correlation_id et mettez-le à jour, ou insérez-en un nouveau. Pour vérifier la signature dans le script, calculez un HMAC-SHA256 sur <X-Fremforge-Timestamp>.<raw body> avec le secret de signature de la destination, et comparez-le à la partie v1 de X-Fremforge-Signature. Protégez la ressource avec le même utilisateur d’intégration et l’auth_header.

Voir aussi