Spencer Niemi

在 Elastic 中使用 OTel 大规模监控克劳德代码/工作

Elastic 的信息安全团队如何利用其本地 OTel 导出功能和 Elastic 的 OTel 摄取基础架构为 Claude Code 和 Claude Cowork 构建监控管道。

阅读时间:8分钟Enablement, Generative AI

随着人工智能编码助手成为工程工作流程中的标准工具,安全团队面临着新的挑战:如何在整个组织内保持对人工智能代理所做工作(及其原因)的可见性?当这些代理可以执行 shell 命令、读取文件、调用 API 并通过 MCP 连接器与内部系统交互时,您就需要实时可观察性来支持威胁检测、事件响应和合规性。

本篇文章将介绍 Elastic 的信息安全团队如何利用其本地 OpenTelemetry (OTel) 导出功能和 Elastic 自己的 OTel 摄取基础架构为 Claude Code Claude Cowork 构建监控管道。我们将介绍遥测模式、网关部署、自定义 Elasticsearch 映射和摄取管道、托管配置交付以及由这些数据支持的安全用例。

为什么 Elastic 的信息安全团队要监控人工智能代理?

在 Elastic,我们将"Customer Zero 称为 "零客户"。"信息安全团队是 Elastic 产品的第一大用户,也是最苛刻的用户,他们总是在生产中运行最新版本的产品。我们的目标是尽可能使用我们自己的产品来改善我们的安全状况。

Claude Code 和 Cowork 现已在 Elastic 的工程组织中广泛使用。Claude Code 可在开发人员机器上本地运行,是一款基于 CLI 的人工智能编码助手。Cowork 是 Claude Desktop 应用程序的一部分,也可在本地运行。它可以读取文件、在沙箱中执行代码、搜索网络,并通过 MCP 连接器与 Slack、GitHub、Jira 和 Google Calendar 等连接服务进行交互。这两种工具都支持连接内部系统,这意味着它们在安全团队需要监控的信任边界内运行。

Claude 代码和 Cowork 通过 OpenTelemetry 输出的内容

这两种产品都通过标准的 OpenTelemetry 协议输出遥测数据,发出相同的五种事件类型:

  • api_request - 模型、成本、令牌计数、延迟
  • tool_result - 工具名称、MCP 服务器和工具名称、成功/失败、持续时间
  • tool_decision - 自动批准与用户批准
  • user_prompt - 用户要求代理做什么
  • api_error - 错误信息、状态代码

每个事件都包括用户身份 (user.email,organization.id) 、会话上下文 (session.id,prompt.id,event.sequence) 和 API 请求事件上的费用/令牌字段。克劳德代码遥测是选择性的,默认情况下会编辑提示和工具参数;可通过OTEL_LOG_USER_PROMPTS=1OTEL_LOG_TOOL_DETAILS=1 启用它们。Cowork 由 Anthropic 管理门户网站集中配置,并自动包含完整的详细信息。

有关完整的遥测模式,请参阅Claude Code Monitoring 文档Claude Cowork Monitoring 文档

架构:将数据导入 Elasticsearch

有两种方法可以将 Claude Code 和 Cowork OTel 数据导入 Elasticsearch。我们首先部署了自管理网关方法,但弹性云用户还有一个更简单的选择。

方案 1:EDOT OTel 网关(自行管理)

这是我们内部采用的方法。由于 Elastic 的信息安全团队运行自我管理的 ECK(Elastic Cloud on Kubernetes)集群,因此我们部署了OpenTelemetry Collector (EDOT) 的 Elastic Distribution作为网关。Claude Code 和 Cowork 都在用户机器上本地运行,并向网关发送 OTLP/HTTP,由网关验证请求并写入 Elasticsearch。

我们使用了带有 EDOT 集电极图像的 开放式遥测 集电极 Helmdocker.elastic.co/elastic-agent/elastic-otel-collector 图()。EDOT 映像提供本地弹性数据流路由,这对于无需额外配置即可将日志导入正确的数据流非常重要。

网关以部署模式运行,通过bearertokenauth 扩展使用承载令牌验证。

下面是核心采集器的配置:

config:
  extensions:
    bearertokenauth:
      scheme: "Bearer"
      token: "${env:OTEL_GATEWAY_TOKEN}"
  receivers:
    otlp:
      protocols:
        http:
          endpoint: "0.0.0.0:4318"
          auth:
            authenticator: bearertokenauth
  processors:
    transform/route:
      log_statements:
        - context: log
          conditions:
            - resource.attributes["service.name"] == "claude-code"
          statements:
            - set(resource.attributes["data_stream.dataset"], "claude_code")
        - context: log
          conditions:
            - resource.attributes["service.name"] == "cowork"
          statements:
            - set(resource.attributes["data_stream.dataset"], "claude_cowork")
  exporters:
    elasticsearch:
      endpoints: ["https://your-elasticsearch:9200"]
      user: "${env:ES_USERNAME}"
      password: "${env:ES_PASSWORD}"
  service:
    extensions: [bearertokenauth]
    pipelines:
      logs:
        receivers: [otlp]
        processors: [transform/route]
        exporters: [elasticsearch]

方案 2:弹性云管理的 OTLP 端点(无需网关)

如果运行的是弹性云(无服务器或托管云),则可以完全跳过网关。Elastic 的托管 OTLP(mOTLP)端点提供了一个弹性、自动扩展的摄取层,可直接接受 OTLP 数据,无需部署或维护采集器基础设施。

要使用它,请将 Claude Code 的 OTLP 输出程序直接指向您的 Elastic Cloud mOTLP 端点:

export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT="https://<your-motlp-endpoint>"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=ApiKey <your-api-key>"
export OTEL_RESOURCE_ATTRIBUTES="data_stream.dataset=claude_code"

data_stream.dataset 资源属性在此非常重要;它控制着接收日志的数据流。没有它,数据就会落入通用的 OTel 数据流中,而您的自定义索引模板和摄取管道将无法应用。将其设置为claude_codeclaude_cowork ,这样数据就会以正确的字段映射路由到专用的logs-claude_code.otel-*logs-claude_cowork.otel-* 数据流。

通过 mOTLP,您可以获得具有自动数据流路由功能的本地 OTLP 摄取、内置故障存储以在索引问题期间保护数据,而且无需 APM 服务器。

受管端点支持下文所述的所有自定义索引模板和摄取管道,只是不需要操作网关。

有关完整设置的详细信息,请参阅Elastic Cloud Managed OTLP 文档

自定义 Elasticsearch 映射和摄取管道

默认情况下,OTel 属性在 Elasticsearch 中被索引为关键字。这种方法适用于筛选和分组,但会破坏数值聚合。不能对关键字段进行 SUM 或 AVG。我们创建了自定义映射来固定字段类型,并创建了一个摄取管道来将 JSON 字符串字段解析为结构化对象。

组件模板

组件模板会覆盖数字和布尔字段的默认关键字映射,并为 JSON 编码的工具参数添加flattened 类型映射:

PUT _component_template/logs-claude_code.otel@custom
{
  "template": {
    "mappings": {
      "properties": {
        "cost_usd":                  { "type": "float" },
        "duration_ms":               { "type": "long" },
        "input_tokens":              { "type": "long" },
        "output_tokens":             { "type": "long" },
        "cache_creation_tokens":     { "type": "long" },
        "cache_read_tokens":         { "type": "long" },
        "prompt_length":             { "type": "long" },
        "tool_result_size_bytes":    { "type": "long" },
        "success":                   { "type": "boolean" },
        "tool_parameters_flattened": { "type": "flattened" },
        "tool_input_flattened":      { "type": "flattened" }
      }
    }
  }
}

flattened 类型在这里很重要。tool_parameterstool_input 都是 JSON 字符串,包含嵌套键,如mcp_server_name,mcp_tool_name,bash_commandcommand 。通过将它们解析为flattened 字段,就可以查询单个键,而无需创建数量庞大的映射字段。

未来的增强功能将是从这些 JSON 有效负载中提取高价值字段到专用映射字段(如 MCP 服务器名称、工具名称和 bash 命令),以便直接根据这些值驱动更丰富的分析、聚合和检测规则。

索引模板

索引模板由所有标准 OTel 组件模板和我们自定义的模板组成。它同时匹配logs-claude_code.otel-*logs-claude_cowork.otel-* ,因此两个数据流共享相同的字段映射:

PUT _index_template/logs-claude_code.otel
{
  "index_patterns": [
    "logs-claude_code.otel-*",
    "logs-claude_cowork.otel-*"
  ],
  "composed_of": [
    "logs@mappings",
    "logs@settings",
    "otel@mappings",
    "otel@settings",
    "logs-otel@mappings",
    "semconv-resource-to-ecs@mappings",
    "logs@custom",
    "logs-otel@custom",
    "logs-claude_code.otel@custom",
    "ecs@mappings"
  ],
  "priority": 150,
  "data_stream": {},
  "allow_auto_create": true,
  "ignore_missing_component_templates": [
    "logs@custom",
    "logs-otel@custom"
  ]
}

采集管道

摄取管道会将tool_parameterstool_input 从 JSON 字符串解析为对象,并写入单独的*_flattened 目标字段,以避免与原始关键字映射属性发生冲突:

PUT _ingest/pipeline/logs-claude_code.otel@custom
{
  "description": "Parse JSON string fields in Claude Code/Cowork OTel telemetry",
  "processors": [
    {
      "json": {
        "field": "attributes.tool_parameters",
        "target_field": "tool_parameters_flattened",
        "if": "ctx.attributes?.tool_parameters != null && ctx.attributes.tool_parameters.startsWith('{')",
        "ignore_failure": true
      }
    },
    {
      "json": {
        "field": "attributes.tool_input",
        "target_field": "tool_input_flattened",
        "if": "ctx.attributes?.tool_input != null && ctx.attributes.tool_input.startsWith('{')",
        "ignore_failure": true
      }
    }
  ]
}

创建所有三个资源后,流入logs-claude_code.otel-*logs-claude_cowork.otel-* 数据流的新数据将具有正确的数字字段类型和可搜索的结构化工具参数。

配置遥测导出

Claude Code 和 Cowork 的配置不同。克劳德代码使用标准的 OpenTelemetry 环境变量。Cowork OTel 的导出由管理员在 Anthropic 管理门户网站上集中配置。

克劳德代码支持管理设置,这些设置由 IT 部门部署,用户无法覆盖。配置是一个 JSON 文件,包含env 块:

{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_LOG_TOOL_DETAILS": "1",
    "OTEL_LOG_USER_PROMPTS": "1",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "https://your-otel-gateway:443",
    "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-token"
  }
}

此管理设置文件可通过 MDM(Jamf、Intune)、Claude.ai 管理控制台的服务器管理设置或基于文件的部署进行交付。有关交付机制及其安全属性的完整列表,请参阅克劳德代码管理设置文档

要进行本地测试,可以先在自己的机器上将相同的配置放到~/.claude/settings.json 中,然后再在整个组织范围内推广。

协同工作

Cowork OTel 的导出由管理员在 Anthropic 管理门户网站上集中配置。管理员在管理控制台设置 OTLP 端点和身份验证标头,Cowork 实例会自动接收配置。默认情况下会包含提示内容和工具详细信息,无需额外标记。

由于 Cowork 是在沙箱中运行的,因此必须将 OTel 网关端点列入允许列表,以便从沙箱环境访问外部网络。否则,遥测导出将无声失败。

安全用例

事件类型、身份字段和工具参数的组合为安全操作创建了丰富的数据集。以下是我们正在构建的检测和调查功能的使用案例。

工具调用审计。每次工具调用都会记录下工具名称和输入参数。对于 MCP 工具,这包括 MCP 服务器名称和工具名称(如slack_send_message,github/search_issues )。您可以检测未经授权的数据访问、异常 shell 命令或意外的 MCP 服务器交互。使用attributes.tool_name + attributes.tool_parameters 字段。

会议重建。session.id 字段与event.sequence 相结合,可在每个会话中提供一个单调递增的计数器。你可以重建克劳德会话的完整序列:用户问了什么、运行了什么工具、访问了什么数据、调用了什么应用程序接口。这对事件响应很有价值--如果检测到可疑的工具调用,就可以调出完整的会话上下文。

许可决策分析。这些 attributes.event.name: tool_decision 通过这些事件,我们可以深入了解每种工具的使用是如何获得批准的。这可以让你检测到用户自动批准有风险的工具类别,或识别整个机群的异常权限模式。

决定来源意义
config通过设置或政策自动允许
hook由配置的钩子脚本决定
user_temporary用户点击接受该调用
user_permanent用户点击"总是允许" 此工具
user_abort用户中止会话
user_reject用户明确拒绝使用工具

成本异常检测。每个api_request 事件上的cost_usd 字段都可用于跟踪每次请求、每次会话和每个用户的成本。您可以对异常昂贵的会话发出警报,或识别具有超大消费模式的用户。

与 EDR 数据相关联。如果您在端点上运行Elastic Defend,您可以将 Claude 的 OTel 遥测与 EDR 进程和文件事件关联起来,以了解全貌。当 Claude Code 执行 Bash 命令时,OTeltool_result 事件会告诉你代理决定运行的内容和原因(通过前面的user_prompt )。相应的 Elastic Defend 进程事件会准确地告诉你主机上发生了什么--生成的子进程、写入的文件、建立的网络连接。通过时间戳和主机连接这两个数据源,就能在一次调查中同时获得意图(来自人工智能代理遥测)和影响(来自端点遥测)。

MCP 服务器访问监控。随着企业通过 MCP 将人工智能代理连接到内部系统,监控哪些服务器被访问以及使用哪些工具变得至关重要。tool_parameters_flattened.mcp_server_nametool_parameters_flattened.mcp_tool_name 字段提供了这种可见性。

例如,要查看 Slack 的工具调用情况,可以查询tool_name: "mcp_tool" AND tool_parameters_flattened.mcp_tool_name:slack*

超越 OTel:克劳德企业审计日志

来自 Claude Code 和 Cowork 的遥测技术涵盖了端点上的代理活动,但并不能捕捉到所有内容。为获得全面的可视性,企业还应从合规性 API 收集克劳德企业审计日志。这是网络界面 (claude.ai) 上活动和传统安全审计事件(如登录活动、权限更改和组织级管理)的唯一来源。结合这两个数据源,安全团队就能全面了解克劳德的所有产品。

结论

人工智能编码助手和自主代理正在成为标准企业工具包的一部分。如果你的安全团队无法看到这些工具在做什么,那么你就存在漏洞。Claude Code 和 Cowork 随附 OpenTelemetry 支持,可提供安全团队所需的遥测信息:身份、会话上下文、工具调用详情、成本数据和权限决策。无论是通过 Elastic Cloud 上的受管 OTLP 端点,还是通过自我管理环境中的 EDOT 收集器,Elastic 的本地 OTel 摄取功能都能直接将这些数据导入 Elasticsearch,并在其中进行搜索、构建仪表盘和编写检测规则。

如果您想开始使用,请注册免费试用 Elastic Cloud并试用托管 OTLP 端点,或在现有环境中安装EDOT OTel 收集器

参考资料

分享这篇文章