Automation
Azure Automation : faire tourner un webhook avant l'expiration du déclencheur de production
Un runbook de production pour inventorier les consommateurs d'un webhook Azure Automation, introduire un second endpoint, prouver une seule exécution par événement, basculer puis révoquer l'ancienne URL avec un rollback testé.
Un webhook Azure Automation approche de son expiration. Il démarre un runbook publié depuis une plateforme d’alerting ou d’orchestration, mais l’équipe ne connaît plus tous les consommateurs de l’URL. Repousser la date paraît anodin. Remplacer le webhook semble plus propre. Dans les deux cas, on peut couper le déclencheur, conserver pendant des années une URL exposée ou exécuter deux fois la même action de production pendant la bascule.
Le cas fil rouge est un webhook qui démarre Invoke-PlatformRemediation après un événement de monitoring approuvé. Le but n’est pas seulement d’obtenir une nouvelle URL. Il faut prouver qui appelle l’endpoint, ce que le runbook acceptera, comment les doublons sont contenus et quand l’ancien credential peut être désactivé sans perdre le chemin de rollback.
Traiter l’URL comme un credential et le déclencheur comme un contrat
L’URL d’un webhook Automation contient le token qui autorise l’invocation. Un appelant qui la connaît peut envoyer un POST sans identité Azure distincte. L’URL est fournie à la création du webhook et doit être capturée à ce moment ; ne supposez pas qu’elle pourra être récupérée plus tard depuis l’inventaire de la ressource.
Figez le contrat opérationnel avant tout changement :
automation_account: aa-platform-prod
runbook: Invoke-PlatformRemediation
old_webhook: remediation-prod-v1
old_expiry_utc: <timestamp>
expected_callers:
- alerting-platform
- approved-orchestrator
execution_target: hybrid-worker-prod
required_fields: [eventId, targetId, action, requestedAt]
deduplication_key: eventId
maximum_event_age: 10m
success_evidence: une requete acceptee produit un seul job tracable
rollback: restaurer la configuration appelant v1 tant que l'ancien webhook reste actif Consignez la version publiée du runbook, les paramètres fixes du webhook, le groupe Hybrid Worker, l’identité managée et le périmètre cible. Le webhook autorise le démarrage, mais l’identité du runbook autorise l’effet. Ces deux frontières doivent rester stables pendant la rotation.
Inventorier les consommateurs par la configuration et les preuves
Ne comptez pas sur le nom du webhook pour identifier les appelants : le système externe n’a besoin que de l’URL. Recherchez sa référence dans les secrets approuvés, receivers d’alerte, Logic Apps, variables de déploiement et configurations d’orchestration. N’affichez pas l’URL dans un transcript terminal, un ticket ou un log CI pendant la recherche.
Comparez ensuite les consommateurs déclarés aux preuves runtime. Inventoriez les métadonnées du webhook et les jobs récents sans exposer les secrets de requête :
$scope = @{
ResourceGroupName = '<resource-group>'
AutomationAccountName = 'aa-platform-prod'
}
$webhook = Get-AzAutomationWebhook @scope -Name 'remediation-prod-v1'
$webhook | Select-Object Name, IsEnabled, ExpiryTime, LastInvokedTime, RunOn,
@{n='Runbook';e={$_.RunbookName}}, Parameters
Get-AzAutomationJob @scope -StartTime (Get-Date).AddDays(-14) |
Where-Object RunbookName -eq 'Invoke-PlatformRemediation' |
Select-Object JobId, CreationTime, StartTime, EndTime, Status L’historique des jobs prouve une exécution, pas l’identité de l’appelant. Corrélez l’eventId accepté et un identifiant d’appelant non secret émis par le runbook avec la plateforme source. Si le runbook actuel ne peut pas attribuer une requête sans journaliser le token ou le payload complet, corrigez ce manque d’observabilité avant de faire tourner un déclencheur critique.
Rejeter les requêtes périmées, invalides et dupliquées dans le runbook
L’URL du webhook ne prouve pas à elle seule l’intention métier. Le runbook doit accepter un payload étroit, valider actions et cibles autorisées, refuser les événements hors d’une courte fenêtre d’âge, puis réserver une clé de déduplication avant tout effet.
param([object] $WebhookData)
if (-not $WebhookData) { throw 'WebhookData is required' }
$request = $WebhookData.RequestBody | ConvertFrom-Json -Depth 10
$allowedActions = @('restart-approved-service', 'refresh-approved-cache')
if ([string]::IsNullOrWhiteSpace($request.eventId)) { throw 'eventId is required' }
if ($request.action -notin $allowedActions) { throw 'action is not allowed' }
if ($request.targetId -notlike '/subscriptions/<approved-subscription>/*') {
throw 'target is outside the approved scope'
}
$requestedAt = [DateTimeOffset]::Parse($request.requestedAt)
if ([DateTimeOffset]::UtcNow - $requestedAt -gt [TimeSpan]::FromMinutes(10)) {
throw 'event is stale'
}
# Creer ou reserver eventId atomiquement dans le state store approuve.
# S'il existe deja, emettre duplicate_ignored et sortir avant toute ecriture. Utilisez un state store dont la création conditionnelle est atomique. Une variable locale au processus, une requête sur l’historique des jobs ou une recherche éventuelle dans les logs n’est pas un verrou de déduplication. Conservez la clé assez longtemps pour couvrir les retries de l’appelant et les rejeux opérateur. Émettez eventId, génération du webhook, résultat de validation, job ID et résultat final, jamais l’URL ni un payload contenant des secrets.
Azure Automation enregistre les paramètres d’entrée du runbook avec le job. Gardez donc toute valeur sensible hors du body et des headers. Si l’opération exige une authentification plus forte de l’appelant, une livraison stateful ou un suivi de job, placez une API authentifiée ou une queue devant le runbook au lieu d’étirer une URL bearer au-delà de son modèle de confiance.
Créer un second webhook sans modifier le premier
Créez un nouveau webhook nommé séparément, lié au même runbook publié, avec les mêmes paramètres fixes et la même cible worker. Définissez une expiration volontaire, alignée sur le cycle de revue et son owner. Capturez l’URI retournée directement dans le secret store approuvé sans l’afficher dans le pipeline.
$webhookParameters = @{
ResourceGroupName = '<resource-group>'
AutomationAccountName = 'aa-platform-prod'
RunbookName = 'Invoke-PlatformRemediation'
Name = 'remediation-prod-v2'
RunOn = 'hybrid-worker-prod'
Parameters = @{ Environment = 'prod'; Mode = 'bounded' }
ExpiryTime = [DateTimeOffset]::UtcNow.AddMonths(12)
IsEnabled = $true
Force = $true
}
$new = New-AzAutomationWebhook @webhookParameters
# Transmettre $new.WebhookURI directement a l'etape de mise a jour du secret.
# Ne pas ecrire l'objet, l'URI ou l'output de deploiement dans les logs. Le second endpoint constitue le mécanisme de rollback. Gardez v1 actif pendant le test de v2, mais n’envoyez pas le trafic normal aux deux à la fois. La fenêtre de coexistence doit avoir un owner, une heure de fin et une surveillance des eventId dupliqués.
Si le webhook existant reste fiable et que seule son expiration pose problème, la repousser avant échéance peut constituer une mesure d’urgence valable. Ce n’est pas une rotation : le credential ne change pas et chaque détenteur inconnu conserve l’accès. N’utilisez cette extension pour éviter la panne qu’avec un remplacement planifié et un horizon court, revu explicitement.
Tester une requête unique par le nouveau chemin
Utilisez un événement synthétique dont la cible est un canari ou dont l’action se réduit à un dry run. La plateforme source doit l’envoyer par la même résolution de secret et le même chemin HTTP que la production. Un curl manuel prouve la joignabilité, pas l’intégration réelle.
Vérifiez quatre enregistrements liés :
- la source a émis un événement avec un
eventIdunique ; - le nouveau webhook l’a accepté et a démarré un seul job Automation ;
- le runbook a consigné validation, déduplication et worker attendu ;
- le canari n’a produit aucun effet de production.
Renvoyez volontairement le même événement. La seconde requête peut démarrer un autre job, car l’endpoint webhook reste un trigger, mais le runbook doit reconnaître le même eventId et sortir avant l’action. Testez aussi un timestamp expiré, une action inconnue et une cible hors périmètre. Une rotation limitée au happy path conserve les modes de panne les plus dangereux.
Basculer une cohorte de consommateurs à la fois
Mettez à jour la plus petite cohorte d’appelants pour référencer la nouvelle version du secret. Observez une fenêtre opérationnelle complète avant de déplacer la suivante. Pendant la coexistence, suivez les requêtes acceptées par génération de webhook et résultat de déduplication.
Pour chaque eventId conserver
systeme source et timestamp de l'evenement
generation du webhook: v1 ou v2
job ID Automation et groupe worker
resultat de validation et de deduplication
action demandee et identifiant de cible borne
resultat de l'effet et validation post-action
Arreter la bascule lorsque
un evenement atteint les deux generations
un appelant ne sait pas quelle version du secret il a chargee
des requetes arrivent sans eventId stable
le runbook consigne une cible ou une action plus large que le contrat Ne déduisez pas la fin de migration du seul LastInvokedTime. Un consommateur peu fréquent peut être sain mais silencieux. Obtenez une confirmation explicite du owner ou un événement contrôlé pour chaque consommateur déclaré avant de révoquer v1.
Désactiver, observer puis supprimer l’ancien webhook
Lorsque tous les consommateurs sont prouvés sur v2, désactivez l’ancien webhook. Cette désactivation est préférable à une suppression immédiate : elle offre une courte fenêtre de rollback explicite sans laisser le credential actif.
$scope = @{
ResourceGroupName = '<resource-group>'
AutomationAccountName = 'aa-platform-prod'
}
Set-AzAutomationWebhook @scope -Name 'remediation-prod-v1' -IsEnabled $false
Get-AzAutomationWebhook @scope -Name 'remediation-prod-v1' |
Select-Object Name, IsEnabled, ExpiryTime, LastInvokedTime Surveillez les échecs de livraison côté source, les démarrages de jobs et l’absence de nouvelles corrélations v1 pendant la fenêtre convenue. Retirez l’ancien secret de chaque consommateur, puis supprimez le webhook désactivé. Si l’URL a été exposée, évitez une longue coexistence : désactivez-la, contenez l’appelant et utilisez un fallback authentifié pendant la validation du nouveau chemin.
Décider validation ou rollback
Validez la rotation lorsque chaque appelant connu utilise v2, que les tests normaux et dupliqués se comportent comme prévu, que l’attribution des jobs est complète et que l’ancien webhook reste inutilisé lorsqu’il est désactivé. Supprimez les diagnostics temporaires, puis enregistrez le owner et l’alerte de prochaine expiration avec la fiche de service.
Le rollback consiste à restaurer la référence appelant vers v1 uniquement tant que ce webhook reste fiable et actif. Rollbackez la configuration de l’appelant, pas le contrat du runbook, puis analysez l’échec de v2. Ne réactivez jamais une URL qui a été remplacée parce qu’elle a fuité. Dans ce cas, le chemin de retour est un déclencheur authentifié séparé ou un nouveau webhook doté d’un nouveau token.
Conclusion
Faire tourner un webhook Azure Automation modifie simultanément un credential et un chemin de livraison. La séquence sûre est : inventorier, durcir le runbook, créer un endpoint parallèle, tester requête normale et doublon, basculer par cohorte, désactiver, observer puis supprimer.
La décision de production repose sur les preuves. Conservez v2 seulement si chaque appelant et chaque événement se corrèlent à un effet borné unique. Rollbackez la référence appelant si le nouveau chemin échoue mais que l’ancien credential reste fiable. Si ownership, déduplication ou attribution manquent, bloquez la rotation avant qu’une coupure silencieuse du trigger ne devienne un rejeu dangereux.