Hace unos días estuve jugando con un escenario que es posible que a más de una compañía le pueda afectar, y es que necesiten que las alertas que ocurren dentro de Microsoft Azure tengan que ser enviadas de alguna forma a otro sistema fuera de la nube. En este artículo te cuento cómo configurar Azure Monitor y Automation para este fin.
Hybrid worker groups en Azure Automation
Antes de lanzar ningún script en una máquina ajena a Microsoft Azure, necesitas configurar los que se llaman hybrid worker groups dentro de una cuenta de Azure Automation. Estos grupos son conjuntos de máquinas que serán las encargadas de lanzar los scripts que tú hayas definido desde Azure. Estas máquinas pueden estar en cualquier sitio y lo habitual es tener más de una registrada en cada grupo, con el objetivo de que el mismo sea altamente disponible.

La forma de configurarlo es instalando el agente en tu máquina Linux o Windows, indicando el nombre del grupo (en mi caso lo he llamado Gateway) y que esta esté encendida para poder recibir dichas peticiones.
El script
El siguiente paso es crear un script en PowerShell que capture nuestras futuras alertas. Siempre es recomendable lanzar el mismo primeramente en una de las máquinas que pertenezcan al hybrid worker group, para confirmar que todo funciona correctamente.
param
(
[Parameter (Mandatory=$true)]
[object] $WebhookData
)
# Get the data object from WebhookData
$WebhookBody = (ConvertFrom-Json -InputObject $WebhookData.RequestBody)
#Show the data from the alert
$WebhookBody
#WebHookName
$WebhookName = $WebhookData.WebhookName
Write-Verbose "WebhookName: $WebhookName"
$header
$content = ""
$schemaId = $WebhookBody.schemaId
Write-Verbose "schemaId: $schemaId" -Verbose
if ($schemaId -eq "azureMonitorCommonAlertSchema") {
# This is the common Metric Alert schema (released March 2019)
$Essentials = [object] ($WebhookBody.data).essentials
# Get the first target only as this script doesn't handle multiple
$alertTargetIdArray = (($Essentials.alertTargetIds)[0]).Split("/")
$SubId = ($alertTargetIdArray)[2]
$ResourceGroupName = ($alertTargetIdArray)[4]
$ResourceType = ($alertTargetIdArray)[6] + "/" + ($alertTargetIdArray)[7]
$ResourceName = ($alertTargetIdArray)[-1]
$status = $Essentials.monitorCondition
}
elseif ($schemaId -eq "AzureMonitorMetricAlert") {
# This is the near-real-time Metric Alert schema
$AlertContext = [object] ($WebhookBody.data).context
$SubId = $AlertContext.subscriptionId
$ResourceGroupName = $AlertContext.resourceGroupName
$ResourceType = $AlertContext.resourceType
$ResourceName = $AlertContext.resourceName
$status = ($WebhookBody.data).status
}
elseif ($schemaId -eq "Microsoft.Insights/activityLogs") {
# This is the Activity Log Alert schema
$AlertContext = [object] (($WebhookBody.data).context).activityLog
$SubId = $AlertContext.subscriptionId
$ResourceGroupName = $AlertContext.resourceGroupName
$ResourceType = $AlertContext.resourceType
$ResourceName = (($AlertContext.resourceId).Split("/"))[-1]
$status = ($WebhookBody.data).status
}
elseif ($schemaId -eq $null) {
# This is the original Metric Alert schema
$AlertContext = [object] $WebhookBody.context
$SubId = $AlertContext.subscriptionId
$ResourceGroupName = $AlertContext.resourceGroupName
$ResourceType = $AlertContext.resourceType
$ResourceName = $AlertContext.resourceName
$status = $WebhookBody.status
}
else {
# Schema not supported
Write-Error "The alert data schema - $schemaId - is not supported."
}
Write-Verbose "status: $status" -Verbose
#Create csv header
$header = "Schema Id, Subscription Id, Resource Group Name, Resource Type Name, Status"
#Create content string
$content = "$schemaId"
$content = "$content,$SubId"
$content = "$content,$ResourceGroupName"
$content = "$content,$ResourceType"
$content = "$content,$ResourceName"
$content = "$content,$status"
#Create a file with the data from the alert
$date = Get-Date -UFormat "%m%d%Y%H%M%S"
$date
$fileName = "$WebhookName-$date.csv"
New-Item "c:\runbook\$fileName"
Set-Content "c:\runbook\$fileName" "$header `n $content"
Como puedes ver, estoy recibiendo como parámetro un objeto llamado WebhookData, que será el que tendrá el contenido de la alerta. Las alertas puedes ser de diferentes tipos y puedo saberlo a través del campo schemaId, por lo que compruebo el mismo para determinar de qué tipo es y así saber dónde están los valores que necesito. Una vez que tengo todos campos, para este ejemplo, creo un archivo con formato CSV y lo guardo en la carpeta c:/runbook de la máquina que lanzó el script. Esta última acción podría ser cualquier cosa, pero por simplicidad sólo escribo en un archivo 🙂
Configurar la alerta
Ya tenemos las máquinas que, en teoría, tienen acceso a nuestros sistemas y también tenemos el script que se lanzará cada vez que ocurra alguna alerta. El último paso es configurar una alerta que haga uso de dicho script y que este se ejecute en las máquinas que pertenezcan al grupo híbrido que configuramos al inicio. En este ejemplo voy a utilizar una alerta cualquiera que configuraré en Azure Monitor. Desde el portal accede ahora a Azure Monitor > Alerts y haz clic sobre el botón New alert rule:

Lo primero que debes elegir es a qué recursos afectará dicha alerta y cuál es la métrica que se debe monitorizar.

Una vez que has definido el qué y el cómo, ahora necesitas saber qué acción o acciones quieres llevar a cabo cuando esta situación se de en el futuro. A través del botón Create action group vas a definir la llamada a nuestro runbook.

Como ves, he dado un nombre largo y corto a este grupo y he seleccionado como acción la de tipo Automation Runbook. La parte más importante a configurar viene en Edit Details, en esta misma linea:

Todo este camino ha sido para llegar hasta aquí, donde debes elegir el tipo Runbook source como User, ya que es un script que hemos definido nosotros, elige la cuenta de Azure Automation y selecciona de la lista el nombre que le diste al runbook donde guardaste el script anterior (en mi caso lo he llamado LaunchItOnPremises). En el apartado Configure parameters es importante que selecciones la opción Hybrid Worker y el grupo sobre el cual quieres que se lance el script. Como el objeto WebHookData es obligatorio, necesitas poner algún valor por defecto. Si quieres que el mismo sea vacío inicialmente (aunque siempre que se lance alguna alerta el contenido será los valores de la misma) puedes poner [EmptyString]. Acepta los cambios para guardar la configuración y haz clic en OK en el Action Group que acabas de configurar para terminar de crearlo.
Para finalizar la creación de la alerta, selecciona el nuevo Action group, una vez finalice su creación, elige un nombre para la alerta, el grupo de recursos donde quieres almacenar la misma, así como el tipo de severidad que supone.

Si has configurado todo correctamente, y tus máquinas llegan a tener más de un 80 por cierto de utilización de la CPU, podrás comprobar que la alerta se lanzará, llamará a tu runbook con la información de la misma y esta generará un fichero en la carpeta c:/runbook de la máquina que ha ejecutado el script.

Como te decía, en este ejemplo simplemente copia el contenido de la alerta a un archivo, pero, como te puedes imaginar, esto podría integrarse con cualquier otro sistema que nos propongamos.
¡Saludos!