Руководство. Настраиваемые отчеты в Azure Data Explorer (ADX) с помощью данных из идентификатора Microsoft Entra
Из этого руководства вы узнаете, как создавать настраиваемые отчеты в Azure Data Explorer (ADX) с помощью данных из идентификатора Microsoft Entra. В этом руководстве дополняются другие варианты создания отчетов, такие как архив и отчет с помощью Azure Monitor и управления правами, которые сосредоточены на экспорте данных журнала аудита для более длительного хранения и анализа. Для сравнения экспорт данных Идентификатора Microsoft Entra в Azure Data Explorer обеспечивает большую гибкость для создания пользовательских отчетов, позволяя агрегировать данные из нескольких источников с массовой масштабируемостью, а также гибкими политиками схемы и хранения.
В этом отчете показано, как показать конфигурацию, пользователей и права доступа, экспортированные из Microsoft Entra вместе с данными, экспортируемыми из других источников, например приложениями с базами данных SQL. Затем можно использовать язык запросов Kusto (KQL) для создания пользовательских отчетов на основе требований вашей организации. Создание этих типов отчетов в Azure Data Explorer может быть особенно полезным, если требуется хранить данные доступа в течение длительного периода, выполнять нерегламентированные исследования или выполнять пользовательские запросы к данным доступа пользователей.
Чтобы создать эти отчеты, сделайте следующее:
- Настройте Azure Data Explorer в подписке Azure.
- Извлеките данные из microsoft Entra и сторонних баз данных или приложений с помощью скриптов PowerShell и MS Graph.
- Импортируйте данные в Azure Data Explorer, быструю и масштабируемую службу аналитики данных.
- Создание пользовательского запроса с помощью язык запросов Kusto.
В конце этого руководства вы создадите навыки для разработки настраиваемых представлений прав доступа и разрешений пользователей в разных приложениях с помощью поддерживаемых корпорацией Майкрософт средств.
Необходимые компоненты
Убедитесь, что у вас есть необходимые разрешения. Вам потребуются правильные разрешения для экспорта типов данных Entra, с которыми вы хотите работать, и разрешения для сохранения экспортированных JSON-файлов.
- Пользовательские данные: глобальный администратор, администратор привилегированных ролей, администратор пользователей
- Группы данных: глобальный администратор, администратор привилегированных ролей, администратор группы
- Назначения ролей приложений и приложений: глобальный администратор, администратор привилегированных ролей, администратор приложений, администратор облачных приложений
Для Параметра PowerShell необходимо задать разрешение user.Read.All, Group.Read.All, Application.Read.All и Directory.Read.All. Дополнительные сведения см . в справочнике по разрешениям Microsoft Graph.
Убедитесь, что у вас есть доступ на запись к каталогу, в котором будут установлены необходимые модули MS Graph PowerShell и где будут сохранены экспортированные данные Entra.
Определите, какие данные необходимо включить в отчеты. Скрипты в этой статье содержат примеры с определенными данными пользователей, групп и приложений из Entra. Эти примеры предназначены для иллюстрации типов отчетов, которые можно создать с помощью этого подхода, но конкретные потребности отчетов могут отличаться и требовать разные или дополнительные данные.
Шаг 1. Настройка Azure Data Explorer
Если вы ранее не использовали Azure Data Explorer, сначала необходимо настроить его. Вы можете создать бесплатный кластер без подписки Azure или кредитной карты или полного кластера, для которого требуется подписка Azure. См . краткое руководство. Создание кластера и базы данных Azure Data Explorer для начала работы.
Шаг 2. Подключение к MS Graph и извлечение данных Entra с помощью PowerShell
Установите модули PowerShell MS Graph и подключитесь к MS Graph.
- Установите необходимые модули MS Graph. Для работы с этим руководством требуются следующие модули: 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
}
- Импорт модулей:
$modules = @('Microsoft.Graph.Users', 'Microsoft.Graph.Groups', 'Microsoft.Graph.Applications', 'Microsoft.Graph.DirectoryObjects')
foreach ($module in $modules) {
Import-Module -Name $module
}
- Подключение к Microsoft Graph
Connect-MgGraph -Scopes "User.Read.All", "Group.Read.All", "Application.Read.All", "Directory.Read.All"
Эта команда предложит выполнить вход с помощью учетных данных MS Graph. Выберите необходимые разрешения. После входа может потребоваться согласие на необходимые разрешения, если это первый раз подключения или если требуются новые разрешения.
Запросы PowerShell для извлечения данных, необходимых для создания пользовательских отчетов в ADX
Следующие запросы извлекают данные Entra из MS Graph с помощью PowerShell и экспортируют данные в JSON-файлы, которые будут импортированы в Azure Data Explorer на шаге 3. Существует несколько сценариев для создания отчетов с этим типом данных:
- Аудитор хотел бы просмотреть отчет, который содержит список участников группы для 10 групп, организованных отделом участников.
- Аудитор хотел бы просмотреть отчет всех пользователей, имеющих доступ к приложению между двумя датами.
- Администратор хотел бы просмотреть все пользователи, добавленные в приложение из идентификатора Microsoft Entra и баз данных SQL.
Эти типы отчетов не встроены в идентификатор Microsoft Entra ID, но вы можете создавать эти отчеты самостоятельно, извлекая данные из Entra и объединяя их с помощью пользовательских запросов в Azure Data Explorer.
В этом руководстве мы извлеким данные Entra из нескольких областей:
- Сведения о пользователе, такие как отображаемое имя, имя участника-пользователя и сведения о задании
- Сведения о группе
- Назначения приложений и ролей
Этот набор данных позволит нам выполнять широкий набор запросов вокруг того, кто получил доступ к приложению, сведениям о роли и связанным временным интервалам. Обратите внимание, что это примеры запросов, и данные и конкретные требования могут отличаться от того, что показано здесь.
Примечание.
Крупные клиенты могут столкнуться с ошибками регулирования или 429, которые будут обрабатываться модулем MS Graph.
В этих сценариях PowerShell мы экспортируем выбранные свойства из объектов Entra в JSON-файлы. Затем данные из этих экспортированных свойств будут использоваться для создания пользовательских отчетов в Azure Data Explorer. Приведенные ниже свойства были включены в эти примеры, так как мы используем эти данные для иллюстрации типов отчетов, которые можно создать в Azure Data Explorer. Так как ваши конкретные потребности в отчетах, скорее всего, будут отличаться от того, что показано ниже, следует включить в эти скрипты определенные свойства, которые вы хотите просмотреть в отчетах, однако вы можете следовать той же схеме, как показано ниже, чтобы помочь создать скрипты.
Мы также включили жестко закодированную дату моментального снимка ниже, которая определяет данные в JSON-файле с определенной датой и позволяет отслеживать аналогичные наборы данных с течением времени в Azure Data Explorer. Дата моментального снимка также полезна для сравнения изменений данных между двумя датами моментального снимка.
Получение данных пользователя Entra
Этот скрипт экспортирует выбранные свойства из объекта пользователя Entra в JSON-файл. Мы импортируем эти данные в Azure Data Explorer на шаге 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
Получение данных группы
Создайте JSON-файл с именами групп и идентификаторами, которые будут использоваться для создания пользовательских представлений в ADX. В этом примере будут включены все группы, но при необходимости можно включить дополнительную фильтрацию. Если вы фильтруете только определенные группы, может потребоваться включить логику в скрипт, чтобы проверить наличие вложенных групп.
# 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"
Получение данных о членстве в группах
Создайте JSON-файл с членством в группах, который будет использоваться для создания пользовательских представлений в 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"
Получение данных приложения и субъекта-службы
Создает JSON-файл со всеми приложениями и соответствующими субъектами-службами в клиенте. Мы импортируем эти данные в ADX на шаге 3, что позволит нам создавать пользовательские отчеты, связанные с приложениями на основе этих данных.
# 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"
Получение данных AppRole
Создайте JSON-файл всех приложений AppRoles для корпоративных приложений в Entra. После импорта в ADX эти данные будут использоваться для создания отчетов с участием назначений ролей приложения для пользователей.
# 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'
Получение данных о назначении appRole
Создайте JSON-файл всех назначений ролей приложения в клиенте.
$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"
Шаг 3. Импорт данных JSON-файла в Azure Data Explorer
На шаге 3 мы импортируем только что созданные JSON-файлы для дальнейшего анализа. Если вы еще не настроите Azure Data Explorer, см. шаг 1 выше.
Azure Data Explorer — это мощный инструмент анализа данных, который является высокомасштабируемым и гибким, предоставляющим идеальную среду для создания настраиваемых отчетов о доступе пользователей. ADX использует язык запросов Kusto (KQL).
После настройки базы данных выполните следующие действия, чтобы получить экспортированные данные в ADX.
- Щелкните правой кнопкой мыши имя базы данных и выберите команду "Получить данные"
- Выберите новую таблицу и введите имя импорта JSON-файла, например, если вы импортируете EntraUsers.json, присвойте таблице EntraUsers имя. После первого импорта таблица уже будет существовать, и ее можно выбрать в качестве целевой таблицы для импорта.
- Выберите JSON-файл.
- ADX автоматически обнаруживает схему и предоставляет предварительную версию. Нажмите кнопку " Готово ", чтобы создать таблицу и импортировать данные.
- Выполните шаги 1–4 для каждого файла JSON, созданного на шаге 1.
Шаг 4. Создание пользовательских отчетов с помощью ADX
Теперь данные, доступные в ADX, готовы приступить к созданию настраиваемых отчетов на основе бизнес-требований. В следующих запросах приведены примеры общих отчетов, но эти отчеты можно настроить в соответствии с потребностями и создать дополнительные отчеты.
Пример 1. Создание назначений ролей приложения для прямых и групповых назначений для определенной даты моментального снимка
Этот отчет предоставляет представление о том, кто имел доступ и когда к целевому приложению и может использоваться для аудита безопасности, проверки соответствия требованиям и понимания шаблонов доступа в организации.
Этот запрос предназначен для конкретного приложения в Entra AD и анализирует назначения ролей по определенной дате. Запрос извлекает как прямые, так и групповые назначения ролей, объединяя эти данные с данными пользователя из таблицы EntraUsers и сведений о ролях из таблицы 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
Пример 2. Создание базового отчета аудитора с данными Entra, показывающими, кто имел доступ к приложению между этими двумя датами.
В этом отчете представлено представление о том, кто имел доступ к целевому приложению между двумя датами и может использоваться для аудита безопасности, проверки соответствия требованиям и понимания шаблонов доступа в организации.
Этот запрос предназначен для конкретного приложения в идентификаторе Microsoft Entra и анализирует назначения ролей между двумя датами. Запрос извлекает прямые назначения ролей из таблицы AppRoleAssignments и объединяет эти данные с данными пользователя из таблицы EntraUsers и сведений о ролях из таблицы 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()
Пример 3. Получение добавленных пользователей в приложение между двумя датами моментального снимка данных
Эти отчеты предоставляют представление о том, какие пользователи получили назначение роли приложения целевому приложению между двумя датами. Эти отчеты можно использовать для отслеживания изменений в доступе к приложению с течением времени.
Этот запрос предназначен для конкретного приложения в идентификаторе Microsoft Entra и изменения назначений ролей между датой начала и окончания.
// 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"
Пример 4. Объединение назначений приложений из записи и второго источника (например, экспорта SQL) для создания отчета всех пользователей (назначений Записей и локальных назначений), имеющих доступ к Salesforce между двумя датами.
В этом отчете показано, как объединить данные из двух отдельных систем для создания пользовательских отчетов в ADX. Он объединяет данные о пользователях, их ролях и других атрибутах из двух систем в унифицированном формате для анализа или отчетности.
// 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()
)