Estaba hablando con mi amigo Sumit Rai, y me preguntó por cómo podíamos aplicar lo aprendido con mi anterior artículo sobre este tema (Sincronizar usuarios entre AAD y Dataverse (andresbiarge.com)) para sincronizar los usuarios de Azure AD / Microsoft Entra ID de forma "automáticamente proactiva" con un entorno Dataverse en PROD.
Nota:
Note: en el artículo, vimos cómo podemos sincronizar usuarios en masa. Justo antes del Go Live de una aplicación con muchos usuarios. Pero cuando tu aplicación lleve ya un tiempo en funcionamiento, tendrás usuarios que necesitarán ser sincronizados automáticamente para superar cualquier obstáculo de adopción.
Así, acordamos estudiar el asunto por separado y reunirnos cuando hubiéramos llegado a alguna solución. Ambos propusimos dos enfoques diferentes:
Utilizar Microsoft Graph Webhooks para recibir notificaciones cada vez que se asigna un usuario al grupo de seguridad.
Utilizar Microsoft Graph Delta Queries para preguntar por los últimos cambios con una aproximación tipo polling.
La diferencia entre los dos enfoques es la de una arquitectura Polling vs Event-driven.
En este artículo, te mostraré lo que he aprendido probando ambos enfoques.
Venga, basta de cháchara 💪.
Vídeo de acompañamiento en YouTube
He creado este vídeo para que tengas un paso a paso más guiado y donde te muestro cómo testearlo. Échale un vistazo aquí:
Método #1 Usando Microsoft Graph Webhooks
Con este diseño, necesitarás crear un Listener / Webhook para recibir cualquier cambio en el Grupo de Seguridad que protege tu entorno Power Platform. La forma más rápida, barata y sencilla de hacerlo es a través de una Azure Function. Para este ejemplo, decidí que no quería invertir mucho en la seguridad de la Azure Function (certificados/client-secrets/etc.), por lo que la sincronización entre Azure Entra ID y Dataverse se realiza a través de un Power Automate cloud flow.
Documentación que necesitarás
Para comprender mejor este enfoque, te recomiendo que leas los siguientes artículos:
Guía general sobre Webhooks y cuáles son los recursos de Graph que admiten Webhooks: Set up notifications for changes in resource data. - Microsoft Graph | Microsoft Learn
Consideraciones de diseño al implementar Webhooks ("throttling", "handshake" de la suscripción, etc.): Receive change notifications through webhooks - Microsoft Graph | Microsoft Learn
PowerShell Webhook Graph Library: Microsoft.Graph.ChangeNotifications Module | Microsoft Learn
Requisitos previos
Antes de explicar cómo configurar todos los recursos, necesitarás:
Power Platform:
Environment al que le puedas prender fuego sin que nadie se queje.
Securizar el environment con un Security Group.
System Administrator security role para tu usuario.
Poder crear Power Automate cloud flows.
Azure:
Un Security Group del que seas dueño (owner).
Una Azure Function App que puedas reventar sin problemas.
Orden de los pasos
Para que te resulte más fácil reproducir este caso, te recomiendo que sigas este orden:
1. Crear el Power Automate Flow.
2. Crea tu Azure Function (recomendación para rendimiento/consumo: PowerShell sobre Linux).
3. Registrar el Webhook en Microsoft Graph.
Configuración del Webhook
Documentación PowerShell: New-MgSubscription (Microsoft.Graph.ChangeNotifications) | Microsoft Learn
Import-Module Microsoft.Graph.ChangeNotifications
Connect-MgGraph -Scopes "User.Read.All","Group.Read.All"
$params = @{
changeType = "updated"
notificationUrl = "The URL of your Az. Function"
resource = "/groups/{your-group-guid}/members"
expirationDateTime = [System.DateTime]::Parse("<up to 29 days>")
clientState = "<your secret for the Graph subscription>"
}
$newGraphSubscription = New-MgSubscription -BodyParameter $params
$newGraphSubscription
Disconnect-MgGraph
Recibirás una respuesta parecida a la siguiente:
$newGraphSubscription | ConvertTo-Json
Creación de la función Az. Function
Normalmente, mi lenguaje preferido para estas tareas es PowerShell. Es genial y un no brainer para configurarlo en cualquier entorno + se ejecuta en cualquier máquina.
Aquí tienes un snippet / plantilla que puedes usar para probar el Webhook:
using namespace System.Net
param($Request, $TriggerMetadata)
#First, we detect if this is the validation request
if ($Request.Query.validationToken) {
$responseBody = [uri]::UnescapeDataString($Request.Query.validationToken)
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
ContentType = "text/plain"
Body = $responseBody
})
}else {
#else,means we got the actual message
foreach ($groupChange in $Request.Body.value) {
if (-not $groupChange.resourceData."members@delta"."@removed") {
#only call Flow when it's a new user.
$webRequestParams = @{
Uri = "<the URL of your HTTP triggered Power Automate Flow>"
Method = "Post"
ContentType = "application/json"
Body = [PSCustomObject]@{
clientState = "$($groupChange.clientState)";
newUserId = "$($groupChange.resourceData."members@delta".id)";
} | ConvertTo-Json
}
Invoke-WebRequest @webRequestParams
}
}
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
ContentType = "text/plain"
Body = "Ok"
})
}
⚠¡Ojo!⚠: Cuidado con el ciclo de vida de los Webhooks
Los webhooks configurados para recibir notificaciones del segmento /groups sólo viven durante 29 días como máximo. Puedes comprobar este límite directamente desde la documentación aquí: subscription resource type - Microsoft Graph v1.0 | Microsoft Learn
Esto significa que tendrá que establecer un proceso para renovar la suscripción: Receive change notifications through webhooks - Microsoft Graph | Microsoft Learn
Son 5 líneas con PowerShell:
Import-Module Microsoft.Graph.ChangeNotifications
$params = @{
expirationDateTime = [System.DateTime]::Parse("<your next renewal datetime>")
}
Update-MgSubscription -SubscriptionId $subscriptionId -BodyParameter $params
Approach #2 Usando Microsoft Graph Delta Queries
Con este patrón, estarás preguntando a Microsoft Graph por cambios en el segmento /groups del Graph API con un patrón tipo polling. Bravo aquí, Microsoft, porque la forma en que está diseñado es muy práctico:
Primero, tendrás que realizar una primera petición al endpoint /delta Graph API en el segmento /groups. Tendrás que utilizar un filtro OData para obtener la información del grupo o grupos que te interesen.
Graph responderá con los cambios (miembros añadidos o eliminados). Debido a las capacidades de paginación de Graph, tendrás que implementar una lógica de "follow through": cada vez que veas un "@odata.nextLink", utiliza ese valor para realizar la siguiente petición de forma recursiva.
Cuando veas que la respuesta de Graph ya no incluye un "@odata.nextLink", verás un "@odata.deltaLink". Guarda este valor en un almacenamiento persistente (por ejemplo, una tabla Dataverse). Este enlace es el que tendrás que utilizar la próxima vez que quieras obtener los cambios en el grupo o grupos de seguridad. Este "@odata.deltaLink" almacena el estado actual en el que lo dejaste, por lo que continuar desde ahí te asegurará obtener los últimos cambios reales en el recurso.
Una posible solución aquí es que configures un Power Automate cloud flow recurrente que realice esta lógica de sondeo con el "@odata.deltaLink" cada día a las 5 AM.
Puedes ver la implementación en vivo en mi vídeo complementario de YouTube.
Consideraciones a nivel Enterprise
Estas dos soluciones son perfectas para un único entorno en PROD. Pero, ¿qué pasa cuando queremos crear una solución más escalable que funcione para empresas con varias grandes soluciones que ya están en PROD?
Mi amigo Sumit y yo estuvimos discutiendo posibles soluciones para eso y llegamos a la conclusión de que usar un Azure Event Hub sería una muy buena solución. Por supuesto, este un enfoque recomendado por Microsoft: Receive change notifications through Azure Event Hubs - Microsoft Graph | Microsoft Learn.
Conclusión
Espero que el planteamiento del problema y la solución te hayan resultado útiles. He intentado explicar cómo abordar la sincronización automática y proactiva entre los nuevos miembros de un grupo de seguridad Azure Entra ID (el viejo Azure Active Directory) en un entorno Dataverse.
Por favor, escribe tus comentarios, preguntas y peticiones de nuevo contenido en la sección de comentarios que encontrarás más abajo. Asegúrate también de ver el vídeo complementario de YouTube y el resto del contenido que estoy intentando recopilar para ti tanto en mi blog como en mi canal de YouTube.
¡Nos vemos! 💪
Andrés
Comments