收集 Office 365 邮件跟踪日志
本文档介绍了如何使用多种注入方法将 Office 365 消息跟踪日志注入到 Google Security Operations。注入标签用于标识将原始日志数据标准化为结构化 UDM 格式的解析器。本文档中的信息适用于具有 OFFICE_365_MESSAGETRACE 注入标签的解析器。
Office 365 邮件跟踪是一项 Microsoft Exchange Online 功能,可跟踪电子邮件在 Exchange Online 邮件流管道中的传输情况。邮件跟踪日志提供有关每封电子邮件的详细信息,包括发件人和收件人地址、主题、递送状态、来源和目标 IP 地址以及邮件大小。这些数据对于排查邮件递送问题、调查可疑电子邮件活动以及监控电子邮件流量模式至关重要。
消息跟踪数据可通过 Exchange Online PowerShell 中的 Get-MessageTraceV2 cmdlet 以编程方式检索。Exchange Online PowerShell 模块 (ExchangeOnlineManagement) 在 Windows、macOS 和 Linux 上受正式支持,前提是使用 PowerShell 7.4.0 或更高版本(在 Windows 上使用 Windows PowerShell 5.1)。
准备工作
请确保满足以下前提条件:
- Google SecOps 实例
- 具有 Exchange Online 的 Microsoft 365 租户
- Microsoft 365 中的全局管理员、Exchange 管理员或安全读取者角色
- 对 Google Cloud Console 的访问权限(用于创建 API 密钥、GCS 和 Webhook)
- 在 Google SecOps 中创建和管理 Feed 的权限
- 用于运行导出脚本的专用 Windows、macOS 或 Linux 服务器或工作站:
- Windows:Windows 10/11 或 Windows Server 2016 或更高版本,并安装了 Windows PowerShell 5.1(内置)或 PowerShell 7.4.0 或更高版本
- macOS:macOS 13 Ventura 或更高版本,且安装了 PowerShell 7.4.0 或更高版本
- Linux:Debian 11 及更高版本、Ubuntu 20.04 及更高版本、RHEL 8 及更高版本,或 Fedora 36 及更高版本,且安装了 PowerShell 7.4.0 或更高版本
- 从导出机器到 Microsoft 365 和 Google SecOps 提取端点的网络连接
设置导出环境
Office 365 邮件跟踪功能没有内置的推送功能。您必须在专用 Windows、macOS 或 Linux 服务器或工作站上运行导出脚本,该脚本使用 PowerShell 从 Exchange Online 检索邮件跟踪数据,并将其发送到 Google SecOps。
您可以通过 Exchange Online PowerShell 获取邮件跟踪数据,但需遵守以下保留期限限制:
Get-MessageTraceV2:返回过去 10 天的数据。结果会立即显示。Start-HistoricalSearch:返回10 天到 90 天的数据。结果将以可下载的 CSV 报告形式提供,可能需要几个小时才能准备就绪。
以下步骤将在您的计算机上安装 PowerShell 和 Exchange Online PowerShell 模块。
安装 PowerShell
Windows
Windows PowerShell 5.1 随附于 Windows 10、Windows 11 和 Windows Server 2016 或更高版本。无需进行额外安装。
如需验证 PowerShell 版本,请打开 PowerShell 并运行以下命令:
$PSVersionTable.PSVersion(可选)如需安装 PowerShell 7 以提高性能,请以管理员身份打开命令提示符或 PowerShell,然后运行:
winget install --id Microsoft.PowerShell --source winget
macOS
- 安装 Homebrew(如果尚未安装)。
打开终端并运行以下命令:
brew install powershell/tap/powershell运行以下命令,验证安装是否成功:
pwsh --version输出应显示
PowerShell 7.x.x或更高版本。
Linux(Debian/Ubuntu)
- 打开具有 root 或 sudo 权限的终端。
运行以下命令:
sudo apt-get update sudo apt-get install -y wget apt-transport-https software-properties-common source /etc/os-release wget -q "https://packages.microsoft.com/config/ubuntu/$VERSION_ID/packages-microsoft-prod.deb" sudo dpkg -i packages-microsoft-prod.deb rm packages-microsoft-prod.deb sudo apt-get update sudo apt-get install -y powershell运行以下命令,验证安装是否成功:
pwsh --version
Linux (RHEL/CentOS/Fedora)
- 打开具有 root 或 sudo 权限的终端。
注册 Microsoft 代码库:
curl "https://packages.microsoft.com/config/rhel/$(rpm -E %rhel)/prod.repo" | sudo tee /etc/yum.repos.d/microsoft.repo安装 PowerShell:
sudo dnf install -y powershell运行以下命令,验证安装是否成功:
pwsh --version
安装 Exchange Online PowerShell 模块
安装 PowerShell 后,安装 Exchange Online 管理模块。此步骤在所有平台上的操作都相同。
启动 PowerShell:
- Windows:以管理员身份打开 PowerShell 或 PowerShell 7
- macOS 和 Linux:打开终端并运行
pwsh
运行以下命令:
Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser -Force如果系统提示您从不受信任的代码库 (PSGallery) 进行安装,请输入
Y以确认。运行以下命令,验证安装是否成功:
Import-Module ExchangeOnlineManagement Get-Module ExchangeOnlineManagement | Select-Object Name, Version
输出应显示模块名称和版本号。
设置基于证书的身份验证(计划脚本必需)
Connect-ExchangeOnline -UserPrincipalName 方法需要进行互动式登录,无法在已安排的脚本中使用。对于无人值守的执行,请设置基于证书的身份验证,并使用 Azure AD (Microsoft Entra ID) 应用。
创建自签名证书
Windows(以管理员身份在 PowerShell 中运行):
mkdir C:\Certs $cert = New-SelfSignedCertificate -Subject "CN=MessageTraceExport" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec KeyExchange -KeyLength 2048 -NotAfter (Get-Date).AddYears(2) $cert.Thumbprint Export-Certificate -Cert $cert -FilePath "C:\Certs\MessageTraceExport.cer"保存指纹值,以便在后续步骤中使用。
macOS 和 Linux(在终端中运行):
mkdir -p /opt/certs openssl req -x509 -newkey rsa:2048 -keyout /opt/certs/messagetrace-key.pem -out /opt/certs/messagetrace-cert.pem -days 730 -nodes -subj "/CN=MessageTraceExport" openssl pkcs12 -export -out /opt/certs/messagetrace.pfx -inkey /opt/certs/messagetrace-key.pem -in /opt/certs/messagetrace-cert.pem -passout pass: chmod 644 /opt/certs/messagetrace.pfx获取证书指纹:
openssl x509 -in /opt/certs/messagetrace-cert.pem -noout -fingerprint -sha1 | sed 's/://g' | cut -d= -f2保存指纹值,以便在后续步骤中使用。
在 Microsoft Entra ID 中注册应用
- 登录 Microsoft Entra 管理中心。
- 依次前往身份 > 应用 > 应用注册。
- 点击 New registration(新注册)。
- 提供以下配置详细信息:
- 名称:输入
MessageTraceExport - 支持的账号类型:选择仅此组织目录中的账号
- 名称:输入
- 点击注册。
- 在应用概览页面上,复制并保存应用(客户端)ID。
- 从概览页面复制目录(租户)ID 并保存。
将证书上传到应用
- 在应用页面上,依次前往证书和密钥 > 证书。
- 点击上传证书。
- 上传证书文件:
- Windows:上传
C:\Certs\MessageTraceExport.cer - macOS 和 Linux:上传
/opt/certs/messagetrace-cert.pem
- Windows:上传
- 点击 Add(添加)。
分配 API 权限
导出脚本会运行 Get-MessageTraceV2 cmdlet,该 cmdlet 需要两项 Office 365 Exchange Online 应用权限:Exchange.ManageAsApp(用于以应用身份进行身份验证)和 ReportingWebService.Read.All(用于读取邮件跟踪数据)。如果缺少 ReportingWebService.Read.All,脚本会失败并显示 403 The caller does not have permission 错误。
- 在应用页面上,前往 API 权限。
- 点击添加权限。
- 选择组织使用的 API。
- 搜索并选择 Office 365 Exchange Online。
- 选择应用权限。
- 添加以下两项权限:
- 展开 Exchange,然后选择 Exchange.ManageAsApp。
- 展开 ReportingWebService,然后选择 ReportingWebService.Read.All。
- 点击添加权限。
点击为 <您的组织> 授予管理员同意书,然后确认。
分配 Exchange 管理员角色
- 在 Microsoft Entra 管理中心内,依次前往身份 > 角色和管理员 > 所有角色。
- 搜索并选择 Exchange 管理员。
- 点击添加分配。
- 点击未选择任何成员,然后搜索
MessageTraceExport应用。 - 选择相应申请,然后点击下一步。
- 选择有效作为分配类型。
- 点击分配。
验证无人值守连接
启动 PowerShell 并运行以下命令:
Windows:
Connect-ExchangeOnline -CertificateThumbprint "<CERTIFICATE_THUMBPRINT>" -AppId "<APPLICATION_ID>" -Organization "yourdomain.onmicrosoft.com" Get-MessageTraceV2 -StartDate (Get-Date).AddHours(-1) -EndDate (Get-Date) -ResultSize 1 Disconnect-ExchangeOnline -Confirm:$falsemacOS 和 Linux(先运行
pwsh):Connect-ExchangeOnline -CertificateFilePath "/opt/certs/messagetrace.pfx" -AppId "<APPLICATION_ID>" -Organization "yourdomain.onmicrosoft.com" Get-MessageTraceV2 -StartDate (Get-Date).AddHours(-1) -EndDate (Get-Date) -ResultSize 1 Disconnect-ExchangeOnline -Confirm:$false将
<CERTIFICATE_THUMBPRINT>、<APPLICATION_ID>和yourdomain.onmicrosoft.com替换为您的实际值。如果该命令返回了消息跟踪数据(或没有错误的空结果集),则表示身份验证正常运作。
选择注入方法
Google SecOps 支持多种 Office 365 邮件跟踪日志注入方法。选择最适合您环境的方法:
| 注入方法 | 使用场景 | 延迟时间 | 设置复杂性 |
|---|---|---|---|
| Webhook | 来自脚本或应用的实时推送 | 秒 | 低 |
| Google Cloud Storage V2 | 批量导出到 GCS 存储桶 | 几分钟到几小时 | 中 |
选项 1:Webhook 提取
如果您有脚本或应用可以向 Google SecOps 发送包含消息跟踪数据的 HTTP POST 请求,请使用此方法。
在 Google SecOps 中创建 Webhook Feed
创建 Feed
- 依次前往 SIEM 设置 > Feed。
- 点击添加新 Feed。
- 在下一页上,点击配置单个 Feed。
- 在 Feed 名称字段中,输入 Feed 的名称(例如
Office 365 Message Trace - Webhook)。 - 选择 Webhook 作为来源类型。
- 选择 Office 365 邮件跟踪作为日志类型。
- 点击下一步。
- 为以下输入参数指定值:
- 定界符(可选):输入
\n以拆分以换行符分隔的 JSON 事件 - 资产命名空间:资产命名空间
- 注入标签:要应用于此 Feed 中事件的标签
- 定界符(可选):输入
- 点击下一步。
- 在最终确定界面中查看新的 Feed 配置,然后点击提交。
生成并保存密钥
创建 Feed 后,您必须生成用于身份验证的密钥:
- 在 Feed 详情页面上,点击生成密钥。
- 系统会显示一个对话框,其中包含密钥。
复制并妥善保存此密钥。
获取 Feed 端点网址
- 前往相应 Feed 的详细信息标签页。
- 在端点信息部分,复制 Feed 端点网址。
网址格式为:
https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate或
https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate保存此网址以供后续步骤使用。
点击完成。
创建 Google Cloud API 密钥
Google SecOps 需要使用 API 密钥进行身份验证。在 Google Cloud Console 中创建受限 API 密钥。
创建 API 密钥
- 前往 Google Cloud 控制台的“凭据”页面。
- 选择您的项目(与您的 Google SecOps 实例关联的项目)。
- 依次点击创建凭据> API 密钥。
- 系统会创建一个 API 密钥,并在对话框中显示该密钥。
- 点击修改 API 密钥以限制密钥。
限制 API 密钥
- 在 API 密钥设置页面中:
- 名称:输入一个描述性名称(例如
Google SecOps Webhook API Key - O365 Message Trace)
- 名称:输入一个描述性名称(例如
- 在 API 限制下:
- 选择限制密钥。
- 在选择 API 下拉菜单中,搜索并选择 Google SecOps API(或 Chronicle API)。
- 点击保存。
- 从页面顶部的 API 密钥字段复制 API 密钥值。
安全地保存 API 密钥。
创建 webhook 导出脚本
在设置了导出环境的机器上创建以下 PowerShell 脚本。此脚本从 Exchange Online 检索邮件跟踪数据,并将其发送到 Google SecOps 网络钩子端点。
Windows
创建脚本目录:
mkdir C:\Scripts创建一个名为
C:\Scripts\messagetrace-webhook.ps1的文件,其中包含以下内容:# Configuration $endpointUrl = "https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate" $apiKey = "<API_KEY>" $secretKey = "<SECRET_KEY>" $certThumbprint = "<CERTIFICATE_THUMBPRINT>" $appId = "<APPLICATION_ID>" $organization = "yourdomain.onmicrosoft.com" # Log file $logFile = "C:\Logs\messagetrace-webhook.log" if (!(Test-Path "C:\Logs")) { New-Item -ItemType Directory -Path "C:\Logs" } try { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Starting message trace export" # Connect to Exchange Online using certificate-based authentication Connect-ExchangeOnline -CertificateThumbprint $certThumbprint -AppId $appId -Organization $organization -ShowBanner:$false # Retrieve message trace data for the last hour (up to 10 days available) $startDate = (Get-Date).AddHours(-1) $endDate = Get-Date $messages = Get-MessageTraceV2 -StartDate $startDate -EndDate $endDate -ResultSize 5000 if ($messages.Count -eq 0) { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - No messages found in the time range" Disconnect-ExchangeOnline -Confirm:$false exit 0 } # Convert to NDJSON (one JSON object per line) $ndjson = ($messages | ForEach-Object { $_ | ConvertTo-Json -Compress }) -join "`n" # Send to Google SecOps webhook $headers = @{ "X-goog-api-key" = $apiKey "X-Webhook-Access-Key" = $secretKey } # Send raw UTF-8 bytes so PowerShell does not re-encode the NDJSON body $bodyBytes = [System.Text.Encoding]::UTF8.GetBytes($ndjson) $response = Invoke-RestMethod -Uri $endpointUrl -Method Post -Headers $headers -Body $bodyBytes -ContentType "application/json" Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Successfully sent $($messages.Count) messages" } catch { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Error: $_" } finally { Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue }替换占位值:
<API_KEY>:Google Cloud API 密钥<SECRET_KEY>:Google SecOps 网络钩子密钥<CERTIFICATE_THUMBPRINT>:身份验证设置中的证书指纹<APPLICATION_ID>:Azure AD 应用(客户端)IDyourdomain.onmicrosoft.com:您的 Microsoft 365 租户网域
macOS 和 Linux
创建脚本目录:
sudo mkdir -p /opt/scripts sudo mkdir -p /var/log/messagetrace创建一个名为
/opt/scripts/messagetrace-webhook.ps1的文件,其中包含以下内容:# Configuration $endpointUrl = "https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate" $apiKey = "<API_KEY>" $secretKey = "<SECRET_KEY>" $certFilePath = "/opt/certs/messagetrace.pfx" $appId = "<APPLICATION_ID>" $organization = "yourdomain.onmicrosoft.com" # Log file $logFile = "/var/log/messagetrace/messagetrace-webhook.log" try { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Starting message trace export" # Connect to Exchange Online using certificate-based authentication Connect-ExchangeOnline -CertificateFilePath $certFilePath -AppId $appId -Organization $organization -ShowBanner:$false # Retrieve message trace data for the last hour (up to 10 days available) $startDate = (Get-Date).AddHours(-1) $endDate = Get-Date $messages = Get-MessageTraceV2 -StartDate $startDate -EndDate $endDate -ResultSize 5000 if ($messages.Count -eq 0) { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - No messages found in the time range" Disconnect-ExchangeOnline -Confirm:$false exit 0 } # Convert to NDJSON (one JSON object per line) $ndjson = ($messages | ForEach-Object { $_ | ConvertTo-Json -Compress }) -join "`n" # Send to Google SecOps webhook $headers = @{ "X-goog-api-key" = $apiKey "X-Webhook-Access-Key" = $secretKey } # Send raw UTF-8 bytes so PowerShell does not re-encode the NDJSON body $bodyBytes = [System.Text.Encoding]::UTF8.GetBytes($ndjson) $response = Invoke-RestMethod -Uri $endpointUrl -Method Post -Headers $headers -Body $bodyBytes -ContentType "application/json" Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Successfully sent $($messages.Count) messages" } catch { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Error: $_" } finally { Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue }替换占位值:
<API_KEY>:Google Cloud API 密钥<SECRET_KEY>:Google SecOps 网络钩子密钥<APPLICATION_ID>:Azure AD 应用(客户端)IDyourdomain.onmicrosoft.com:您的 Microsoft 365 租户网域
设置文件权限:
sudo chmod 700 /opt/scripts/messagetrace-webhook.ps1
安排导出脚本
将脚本配置为定期自动运行(例如每小时运行一次)。
Windows
- 打开任务计划程序:按
Win+R,输入taskschd.msc,然后按Enter。 - 在右侧窗格中,点击创建任务。
- 在常规标签页上:
- 名称:输入
MessageTrace Webhook Export - 选择无论用户是否已登录,都运行
- 选择以最高权限运行
- 名称:输入
- 在触发器标签页上:
- 点击 New(新建)。
- 将开始任务设置为按计划。
- 选择每天,将开始时间设置为
12:00:00 AM(午夜,以便按整点重复),然后设置每 1 天重复一次。 - 选择每
1 hour重复一次任务,持续时间为无限期。 - 选择已启用。
- 点击确定。
在操作标签页上:
- 点击 New(新建)。
- 将操作设置为启动程序。
在程序/脚本字段中,输入:
powershell.exe在添加实参字段中,输入:
-NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\messagetrace-webhook.ps1"点击确定。
在设置标签页中:
- 选择允许按需运行任务
- 清除如果任务运行时间超过复选框
点击确定,然后在系统提示时输入服务账号凭据。
macOS
在
~/Library/LaunchAgents/com.chronicle.messagetrace-webhook.plist中创建 launchd plist 文件:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.chronicle.messagetrace-webhook</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/pwsh</string> <string>-NoProfile</string> <string>-File</string> <string>/opt/scripts/messagetrace-webhook.ps1</string> </array> <key>StartInterval</key> <integer>3600</integer> <key>StandardOutPath</key> <string>/var/log/messagetrace/launchd-stdout.log</string> <key>StandardErrorPath</key> <string>/var/log/messagetrace/launchd-stderr.log</string> <key>RunAtLoad</key> <true/> </dict> </plist>加载作业:
launchctl load ~/Library/LaunchAgents/com.chronicle.messagetrace-webhook.plist验证作业是否已加载:
launchctl list | grep messagetrace
Linux
打开 crontab 编辑器:
crontab -e添加以下代码行,以便每小时运行一次脚本:
0 * * * * /usr/bin/pwsh -NoProfile -File /opt/scripts/messagetrace-webhook.ps1 >> /var/log/messagetrace/cron.log 2>&1保存并退出编辑器。
验证 Cron 作业是否已注册:
crontab -l
验证日志注入
手动运行脚本以进行测试:
Windows:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\messagetrace-webhook.ps1"macOS 和 Linux:
pwsh -NoProfile -File /opt/scripts/messagetrace-webhook.ps1检查日志文件是否存在错误:
Windows:
Get-Content "C:\Logs\messagetrace-webhook.log" -Tail 10macOS 和 Linux:
tail -10 /var/log/messagetrace/messagetrace-webhook.log在 Google SecOps 中,前往搜索,并验证是否显示了带有
metadata.log_type = "OFFICE_365_MESSAGETRACE"的日志。
方案 2:Google Cloud Storage V2 提取
如果导出脚本将消息跟踪日志写入 Google Cloud Storage 存储桶,请使用此方法。
创建 GCS 存储桶
- 前往 Google Cloud 控制台。
- 选择您的项目或创建新项目。
- 在导航菜单中,依次前往 Cloud Storage > 存储分区。
- 点击创建存储分区。
提供以下配置详细信息:
设置 值 为存储桶命名 输入一个全局唯一的名称(例如 office365-messagetrace-logs)位置类型 根据您的需求进行选择(区域级、双区域、多区域) 位置 选择营业地点(例如 us-central1)存储类别 标准(建议用于经常访问的日志) 访问权限控制 均匀(推荐) 保护工具 可选:启用对象版本控制或保留政策 点击创建。
安装 Google Cloud CLI
在设置导出环境的同一台机器上安装 Google Cloud CLI。gsutil 命令(随 Google Cloud CLI 一起提供)用于将文件上传到 GCS 存储桶。
Windows
- 下载 Google Cloud CLI 安装程序 (
GoogleCloudSDKInstaller.exe)。 - 运行
GoogleCloudSDKInstaller.exe。在安装选项界面上,保留默认选择。点击安装。安装完成后,保持选中运行gcloud init,然后点击完成。 打开命令提示符并运行以下命令,验证安装是否成功:
gcloud --version gsutil --version
macOS
打开终端并运行以下命令:
brew install google-cloud-sdk验证安装:
gcloud --version gsutil --version
Linux(Debian/Ubuntu)
- 打开具有 root 或 sudo 权限的终端。
运行以下命令:
sudo apt-get install -y apt-transport-https ca-certificates gnupg curl curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee /etc/apt/sources.list.d/google-cloud-sdk.list sudo apt-get update sudo apt-get install -y google-cloud-cli验证安装:
gcloud --version gsutil --version
Linux (RHEL/CentOS/Fedora)
- 打开具有 root 或 sudo 权限的终端。
创建代码库文件:
sudo tee /etc/yum.repos.d/google-cloud-sdk.repo << 'EOF' [google-cloud-cli] name=Google Cloud CLI baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el9-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=0 gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF安装 Google Cloud CLI:
sudo dnf install -y google-cloud-cli验证安装:
gcloud --version gsutil --version
对 Google Cloud CLI 进行身份验证
运行以下命令进行身份验证:
gcloud auth login设置包含您的 GCS 存储桶的项目:
gcloud config set project <PROJECT_ID>将
<PROJECT_ID>替换为您的 Google Cloud 项目 ID。
对于无人值守(已安排)的使用,请使用服务账号密钥进行身份验证。导出脚本使用此服务账号将文件上传到 GCS 存储桶。它与用于从存储桶读取数据的 Google SecOps 服务账号(在后续步骤中配置)是分开的。
- 前往 Google Cloud 控制台,然后选择您的项目。
- 点击创建服务账号。
- 在服务账号名称字段中,输入一个名称(例如
chronicle-gcs-export)。 - 点击创建并继续。
- 在向此服务账号授予对项目的访问权限部分,选择 Storage Object Creator 角色。
- 点击完成。
- 在服务账号列表中,点击您创建的服务账号。
- 前往密钥标签页。
- 点击添加密钥 > 创建新密钥。
- 选择 JSON,然后点击创建。
- 保存下载的 JSON 密钥文件:
- Windows:
C:\Certs\gcs-service-account.json - macOS 和 Linux:
/opt/certs/gcs-service-account.json
- Windows:
激活服务账号:
gcloud auth activate-service-account --key-file=<PATH_TO_KEY_FILE>
创建 GCS 导出脚本
Windows
创建一个名为
C:\Scripts\messagetrace-gcs.ps1的文件,其中包含以下内容:# Configuration $certThumbprint = "<CERTIFICATE_THUMBPRINT>" $appId = "<APPLICATION_ID>" $organization = "yourdomain.onmicrosoft.com" $gcsBucket = "gs://office365-messagetrace-logs/messagetrace/" $localLogDir = "C:\Logs\MessageTrace" # Log file $logFile = "C:\Logs\messagetrace-gcs.log" if (!(Test-Path $localLogDir)) { New-Item -ItemType Directory -Path $localLogDir } try { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Starting message trace export to GCS" # Connect to Exchange Online using certificate-based authentication Connect-ExchangeOnline -CertificateThumbprint $certThumbprint -AppId $appId -Organization $organization -ShowBanner:$false # Retrieve message trace data for the last hour (up to 10 days available) $startDate = (Get-Date).AddHours(-1) $endDate = Get-Date $messages = Get-MessageTraceV2 -StartDate $startDate -EndDate $endDate -ResultSize 5000 if ($messages.Count -eq 0) { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - No messages found in the time range" Disconnect-ExchangeOnline -Confirm:$false exit 0 } # Convert to NDJSON (one JSON object per line) $ndjson = $messages | ForEach-Object { $_ | ConvertTo-Json -Compress } $fileName = "messagetrace_$(Get-Date -Format 'yyyyMMddHHmmss').json" $filePath = Join-Path $localLogDir $fileName $ndjson | Out-File -FilePath $filePath -Encoding UTF8 # Upload to GCS gsutil cp $filePath $gcsBucket Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Uploaded $fileName with $($messages.Count) messages" # Remove local file after successful upload Remove-Item $filePath } catch { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Error: $_" } finally { Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue }替换占位值:
<CERTIFICATE_THUMBPRINT>:身份验证设置中的证书指纹<APPLICATION_ID>:Azure AD 应用(客户端)IDyourdomain.onmicrosoft.com:您的 Microsoft 365 租户网域office365-messagetrace-logs:您的 GCS 存储桶名称
macOS 和 Linux
创建一个名为
/opt/scripts/messagetrace-gcs.ps1的文件,其中包含以下内容:# Configuration $certFilePath = "/opt/certs/messagetrace.pfx" $appId = "<APPLICATION_ID>" $organization = "yourdomain.onmicrosoft.com" $gcsBucket = "gs://office365-messagetrace-logs/messagetrace/" $localLogDir = "/var/log/messagetrace/export" # Log file $logFile = "/var/log/messagetrace/messagetrace-gcs.log" if (!(Test-Path $localLogDir)) { New-Item -ItemType Directory -Path $localLogDir } try { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Starting message trace export to GCS" # Connect to Exchange Online using certificate-based authentication Connect-ExchangeOnline -CertificateFilePath $certFilePath -AppId $appId -Organization $organization -ShowBanner:$false # Retrieve message trace data for the last hour (up to 10 days available) $startDate = (Get-Date).AddHours(-1) $endDate = Get-Date $messages = Get-MessageTraceV2 -StartDate $startDate -EndDate $endDate -ResultSize 5000 if ($messages.Count -eq 0) { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - No messages found in the time range" Disconnect-ExchangeOnline -Confirm:$false exit 0 } # Convert to NDJSON (one JSON object per line) $ndjson = $messages | ForEach-Object { $_ | ConvertTo-Json -Compress } $fileName = "messagetrace_$(Get-Date -Format 'yyyyMMddHHmmss').json" $filePath = Join-Path $localLogDir $fileName $ndjson | Out-File -FilePath $filePath -Encoding UTF8 # Upload to GCS gsutil cp $filePath $gcsBucket Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Uploaded $fileName with $($messages.Count) messages" # Remove local file after successful upload Remove-Item $filePath } catch { Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Error: $_" } finally { Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue }替换占位值:
<APPLICATION_ID>:Azure AD 应用(客户端)IDyourdomain.onmicrosoft.com:您的 Microsoft 365 租户网域office365-messagetrace-logs:您的 GCS 存储桶名称
设置文件权限:
sudo chmod 700 /opt/scripts/messagetrace-gcs.ps1
安排 GCS 导出脚本
Windows
- 打开任务计划程序:按
Win+R,输入taskschd.msc,然后按Enter。 - 在右侧窗格中,点击创建任务。
- 在常规标签页上:
- 名称:输入
MessageTrace GCS Export - 选择无论用户是否已登录,都运行
- 选择以最高权限运行
- 名称:输入
- 在触发器标签页上:
- 点击 New(新建)。
- 将开始任务设置为按计划。
- 选择每天,将开始时间设置为
12:00:00 AM(午夜,以便按整点重复),然后设置每 1 天重复一次。 - 选择每
1 hour重复一次任务,持续时间为无限期。 - 选择已启用。
- 点击确定。
在操作标签页上:
- 点击 New(新建)。
- 将操作设置为启动程序。
在程序/脚本字段中,输入:
powershell.exe在添加实参字段中,输入:
-NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\messagetrace-gcs.ps1"点击确定。
在设置标签页中:
- 选择允许按需运行任务
- 清除如果任务运行时间超过复选框
点击确定,然后在系统提示时输入服务账号凭据。
macOS
在
~/Library/LaunchAgents/com.chronicle.messagetrace-gcs.plist中创建 launchd plist 文件:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.chronicle.messagetrace-gcs</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/pwsh</string> <string>-NoProfile</string> <string>-File</string> <string>/opt/scripts/messagetrace-gcs.ps1</string> </array> <key>StartInterval</key> <integer>3600</integer> <key>StandardOutPath</key> <string>/var/log/messagetrace/launchd-gcs-stdout.log</string> <key>StandardErrorPath</key> <string>/var/log/messagetrace/launchd-gcs-stderr.log</string> <key>RunAtLoad</key> <true/> </dict> </plist>加载作业:
launchctl load ~/Library/LaunchAgents/com.chronicle.messagetrace-gcs.plist验证作业是否已加载:
launchctl list | grep messagetrace
Linux
打开 crontab 编辑器:
crontab -e添加以下代码行,以便每小时运行一次脚本:
0 * * * * /usr/bin/pwsh -NoProfile -File /opt/scripts/messagetrace-gcs.ps1 >> /var/log/messagetrace/cron-gcs.log 2>&1保存并退出编辑器。
验证 Cron 作业是否已注册:
crontab -l
验证 GCS 上传
手动运行脚本以进行测试:
Windows:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\messagetrace-gcs.ps1"macOS 和 Linux:
pwsh -NoProfile -File /opt/scripts/messagetrace-gcs.ps1验证文件是否已上传到 GCS 存储桶:
gsutil ls gs://office365-messagetrace-logs/messagetrace/检查日志文件是否存在错误:
Windows:
Get-Content "C:\Logs\messagetrace-gcs.log" -Tail 10macOS 和 Linux:
tail -10 /var/log/messagetrace/messagetrace-gcs.log
获取 Google SecOps 服务账号
- 依次前往 SIEM 设置 > Feed。
- 点击添加新 Feed。
- 点击配置单个 Feed。
- 在 Feed 名称字段中,输入 Feed 的名称(例如
Office 365 Message Trace - GCS)。 - 选择 Google Cloud Storage V2 作为来源类型。
- 选择 Office 365 邮件跟踪作为日志类型。
- 点击获取服务账号。
系统会显示一个唯一的服务账号电子邮件地址,例如:
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com复制此电子邮件地址,以便在下一步中使用。
授予 IAM 权限
- 前往 Cloud Storage > 存储分区。
- 点击您的存储桶名称。
- 前往权限标签页。
- 点击授予访问权限。
- 提供以下配置详细信息:
- 添加主账号:粘贴 Google SecOps 服务账号电子邮件地址
- 分配角色:选择 Storage Object Viewer
点击保存。
为 GCS 配置 Google SecOps Feed
- 从 Feed 创建页面继续操作(或前往 SIEM 设置 > Feed > 添加新 Feed)。
- 点击下一步。
为以下输入参数指定值:
存储桶网址:输入带有前缀路径的 GCS 存储桶 URI:
gs://office365-messagetrace-logs/messagetrace/
- 来源删除选项:根据您的偏好选择删除选项:
- 永不:转移后永不删除任何文件(建议用于测试)
- 删除已转移的文件:在成功转移后删除文件
- 删除已转移的文件和空目录:成功转移后删除文件和空目录
- 文件存在时间上限:包含在过去指定天数内修改的文件(默认值为 180 天)
- 资产命名空间:资产命名空间
- 注入标签:要应用于此 Feed 中事件的标签
点击下一步。
在最终确定界面中查看新的 Feed 配置,然后点击提交。
UDM 映射表
下表列出了 OFFICE_365_MESSAGETRACE 日志类型的日志字段及其对应的 UDM 字段。
| 日志字段 | UDM 映射 | 逻辑 |
|---|---|---|
additional_AdditionalFields |
additional.fields |
已合并 |
additional_DeliveryLocation |
additional.fields |
已合并 |
additional_OrgLevelPolicy |
additional.fields |
已合并 |
additional_connectors |
additional.fields |
已合并 |
additional_delivery_action |
additional.fields |
已合并 |
additional_fields_UrlLocation |
additional.fields |
已合并 |
additional_orgLevelAction |
additional.fields |
已合并 |
end_date_label |
additional.fields |
已合并 |
index_label |
additional.fields |
已合并 |
metadata_id_label |
additional.fields |
已合并 |
operationName_label |
additional.fields |
已合并 |
start_date_label |
additional.fields |
已合并 |
tenant_label |
additional.fields |
已合并 |
type_label |
additional.fields |
已合并 |
properties.AuthenticationDetails |
extensions.auth.auth_details |
直接映射 |
Received |
metadata.event_timestamp |
解析为 UNIX_MS |
time |
metadata.event_timestamp |
解析为 ISO8601 |
tenantId |
metadata.product_deployment_id |
直接映射 |
category |
metadata.product_event_type |
直接映射 |
MessageTraceId |
metadata.product_log_id |
直接映射 |
SenderAddress |
network.email.from |
直接映射 |
properties.SenderFromAddress |
network.email.from |
直接映射 |
MessageId |
network.email.mail_id |
直接映射 |
Subject |
network.email.subject |
已合并 |
properties.Subject |
network.email.subject |
已合并 |
RecipientAddress |
network.email.to |
已合并 |
properties.RecipientEmailAddress |
network.email.to |
已合并 |
Size |
network.received_bytes |
直接映射 |
Organization |
principal.administrative_domain |
直接映射 |
properties.SenderFromDomain |
principal.administrative_domain |
直接映射 |
FromIP |
principal.ip |
已合并 |
properties.FileName |
principal.process.file.names |
已合并 |
properties.SHA256 |
principal.process.file.sha256 |
直接映射 |
properties.FileSize |
principal.process.file.size |
已重命名/已映射 |
additional_UserLevelAction |
principal.user.attribute.labels |
已合并 |
additional_UserLevelPolicy |
principal.user.attribute.labels |
已合并 |
sender_email_from_domain_label |
principal.user.attribute.labels |
已合并 |
properties.SenderFromAddress |
principal.user.email_addresses |
已合并 |
properties.SenderObjectId |
principal.user.product_object_id |
直接映射 |
properties.SenderDisplayName |
principal.user.user_display_name |
直接映射 |
action |
security_result.action |
已合并 |
Status |
security_result.action_details |
直接映射 |
security_result_category |
security_result.category |
已合并 |
properties.ConfidenceLevel |
security_result.confidence_details |
直接映射 |
detect_method |
security_result.detection_fields |
已合并 |
detection_method |
security_result.rule_name |
直接映射 |
properties.ThreatNames |
security_result.threat_name |
直接映射 |
properties.UrlDomain |
target.asset.hostname |
直接映射 |
ToIP |
target.asset.ip |
已合并 |
properties.UrlDomain |
target.hostname |
直接映射 |
ToIP |
target.ip |
已合并 |
properties.Url |
target.url |
直接映射 |
properties.RecipientEmailAddress |
target.user.email_addresses |
已合并 |
properties.RecipientObjectId |
target.user.product_object_id |
直接映射 |
| 不适用 | metadata.event_type |
常量:EMAIL_TRANSACTION |
| 不适用 | network.direction |
常量:INBOUND |
| 不适用 | principal.process.file.file_type |
常量:FILE_TYPE_PNG |
| 不适用 | security_result.confidence |
常量:HIGH_CONFIDENCE |
id |
event.idm.read_only_udm.metadata.product_log_id |
从变更日志映射 |
receivedDateTime |
event.idm.read_only_udm.metadata.event_timestamp |
从变更日志映射 |
fromIP |
event.idm.read_only_udm.principal.ip和event.idm.read_only_udm.principal.asset.ip之间 |
从变更日志映射 |
toIP |
event.idm.read_only_udm.target.ip和event.idm.read_only_udm.target.asset.ip之间 |
从变更日志映射 |
status |
event.idm.read_only_udm.security_result.action_details |
从变更日志映射 |
size |
event.idm.read_only_udm.network.received_bytes |
从变更日志映射 |
senderAddress |
event.idm.read_only_udm.network.email.from |
从变更日志映射 |
recipientAddress |
event.idm.read_only_udm.network.email.to |
从变更日志映射 |
subject |
event.idm.read_only_udm.network.email.subject |
从变更日志映射 |
messageId |
event.idm.read_only_udm.network.email.mail_id |
从变更日志映射 |
properties.SenderMailFromDomain", "properties.UserLevelAction", and "properties.UserLevelPolicy |
principal.user.attribute.labels |
从变更日志映射 |
properties.EmailDirection |
network.direction |
从变更日志映射 |
properties.DeliveryAction", "properties.DeliveryLocation", "properties.Connectors", "properties.OrgLevelAction", "properties.OrgLevelPolicy", "properties.AdditionalFields", and "properties.UrlLocation |
additional.fields |
从变更日志映射 |
operationName", "Tenant |
additional.fields |
从变更日志映射 |
properties.DetectionMethods |
security_result.detection_fields |
从变更日志映射 |
更新日志
需要更多帮助?获得社区成员和 Google SecOps 专业人士的解答。