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