Compartir a través de


Tutorial: Informes personalizados en Azure Data Explorer (ADX) mediante datos de Microsoft Entra ID

En este tutorial, aprenderá a crear informes personalizados en Azure Data Explorer (ADX) mediante datos de Microsoft Entra ID. Este tutorial complementa otras opciones de informes como Archive & report con Azure Monitor y la administración de derechos, que se centra en exportar datos de registro de auditoría para una retención y análisis más largos. En comparación, la exportación de datos de Id. de Entra de Microsoft a Azure Data Explorer proporciona una mayor flexibilidad para crear informes personalizados al permitir la agregación de datos de varios orígenes con escalabilidad masiva y directivas de esquema y retención flexibles.

En este informe se muestra cómo mostrar los derechos de configuración, usuarios y acceso exportados desde Microsoft Entra junto con los datos exportados desde otros orígenes, como las aplicaciones con bases de datos SQL. A continuación, puede usar el lenguaje de consulta kusto (KQL) para crear informes personalizados en función de los requisitos de la organización. La generación de estos tipos de informes en Azure Data Explorer puede resultar especialmente útil si necesita conservar los datos de acceso durante períodos más largos, realizar investigaciones ad hoc o ejecutar consultas personalizadas en datos de acceso de usuario.

Realizará los pasos siguientes para crear estos informes:

  1. Configure Azure Data Explorer en una suscripción de Azure.
  2. Extraiga datos de bases de datos o aplicaciones de Microsoft Entra y de terceros mediante scripts de PowerShell y MS Graph.
  3. Importe los datos en Azure Data Explorer, un servicio de análisis de datos rápido y escalable.
  4. Cree una consulta personalizada mediante el lenguaje de consulta Kusto.

Al final de este tutorial, habrá creado aptitudes para desarrollar vistas personalizadas de los derechos de acceso y los permisos de los usuarios en distintas aplicaciones mediante herramientas compatibles con Microsoft.

Requisitos previos

  • Asegúrese de que tiene los permisos necesarios. Necesitará los permisos adecuados para exportar el tipo de datos entra con los que desea trabajar y los permisos para guardar los archivos JSON exportados.

    • Datos de usuario: Administrador global, Administrador de funciones privilegiadas, Administrador de usuarios
    • Datos de grupos: Administrador global, Administrador de roles con privilegios, Administrador de grupos
    • Aplicaciones/Asignación de roles: Administrador global, Administrador de roles privilegiados, Administrador de aplicaciones, Administrador de aplicaciones en la nube
  • PowerShell debe establecerse para permitir User.Read.All, Group.Read.All, Application.Read.All y Directory.Read.All. Consulte Referencia de permisos de Microsoft Graph para obtener más información.

  • Asegúrese de que tiene acceso de escritura al directorio donde instalará los módulos de PowerShell de MS Graph necesarios y dónde se guardarán los datos entra exportados.

  • Determine qué datos desea incluir en los informes. Los scripts de este artículo proporcionan ejemplos con datos específicos de usuarios, grupos y aplicaciones de Entra. Estos ejemplos están diseñados para ilustrar los tipos de informes que puede generar con este enfoque, pero sus necesidades de informes específicas pueden variar y requerir datos diferentes o adicionales.

Paso 1: Configuración de Azure Data Explorer

Si no ha usado anteriormente Azure Data Explorer, primero deberá configurarlo. Puede crear un clúster gratuito sin una suscripción de Azure o una tarjeta de crédito o un clúster completo que requiera una suscripción de Azure. Consulte Inicio rápido: Cree un clúster y una base de datos Azure Data Explorer para empezar.

Paso 2: Conexión a MS Graph y extracción de datos entra con PowerShell

Instale los módulos de PowerShell de MS Graph y Conéctese a MS Graph.

  1. Instale los módulos de MS Graph necesarios. Los siguientes módulos son necesarios para este tutorial: Microsoft.Graph.Users, Microsoft.Graph.Groups, Microsoft.Graph.Applications, Microsoft.Graph.DirectoryObjects
   $modules = @('Microsoft.Graph.Users', 'Microsoft.Graph.Groups', 'Microsoft.Graph.Applications', 'Microsoft.Graph.DirectoryObjects') 
   foreach ($module in $modules) { 
   Install-Module -Name $module -Scope CurrentUser -AllowClobber -Force
   } 
  1. Importe los módulos:
  $modules = @('Microsoft.Graph.Users', 'Microsoft.Graph.Groups', 'Microsoft.Graph.Applications', 'Microsoft.Graph.DirectoryObjects') 
  foreach ($module in $modules) { 
  Import-Module -Name $module 
  } 
  1. Conexión con Microsoft Graph
  Connect-MgGraph -Scopes "User.Read.All", "Group.Read.All", "Application.Read.All", "Directory.Read.All" 

Este comando le pedirá que inicie sesión con las credenciales de MS Graph. Seleccione Permisos necesarios: después de iniciar sesión, es posible que tenga que dar su consentimiento a los permisos necesarios si es la primera vez que se conecta o si se requieren nuevos permisos.

Consultas de PowerShell para extraer datos necesarios para crear informes personalizados en ADX

Las siguientes consultas extraen datos entra de MS Graph mediante PowerShell y exportan los datos a archivos JSON que se importarán en Azure Data Explorer en el paso 3. Puede haber varios escenarios para generar informes con este tipo de datos:

  • Un auditor desea ver un informe que enumera los miembros del grupo para 10 grupos, organizados por el departamento de los miembros.
  • Un auditor desea ver un informe de todos los usuarios que tenían acceso a una aplicación entre dos fechas.
  • Un administrador desea ver todos los usuarios agregados a una aplicación de Microsoft Entra ID y bases de datos SQL.

Estos tipos de informes no están integrados en el identificador de Microsoft Entra, pero puede crear estos informes usted mismo extrayendo datos de Entra y combinándolos mediante consultas personalizadas en Azure Data Explorer.

En este tutorial, extraeremos datos de Entra de varias áreas:

  • Información del usuario, como el nombre para mostrar, el UPN y los detalles del trabajo
  • Información del grupo
  • Asignaciones de aplicaciones y roles

Este conjunto de datos nos permitirá realizar un amplio conjunto de consultas en torno a quién se le ha concedido acceso a una aplicación, información de roles y el período de tiempo asociado. Tenga en cuenta que se trata de consultas de ejemplo y los datos y requisitos específicos pueden variar de lo que se muestra aquí.

Nota:

Los inquilinos más grandes pueden experimentar errores de limitación o 429 que controlará el módulo de MS Graph.

En estos scripts de PowerShell, exportaremos las propiedades seleccionadas de los objetos Entra a archivos JSON. Los datos de estas propiedades exportadas se usarán para generar informes personalizados en Azure Data Explorer. Las propiedades específicas siguientes se incluyeron en estos ejemplos, ya que usamos estos datos para ilustrar los tipos de informes que puede crear en Azure Data Explorer. Dado que es probable que sus necesidades de informes específicas variarán de lo que se muestra a continuación, debe incluir las propiedades específicas en estos scripts que le interesan ver en los informes, pero puede seguir el mismo patrón que se muestra a continuación para ayudar a compilar los scripts.

También hemos incluido una fecha de instantánea codificada de forma rígida a continuación que identifica los datos del archivo JSON con una fecha específica y nos permitirá realizar un seguimiento de conjuntos de datos similares a lo largo del tiempo en Azure Data Explorer. La fecha de instantánea también es útil para comparar los cambios en los datos entre dos fechas de instantáneas.

Obtención de datos de usuario de Entra

Este script exportará las propiedades seleccionadas del objeto de usuario Entra a un archivo JSON. Importaremos estos datos en Azure Data Explorer en el paso 3.

  function Export-EntraUsersToJson { 

  # Define a hash table for property mappings 
   $propertyMappings = @{ 
    "Id" = "ObjectID" 
    "DisplayName" = "DisplayName" 
    "UserPrincipalName" = "UserPrincipalName" 
    "EmployeeId" = "EmployeeId" 
    "UserType" = "UserType" 
    "CreatedDateTime" = "CreatedDateTime" 
    "JobTitle" = "JobTitle" 
    "Department" = "Department" 
    "AccountEnabled" = "AccountEnabled" 

   # Add custom properties as needed 
    "custom_extension" = "CustomExtension" 
   } 
  # Retrieve users with specified properties and create custom objects directly 
   $users = Get-MgUser -Select ($propertyMappings.Keys) -All | ForEach-Object { 
      $userObject = @{} 
      foreach ($key in $propertyMappings.Keys) { 
        if ($key -eq "CreatedDateTime") { 
          # Convert date string directly to DateTime and format it 
          $date = [datetime]::Parse($_.$key) 
          $userObject[$propertyMappings[$key]] = $date.ToString("yyyy-MM-dd") 
        } else { 
          $userObject[$propertyMappings[$key]] = $_.$key 
        } 
      } 
      # Additional properties or transformations 
      $userObject["SnapshotDate"] = "2024-01-11" 
      [pscustomobject]$userObject 
    } 
    # Convert the user data to JSON and save it to a file 
    $users | ConvertTo-Json -Depth 2 | Set-Content ".\EntraUsers.json" 
  } 
  # Execute the function 
  Export-EntraUsersToJson 

Obtener datos de grupo

Genere un archivo JSON con nombres de grupo e identificadores que se usarán para crear vistas personalizadas en ADX. El ejemplo incluirá todos los grupos, pero se puede incluir un filtrado adicional si es necesario. Si va a filtrar para incluir solo determinados grupos, es posible que quiera incluir lógica en el script para comprobar si hay grupos anidados.

    # Get all groups and select Id and DisplayName 
    $groups = Get-MgGroup -All | Select-Object Id,DisplayName 
    # Export the groups to a JSON file 
    $groups | ConvertTo-Json | Set-Content ".\EntraGroups.json" 

Obtener datos de pertenencia de grupo

Genere un archivo JSON con pertenencia a grupos que se usará para crear vistas personalizadas en ADX.

    # Retrieve all groups from Microsoft Entra (Azure AD) 
    $groups = Get-MgGroup -All 
    # Initialize an array to store results 
    $results = @() 
    # Iterate over each group 
    foreach ($group in $groups) { 
      # Extract the group ID 
      $groupId = $group.Id 
      # Get members of the current group and select their IDs 
      $members = Get-MgGroupMember -GroupId $groupId | Select-Object -ExpandProperty Id 
      # Add a custom object with group ID and member IDs to the results array 
      $results += [PSCustomObject]@{ 
        GroupId = $groupId 
        Members = $members 
      } 
      # Pause for a short time to avoid rate limits 
      Start-Sleep -Milliseconds 200 
    } 
    # Convert the results array to JSON format and save it to a file 
    $results | ConvertTo-Json | Set-Content "EntraGroupMembership.json" 

Obtener datos de aplicación y entidad de servicio principal

Genera un archivo JSON con todas las aplicaciones y las entidades de servicio correspondientes en el inquilino. Importaremos estos datos en ADX en el paso 3, lo que nos permitirá generar informes personalizados relacionados con aplicaciones basadas en estos datos.

    # Fetch applications and their corresponding service principals, then export to JSON 
    Get-MgApplication -All | ForEach-Object { 
      $app = $_ 
      $sp = Get-MgServicePrincipal -Filter "appId eq '$($app.AppId)'" 
      [pscustomobject]@{ 
        Name        = $app.DisplayName 
        ApplicationId   = $app.AppId 
        ServicePrincipalId = $sp.Id 
      } 
    } | ConvertTo-Json -Depth 10 | Set-Content "Applications.json" 

Obtención de datos de AppRole

Genere un archivo JSON de todas las aplicaciones appRoles para empresas en Entra. Una vez importados a ADX, usaremos estos datos para generar informes que impliquen asignaciones de roles de aplicación para los usuarios.

    # Get a list of all applications, handle pagination manually if necessary 
    $apps = Get-MgApplication -All 
    # Loop through each application to gather the desired information 
    $results = foreach ($app in $apps) { 
      # Get the service principal for the application using its appId 
      $spFilter = "appId eq '$($app.AppId)'" 
      $sp = Get-MgServicePrincipal -Filter $spFilter | Select-Object -First 1 
      # Process AppRoles, if any, for the application 
      $appRoles = if ($app.AppRoles) { 
        $app.AppRoles | Where-Object { $_.AllowedMemberTypes -contains "User" } | 
        Select-Object Id, Value, DisplayName 
      } 
      # Construct a custom object with application and service principal details 
      [PSCustomObject]@{ 
        ApplicationId    = $app.AppId 
        DisplayName     = $app.DisplayName 
        ServicePrincipalId = $sp.Id 
        AppRoles      = $appRoles 
      } 
    } 
    # Export the results to a JSON file 
    $results | ConvertTo-Json -Depth 4 | Out-File 'AppRoles.json' 

Obtención de datos de asignación de AppRole

Genere un archivo JSON de todas las asignaciones de roles de aplicación en el inquilino.

    $users = Get-MgUser -All 
    $result = @() 
    foreach ($user in $users) { 
      Get-MgUserAppRoleAssignment -UserId $user.Id | ForEach-Object { 
        # Use the same date formatting approach 
        $createdDateTime = $_.CreatedDateTime -replace "\\/Date\((\d+)\)\\/", '$1' 
        # Convert the milliseconds timestamp to a readable date format if needed 
        $result += [PSCustomObject]@{ 
          AppRoleId      = $_.AppRoleId 
          CreatedDateTime   = $createdDateTime 
          PrincipalDisplayName = $_.PrincipalDisplayName 
          PrincipalId     = $_.PrincipalId 
          ResourceDisplayName = $_.ResourceDisplayName 
          ResourceId      = $_.ResourceId 
          SnapshotDate     = "2024-03-13" # Hard-coded date 
        } 
      } 
    } 
    $result | ConvertTo-Json -Depth 10 | Out-File "AppRoleAssignments.json" 

Paso 3: Importación de datos de archivos JSON en Azure Data Explorer

En el paso 3, importaremos los archivos JSON recién creados para su posterior análisis. Si aún no ha configurado Azure Data Explorer, consulte el paso 1 anterior.

Azure Data Explorer es una eficaz herramienta de análisis de datos que es altamente escalable y flexible, lo que proporciona un entorno ideal para generar informes de acceso de usuarios personalizados. ADX utiliza el lenguaje de consulta Kusto (KQL).

Una vez que haya configurado una base de datos, siga estos pasos para obtener los datos exportados a ADX.

  1. Haga clic con el botón derecho en el nombre de la base de datos y elija Obtener datos
  2. Elija Nueva tabla y escriba el nombre del archivo JSON que va a importar, por ejemplo, si va a importar EntraUsers.json, asigne el nombre EntraUsers a la tabla. Después de la primera importación, la tabla ya existirá y puede seleccionarla como tabla de destino para la importación.
  3. Seleccione el archivo JSON.
  4. ADX detectará automáticamente el esquema y proporcionará una vista previa. Haga clic en Finalizar para crear la tabla e importar los datos.
  5. Siga los pasos del 1 al 4 para cada uno de los archivos JSON que generó en el paso 1.

Paso 4: Uso de ADX para compilar informes personalizados

Con los datos disponibles ahora en ADX, está listo para empezar a crear informes personalizados en función de sus requisitos empresariales. Las siguientes consultas proporcionan ejemplos de informes comunes, pero puede personalizar estos informes para satisfacer sus necesidades y crear informes adicionales.

Ejemplo 1: Generación de asignaciones de roles de aplicación para asignaciones directas y de grupo para una fecha de instantánea específica

Este informe proporciona una vista de quién tenía el acceso y cuándo a la aplicación de destino y se puede usar para auditorías de seguridad, comprobación de cumplimiento y comprensión de los patrones de acceso dentro de la organización.

Esta consulta tiene como destino una aplicación específica dentro de Entra AD y analiza las asignaciones de roles a partir de una fecha determinada. La consulta recupera asignaciones de roles directas y basadas en grupos, combinando estos datos con detalles de usuario de la tabla EntraUsers e información de roles de la tabla AppRoles.

/// Define constants 
let targetServicePrincipalId = "<your service principal-id>"; // Target Service Principal ID 
let targetSnapshotDate = datetime("2024-01-13"); // Target Snapshot Date for the data 

// Extract role assignments for the target Service Principal and Snapshot Date 
let roleAssignments = AppRoleAssignments 
    | where ResourceId == targetServicePrincipalId and startofday(SnapshotDate) == targetSnapshotDate 
    | extend AppRoleIdStr = tostring(AppRoleId); // Convert AppRoleId to string for easier comparison 

// Prepare user data from EntraUsers table 
let users = EntraUsers 
    | project ObjectID, UserPrincipalName, DisplayName, ObjectIDStr = tostring(ObjectID); // Include ObjectID as string for joining 

// Prepare role data from AppRoles table 
let roles = AppRoles 
    | mvexpand AppRoles // Expand AppRoles to handle multiple roles 
    | extend RoleName = AppRoles.DisplayName, RoleId = tostring(AppRoles.Id) // Extract Role Name and ID 
    | project RoleId, RoleName; 
// Process direct assignments 
let directAssignments = roleAssignments 
    | join kind=inner users on $left.PrincipalId == $right.ObjectID // Join with EntraUsers on PrincipalId 
    | join kind=inner roles on $left.AppRoleIdStr == $right.RoleId // Join with roles to get Role Names 
    | project UserPrincipalName, DisplayName, CreatedDateTime, RoleName, AssignmentType = "Direct", SnapshotDate; 

// Process group-based assignments 

let groupAssignments = roleAssignments 
    | join kind=inner EntraGroupMembership on $left.PrincipalId == $right.GroupId // Join with Group Membership 
    | mvexpand Members // Expand group members 
    | extend MembersStr = tostring(Members) // Convert member ID to string 
    | distinct MembersStr, CreatedDateTime, AppRoleIdStr, SnapshotDate // Get distinct values 
    | join kind=inner users on $left.MembersStr == $right.ObjectIDStr // Join with EntraUsers for user details 
    | join kind=inner roles on $left.AppRoleIdStr == $right.RoleId // Join with roles for role names 
    | project UserPrincipalName, DisplayName, CreatedDateTime, RoleName, AssignmentType = "Group", SnapshotDate; 

// Combine results from direct and group-based assignments 
directAssignments 
| union groupAssignments 

Ejemplo 2: Creación de un informe de auditoría básico con datos entra que muestran quién tenía acceso a una aplicación entre estas dos fechas

Este informe proporciona una vista de quién tenía el acceso a la aplicación de destino entre dos fechas y se puede usar para auditorías de seguridad, comprobación de cumplimiento y comprensión de los patrones de acceso dentro de la organización.

Esta consulta tiene como destino una aplicación específica dentro del identificador de Microsoft Entra y analiza las asignaciones de roles entre dos fechas. La consulta recupera asignaciones de roles directas de la tabla AppRoleAssignments y combina estos datos con los detalles del usuario de la tabla EntraUsers y la información de roles de la tabla AppRoles.

// Set the date range and service principal ID for the query 
let startDate = datetime('2024-01-01'); 
let endDate = datetime('2024-03-14'); 
let servicePrincipalId = "<your service principal-id>"; 

// Query AppRoleAssignments for the specified service principal within the date range 
AppRoleAssignments 
| where ResourceId == servicePrincipalId and 
    todatetime(CreatedDateTime) between (startDate .. endDate) 

// Extend AppRoleId to a string for joining 
| extend AppRoleIdStr = tostring(AppRoleId) 

// Project the necessary fields for the join with EntraUsers and AppRoles 
| project PrincipalId, AppRoleIdStr, CreatedDateTime 

// Join with EntraUsers to get user details 
| join kind=inner (EntraUsers | project UserPrincipalName, DisplayName, ObjectID) on $left.PrincipalId == $right.ObjectID 

// Join with AppRoles to get the role display names 
| join kind=inner ( 
  AppRoles | mvexpand AppRoles | project RoleIdStr = tostring(AppRoles.Id), RoleDisplayName = tostring(AppRoles.DisplayName) 
) on $left.AppRoleIdStr == $right.RoleIdStr 

// Final projection of the report with the current date and time 
| project UserPrincipalName, DisplayName, RoleDisplayName, CreatedDateTime, ReportDate = now() 

Ejemplo 3: Obtención de usuarios agregados a una aplicación entre dos fechas de instantánea de datos

Estos informes proporcionan una vista de los usuarios a los que se les ha asignado una asignación de roles de aplicación a la aplicación de destino entre dos fechas. Estos informes se pueden usar para realizar un seguimiento de los cambios en el acceso a la aplicación a lo largo del tiempo.

Esta consulta tiene como destino una aplicación específica dentro del identificador de Entra de Microsoft y cambia a las asignaciones de roles entre una fecha de inicio y finalización.

// Define the date range and service principal ID for the query 

let startDate = datetime("2024-03-01"); 
let endDate = datetime("2024-03-14"); 
let servicePrincipalId = "<your service principal-id>"; 
let earlierDate = startDate; // Update this to your specific earlier date 

AppRoleAssignments 
| where SnapshotDate < endDate and ResourceId == servicePrincipalId
| project PrincipalId, AppRoleId2 = tostring(AppRoleId), CreatedDateTime 
| join kind=anti ( 
    AppRoleAssignments 
    | where SnapshotDate < earlierDate and ResourceId == servicePrincipalId 
    | project PrincipalId, AppRoleId1 = tostring(AppRoleId) 
) on PrincipalId 
| join kind=inner (EntraUsers) on $left.PrincipalId == $right.ObjectID 
| join kind=inner (AppRoles 
                   | mvexpand AppRoles 
                   | project AppRoleId=tostring(AppRoles.Id), RoleDisplayName=tostring(AppRoles.DisplayName) 
                  ) on $left.AppRoleId2 == $right.AppRoleId 
| project UserPrincipalName, DisplayName, RoleDisplayName, CreatedDateTime, PrincipalId, Change = "Added" 

Ejemplo 4: Combinar asignaciones de aplicaciones de un Entra y un segundo origen (por ejemplo, exportación de SQL) para crear un informe de todos los usuarios (asignaciones entra y asignaciones locales) que tenían acceso a Salesforce entre dos fechas

En este informe se muestra cómo puede combinar datos de dos sistemas independientes para crear informes personalizados en ADX. Agrega datos sobre los usuarios, sus roles y otros atributos de dos sistemas en un formato unificado para el análisis o los informes.

// Define the date range and service principal ID for the query 

let startDate = datetime("2023-06-01"); 
let endDate = datetime("2024-03-13"); 
let servicePrincipalId = "<your service principal-id>"; 

// Pre-process AppRoleAssignments with specific filters and projections 
let processedAppRoleAssignments = AppRoleAssignments 
    | where ResourceId == servicePrincipalId and todatetime(CreatedDateTime) between (startDate .. endDate) 
    | extend AppRoleId = tostring(AppRoleId) 
    | project PrincipalId, AppRoleId, CreatedDateTime, ResourceDisplayName; // Exclude DeletedDateTime and keep ResourceDisplayName 

// Pre-process AppRoles to get RoleDisplayName for each role 
let processedAppRoles = AppRoles 
    | mvexpand AppRoles 
    | project AppRoleId = tostring(AppRoles.Id), RoleDisplayName = tostring(AppRoles.DisplayName); 

// Main query: Process EntraUsers by joining with processed role assignments and roles 
EntraUsers 
    | join kind=inner processedAppRoleAssignments on $left.ObjectID == $right.PrincipalId // Join with role assignments 
    | join kind=inner processedAppRoles on $left.AppRoleId == $right.AppRoleId // Join with roles to get display names 

    // Summarize to get the latest record for each unique combination of user and role attributes 
    | summarize arg_max(AccountEnabled, *) by UserPrincipalName, DisplayName, tostring(EmployeeId), Department, JobTitle, ResourceDisplayName, RoleDisplayName, CreatedDateTime 

    // Final projection of relevant fields including source indicator and report date 
    | project UserPrincipalName, DisplayName, EmployeeId=tostring(EmployeeId), Department, JobTitle, AccountEnabled=tostring(AccountEnabled), ResourceDisplayName, RoleDisplayName, CreatedDateTime, Source="EntraUsers", ReportDate = now() 

// Union with processed salesforceAssignments to create a combined report 
| union ( 
    salesforceAssignments 

    // Project fields from salesforceAssignments to align with the EntraUsers data structure 
    | project UserPrincipalName = UserName, DisplayName = Name, EmployeeId = tostring(EmployeeId), Department, JobTitle, AccountEnabled = "N/A", ResourceDisplayName = AppName, RoleDisplayName = Role, CreatedDateTime, Source = "salesforceAssignments", ReportDate = now() 
) 

Pasos siguientes