Cloud
Azure WAF : préparer un evidence pack avant une PR de policy
Un runbook de production pour documenter une modification Azure WAF avec preuves KQL, diff de policy, probes applicatives, validation sécurité, décision de merge et rollback.
Une modification Azure WAF paraît souvent petite dans une pull request : une exclusion, une custom rule, un changement de priorité, une condition sur un header ou un passage de mode. En production, ce diff peut changer le comportement d’entrée d’une application entière. Le problème n’est pas seulement de savoir si la règle est correcte. Il faut pouvoir prouver pourquoi elle est nécessaire, quel trafic elle touche, comment elle sera validée et comment revenir en arrière.
Le cas d’usage est une équipe plateforme qui gère une policy WAF Application Gateway en infrastructure as code. Une équipe applicative demande une modification après des blocages légitimes ou une nouvelle exposition. Le runbook vise une décision simple : merger la PR, demander plus de preuves, appliquer une alternative plus sûre ou préparer un rollback borné.
Définir l’objet exact du changement
Avant d’ouvrir la discussion sécurité, il faut nommer précisément ce qui change. Une PR WAF ne devrait pas contenir seulement une intention comme “corriger le faux positif”. Elle doit isoler la règle, le chemin, le champ matché, le mode et l’effet attendu.
Objet du changement
Application Gateway et policy WAF concernés
Hostname et chemin applicatif
Règle managée, exclusion ou custom rule modifiée
Champ matché: cookie, header, query arg, body, multipart, IP, method
Action attendue: allow, block, log, exclusion ciblée, changement de priorité
Environnement: staging, production, shared gateway
Contexte
Symptôme observé
RuleId ou custom rule impliquée
Fenêtre temporelle des logs
Client, intégration ou parcours métier touché
Risque si la modification n'est pas appliquée
Risque si la modification est trop large Cette fiche évite les PR ambiguës. Si l’équipe ne sait pas dire quel champ et quel chemin sont concernés, le changement est probablement trop tôt pour être mergé.
Construire le pack de preuves KQL
L’evidence pack commence par les logs. Il doit montrer la réalité du blocage, son volume, son périmètre et les échantillons utiles. Le but n’est pas de prouver que le WAF gêne, mais de prouver que la modification proposée correspond au signal observé.
let Window = 7d;
let Hostname = "api.example.com";
let PathPrefix = "/api/import";
AzureDiagnostics
| where TimeGenerated > ago(Window)
| where Category == "ApplicationGatewayFirewallLog"
| extend hostname = tostring(host_s)
| extend uri = tostring(requestUri_s)
| extend method = tostring(requestMethod_s)
| extend action = tostring(action_s)
| extend ruleId = tostring(ruleId_s)
| extend message = tostring(message_s)
| extend clientIp = tostring(clientIp_s)
| extend transactionId = tostring(transactionId_g)
| where hostname == Hostname
| where uri startswith PathPrefix
| summarize hits=count(),
clients=dcount(clientIp),
firstSeen=min(TimeGenerated),
lastSeen=max(TimeGenerated),
sampleMessages=make_set(message, 5),
sampleTransactions=make_set(transactionId, 5)
by hostname, uri, method, action, ruleId
| order by hits desc Une bonne preuve contient aussi ce qui n’est pas touché. Si la PR prétend ne viser que /api/import, il faut vérifier qu’elle ne masque pas des blocages sur /login, /admin ou un webhook externe.
let Window = 7d;
let Hostname = "api.example.com";
AzureDiagnostics
| where TimeGenerated > ago(Window)
| where Category == "ApplicationGatewayFirewallLog"
| extend hostname = tostring(host_s)
| extend uri = tostring(requestUri_s)
| extend action = tostring(action_s)
| extend ruleId = tostring(ruleId_s)
| where hostname == Hostname
| where action has_any ("Blocked", "Matched", "Detected")
| summarize hits=count(), rules=make_set(ruleId, 10) by path=split(uri, "?")[0]
| order by hits desc Si l’evidence pack ne montre qu’un exemple isolé sans contexte de volume, la revue doit demander une fenêtre plus large ou des logs applicatifs complémentaires.
Relier le diff IaC à l’effet opérationnel
Le diff de policy doit être lisible par quelqu’un qui n’a pas écrit le module Terraform, Bicep ou ARM. Le reviewer doit voir l’avant, l’après et le comportement attendu.
Dans la PR
Fichier modifié et policy exacte
Ancienne condition et nouvelle condition
Ancienne priorité et nouvelle priorité si custom rule
RuleId ciblé si exclusion
Match variable et selector précis
Action finale après évaluation des règles
Environnements affectés
Questions de revue
La règle est-elle plus large que le symptôme ?
Une exclusion managée suffit-elle au lieu d'une allow rule ?
La priorité peut-elle court-circuiter une règle de blocage utile ?
Le changement touche-t-il plusieurs hostnames via une policy partagée ?
Existe-t-il une expiration ou une revue planifiée ?
Le rollback est-il un revert simple ou une action manuelle ? Une custom rule Allow prioritaire sur un chemin large n’a pas le même risque qu’une exclusion OWASP ciblée sur un argument stable. L’evidence pack doit rendre cette différence évidente.
Ajouter une validation applicative reproductible
La preuve WAF ne suffit pas. Il faut rejouer le parcours légitime et, si possible, un cas qui doit rester bloqué. Une validation utile produit un résultat avant/après, pas seulement un “test OK”.
HOST=api.example.com
BASE_URL="https://$HOST"
CORRELATION_ID="waf-pr-$(date +%Y%m%d%H%M%S)"
curl -sk -o /tmp/import-response.txt -w "%{http_code}
" "$BASE_URL/api/import" -H "x-correlation-id: $CORRELATION_ID" -H "content-type: application/json" --data @representative-import-payload.json
curl -sk -o /tmp/negative-response.txt -w "%{http_code}
" "$BASE_URL/api/import" -H "x-correlation-id: $CORRELATION_ID-negative" -H "content-type: application/json" --data @known-bad-payload.json
echo "correlation_id=$CORRELATION_ID" Le test négatif n’a pas besoin d’être destructif. Il peut être un payload synthétique attendu comme bloqué dans un environnement de test, ou une vérification de non-régression sur des chemins sensibles. L’important est d’éviter une PR qui prouve seulement que le cas légitime passe, sans vérifier que la protection reste active.
Automatiser la checklist sans automatiser la décision
L’automatisation aide à rendre la revue régulière : générer les requêtes, joindre le diff, vérifier les slugs de policy, lancer des probes, vérifier la présence d’un rollback. Elle ne doit pas transformer la sécurité en bouton de merge automatique.
evidence_pack:
change:
policy: appgw-waf-prod
environment: production
type: managed_rule_exclusion
scope: api.example.com/api/import
required:
- waf_logs_window
- affected_rule_id
- policy_diff
- representative_payload
- negative_or_non_regression_test
- rollback_step
- owner_approval
gates:
merge_allowed_when:
- scope_matches_logs
- no_broader_hostname_impact
- probes_pass
- rollback_is_revertable
merge_blocked_when:
- missing_rule_id
- broad_allow_rule_without_expiration
- policy_shared_without_impact_review
- no_production_observability Cette checklist peut être générée par pipeline ou remplie dans la PR. La décision reste humaine quand le changement modifie une surface exposée en production.
Décider merge, hold ou rollback
La revue doit finir par une décision opérationnelle. “LGTM” n’est pas assez précis pour une policy qui peut bloquer ou laisser passer du trafic.
Decision: merge
Le ruleId ou la custom rule est identifié
Le périmètre du diff correspond aux logs
Les probes légitimes passent
Les contrôles négatifs ou non-régression restent acceptables
Le rollback est simple et documenté
Decision: hold
Les logs sont insuffisants
Le chemin critique n'a pas été rejoué
L'effet sur une policy partagée n'est pas compris
Le changement doit être réduit ou expiré
Decision: rollback après merge
403 légitimes sur un chemin critique
Hausse d'erreurs applicatives corrélée au changement
Règle plus large que prévu
Perte de visibilité WAF ou applicative
Contournement détecté sur un contrôle attendu comme bloqué Le rollback doit conserver les preuves. Revenir au commit précédent sans garder les transactions, probes et décisions condamne l’équipe à rejouer la même discussion au prochain faux positif.
Conclusion
Une PR Azure WAF exploitable ne se résume pas à un diff de policy. Elle doit porter un evidence pack : logs KQL, périmètre exact, diff compréhensible, probes applicatives, contrôle de non-régression, approbation et rollback.
La décision devient alors plus nette. Merger quand le changement est ciblé et validé. Bloquer quand la preuve manque. Rollbacker quand le comportement réel dépasse le périmètre annoncé. C’est cette discipline qui permet de faire évoluer le WAF sans transformer chaque exception en dette de sécurité invisible.