收集 LenelS2 OnGuard 日志

支持的平台:

本文档介绍了如何从 LenelS2 (Honeywell) OnGuard 收集日志,并使用 Webhook Feed 将其转发到 Google Security Operations。由于 OnGuard 本身不支持直接 webhook 或 HTTP POST 传送,因此本指南使用自定义中间件脚本来轮询 OnGuard OpenAccess REST API 以获取事件,并将这些事件转发到 Google SecOps webhook 提取端点。

LenelS2 OnGuard 是一套实体访问权限控制和徽章管理系统,可管理企业设施中的持卡人、凭据、读卡器、面板和门禁事件。OpenAccess REST API 可提供对 OnGuard 数据的程序化访问,包括已记录的事件,例如访问权限授予、访问权限拒绝、门保持打开、门被强行打开和警报事件。

准备工作

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

  • Google SecOps 实例
  • 已激活 OpenAccess 许可的 OnGuard 服务器(版本 7.5 或更高版本)
  • 在 OpenAccess 服务器上运行的以下 OnGuard 服务:

    • LS Communication Server
    • LS 事件上下文提供程序
    • LS Web Event Bridge
    • LS OpenAccess
    • LS Web 服务
  • 具有以下最低权限的内部 OnGuard 用户账号:

    • 系统权限:在访问权限控制硬件下,对门禁面板读卡器警报面板查询权限
    • 系统权限:在访问权限控制下,对细分拥有查询权限
    • 监控权限:在控制下,开门继电器和读卡器输出
  • 从中间件主机到 OnGuard 服务器(通过 TCP 端口 8080,即默认的 OpenAccess 端口)的网络连接

  • 从中间件主机到互联网的网络连接(用于访问 Google SecOps webhook 端点)

  • 中间件主机上安装了 Python 3.8 或更高版本

  • 对 Google Cloud Console 的访问权限(用于创建 API 密钥)

在 Google SecOps 中创建 Webhook Feed

创建 Feed

  1. 依次前往 SIEM 设置 > Feed
  2. 点击添加新 Feed
  3. 在下一页上,点击配置单个 Feed
  4. Feed 名称字段中,输入 Feed 的名称(例如 LenelS2 OnGuard Events)。
  5. 选择 Webhook 作为来源类型
  6. 选择 Lenel OnGuard 作为日志类型
  7. 点击下一步
  8. 为以下输入参数指定值:
    • 拆分定界符:输入 \n(换行符定界符,因为中间件以 NDJSON 格式发送事件)
    • 资产命名空间资产命名空间
    • 注入标签:要应用于此 Feed 中事件的标签
  9. 点击下一步
  10. 最终确定界面中查看新的 Feed 配置,然后点击提交

生成并保存密钥

创建 Feed 后,您必须生成用于身份验证的密钥:

  1. 在 Feed 详情页面上,点击生成密钥
  2. 系统会显示一个对话框,其中包含密钥。
  3. 复制并妥善保存此密钥。

获取 Feed 端点网址

  1. 前往相应 Feed 的详细信息标签页。
  2. 端点信息部分,复制 Feed 端点网址
  3. 网址格式为:

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    

    https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    
  4. 保存此网址以供后续步骤使用。

  5. 点击完成

创建 Google Cloud API 密钥

Chronicle 需要 API 密钥才能进行身份验证。在 Google Cloud Console 中创建受限 API 密钥。

创建 API 密钥

  1. 前往 Google Cloud 控制台的“凭据”页面
  2. 选择您的项目(与您的 Chronicle 实例关联的项目)。
  3. 依次点击创建凭据> API 密钥
  4. 系统会创建一个 API 密钥,并在对话框中显示该密钥。
  5. 点击修改 API 密钥以限制密钥。

限制 API 密钥

  1. API 密钥设置页面中:
    • 名称:输入一个描述性名称(例如 Chronicle Webhook API Key
  2. API 限制下:
    1. 选择限制密钥
    2. 选择 API 下拉菜单中,搜索并选择 Google SecOps API(或 Chronicle API)。
  3. 点击保存
  4. 从页面顶部的 API 密钥字段复制 API 密钥值。
  5. 安全地保存 API 密钥。

验证 OnGuard OpenAccess 前提条件

在配置中间件之前,请验证 OnGuard OpenAccess API 是否正常运行。

验证 OpenAccess 服务是否正在运行

  1. 在 OnGuard 服务器上,打开 Windows 服务 (services.msc)。
  2. 确认以下服务正在运行:
    • LS OpenAccess
    • LS Communication Server
    • LS 事件上下文提供程序
    • LS Web Event Bridge
    • LS Web 服务
    • LS Message Broker (RabbitMQ)
  3. 如果任何服务已停止,请右键点击该服务,然后选择启动

验证 OpenAccess API 是否可访问

  1. 在中间件主机上打开网络浏览器。
  2. 导航到以下网址:

    https://<ONGUARD_SERVER>:8080/api/access/onguard/openaccess/version?version=1.0
    
  3. <ONGUARD_SERVER> 替换为 OnGuard 服务器的 IP 地址或主机名。

  4. API 会返回一个包含 OpenAccess 版本详细信息的 JSON 响应,以确认该服务可访问。

检索身份验证目录

  1. 发送 GET 请求以检索可用的身份验证目录:

    https://<ONGUARD_SERVER>:8080/api/access/onguard/openaccess/directories?version=1.0
    
  2. 响应包含目录列表。记下您将用于身份验证的目录(通常是内部 OnGuard 目录)的 IDName

验证 OnGuard 用户账号

  1. 在 OnGuard 服务器上打开 OnGuard 系统管理应用。
  2. 依次前往管理 > 用户
  3. 选择指定用于 API 访问的用户账号。
  4. 点击权限标签页。
  5. 系统权限组下,确认已启用以下权限:
    • 访问权限控制硬件下:查询门禁面板读卡器警报面板
    • 访问权限控制下:对细分进行查询
  6. 监控权限组下,确认已启用以下权限:
    • 控制下:打开车门
    • 控制下:Relay 和阅读器输出

获取应用 ID

使用 OpenAccess API 的每个应用都必须具有唯一的应用 ID。这是您定义的字符串值(例如 ChronicleForwarder)。系统会随每个 API 请求一起发送应用 ID 作为 Application-Id HTTP 标头。

配置 OnGuard-to-Chronicle 中间件

由于 OnGuard 本身不支持出站 webhook 或 HTTP POST 传送,因此需要一个中间件脚本来轮询 OpenAccess REST API 以获取已记录的事件,并将这些事件转发到 Google SecOps webhook 端点。

构建 Chronicle 网络钩子网址

  • 将 Chronicle 端点网址和 API 密钥组合在一起:

    <ENDPOINT_URL>?key=<API_KEY>
    
  • 示例

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...
    

创建中间件脚本

  1. 在中间件主机上,为脚本创建一个目录:

    mkdir -p /opt/onguard-chronicle-forwarder
    cd /opt/onguard-chronicle-forwarder
    
  2. 安装所需的 Python 软件包:

    pip3 install requests
    
  3. 创建转发器脚本:

    nano onguard_to_chronicle.py
    
  4. 将以下内容添加到脚本中:

    #!/usr/bin/env python3
    """LenelS2 OnGuard to Google SecOps (Chronicle) Event Forwarder.
    
    Polls the OnGuard OpenAccess REST API for logged events and forwards
    them to a Chronicle webhook ingestion endpoint.
    """
    
    import json
    import logging
    import os
    import sys
    import time
    from datetime import datetime, timedelta, timezone
    
    import requests
    import urllib3
    
    # Suppress SSL warnings if using self-signed certificates
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    
    # ── Configuration ──────────────────────────────────────────────────
    ONGUARD_HOST = os.environ.get("ONGUARD_HOST", "192.168.1.100")
    ONGUARD_PORT = os.environ.get("ONGUARD_PORT", "8080")
    ONGUARD_USERNAME = os.environ.get("ONGUARD_USERNAME", "")
    ONGUARD_PASSWORD = os.environ.get("ONGUARD_PASSWORD", "")
    ONGUARD_DIRECTORY_ID = os.environ.get("ONGUARD_DIRECTORY_ID", "")
    APPLICATION_ID = os.environ.get("APPLICATION_ID", "ChronicleForwarder")
    VERIFY_SSL = os.environ.get("VERIFY_SSL", "false").lower() == "true"
    
    CHRONICLE_ENDPOINT = os.environ.get("CHRONICLE_ENDPOINT", "")
    CHRONICLE_API_KEY = os.environ.get("CHRONICLE_API_KEY", "")
    CHRONICLE_SECRET_KEY = os.environ.get("CHRONICLE_SECRET_KEY", "")
    
    POLL_INTERVAL_SECONDS = int(os.environ.get("POLL_INTERVAL_SECONDS", "30"))
    PAGE_SIZE = int(os.environ.get("PAGE_SIZE", "100"))
    LOOKBACK_MINUTES = int(os.environ.get("LOOKBACK_MINUTES", "5"))
    
    # ── Logging ────────────────────────────────────────────────────────
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(message)s",
        handlers=[
            logging.StreamHandler(sys.stdout),
            logging.FileHandler("/opt/onguard-chronicle-forwarder/forwarder.log"),
        ],
    )
    logger = logging.getLogger(__name__)
    
    BASE_URL = f"https://{ONGUARD_HOST}:{ONGUARD_PORT}/api/access/onguard/openaccess"
    
    class OnGuardClient:
        """Client for the OnGuard OpenAccess REST API."""
    
        def __init__(self):
            self.session_token = None
            self.headers = {
                "Content-Type": "application/json",
                "Application-Id": APPLICATION_ID,
            }
    
        def authenticate(self):
            """Authenticate to OpenAccess and obtain a session token."""
            url = f"{BASE_URL}/authentication?version=1.0"
            payload = {
                "user_name": ONGUARD_USERNAME,
                "password": ONGUARD_PASSWORD,
                "directory_id": ONGUARD_DIRECTORY_ID,
            }
            try:
                resp = requests.post(
                    url,
                    headers=self.headers,
                    json=payload,
                    verify=VERIFY_SSL,
                    timeout=30,
                )
                resp.raise_for_status()
                data = resp.json()
                self.session_token = data.get("session_token")
                self.headers["Session-Token"] = self.session_token
                logger.info("Successfully authenticated to OnGuard OpenAccess.")
            except requests.exceptions.RequestException as exc:
                logger.error("Authentication failed: %s", exc)
                raise
    
        def keepalive(self):
            """Renew the session idle timeout."""
            url = f"{BASE_URL}/keepalive?version=1.0"
            try:
                resp = requests.get(
                    url, headers=self.headers, verify=VERIFY_SSL, timeout=15
                )
                resp.raise_for_status()
            except requests.exceptions.RequestException:
                logger.warning("Keepalive failed. Re-authenticating.")
                self.authenticate()
    
        def get_logged_events(self, start_time, page_number=1):
            """Retrieve a page of logged events since start_time."""
            url = f"{BASE_URL}/logged_events?version=1.0"
            params = {
                "filter": f"timestamp >= '{start_time}'",
                "page_number": page_number,
                "page_size": PAGE_SIZE,
                "order_by": "timestamp",
            }
            try:
                resp = requests.get(
                    url,
                    headers=self.headers,
                    params=params,
                    verify=VERIFY_SSL,
                    timeout=30,
                )
                resp.raise_for_status()
                return resp.json()
            except requests.exceptions.RequestException as exc:
                logger.error("Failed to retrieve logged events: %s", exc)
                return None
    
        def logout(self):
            """Logout and invalidate the session token."""
            url = f"{BASE_URL}/authentication?version=1.0"
            try:
                requests.delete(
                    url, headers=self.headers, verify=VERIFY_SSL, timeout=15
                )
                logger.info("Logged out of OnGuard OpenAccess.")
            except requests.exceptions.RequestException:
                pass
    
    def send_to_chronicle(events):
        """Send a batch of events to the Chronicle webhook endpoint."""
        if not events:
            return True
    
        url = f"{CHRONICLE_ENDPOINT}?key={CHRONICLE_API_KEY}"
        headers = {
            "Content-Type": "application/json",
            "x-chronicle-auth": CHRONICLE_SECRET_KEY,
        }
        # Send events as NDJSON (newline-delimited JSON)
        body = "\n".join(json.dumps(event) for event in events)
    
        try:
            resp = requests.post(url, headers=headers, data=body, timeout=30)
            resp.raise_for_status()
            logger.info("Sent %d events to Chronicle.", len(events))
            return True
        except requests.exceptions.RequestException as exc:
            logger.error("Failed to send events to Chronicle: %s", exc)
            return False
    
    def main():
        """Main polling loop."""
        logger.info("Starting OnGuard-to-Chronicle forwarder.")
        client = OnGuardClient()
        client.authenticate()
    
        last_poll_time = datetime.now(timezone.utc) - timedelta(minutes=LOOKBACK_MINUTES)
    
        while True:
            try:
                current_time = datetime.now(timezone.utc)
                start_time_str = last_poll_time.strftime("%Y-%m-%dT%H:%M:%SZ")
    
                all_events = []
                page = 1
                while True:
                    result = client.get_logged_events(start_time_str, page_number=page)
                    if result is None:
                        # Session may have expired; re-authenticate
                        client.authenticate()
                        result = client.get_logged_events(
                            start_time_str, page_number=page
                        )
                        if result is None:
                            break
    
                    events = result.get("logged_events", [])
                    if not events:
                        break
                    all_events.extend(events)
    
                    total = result.get("total_items", 0)
                    if page * PAGE_SIZE >= total:
                        break
                    page += 1
    
                if all_events:
                    success = send_to_chronicle(all_events)
                    if success:
                        last_poll_time = current_time
                else:
                    last_poll_time = current_time
                    logger.debug("No new events found.")
    
                # Send keepalive to maintain session
                client.keepalive()
    
            except KeyboardInterrupt:
                logger.info("Shutting down.")
                client.logout()
                sys.exit(0)
            except Exception as exc:
                logger.error("Unexpected error: %s", exc)
                try:
                    client.authenticate()
                except Exception:
                    pass
    
            time.sleep(POLL_INTERVAL_SECONDS)
    
    if __name__ == "__main__":
        main()
    
  5. 保存并关闭文件。

配置环境变量

  1. 为转发器创建环境文件:

    nano /opt/onguard-chronicle-forwarder/.env
    
  2. 添加以下配置值:

    ONGUARD_HOST=<ONGUARD_SERVER_IP_OR_HOSTNAME>
    ONGUARD_PORT=8080
    ONGUARD_USERNAME=<ONGUARD_API_USERNAME>
    ONGUARD_PASSWORD=<ONGUARD_API_PASSWORD>
    ONGUARD_DIRECTORY_ID=<DIRECTORY_ID>
    APPLICATION_ID=ChronicleForwarder
    VERIFY_SSL=false
    CHRONICLE_ENDPOINT=<CHRONICLE_WEBHOOK_ENDPOINT_URL>
    CHRONICLE_API_KEY=<GOOGLE_CLOUD_API_KEY>
    CHRONICLE_SECRET_KEY=<CHRONICLE_FEED_SECRET_KEY>
    POLL_INTERVAL_SECONDS=30
    PAGE_SIZE=100
    LOOKBACK_MINUTES=5
    
    • ONGUARD_HOST:运行 OpenAccess 服务的 OnGuard 服务器的 IP 地址或主机名(例如 192.168.1.100
    • ONGUARD_PORT:OpenAccess 服务监听的端口(默认值:8080
    • ONGUARD_USERNAME:OnGuard 内部用户账号的用户名
    • ONGUARD_PASSWORD:OnGuard 用户账号的密码
    • ONGUARD_DIRECTORY_ID:从 GET /directories 端点检索到的目录 ID
    • APPLICATION_ID:相应集成的唯一标识符(例如 ChronicleForwarder
    • VERIFY_SSL:如果 OnGuard 服务器使用受信任的 SSL 证书,则设置为 true;如果使用自签名证书,则设置为 false
    • CHRONICLE_ENDPOINT:来自 Chronicle Feed 配置的 Webhook 端点网址
    • CHRONICLE_API_KEY:之前创建的 Google Cloud API 密钥
    • CHRONICLE_SECRET_KEY:在创建 Chronicle Feed 期间生成的密钥
    • POLL_INTERVAL_SECONDS:轮询新事件的频率(以秒为单位)(默认值:30
    • PAGE_SIZE:每个 API 页面要检索的事件数(默认值:100,最大值:1000
    • LOOKBACK_MINUTES:在初始启动时,要检索多少分钟的历史事件(默认值:5
  3. 保护环境文件:

    chmod 600 /opt/onguard-chronicle-forwarder/.env
    

作为 systemd 服务安装

  1. 创建 systemd 服务文件:

    sudo nano /etc/systemd/system/onguard-chronicle-forwarder.service
    
  2. 添加以下内容:

    [Unit]
    Description=LenelS2 OnGuard to Chronicle Event Forwarder
    After=network.target
    
    [Service]
    Type=simple
    User=root
    WorkingDirectory=/opt/onguard-chronicle-forwarder
    EnvironmentFile=/opt/onguard-chronicle-forwarder/.env
    ExecStart=/usr/bin/python3 /opt/onguard-chronicle-forwarder/onguard_to_chronicle.py
    Restart=always
    RestartSec=10
    
    [Install]
    WantedBy=multi-user.target
    
  3. 启用并启动服务:

    sudo systemctl daemon-reload
    sudo systemctl enable onguard-chronicle-forwarder.service
    sudo systemctl start onguard-chronicle-forwarder.service
    
  4. 验证服务是否正在运行:

    sudo systemctl status onguard-chronicle-forwarder.service
    
  5. 检查转发器日志,确认操作是否成功:

    tail -f /opt/onguard-chronicle-forwarder/forwarder.log
    

    成功启动后,系统会显示:

    Starting OnGuard-to-Chronicle forwarder.
    Successfully authenticated to OnGuard OpenAccess.
    Sent <N> events to Chronicle.
    

OpenAccess API 参考文档

中间件使用以下 OnGuard OpenAccess REST API 端点。所有端点均相对于 https://<ONGUARD_SERVER>:8080/api/access/onguard/openaccess

身份验证

方法 端点 说明
POST /authentication?version=1.0 登录并检索会话令牌
DELETE /authentication?version=1.0 退出并使会话令牌失效
GET /directories?version=1.0 获取可用的身份验证目录
GET /keepalive?version=1.0 续订会话空闲超时时间

所有经过身份验证的请求所需的 HTTP 标头

标题 说明
Application-Id 唯一的应用标识符字符串(例如 ChronicleForwarder
Session-Token POST /authentication 返回的会话令牌
Content-Type application/json

事件

方法 端点 说明
GET /logged_events?version=1.0 检索记录的事件的某个页面
POST /event_subscriptions?version=1.0 创建实时事件订阅
GET /event_subscriptions?version=1.0 列出事件订阅

事件类型

OnGuard 会生成以下类别的事件,并将其转发到 Google SecOps:

  • “访问权限已授予”事件:在读卡器上接受了徽章刷卡
  • “拒绝访问”事件:刷卡遭拒(卡无效、已过期、访问权限级别错误)
  • 门保持打开状态事件:门保持打开状态的时间超过了配置的时间
  • 门被强行打开事件:门在未刷有效门禁卡的情况下被打开
  • 警报事件:警报输入已触发或已确认
  • 状态事件:面板在线/离线、通信故障、篡改
  • 持卡人事件:添加、修改或删除持卡人
  • 徽章事件:徽章已激活、已停用或已丢失
  • 访问者事件:访问者登录或退出

身份验证方法参考

Chronicle webhook Feed 支持多种身份验证方法。选择供应商支持的方法。

如果您的供应商支持自定义 HTTP 标头,请使用此方法以提高安全性。

  • 请求格式

    POST <ENDPOINT_URL> HTTP/1.1
    Content-Type: application/json
    x-goog-chronicle-auth: <API_KEY>
    x-chronicle-auth: <SECRET_KEY>
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

优点: - API 密钥和密钥不会显示在网址中 - 更安全(标头不会记录在 Web 服务器访问日志中) - 如果供应商支持,则首选此方法

方法 2:查询参数

如果您的供应商不支持自定义标头,请将凭据附加到网址。

  • 网址格式

    <ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>
    
  • 示例

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...&secret=abcd1234...
    
  • 请求格式

    POST <ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY> HTTP/1.1
    Content-Type: application/json
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

缺点:

  • 网址中显示的凭据
  • 可能会记录在 Web 服务器访问日志中
  • 安全性不如标头

方法 3:混合(网址 + 标头)

某些配置在网址中使用 API 密钥,在标头中使用密钥。

  • 请求格式

    POST <ENDPOINT_URL>?key=<API_KEY> HTTP/1.1
    Content-Type: application/json
    x-chronicle-auth: <SECRET_KEY>
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

身份验证标头名称

Chronicle 接受以下身份验证标头名称:

对于 API 密钥

  • x-goog-chronicle-auth(推荐)
  • X-Goog-Chronicle-Auth(不区分大小写)

对于密钥

  • x-chronicle-auth(推荐)
  • X-Chronicle-Auth(不区分大小写)

问题排查

OpenAccess API 连接失败

如果中间件无法连接到 OpenAccess API,请执行以下操作:

  1. 验证 OnGuard 服务器是否可从中间件主机访问:

    curl -k https://<ONGUARD_SERVER>:8080/api/access/onguard/openaccess/version?version=1.0
    
  2. 确认 OnGuard 服务器防火墙上的端口 8080 已打开。

  3. 在 OnGuard 服务器上,运行以下命令以验证端口是否正在侦听:

    netstat -anb | findstr 8080
    
  4. 如果端口未处于监听状态,请重启 LS OpenAccess 服务:

    • 在 OnGuard 服务器上打开 Windows 服务 (services.msc)。
    • 右键点击 LS OpenAccess,然后选择重新启动

身份验证失败

如果中间件收到身份验证错误:

  1. 验证 OnGuard 用户名和密码是否正确。
  2. 确认 ONGUARD_DIRECTORY_IDGET /directories 返回的有效目录匹配。
  3. 确保 OnGuard 用户账号未因暴力破解防护功能而被锁定。OnGuard 会在多次登录尝试失败后锁定账号。
  4. 如果 openaccess.ini 文件位于 C:\ProgramData\lnl\openaccess.ini,请验证其配置是否正确。

Chronicle 中未收到任何事件

如果中间件运行正常,但 Chronicle 中未显示任何事件,请执行以下操作:

  1. 通过检查 Alarm Monitoring 应用,验证 OnGuard 中是否正在生成事件。
  2. 确认已在 OnGuard 数据库中启用事件发布。在 OnGuard 数据库服务器上,运行以下 SQL 查询:

    SELECT * FROM LNL_SYSTEMSETTINGS WHERE SETTINGNAME = 'EventPublishingDisabled'
    
    • 如果结果为 0 或没有结果,则表示已启用事件发布。
    • 如果结果为 1,则表示事件发布已停用,必须重新启用。
  3. 检查转发器日志文件 (/opt/onguard-chronicle-forwarder/forwarder.log) 中是否有错误消息。

  4. 验证 .env 文件中的 Chronicle Webhook 端点网址、API 密钥和密钥是否正确。

请求池已满错误

如果中间件从 OpenAccess 收到 request pool full 错误:

  1. 在 OnGuard 服务器上,创建或修改文件 C:\ProgramData\Lnl\OpenAccess.ini
  2. 添加以下内容:

    [http_request]
    request_pool_size=128
    
  3. 重启 LS OpenAccess 服务以使更改生效。

Webhook 限制和最佳实践

请求限制

限制
最大请求大小 4 MB
最大 QPS(每秒查询次数) 15000
请求超时 30 秒
重试行为 自动(使用指数退避算法)

UDM 映射表

原始日志字段 UDM 映射 逻辑
timestamp metadata.event_timestamp 直接从活动时间戳映射
description metadata.description 活动说明文本
event_type metadata.product_event_type OnGuard 事件类型标识符
badge_id principal.user.product_object_id 与活动关联的徽章编号
cardholder_first_name principal.user.first_name 持卡人的名字
cardholder_last_name principal.user.last_name 持卡人的姓氏
device principal.asset.hostname 读卡器或面板名称
source target.asset.hostname 来源设备或面板
serial_number principal.asset.hardware.serial_number 面板序列号
access_result security_result.action 根据授予或拒绝的访问权限来允许或屏蔽
cardnumber", "device", "eid", "machine", "serialnum", and "site additional.fields 从变更日志映射

更新日志

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

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