Wazuh Azure 集成实战:配置 Log Analytics、Microsoft Graph 与 Azure Storage 日志采集模块
【免费下载链接】wazuhWazuh - The Open Source Security Platform. Unified XDR and SIEM protection for endpoints and cloud workloads.项目地址: https://gitcode.com/GitHub_Trending/wa/wazuh
Wazuh 的 Azure 集成以 Wazuh Agent 上的 wodle(Python 脚本)形式运行,可对接三类 Microsoft Azure 数据源:使用 KQL 查询的Log Analytics、通过 Microsoft Graph API 获取目录与安全数据的Graph,以及从 Blob 容器读取日志的Azure Storage。本文基于仓库文档 azure.md 与实现代码 azure-logs.py 展开,带你完成应用注册、凭证文件配置、XML 配置编写与集成验证,并深入源码理解时间窗口过滤、状态持久化与事件投递到 analysisd 的完整链路。
一、模块架构与运行方式
Azure 模块作为 Wazuh wodle 在 Agent 上运行:<wodle name="azure-logs">配置项最终会调用 wodles/azure/azure-logs.py 脚本连接 Azure 服务。入口脚本的职责很清晰(见 azure-logs.py):
- 通过 get_script_arguments() 解析命令行参数,其中
--log_analytics、--graph、--storage构成互斥必填组,即一次调用只能激活一种数据源; - 调用 check_database_integrity() 检查状态数据库完整性,失败则退出;
- 按参数分发到三个服务模块:
- start_log_analytics()(analytics.py)
- start_graph()(graph.py)
- start_storage()(storage.py)
前置条件(摘自原文档):
- 一个已启用所需服务的 Azure 订阅;
- 一个注册了相应 API 权限的 Azure AD 应用;
- Wazuh Agent 上已安装 Python 3 与所需 Azure Python 库。
二、Azure AD 应用注册与凭证文件
2.1 注册应用并授权
按 azure.md 的操作步骤:
- 在 Azure 门户中进入Azure Active Directory>App registrations;
- 注册一个新应用;
- 在API permissions中按需添加权限:
- Log Analytics:
Log Analytics API>Data.Read - Graph API:
Microsoft Graph>AuditLog.Read.All、Directory.Read.All
- Log Analytics:
- 为这些权限授予管理员同意(admin consent);
- 在Certificates & secrets下创建客户端机密(client secret)。
2.2 凭证文件
文档给出的凭证文件结构如下。Log Analytics 与 Graph API 共用:
{ "application_id": "YOUR_APPLICATION_ID", "application_key": "YOUR_CLIENT_SECRET", "tenant_id": "YOUR_TENANT_ID" }Storage 使用:
{ "account_name": "YOUR_STORAGE_ACCOUNT_NAME", "account_key": "YOUR_STORAGE_ACCOUNT_KEY" }需要特别说明的是:从源码实现看,当前 read_auth_file() 实际按“每行一条field = value”的两行格式解析凭证文件,并要求文件恰好包含所需字段。测试数据文件(如 valid_authentication_file、valid_authentication_file_storage)也印证了这一点:
application_id = YOUR_APPLICATION_ID application_key = YOUR_CLIENT_SECRETaccount_name = YOUR_STORAGE_ACCOUNT_NAME account_key = YOUR_STORAGE_ACCOUNT_KEY解析逻辑会去除空格与换行、按=分割键值,缺少application_id/application_key(Storage 为account_name/account_key)任一字段时记录错误并退出。因此建议参照源码的field = value行格式书写凭证文件,并妥善保管该文件权限。
三、XML 配置详解
Azure 模块配置写在 Wazuh Agent 配置文件(ossec.conf)的<ossec_config>块中,wodle 名称为azure-logs。
3.1 通用选项
| 选项 | 必填 | 默认值 | 说明 |
|---|---|---|---|
disabled | 否 | no | 设为yes时禁用 Azure 模块 |
run_on_start | 否 | yes | 模块启动时立即处理日志 |
interval | 否 | 1h | 两次 Azure API 查询之间的时间间隔 |
timeout | 否 | 3600 | 每次运行的最大执行时间(秒) |
3.2 Log Analytics 配置
<wodle name="azure-logs"> <disabled>no</disabled> <run_on_start>yes</run_on_start> <interval>1h</interval> <log_analytics> <auth_path>/var/ossec/etc/azure_auth.json</auth_path> <tenantdomain>my-tenant.onmicrosoft.com</tenantdomain> <request> <tag>azure-activity</tag> <query>AzureActivity | where Level != "Informational"</query> <workspace>workspace-id-here</workspace> <time_offset>1h</time_offset> </request> </log_analytics> </wodle>3.3 Microsoft Graph 配置
<wodle name="azure-logs"> <disabled>no</disabled> <run_on_start>yes</run_on_start> <interval>1h</interval> <graph> <auth_path>/var/ossec/etc/azure_auth.json</auth_path> <tenantdomain>my-tenant.onmicrosoft.com</tenantdomain> <request> <tag>azure-graph</tag> <query>auditLogs/signIns</query> <time_offset>1h</time_offset> </request> </graph> </wodle>3.4 Azure Storage 配置
<wodle name="azure-logs"> <disabled>no</disabled> <run_on_start>yes</run_on_start> <interval>1h</interval> <storage> <auth_path>/var/ossec/etc/azure_storage_auth.json</auth_path> <tag>azure-storage</tag> <container name="insights-logs-networksecuritygroupflowevent"> <blobs>.json</blobs> <content_type>json</content_type> <time_offset>1h</time_offset> </container> </storage> </wodle>3.5 Log Analytics 与 Graph 专用选项
| 选项 | 必填 | 默认值 | 说明 |
|---|---|---|---|
application_id | 否 | — | Azure AD 应用 ID(已弃用,建议使用auth_path) |
application_key | 否 | — | Azure AD 应用密钥(已弃用,建议使用auth_path) |
auth_path | 否 | — | 包含认证凭证的 JSON 文件路径 |
tenantdomain | 是 | — | Azure AD 租户域名(例如contoso.onmicrosoft.com) |
request | 是 | — | 定义一次查询请求,支持多个request块 |
tag | 否 | — | 添加到生成告警中的自定义标签,用于标识来源 |
query | 是 | — | KQL 查询(Log Analytics)或 Graph API 资源路径 |
workspace | Log Analytics 必填 | — | Log Analytics 工作区 ID |
time_offset | 否 | — | 查询时间范围(例如1h、1d) |
timeout | 否 | 3600 | 该请求的最大执行时间(秒) |
3.6 Storage 专用选项
| 选项 | 必填 | 默认值 | 说明 |
|---|---|---|---|
account_name | 否 | — | Azure 存储账户名(已弃用,建议使用auth_path) |
account_key | 否 | — | Azure 存储账户密钥(已弃用,建议使用auth_path) |
auth_path | 否 | — | 包含存储认证凭证的 JSON 文件路径 |
tag | 否 | — | 添加到生成告警中的自定义标签 |
container | 是 | — | 定义要监控的 Blob 容器,用name属性指定容器名 |
blobs | 否 | — | Blob 名称过滤器(例如.json匹配 JSON 文件) |
content_type | 否 | — | 预期 Blob 内容类型(例如json、text) |
path | 否 | — | Blob 前缀过滤器 |
time_offset | 否 | — | Blob 选择的时间范围(例如1h、1d) |
timeout | 否 | 3600 | 容器扫描的最大执行时间(秒) |
关于content_type,从源码看它映射到 arg_valid 参数 中的--json_file/--json_inline两个开关:json表示 Blob 内容为 JSON 事件文件,text为默认(纯文本逐行处理)。path对应--prefix参数,用于按前缀限定日志目录。
四、源码级原理剖析
4.1 认证:OAuth2 客户端凭证模式
Log Analytics 与 Graph 都通过 get_token() 获取访问令牌:向https://login.microsoftonline.com/{tenantdomain}/oauth2/v2.0/token发起client_credentials授权请求。该函数对常见错误做了精准提示:
unauthorized_client→ “application id provided is not valid”;invalid_client→ “application key provided is not valid”;invalid_request且error_codes含 90002 → 租户域名不存在。
两个服务的 scope 不同:Log Analytics 使用{https://api.loganalytics.io}/.default(见 analytics.py),Graph 使用{https://graph.microsoft.com}/.default(见 graph.py)。这也解释了为什么注册应用时两种数据源需要不同的 API 权限。
4.2 时间窗口过滤:不重不漏的增量拉取
三个服务都依赖time_offset实现增量采集,且各自维护已处理时间区间:
- Log Analytics:build_log_analytics_query() 会把用户 KQL 查询改写为带时间过滤的形式,例如
TimeGenerated >= datetime(2026-09-13T08:00:00.000000Z);当time_offset早于历史已处理的最小时间时,会构造(TimeGenerated < min and TimeGenerated >= desired) or (TimeGenerated > max)的双区间条件,以补回可能漏掉的早期事件。若配置了 reparse,则忽略已处理区间直接按 offset 拉取。 - Graph:build_graph_url() 用 OData
$filter语法拼接时间条件,并依据资源类型自动选择时间字段——查询路径包含signins时用createdDateTime,否则用activityDateTime;随后按@odata.nextLink递归翻页(get_graph_events()),把每一页事件逐条发送。 - Storage:get_blobs() 以 Blob 的
last_modified时间戳判断是否已处理,空 Blob、嵌套在path前缀之下的 Blob、以及名称不匹配blobs过滤器的 Blob 都会被跳过;内容按json_file(解析records数组)、json_inline或纯文本三种模式投递。
时间偏移解析由 offset_to_datetime() 完成:取数字加单位字符,源码中实际支持的单位是h(小时)、m(分钟)、d(天),与当前 UTC 时间相减得到查询起点,非法单位会直接报错退出。因此文档示例里的1h、1d均受支持,配置时请以该函数为准。
4.3 状态持久化:SQLite 数据库与历史迁移
模块状态记录已从旧版的last_dates.json迁移到 SQLite 数据库 azure.db。表结构由 AzureTable 定义,分graph、log_analytics、storage三张表,主键md5是对查询标识的确定性哈希(create_pk()),每行保存query、min_processed_date、max_processed_date三个字段。关键行为:
- 首次运行时,create_new_row() 会插入一行:若提供了
time_offset,起点为当前时间 - offset;否则默认从当天 0 点(UTC)开始; - update_row_object() 采用“只向外扩张”策略——只有当新事件的最小时间早于记录或最大时间晚于记录时才写库,从而容忍乱序/补采到的历史数据;
- 启动时的 check_database_integrity() 会自动建库,并在检测到旧版
last_dates.json时执行 migrate_from_last_dates_file() 完成数据迁移(含对旧格式日期的模糊解析与校验),迁移成功后删除旧文件。
4.4 事件投递:带1:Azure:头的 Unix 数据报
拉取到的每条事件经 send_message() 封装为1:Azure:{json}格式的 Unix datagram,发送到 analysisd 队列(SOCKET_HEADER)。几个值得注意的细节:
- 超过
MAX_EVENT_SIZE的事件会输出 WARNING,但仍会尝试发送; - errno 111(连接被拒)提示 “Wazuh must be running”,errno 90 时跳过该条消息——排查“模块有日志但无告警”时可优先确认 Wazuh 是否在运行;
- 各服务会给事件追加标识字段:Log Analytics 事件带
azure_tag: azure-log-analytics及自定义log_analytics_tag(见 iter_log_analytics_events()),Graph 事件带azure_tag: azure-ad-ad-graph/azure-ad-graph及azure_aad_tag(见 graph.py),Storage 事件带azure_tag: azure-storage及azure_storage_tag(见 storage.py)。这些字段是后处理规则区分事件来源的依据; - Storage 下载带重试机制:download_blob() 在遇到
ResourceModifiedError(下载期间 Blob 被修改)时最多重试 3 次。
五、验证集成
应用配置后重启 Wazuh Agent:
systemctl restart wazuh-agent检查模块日志:
grep "azure" /var/ossec/logs/ossec.log正常运行的日志会依次出现 “Azure Log Analytics starting.”、”Getting authentication token.”、”Sending a request to the Log Analytics API.” 等(对应 analytics.py 中的logging.info调用)。Azure 事件最终生成带有azure数据字段的告警,可结合azure_tag、log_analytics_tag等字段进行检索与规则匹配。若日志中出现 “No results”(对应源码 “There are no new results for {tenant}”),通常意味着时间窗口内确无新事件,属于正常现象。
六、常见排查与小结
| 现象 | 可能原因(依据源码) |
|---|---|
| 启动即报认证失败 | 凭证文件缺少必需字段或格式不符(read_auth_file());应用 ID/密钥错误(get_token() 的错误分支) |
| “Wazuh must be running” | Agent 服务未启动导致 analysisd 队列不可达(errno 111,见 azure_utils.py) |
| 事件过大告警 | 单条事件超过MAX_EVENT_SIZE,会记录 WARNING(azure_utils.py) |
| 容器不存在 | Storage 启动时会校验容器是否存在,直接报错退出(storage.py) |
time_offset报 “Invalid offset format” | 单位必须是h、m、d之一(azure_utils.py) |
小结:Wazuh 的 Azure 集成通过一个 wodle 入口、三个服务实现与一个轻量 SQLite 状态库,把 Azure 目录审计、KQL 日志查询和 Blob 存储日志统一转化为带1:Azure:头的 analysisd 事件流。配置层面,只需注册带正确权限的 Azure AD 应用、准备凭证文件,并按本文第三节编写azure-logswodle 配置;实现层面,理解“OAuth2 取令牌 → 时间窗口过滤 → 增量状态入库 → 数据报投递”这条链路,就能快速定位认证、窗口、状态与投递四类问题。相关实现与测试可进一步参阅 wodles/azure/ 目录及 test_azure_logs.py、test_analytics.py、test_graph.py、test_storage.py 等测试用例。
【免费下载链接】wazuhWazuh - The Open Source Security Platform. Unified XDR and SIEM protection for endpoints and cloud workloads.项目地址: https://gitcode.com/GitHub_Trending/wa/wazuh
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考