收集 Workday HCM 日志
本文档介绍了如何使用第三方 API 设置 Feed,以将 Workday HCM 日志注入到 Google Security Operations。
解析器从 JSON 格式的日志中提取 Workday HCM 用户数据。它可处理各种数据转换,包括重命名字段、合并嵌套对象、解析日期,以及填充用户属性、就业详情和组织结构的 UDM 字段。
准备工作
确保您满足以下前提条件:
- Google SecOps 实例。
- 拥有 Workday 的特权访问权限,并具有安全管理员或同等权限。
配置 Workday API 身份验证
创建集成系统用户 (ISU)
- 以管理员权限登录 Workday。
- 在搜索栏中,输入创建集成系统用户,然后选择该任务。
- 输入用户名(例如
ISU_SecOps_HCM)。 - 设置密码。
- 将会话超时时间(分钟)设置为
0,以防止 ISU 超时。 - 启用不允许界面会话,以通过限制界面登录来增强安全性。
- 前往维护密码规则任务。
- 将集成系统用户添加到不受密码过期限制的系统用户字段。
创建集成安全组
- 在搜索栏中,输入创建安全群组,然后选择相应任务。
- 找到租户安全群组的类型字段,然后选择集成系统安全群组(不受约束)。
- 为安全组提供名称(例如
ISG_SecOps_HCM)。 - 点击确定。
- 点击新创建的安全组对应的修改。
- 将上一步中的集成系统用户分配给安全组。
- 点击完成。
向安全群组授予网域访问权限
Google SecOps Feed 从四个 Workday REST API 端点检索数据。每个端点都需要向集成安全组授予特定的网域安全政策权限。
- 在搜索栏中,输入维护安全群组的权限,然后选择该任务。
- 从源安全组列表中选择您创建的安全组(例如
ISG_SecOps_HCM)。 - 点击确定。
- 前往网域安全政策权限。
为以下每个网域添加 GET 访问权限:
API 端点 必需的网域安全政策 /workers- 工作人员名单、个人资料和当前人员配备情况Worker Data: Public Worker Reports、Worker Data: Current Staffing Information、Person Data: Work Contact Information/workers/{id}/timeOffEntries- 休假余额Worker Data: Time Off (Time Off Balances),Worker Data: Time Off (Time Off Balances Manager View)/workers/{id}/history- 工作人员配置历史记录Worker Data: Current Staffing Information/supervisoryOrganizations- 组织结构Worker Data: Organization Information点击确定。
点击完成以保存更改。
激活安全政策更改
- 在搜索栏中,输入激活待处理的安全政策更改,然后选择相应任务。
- 在注释字段中输入更改原因(例如
Granting API access for Google SecOps HCM integration)。 - 点击确定。
- 选择确认,然后点击确定。
注册 API 客户端以进行集成
- 在搜索栏中,输入为集成注册 API 客户端,然后选择该任务。
- 点击创建。
提供以下配置详细信息:
- 客户端名称:输入一个名称(例如
Google SecOps HCM Client)。 - 系统用户:选择您创建的集成系统用户(例如
ISU_SecOps_HCM)。 范围:选择以下范围:
范围 对于以下各项是必需的 人员配备 /workers和/workers/{id}/history端点联系信息 /workers返回的工作电子邮件地址和手机字段(用于 UDM 相关性分析)休假和请假 /workers/{id}/timeOffEntries个端点组织和角色 /supervisoryOrganizations个端点租户不可配置 任何 OAuth 2.0 API 客户端(系统级集成和令牌轮换)
- 客户端名称:输入一个名称(例如
点击保存。
点击确定。
立即复制并保存客户端 ID 和客户端密钥。
生成 OAuth 2.0 刷新令牌
- 在搜索栏中,输入管理集成刷新令牌,然后选择该选项。
- 点击 Generate New Refresh Token(生成新的刷新令牌)。
- 在 Workday 账号字段中,搜索并选择集成系统用户(例如
ISU_SecOps_HCM)。 - 选择您创建的 API 客户端,然后点击确定。
- 复制并保存刷新令牌。
获取 API 端点网址
- 在搜索栏中,输入查看 API 客户端,然后选择该选项。
- 在 API Clients for Integrations 下,找到您创建的客户端(例如
Google SecOps HCM Client)。 复制并保存以下详细信息:
- 令牌端点:用于获取访问令牌的网址(例如
https://wd2-impl-services1.workday.com/ccx/oauth2/YOUR_TENANT/token)。 - Workday REST API 端点:API 调用的基础网址(例如
https://wd2-impl-services1.workday.com/ccx/api/v1/YOUR_TENANT)。
- 令牌端点:用于获取访问令牌的网址(例如
生成 OAuth 访问令牌
使用 curl 或类似的 HTTP 客户端向令牌端点发送 POST 请求:
curl -X POST "https://HOSTNAME/ccx/oauth2/TENANT/token" \
-d "grant_type=refresh_token" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "refresh_token=YOUR_REFRESH_TOKEN"
这会返回一个访问令牌(例如 "access_token": "abcd1234")。复制并保存该访问令牌。
验证 API 访问权限
在配置 Feed 之前,请验证 ISU 是否拥有关键端点所需的权限。将变量替换为您的实际值:
TOKEN="your-access-token"
HOST="your-workday-host"
TENANT="your-tenant"
# Test 1: Workers (should return worker list)
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"https://$HOST/ccx/api/v1/$TENANT/workers?limit=1"
# Test 2: Time off entries (replace WORKER_ID with an ID from Test 1)
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"https://$HOST/ccx/api/v1/$TENANT/workers/WORKER_ID/timeOffEntries"
# Test 3: Worker history (replace WORKER_ID with an ID from Test 1)
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"https://$HOST/ccx/api/v1/$TENANT/workers/WORKER_ID/history"
# Test 4: Supervisory organizations
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"https://$HOST/ccx/api/v1/$TENANT/supervisoryOrganizations"
每项测试都应返回 HTTP 状态 200。如果任何端点返回 403,请参阅下文的问题排查部分。
在 Google SecOps 中配置 Feed 以注入 Workday HCM 数据
设置 Feed
- 依次前往 SIEM 设置 > Feed。
- 点击添加新 Feed。
- 在下一页上,点击配置单个 Feed。
- 在 Feed 名称字段中,输入 Feed 的名称(例如
Workday HCM)。 - 选择第三方 API 作为来源类型。
- 选择 Workday 作为日志类型。
- 点击下一步。
配置 Feed 参数
为以下输入参数指定值:
API 主机名:Workday REST API 端点的完全限定域名(例如
wd2-impl-services1.workday.com)。租户:Workday REST API 端点的最后一个路径元素,用于标识您的 Workday 实例。
访问令牌:上一部分中生成的 OAuth 访问令牌。
高级选项:
- 资产命名空间:资产命名空间。
- 注入标签:要应用于此 Feed 中事件的标签。
- 点击下一步。
- 在最终确定界面中查看新的 Feed 配置,然后点击提交。
问题排查
特定端点上的 403 禁止访问错误
如果 Feed 报告错误,或者验证 curl 命令针对特定端点返回 403,则表示集成系统用户缺少权限。
| 失败的端点 | 修复 |
|---|---|
/workers/{id}/timeOffEntries |
为 Worker Data: Time Off (Time Off Balances) 和 Worker Data: Time Off (Time Off Balances Manager View) 网域添加 GET 访问权限。向 API 客户端添加休假和请假范围。 |
/workers/{id}/history |
为 Worker Data: Historical Staffing Information 网域添加 GET 访问权限。验证是否已为 API 客户端分配 Staffing 范围。 |
/supervisoryOrganizations |
为 Manage: Supervisory Organization 或 View: Supervisory Organization 网域添加 GET 访问权限。向 API 客户端添加组织和角色范围。 |
更改权限后:
- 在 Workday 中运行激活待处理的安全政策更改。
- 如果您向 API 客户端添加了新范围,请通过管理集成项目的刷新令牌生成新的刷新令牌,然后生成新的访问令牌。
- 如果访问令牌发生更改,请使用新访问令牌更新 Feed 配置。
身份验证错误
- 401 未经授权:访问令牌已过期。使用刷新令牌生成新令牌并更新 Feed。
- 客户端无效:验证客户端 ID 和客户端密钥是否正确。
- 刷新令牌无效:刷新令牌可能已被撤消。通过管理集成刷新令牌生成新的刷新令牌。
UDM 映射表
| 日志字段 | UDM 映射 | 逻辑 |
|---|---|---|
entity_host_name |
entity.asset.hostname |
直接映射 |
location.descriptor |
entity.location.city |
直接映射 |
AU_EFFECTIVE_DATE |
entity.resource.attribute.labels.value |
直接映射 |
COMPANY_EFFECTIVE_DATE |
entity.resource.attribute.labels.value |
直接映射 |
ORIG_HIRE_DT |
entity.resource.attribute.labels.value |
直接映射 |
STATUS_EFFECTIVE_DATE |
entity.resource.attribute.labels.value |
直接映射 |
href |
entity.url |
直接映射 |
CONT_START_DTE |
entity.user.attribute.labels.value |
直接映射 |
EMPL_TYPE |
entity.user.attribute.labels.value |
直接映射 |
EXEC_CD |
entity.user.attribute.labels.value |
直接映射 |
EXEC_DESCR |
entity.user.attribute.labels.value |
直接映射 |
HR_Status |
entity.user.attribute.labels.value |
直接映射 |
Is_Active |
entity.user.attribute.labels.value |
直接映射 |
Is_Manager |
entity.user.attribute.labels.value |
直接映射 |
JOB_CODE |
entity.user.attribute.labels.value |
直接映射 |
ORG_CD |
entity.user.attribute.labels.value |
直接映射 |
ORG_Container |
entity.user.attribute.labels.value |
直接映射 |
ORG_Container_Name |
entity.user.attribute.labels.value |
直接映射 |
PER_Status |
entity.user.attribute.labels.value |
直接映射 |
POSITION_NBR |
entity.user.attribute.labels.value |
直接映射 |
PS_ELID |
entity.user.attribute.labels.value |
直接映射 |
REG_TEMP |
entity.user.attribute.labels.value |
直接映射 |
WB_LOGON_ID |
entity.user.attribute.labels.value |
直接映射 |
ORG_DESCR |
entity.user.department |
已合并 |
primarySupervisoryOrganization.descriptor |
entity.user.department |
已合并 |
Email |
entity.user.email_addresses |
已合并 |
Work_Email |
entity.user.email_addresses |
已合并 |
primaryWorkEmail |
entity.user.email_addresses |
已合并 |
EMPLID |
entity.user.employee_id |
直接映射 |
Employee_ID |
entity.user.employee_id |
直接映射 |
First_Name |
entity.user.first_name |
直接映射 |
Legal_Name_First_Name |
entity.user.first_name |
直接映射 |
HIRE_DATE |
entity.user.hire_date |
解析为 RFC 3339 |
Hire_Date |
entity.user.hire_date |
解析为 RFC 3339 |
Last_Name |
entity.user.last_name |
直接映射 |
Legal_Name_Last_Name |
entity.user.last_name |
直接映射 |
gopher-supervisor.primaryWorkEmail |
entity.user.managers.email_addresses |
已合并 |
Reports_To_EMPLID |
entity.user.managers.employee_id |
直接映射 |
gopher-supervisor.id |
entity.user.managers.product_object_id |
已重命名/已映射 |
Reports_To_Name |
entity.user.managers.user_display_name |
直接映射 |
gopher-supervisor.descriptor |
entity.user.managers.user_display_name |
已重命名/已映射 |
primaryWorkPhone |
entity.user.phone_numbers |
已合并 |
Termination_Date |
entity.user.termination_date |
解析为 RFC 3339 |
timeoff.descriptor |
entity.user.time_off.description |
直接映射 |
timeoff.date |
entity.user.time_off.interval.start_time |
解析为 RFC 3339 |
HR_JOB_TITLE |
entity.user.title |
直接映射 |
Job_Profile |
entity.user.title |
直接映射 |
businessTitle |
entity.user.title |
直接映射 |
Full_Name |
entity.user.user_display_name |
直接映射 |
descriptor |
entity.user.user_display_name |
直接映射 |
udm_metadata |
metadata |
已重命名/已映射 |
metadata_entity_type |
metadata.entity_type |
直接映射 |
actual_completed_date_and_time |
metadata.event_timestamp |
解析为 MM/dd/yyyy HH:mm:ss a |
body.time |
metadata.event_timestamp |
解析为 UNIX_MS |
requestTime |
metadata.event_timestamp |
解析为 RFC 3339 |
timestamp |
metadata.event_timestamp |
解析为 RFC 3339 |
EMPLID |
metadata.product_entity_id |
直接映射 |
Employee_ID |
metadata.product_entity_id |
直接映射 |
id |
metadata.product_entity_id |
直接映射 |
Source_Name |
metadata.product_name |
直接映射 |
userAgent |
network.http.parsed_user_agent |
已重命名/已映射 |
userAgent |
network.http.user_agent |
直接映射 |
sessionId |
network.session_id |
直接映射 |
ipAddress |
principal.ip |
已合并 |
taskId |
principal.process.pid |
直接映射 |
activityAction_label |
principal.resource.attribute.labels |
已合并 |
body.event.Submitted_By |
principal.user.userid |
直接映射 |
body.event.Response_Message |
security_result.action_details |
直接映射 |
body.event.Messages |
security_result.description |
直接映射 |
actual_start_date_and_time_label |
security_result.detection_fields |
已合并 |
background_process_is_running_label |
security_result.detection_fields |
已合并 |
by_person_label |
security_result.detection_fields |
已合并 |
created_from_trigger_label |
security_result.detection_fields |
已合并 |
items_processed_label |
security_result.detection_fields |
已合并 |
percent_complete_label |
security_result.detection_fields |
已合并 |
processing_time_label |
security_result.detection_fields |
已合并 |
scheduled_start_date_and_time_label |
security_result.detection_fields |
已合并 |
sent_on_label |
security_result.detection_fields |
已合并 |
total_duration_label |
security_result.detection_fields |
已合并 |
body.event.Integration_Event_Status |
security_result.summary |
直接映射 |
body.event.Integration_System |
target.application |
直接映射 |
target_data.id |
target.resource.product_object_id |
直接映射 |
deviceType |
target.resource.resource_subtype |
直接映射 |
deviceType |
target.resource.type |
已映射:(?i)(Desktop/Laptop/Mobile) → DEVICE |
user_display_name |
target.user.user_display_name |
直接映射 |
systemAccount |
target.user.userid |
直接映射 |
| 不适用 | entity.resource.attribute.labels.key |
常量:COMPANY_EFFECTIVE_DATE |
| 不适用 | entity.user.attribute.labels.key |
常量:ORG_Container |
| 不适用 | metadata.product_name |
常量:HCM |
| 不适用 | metadata.vendor_name |
常量:Workday |
| 不适用 | target.resource.type |
常量:DEVICE |