收集 Lucid 审核日志

支持的平台:

本文档介绍了如何使用 Google Cloud Storage V2 将 Lucid 审核日志注入到 Google Security Operations。

Lucid Software 提供了一套可视化协作套件,包括 Lucidchart、Lucidspark 和 Lucidscale。审核日志 API 仅供 Enterprise Shield 客户使用,可捕获整个组织中的安全和合规性事件,包括账号访问、文档活动、用户管理、管理员操作和团队运营。

准备工作

请确保满足以下前提条件:

  • Google SecOps 实例
  • 已启用 Cloud Storage API 的 GCP 项目
  • 创建和管理 GCS 存储分区的权限
  • 管理 GCS 存储分区的 IAM 政策的权限
  • 创建 Cloud Run 服务、Pub/Sub 主题和 Cloud Scheduler 作业的权限
  • 具有管理员或账号所有者权限的 Lucid Enterprise Shield 账号
  • 访问已启用开发者工具的 Lucid 开发者门户

在 Lucid 中启用开发者工具

在创建 API 凭据之前,您必须有权访问 Lucid 开发者门户。您可以通过以下两种方式启用开发者工具:

方法 1:通过用户设置启用

  1. 登录 lucid.app
  2. 点击右上角的个人资料图标。
  3. 选择账号设置
  4. 勾选启用开发者工具复选框。

方法 2:通过分配管理员角色启用

  1. 以账号所有者或团队管理员的身份登录 lucid.app
  2. 前往管理面板。
  3. 前往用户部分。
  4. 选择目标用户。
  5. 修改用户的角色,并分配 Developer 角色。

配置 Lucid API 访问权限

如需让 Google SecOps 检索审核日志,您需要创建 OAuth 2.0 客户端,并生成具有 account.audit.logs 范围的账号级访问令牌。

创建 OAuth 2.0 应用和客户端

  1. 前往 Lucid 开发者门户
  2. 点击创建应用
  3. 输入应用的名称(例如 Chronicle SIEM Integration)。
  4. 点击新创建的应用以访问其设置。
  5. 前往 OAuth 2.0 标签页。
  6. 为您的 OAuth 2.0 客户端输入一个名称(例如 Chronicle Audit Log Collector)。

  7. 点击创建 OAuth 2.0 客户端

记录客户端凭据

创建 OAuth 2.0 客户端后,门户会显示您的凭据:

  • 客户端 ID:您的唯一客户端标识符。
  • 客户端密钥:您的 API 密钥。

重要提示:请立即复制并保存客户端密钥。如果客户端密钥泄露,请点击 OAuth 2.0 设置页面上的重置客户端密钥按钮。重置密钥会立即撤消访问权限,直到您在集成中更新新密钥为止。

注册重定向 URI

  1. 在 OAuth 2.0 设置页面上,点击添加重定向 URI
  2. 输入集成的重定向 URI。如果使用 Lucid 提供的测试重定向,请输入:

    https://lucid.app/oauth2/clients/<CLIENT_ID>/redirect
    

    <CLIENT_ID> 替换为您的实际客户端 ID。

获取账号级访问令牌

Audit Logs API 需要账号令牌(而非用户令牌)。账号管理员必须授权 OAuth 2.0 客户端代表账号创建令牌。

  1. 引导账号管理员在浏览器中前往以下授权网址:

    https://lucid.app/oauth2/authorizeAccount?client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&scope=account.audit.logs
    

    <CLIENT_ID><REDIRECT_URI> 替换为实际值。

  2. 管理员在权限请求页面上查看所请求的权限,然后点击允许

  3. Lucid 会重定向到包含授权 code 查询参数的重定向 URI。

  4. 通过向令牌端点发出 POST 请求,使用授权代码换取访问令牌:

    curl --request POST \
      --url https://api.lucid.co/oauth2/token \
      --header 'Content-Type: application/json' \
      --data '{
        "grant_type": "authorization_code",
        "client_id": "<CLIENT_ID>",
        "client_secret": "<CLIENT_SECRET>",
        "code": "<AUTHORIZATION_CODE>",
        "redirect_uri": "<REDIRECT_URI>"
      }'
    
  5. 响应包含 access_tokenrefresh_token。请安全地记录这两个值。

验证 API 访问权限

  • 通过发出测试请求来确认访问令牌是否有效:

    curl --request GET \
      --url 'https://api.lucid.co/auditLogs?pageSize=1' \
      --header 'Authorization: Bearer <ACCESS_TOKEN>' \
      --header 'Lucid-Api-Version: 1' \
      --header 'Accept: application/json'
    

成功的响应会返回一个审核日志事件 JSON 数组。

所需 API 权限

  • OAuth 2.0 客户端需要以下范围:

    范围 令牌类型 用途
    account.audit.logs 账号 检索账号的审核日志事件

创建 Google Cloud Storage 存储桶

  1. 前往 Google Cloud 控制台
  2. 选择您的项目或创建新项目。
  3. 在导航菜单中,依次前往 Cloud Storage > 存储分区
  4. 点击创建存储分区
  5. 提供以下配置详细信息:

    设置
    为存储桶命名 输入一个全局唯一的名称(例如 lucid-audit-logs-gcs
    位置类型 根据您的需求进行选择(区域级、双区域、多区域)
    位置 选择营业地点(例如 us-central1
    存储类别 标准(建议用于经常访问的日志)
    访问权限控制 均匀(推荐)
    保护工具 可选:启用对象版本控制或保留政策
  6. 点击创建

为 Cloud Run 函数创建服务账号

  1. GCP 控制台中,依次前往 IAM 和管理 > 服务账号
  2. 点击创建服务账号
  3. 提供以下配置详细信息:
    • 服务账号名称:输入 lucid-audit-collector-sa
    • 服务账号说明:输入 Service account for Cloud Run function to collect Lucid audit logs
  4. 点击创建并继续
  5. 向此服务账号授予对项目的访问权限部分中,添加以下角色:
    1. 点击选择角色
    2. 搜索并选择 Storage Object Admin
    3. 点击 + 添加其他角色
    4. 搜索并选择 Cloud Run Invoker
    5. 点击 + 添加其他角色
    6. 搜索并选择 Cloud Functions Invoker
  6. 点击继续
  7. 点击完成

授予对 GCS 存储桶的 IAM 权限

  1. 前往 Cloud Storage > 存储分区
  2. 点击您的存储桶名称 (lucid-audit-logs-gcs)。
  3. 前往权限标签页。
  4. 点击授予访问权限
  5. 提供以下配置详细信息:
    • 添加主账号:输入服务账号电子邮件地址 (lucid-audit-collector-sa@PROJECT_ID.iam.gserviceaccount.com)
    • 分配角色:选择 Storage Object Admin
  6. 点击保存

创建 Pub/Sub 主题

  1. GCP 控制台中,前往 Pub/Sub > 主题
  2. 点击创建主题
  3. 提供以下配置详细信息:
    • 主题 ID:输入 lucid-audit-trigger
    • 将其他设置保留为默认值
  4. 点击创建

创建 Cloud Run 函数以收集日志

Cloud Run 函数将由来自 Cloud Scheduler 的 Pub/Sub 消息触发,以从 Lucid Audit Logs API 中提取日志并将其写入 GCS。

  1. GCP 控制台中,前往 Cloud Run
  2. 点击创建服务
  3. 选择函数(使用内嵌编辑器创建函数)。
  4. 配置部分中,提供以下配置详细信息:

    设置
    Service 名称 lucid-audit-collector
    区域 选择与您的 GCS 存储桶匹配的区域(例如 us-central1
    运行时 选择 Python 3.12 或更高版本
  5. 触发器(可选)部分中:

    1. 点击 + 添加触发器
    2. 选择 Cloud Pub/Sub
    3. 选择 Cloud Pub/Sub 主题中,选择 lucid-audit-trigger
    4. 点击保存
  6. 身份验证部分中:

    1. 选择需要进行身份验证
    2. 检查 Identity and Access Management (IAM)
  7. 向下滚动并展开容器、网络、安全性

  8. 前往安全性标签页:

    • 服务账号:选择 lucid-audit-collector-sa
  9. 前往容器标签页:

    1. 点击变量和密钥
    2. 为每个环境变量点击+ 添加变量
    变量名称 示例值 说明
    GCS_BUCKET lucid-audit-logs-gcs GCS 存储桶名称
    GCS_PREFIX lucid-audit 日志文件的前缀
    STATE_KEY lucid-audit/state.json 状态文件路径
    LUCID_CLIENT_ID your-oauth-client-id Lucid OAuth 2.0 客户端 ID
    LUCID_CLIENT_SECRET your-oauth-client-secret Lucid OAuth 2.0 客户端密钥
    LUCID_REFRESH_TOKEN your-refresh-token Lucid OAuth 2.0 刷新令牌
    LOOKBACK_HOURS 24 初始回溯期
    PAGE_SIZE 200 每个 API 页面的记录数(最多 200 条)
    MAX_PAGES 50 每次运行的页面数上限
  10. 变量和 Secret 部分中,向下滚动到请求

    • 请求超时:输入 600 秒(10 分钟)
  11. 前往设置标签页:

    • 资源部分中:
      • 内存:选择 512 MiB 或更高值
      • CPU:选择 1
  12. 修订版本伸缩部分中:

    • 实例数下限:输入 0
    • 实例数上限:输入 100
  13. 点击创建

  14. 等待服务创建完成(1-2 分钟)。

  15. 创建服务后,系统会自动打开内嵌代码编辑器

添加函数代码

  1. 入口点字段中输入 main
  2. 在内嵌代码编辑器中,创建两个文件:
  • main.py:

    import functions_framework
    from google.cloud import storage
    import json
    import os
    import urllib3
    from datetime import datetime, timezone, timedelta
    import re
    
    http = urllib3.PoolManager(
        timeout=urllib3.Timeout(connect=10.0, read=60.0),
        retries=False,
    )
    
    storage_client = storage.Client()
    
    GCS_BUCKET = os.environ.get('GCS_BUCKET')
    GCS_PREFIX = os.environ.get('GCS_PREFIX', 'lucid-audit')
    STATE_KEY = os.environ.get('STATE_KEY', 'lucid-audit/state.json')
    LUCID_CLIENT_ID = os.environ.get('LUCID_CLIENT_ID')
    LUCID_CLIENT_SECRET = os.environ.get('LUCID_CLIENT_SECRET')
    LUCID_REFRESH_TOKEN = os.environ.get('LUCID_REFRESH_TOKEN')
    LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24'))
    PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '200'))
    MAX_PAGES = int(os.environ.get('MAX_PAGES', '50'))
    
    API_BASE = 'https://api.lucid.co'
    
    @functions_framework.cloud_event
    def main(cloud_event):
        if not all([GCS_BUCKET, LUCID_CLIENT_ID, LUCID_CLIENT_SECRET, LUCID_REFRESH_TOKEN]):
            print('Error: Missing required environment variables')
            return
    
        try:
            bucket = storage_client.bucket(GCS_BUCKET)
            state = load_state(bucket)
            now = datetime.now(timezone.utc)
    
            if isinstance(state, dict) and state.get('last_event_time'):
                try:
                    last_val = state['last_event_time']
                    if last_val.endswith('Z'):
                        last_val = last_val[:-1] + '+00:00'
                    last_time = datetime.fromisoformat(last_val)
                    last_time = last_time - timedelta(minutes=2)
                except Exception as e:
                    print(f"Warning: Could not parse last_event_time: {e}")
                    last_time = now - timedelta(hours=LOOKBACK_HOURS)
            else:
                last_time = now - timedelta(hours=LOOKBACK_HOURS)
    
            print(f"Fetching audit logs from {last_time.isoformat()} to {now.isoformat()}")
    
            access_token, new_refresh_token = refresh_access_token()
    
            if new_refresh_token:
                save_refresh_token(bucket, new_refresh_token)
    
            records, newest_event_time = fetch_audit_logs(access_token, last_time, now)
    
            if not records:
                print("No new audit log records found.")
                save_state(bucket, now.isoformat())
                return
    
            timestamp = now.strftime('%Y%m%d_%H%M%S')
            object_key = f"{GCS_PREFIX}/lucid_audit_{timestamp}.ndjson"
            blob = bucket.blob(object_key)
    
            ndjson = '\n'.join(
                [json.dumps(record, ensure_ascii=False) for record in records]
            ) + '\n'
            blob.upload_from_string(ndjson, content_type='application/x-ndjson')
    
            print(f"Wrote {len(records)} records to gs://{GCS_BUCKET}/{object_key}")
    
            if newest_event_time:
                save_state(bucket, newest_event_time)
            else:
                save_state(bucket, now.isoformat())
    
            print(f"Successfully processed {len(records)} audit log records")
    
        except Exception as e:
            print(f'Error processing logs: {str(e)}')
            raise
    
    def refresh_access_token():
        url = f"{API_BASE}/oauth2/token"
        body = json.dumps({
            'grant_type': 'refresh_token',
            'refresh_token': LUCID_REFRESH_TOKEN,
            'client_id': LUCID_CLIENT_ID,
            'client_secret': LUCID_CLIENT_SECRET
        }).encode('utf-8')
    
        response = http.request(
            'POST', url,
            body=body,
            headers={'Content-Type': 'application/json'}
        )
    
        if response.status != 200:
            raise Exception(
                f"Token refresh failed: {response.status} - "
                f"{response.data.decode('utf-8')}"
            )
    
        data = json.loads(response.data.decode('utf-8'))
        access_token = data.get('access_token')
        new_refresh_token = data.get('refresh_token')
    
        if not access_token:
            raise Exception("No access_token in token refresh response")
    
        print("Successfully refreshed Lucid API access token")
        return access_token, new_refresh_token
    
    def fetch_audit_logs(access_token, start_time, end_time):
        records = []
        newest_time = None
        page_num = 0
        next_page_url = None
    
        since_str = start_time.strftime('%Y-%m-%dT%H:%M:%S.000Z')
        until_str = end_time.strftime('%Y-%m-%dT%H:%M:%S.000Z')
    
        while page_num < MAX_PAGES:
            page_num += 1
    
            if next_page_url:
                url = next_page_url
            else:
                url = (
                    f"{API_BASE}/auditLogs"
                    f"?pageSize={PAGE_SIZE}"
                    f"&since={since_str}"
                    f"&until={until_str}"
                )
    
            headers = {
                'Authorization': f'Bearer {access_token}',
                'Lucid-Api-Version': '1',
                'Accept': 'application/json'
            }
    
            response = http.request('GET', url, headers=headers)
    
            if response.status == 429:
                print(f"Rate limited on page {page_num}. Stopping pagination.")
                break
    
            if response.status != 200:
                print(
                    f"API error on page {page_num}: {response.status} - "
                    f"{response.data.decode('utf-8')}"
                )
                break
    
            page_results = json.loads(response.data.decode('utf-8'))
    
            if not page_results:
                print(f"No more results at page {page_num}")
                break
    
            records.extend(page_results)
            print(f"Page {page_num}: Retrieved {len(page_results)} events "
                  f"(total: {len(records)})")
    
            for event in page_results:
                try:
                    event_time = event.get('eventTimestamp')
                    if event_time:
                        if newest_time is None or event_time > newest_time:
                            newest_time = event_time
                except Exception as e:
                    print(f"Warning: Could not parse event time: {e}")
    
            link_header = response.headers.get('Link', '')
            next_page_url = parse_link_header(link_header)
    
            if not next_page_url:
                print(f"No next page link found. Pagination complete.")
                break
    
            if len(page_results) < PAGE_SIZE:
                break
    
        print(f"Total audit log records fetched: {len(records)} from {page_num} pages")
        return records, newest_time
    
    def parse_link_header(link_header):
        if not link_header:
            return None
    
        match = re.search(r'<([^>]+)>;\s*rel="next"', link_header)
        if match:
            return match.group(1)
        return None
    
    def load_state(bucket):
        try:
            blob = bucket.blob(STATE_KEY)
            if blob.exists():
                return json.loads(blob.download_as_text())
        except Exception as e:
            print(f"Warning: Could not load state: {e}")
        return {}
    
    def save_state(bucket, last_event_time_iso):
        try:
            state = {
                'last_event_time': last_event_time_iso,
                'last_run': datetime.now(timezone.utc).isoformat()
            }
            blob = bucket.blob(STATE_KEY)
            blob.upload_from_string(
                json.dumps(state, indent=2),
                content_type='application/json'
            )
            print(f"Saved state: last_event_time={last_event_time_iso}")
        except Exception as e:
            print(f"Warning: Could not save state: {e}")
    
    def save_refresh_token(bucket, new_refresh_token):
        try:
            token_key = f"{GCS_PREFIX}/refresh_token.json"
            blob = bucket.blob(token_key)
            blob.upload_from_string(
                json.dumps({'refresh_token': new_refresh_token}, indent=2),
                content_type='application/json'
            )
            print("Saved new refresh token to GCS")
        except Exception as e:
            print(f"Warning: Could not save refresh token: {e}")
    
  • requirements.txt:

      functions-framework==3.*
      google-cloud-storage==2.*
      urllib3>=2.0.0
      ```
    
  1. 点击部署以保存并部署该函数。
  2. 等待部署完成(2-3 分钟)。

创建 Cloud Scheduler 作业

  1. GCP Console 中,前往 Cloud Scheduler
  2. 点击创建作业
  3. 提供以下配置详细信息:

    设置
    名称 lucid-audit-collector-hourly
    区域 选择与 Cloud Run 函数相同的区域
    频率 0 * * * *(每小时一次,整点时)
    时区 选择时区(建议选择世界协调时间 [UTC])
    目标类型 Pub/Sub
    主题 选择lucid-audit-trigger
    消息正文 {}(空 JSON 对象)
  4. 点击创建

测试集成

  1. Cloud Scheduler 控制台中,找到您的作业 (lucid-audit-collector-hourly)。
  2. 点击强制运行以手动触发作业。
  3. 等待几秒钟。
  4. 前往 Cloud Run > 服务
  5. 点击 lucid-audit-collector
  6. 点击日志标签页。
  7. 验证函数是否已成功执行。请查找以下内容:

    Fetching audit logs from YYYY-MM-DDTHH:MM:SS+00:00 to YYYY-MM-DDTHH:MM:SS+00:00
    Successfully refreshed Lucid API access token
    Page 1: Retrieved X events (total: X)
    Wrote X records to gs://lucid-audit-logs-gcs/lucid-audit/lucid_audit_YYYYMMDD_HHMMSS.ndjson
    Successfully processed X audit log records
    
  8. 前往 Cloud Storage > 存储分区

  9. 点击 lucid-audit-logs-gcs

  10. 转到 lucid-audit/ 文件夹。

  11. 验证是否已创建具有当前时间戳的新 .ndjson 文件。

如果您在日志中看到错误,请执行以下操作:

  • HTTP 401:验证 LUCID_CLIENT_IDLUCID_CLIENT_SECRETLUCID_REFRESH_TOKEN 环境变量是否正确
  • HTTP 403:验证 OAuth 2.0 客户端是否具有 account.audit.logs 范围,以及令牌是否为账号令牌
  • HTTP 429:速率限制 - 函数将停止分页,并在下次预定运行时恢复
  • 缺少环境变量:验证是否已在 Cloud Run 函数配置中设置所有必需的变量

审核日志事件类别

Lucid 审核日志分为以下事件类别:

类别 说明
登录 与用户登录相关的事件
内容 与文档和文件夹访问及修改相关的事件
管理 与管理员活动和账号变更相关的事件
用户 与用户对个人设置执行的操作相关的事件
团队 与团队运营相关的活动

如需查看事件类型及其架构的完整列表,请参阅 Lucid 审核日志事件文档。

FedRAMP 环境

Lucid FedRAMP 环境中的用户使用不同的授权和 API 端点。如需了解正确的端点网址,请参阅 Lucid FedRAMP 环境文档。

检索 Google SecOps 服务账号

  1. 依次前往 SIEM 设置 > Feed
  2. 点击添加新 Feed
  3. 点击配置单个 Feed
  4. Feed 名称字段中,输入 Feed 的名称(例如 Lucid Audit Logs)。
  5. 选择 Google Cloud Storage V2 作为来源类型
  6. 选择 Lucid 作为日志类型
  7. 点击获取服务账号。系统会显示一个唯一的服务账号电子邮件地址,例如:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. 复制此电子邮件地址,以便在下一步中使用。

  9. 点击下一步

  10. 为以下输入参数指定值:

    • 存储桶网址:输入带有前缀路径的 GCS 存储桶 URI:

      gs://lucid-audit-logs-gcs/lucid-audit/
      
    • 来源删除选项:根据您的偏好选择删除选项:

      • 永不:转移后永不删除任何文件(建议用于测试)。
      • 删除已转移的文件:在成功转移后删除文件。
      • 删除已转移的文件和空目录:成功转移后删除文件和空目录。

    • 文件存在时间上限:包含在过去指定天数内修改的文件(默认值为 180 天)

    • 资产命名空间资产命名空间

    • 注入标签:要应用于此 Feed 中事件的标签

  11. 点击下一步

  12. 最终确定界面中查看新的 Feed 配置,然后点击提交

向 Google SecOps 服务账号授予 IAM 权限

Google SecOps 服务账号需要您的 GCS 存储桶的 Storage Object Viewer 角色。

  1. 前往 Cloud Storage > 存储分区
  2. 点击 lucid-audit-logs-gcs
  3. 前往权限标签页。
  4. 点击授予访问权限
  5. 提供以下配置详细信息:
    • 添加主账号:粘贴 Google SecOps 服务账号电子邮件地址
    • 分配角色:选择 Storage Object Viewer
  6. 点击保存

UDM 映射表

日志字段 UDM 映射 逻辑
document_opened additional.fields 如果非空,则与从每个来源字段创建的标签合并
share_link_enable additional.fields
restricted_account_enable additional.fields
event1.documentIds additional.fields
team_folder additional.fields
method_type additional.fields
extensions.auth.type extensions.auth.type 对于登录/退出登录事件,请设置为“AUTHTYPE_UNSPECIFIED”
eventTimestamp metadata.event_timestamp 使用日期匹配 ISO8601 或 yyyy-MM-ddTHH:mm:ss.SSSSSSZ 进行转换
has_user_login metadata.event_type 根据 has_* 标志设置:如果 has_user_login 和 has_target_user 为 true,则为 USER_LOGIN;如果 has_user_logout 和 has_target_user 为 true,则为 USER_LOGOUT;如果 has_user_resource_updated、has_target_resource 和 has_principal_user 为 true,则为 USER_RESOURCE_UPDATE_CONTENT;如果 has_principal_user、has_target_application 和 has_target_user 为 true,则为 USER_CREATION;如果 has_target_resource 和 has_principal_user 为 true,则为 USER_RESOURCE_CREATION;如果 has_target_file、has_principal 和 has_target 为 true,则为 FILE_CREATION;如果 has_target_resource 为 true,则为 USER_RESOURCE_ACCESS;如果 has_principal_user 为 true,则为 USER_COMMUNICATION;如果 has_principal 为 true 且 has_target 为 false,则为 STATUS_UPDATE;否则为 GENERIC_EVENT
has_user_logout metadata.event_type
has_user_resource_updated metadata.event_type
has_principal_user metadata.event_type
has_target_resource metadata.event_type
has_target_file metadata.event_type
has_principal metadata.event_type
has_target_user metadata.event_type
has_target_application metadata.event_type
has_target metadata.event_type
event1.event1Type metadata.product_event_type 直接复制值
actor.actorIp principal.asset.ip 如果值不为空,则直接复制
actor.actorIp principal.ip 如果值不为空,则直接复制
actor.actorAccountId principal.resource.id 如果值不为空,则直接复制
actor.actorClient principal.resource.name 如果值不为空,则直接复制
flowId principal.resource.product_object_id 如果值不为空,则直接复制
actor.actorType principal.user.attribute.roles 如果 eventType 不是登录/退出,且 actor_type 不为空,则从 actor_type 合并
actor.actorEmail principal.user.email_addresses 如果 actor_email 不为空且是有效的电子邮件地址,并且 eventType 不是登录/退出,则合并
actor.actorUserId principal.user.userid 如果该值不为空且 eventType 不是登录/退出登录,则直接复制该值
event1.registrationMethod security_result.description 如果值不为空,则直接复制
event1.source target.application 如果值不为空,则直接复制
event1.publishedLink.link target.file.full_path 如果值不为空,则直接复制
event1.filename target.file.names 如果不为空,则合并
targetData._targetType target.resource.attribute.labels 如果非空,则与从每个来源字段创建的标签合并
targetData._targetId target.resource.attribute.labels
event1.format target.resource.attribute.labels
event1.method target.resource.attribute.labels
event1.publishedLink.format target.resource.attribute.labels
accountId target.resource.id 如果值不为空,则直接复制
event1.destinationFolderName target.resource.name 如果不为空,则设置为 destinationFolderName;否则,如果不为空,则设置为 folderName;否则,如果不为空,则设置为 publishedLink.name
event1.folderName target.resource.name
event1.publishedLink.name target.resource.name
event1.documentId target.resource.product_object_id 如果值不为空,则直接复制
actor.actorType target.user.attribute.roles 如果 eventType 为登录/退出,则从 actor_type 合并;如果非空,则从 event_role 合并
event1.role target.user.attribute.roles
actor.actorEmail target.user.email_addresses 如果登录/退出有效,则从 actor_email 合并,否则从 _target 中的 userEmail 合并
targetData.userEmail target.user.email_addresses
event1.destinationFolderId target.user.product_object_id 如果不为空,则设置为 destinationFolderId;否则,如果不为空,则设置为 folderId
event1.folderId target.user.product_object_id
targetData.displayName target.user.user_display_name 如果值不为空,则直接复制
actor.actorUserId target.user.userid 如果不为空且 eventType 为登录/退出,则直接复制该值
event1.product metadata.product_name 如果商品中的值不为空,则使用该值,否则使用“LUCID”
metadata.vendor_name metadata.vendor_name 设置为“LUCID”

更新日志

查看相应解析器的更改日志

需要更多帮助?获得社区成员和 Google SecOps 专业人士的解答。