Spencer Niemi

Surveillance du code/travail de Claude à l'échelle avec OTel dans Elastic

Comment l'équipe InfoSec d'Elastic a construit un pipeline de surveillance pour Claude Code et Claude Cowork en utilisant leurs capacités d'exportation OTel natives et l'infrastructure d'ingestion OTel d'Elastic.

8 minutes de lectureEnablement, Generative AI

Alors que les assistants de codage de l'IA deviennent des outils standard dans les flux de travail d'ingénierie, les équipes de sécurité sont confrontées à un nouveau défi : comment maintenir la visibilité sur ce qu'un agent d'IA fait (et pourquoi) au sein de votre organisation ? Lorsque ces agents peuvent exécuter des commandes shell, lire des fichiers, appeler des API et interagir avec des systèmes internes via des connecteurs MCP, vous avez besoin d'une observabilité en temps réel pour prendre en charge la détection des menaces, la réponse aux incidents et la conformité.

Ce billet explique comment l'équipe InfoSec d'Elastic a construit un pipeline de surveillance pour Claude Code et Claude Cowork en utilisant leurs capacités d'exportation OpenTelemetry (OTel) et l'infrastructure d'ingestion OTel d'Elastic. Nous couvrons le schéma de télémétrie, le déploiement de la passerelle, les mappings Elasticsearch personnalisés et les pipelines d'ingestion, la livraison de configuration gérée et les cas d'utilisation de la sécurité permis par ces données.

Pourquoi l'équipe InfoSec d'Elastic surveille les agents d'IA

Chez Elastic, nous pratiquons ce que nous appelons "Customer Zero." L'équipe InfoSec est le premier et le plus exigeant des utilisateurs des produits Elastic, utilisant toujours les versions les plus récentes en production. Notre objectif est d'utiliser nos propres produits pour améliorer notre posture de sécurité chaque fois que nous le pouvons.

Claude Code et Cowork sont désormais utilisés activement par les ingénieurs d'Elastic. Claude Code fonctionne localement sur les machines des développeurs en tant qu'assistant de codage IA basé sur une CLI. Cowork fait partie de l'application Claude Desktop et fonctionne également localement. Il peut lire des fichiers, exécuter du code dans un bac à sable, effectuer des recherches sur le web et interagir avec des services connectés tels que Slack, GitHub, Jira et Google Calendar grâce à des connecteurs MCP. Ces deux outils permettent de se connecter à des systèmes internes, ce qui signifie qu'ils fonctionnent dans une zone de confiance que les équipes de sécurité doivent surveiller.

Ce que Claude Code et Cowork exportent via OpenTelemetry

Les deux produits exportent des données télémétriques par le biais de protocoles OpenTelemetry standard, en émettant les mêmes cinq types d'événements :

  • api_request - modèle, coût, nombre de jetons, latence
  • tool_result - nom de l'outil, nom du serveur MCP et de l'outil, succès/échec, durée
  • tool_decision - approbation automatique ou approbation par l'utilisateur
  • user_prompt - ce que l'utilisateur a demandé à l'agent de faire
  • api_error - message d'erreur, code d'état

Chaque événement comprend l'identité de l'utilisateur (user.email, organization.id), le contexte de la session (session.id, prompt.id, event.sequence) et les champs coût/token sur les événements de demande d'API. La télémétrie du code Claude est facultative et expurge les invites et les arguments des outils par défaut ; activez-les avec OTEL_LOG_USER_PROMPTS=1 et OTEL_LOG_TOOL_DETAILS=1. Le coworking est configuré de manière centralisée dans le portail d'administration d'Anthropic et inclut automatiquement tous les détails.

Pour le schéma complet de télémétrie, voir la documentation sur la surveillance du code de Claude et la documentation sur la surveillance du coworking de Claude.

Architecture : Acheminer les données vers Elasticsearch

Il y a deux façons d'obtenir les données de Claude Code et Cowork OTel dans Elasticsearch. Nous avons d'abord déployé l'approche de la passerelle autogérée, mais les utilisateurs d'Elastic Cloud disposent d'une option plus simple.

Option 1 : Passerelle OTel EDOT (autogérée)

C'est l'approche que nous avons utilisée en interne. Étant donné que l'équipe InfoSec d'Elastic exécute des clusters ECK (Elastic Cloud on Kubernetes) autogérés, nous avons déployé une distribution Elastic du collecteur OpenTelemetry (EDOT) en tant que passerelle. Claude Code et Cowork fonctionnent localement sur les machines des utilisateurs et envoient OTLP/HTTP à la passerelle, qui authentifie la demande et écrit dans Elasticsearch.

Nous avons utilisé la carte Helm d'opentelemetry-collector avec l'image du collecteur EDOT (docker.elastic.co/elastic-agent/elastic-otel-collector). L'image EDOT fournit un routage natif des flux de données Elastic, ce qui est important pour placer les journaux dans les bons flux de données sans configuration supplémentaire.

La passerelle fonctionne en mode déploiement et utilise l'authentification par jeton via l'extensionbearertokenauth .

Voici la configuration du collecteur de base :

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]

Option 2 : Point final OTLP géré par Elastic Cloud (aucune passerelle n'est nécessaire)

Si vous utilisez Elastic Cloud (sans serveur ou hébergé), vous pouvez ignorer complètement la passerelle. Le point d'extrémité Managed OTLP (mOTLP ) d'Elastic fournit une couche d'ingestion résiliente et évolutive qui accepte directement les données OTLP - aucune infrastructure de collecteur à déployer ou à maintenir.

Pour l'utiliser, pointez l'exportateur OTLP de Claude Code directement sur votre point d'arrivée 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"

L'attribut de ressource data_stream.dataset est important ici ; il contrôle le flux de données qui reçoit les journaux. Sans cela, les données atterrissent dans un flux de données OTel générique où vos modèles d'index personnalisés et vos pipelines d'ingestion ne s'appliquent pas. Définissez-le sur claude_code ou claude_cowork pour que les données soient acheminées vers les flux dédiés logs-claude_code.otel-* ou logs-claude_cowork.otel-* avec les correspondances de champs correctes.

Avec mOTLP, vous bénéficiez d'une ingestion OTLP native avec routage automatique des flux de données, d'un magasin de défaillances intégré pour protéger les données en cas de problèmes d'indexation, et vous n'avez pas besoin du serveur APM.

Le point final géré prend en charge tous les modèles d'index personnalisés et les pipelines d'ingestion décrits ci-dessous, vous n'avez simplement pas besoin de faire fonctionner la passerelle.

Pour plus de détails sur la configuration, consultez la documentation Elastic Cloud Managed OTLP.

Mappings Elasticsearch et pipelines d'ingestion personnalisés

Par défaut, les attributs OTel sont indexés comme des mots-clés dans Elasticsearch. Cela fonctionne pour le filtrage et le regroupement, mais ne permet pas les agrégations numériques. Vous ne pouvez pas faire la SOMME ou la MOYENNE d'un champ de mots-clés. Nous avons créé des mappings personnalisés pour fixer les types de champs et un pipeline d'ingestion pour analyser les champs JSON en objets structurés.

Modèle de composant

Le modèle de composant remplace les correspondances de mots-clés par défaut pour les champs numériques et booléens, et ajoute des correspondances de type flattened pour les paramètres d'outils codés en JSON :

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" }
      }
    }
  }
}

Le type de flattened est important ici. tool_parameters et tool_input arrivent sous forme de chaînes JSON contenant des clés imbriquées telles que mcp_server_name, mcp_tool_name, bash_command ou command. En les analysant en champs flattened, vous pouvez interroger des clés individuelles sans créer un nombre illimité de champs mappés.

Une amélioration future consistera à extraire les champs de grande valeur de ces charges utiles JSON dans des champs mappés dédiés (noms de serveurs MCP, noms d'outils et commandes bash, par exemple) afin de réaliser des analyses, des agrégations et des règles de détection plus riches directement à partir de ces valeurs.

Modèle d'index

Le modèle d'index se compose de tous les modèles de composants OTel standard et de notre modèle personnalisé. Il correspond à la fois à logs-claude_code.otel-* et à logs-claude_cowork.otel-*, de sorte que les deux flux de données partagent les mêmes correspondances de champs :

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"
  ]
}

Pipeline d’ingestion

Le pipeline d'ingestion analyse tool_parameters et tool_input à partir de chaînes JSON en objets, en écrivant dans des champs cibles *_flattened distincts pour éviter les conflits avec les attributs originaux mappés par mot-clé :

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
      }
    }
  ]
}

Après la création de ces trois ressources, les nouvelles données qui circulent dans les flux de données logs-claude_code.otel-* et logs-claude_cowork.otel-* auront des types de champs numériques corrects et des paramètres d'outils structurés consultables.

Configuration de l'exportation de données télémétriques

Claude Code et Cowork sont configurés différemment. Claude Code utilise les variables d'environnement standard d'OpenTelemetry. L'exportation de Cowork OTel est configurée de manière centralisée par les administrateurs dans le portail d'administration d'Anthropic.

Claude Code prend en charge les paramètres gérés qui sont déployés par le service informatique et ne peuvent pas être remplacés par les utilisateurs. La configuration est un fichier JSON contenant un bloc 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"
  }
}

Ce fichier de paramètres gérés peut être fourni via MDM (Jamf, Intune), des paramètres gérés par le serveur via la console d'administration Claude.ai, ou un déploiement basé sur un fichier. Consultez la documentation sur les paramètres gérés par Claude Code pour obtenir la liste complète des mécanismes de livraison et de leurs propriétés de sécurité.

Pour les tests locaux, vous pouvez mettre la même configuration à l'adresse ~/.claude/settings.json sur votre propre machine avant de la déployer à l'échelle de l'entreprise.

Coworking

L'exportation de Cowork OTel est configurée de manière centralisée par les administrateurs dans le portail d'administration d'Anthropic. Les administrateurs définissent le point de terminaison OTLP et les en-têtes d'authentification dans la console d'administration, et les instances Cowork reprennent automatiquement la configuration. Le contenu de l'invite et les détails de l'outil sont inclus par défaut sans nécessiter de drapeaux supplémentaires.

Comme Cowork fonctionne dans un bac à sable, le point d'extrémité de la passerelle OTel doit être inscrit sur une liste d'autorisation pour l'accès au réseau sortant depuis l'environnement du bac à sable. Sans cela, l'exportation de données télémétriques échouera silencieusement.

Cas d'utilisation de la sécurité

La combinaison des types d'événements, des champs d'identité et des paramètres de l'outil crée un ensemble de données riche pour les opérations de sécurité. Voici les cas d'utilisation pour lesquels nous développons des capacités de détection et d'investigation.

Audit des invocations d'outils. Chaque appel d'outil est enregistré avec le nom de l'outil et les paramètres d'entrée. Pour les outils MCP, il s'agit du nom du serveur MCP et du nom de l'outil (par exemple, slack_send_message, github/search_issues). Vous pouvez détecter les accès non autorisés aux données, les commandes shell inhabituelles ou les interactions inattendues avec le serveur MCP. Utilisez les champs attributes.tool_name + attributes.tool_parameters.

Reconstruction de la session. Le champ session.id combiné à event.sequence fournit un compteur qui augmente de façon monotone au cours de chaque session. Vous pouvez reconstituer le déroulement complet d'une session Claude : les questions posées par l'utilisateur, les outils exécutés, les données consultées et les API appelées. Cela est très utile pour la réponse aux incidents - si vous détectez un appel d'outil suspect, vous pouvez obtenir le contexte complet de la session.

Analyse de la décision d'autorisation. Les événements attributes.event.name: tool_decision permettent de comprendre comment l'utilisation de chaque outil a été approuvée. Cela vous permet de détecter les utilisateurs qui approuvent automatiquement des catégories d'outils à risque, ou d'identifier des schémas d'autorisation inhabituels dans l'ensemble du parc.

Source de décisionSignification
configAuto-autorisé par les paramètres ou la politique
hookDécidé par un script de crochet configuré
user_temporaryL'utilisateur a cliqué sur "Accepter" pour cette invocation
user_permanentL'utilisateur a cliqué sur "et autorise toujours" à utiliser cet outil.
user_abortL'utilisateur a interrompu la session
user_rejectL'utilisateur a explicitement rejeté l'utilisation de l'outil

Détection des anomalies de coûts. Le champ cost_usd de chaque événement api_request permet de suivre les coûts par demande, par session et par utilisateur. Vous pouvez lancer des alertes en cas de sessions inhabituellement coûteuses ou identifier les utilisateurs dont les habitudes de consommation sont excessives.

Corrélation avec les données EDR. Si vous utilisez Elastic Defend sur vos terminaux, vous pouvez corréler la télémétrie OTel de Claude avec les événements de processus et de fichiers EDR pour avoir une vue d'ensemble. Lorsque Claude Code exécute une commande Bash, l'événement OTel tool_result vous indique ce que l'agent a décidé d'exécuter et pourquoi (via le précédent user_prompt). L'événement de processus Elastic Defend correspondant vous indique exactement ce qui s'est passé sur l'hôte - les processus enfants créés, les fichiers écrits, les connexions réseau établies. En joignant ces deux sources de données par horodatage et par hôte, vous obtenez à la fois l'intention (à partir de la télémétrie de l'agent d'intelligence artificielle) et l'impact (à partir de la télémétrie du point d'extrémité) en une seule enquête.

Surveillance de l'accès au serveur MCP. À mesure que les organisations connectent des agents d'IA à des systèmes internes par le biais de MCP, il devient essentiel de surveiller les serveurs auxquels ils accèdent et les outils qu'ils utilisent. Les champs tool_parameters_flattened.mcp_server_name et tool_parameters_flattened.mcp_tool_name offrent cette visibilité.

Par exemple, pour voir les invocations d'outils pour Slack, vous pouvez interroger tool_name: "mcp_tool" AND tool_parameters_flattened.mcp_tool_name:slack*.

Au-delà de l'OTel : les journaux d'audit de l'entreprise Claude

La télémétrie de Claude Code et Cowork couvre l'activité des agents sur les points d'extrémité, mais elle ne saisit pas tout. Pour une visibilité totale, les entreprises devraient également collecter les journaux d'audit de l'entreprise Claude à partir de l'API de conformité. C'est la seule source d'activité sur l'interface web (claude.ai) et d'événements d'audit de sécurité traditionnels, tels que l'activité de connexion, les changements de permission et l'administration au niveau de l'organisation. La combinaison de ces deux sources de données permet aux équipes de sécurité d'avoir une vue d'ensemble de tous les produits Claude.

Conclusion

Les assistants de codage et les agents autonomes de l'IA font de plus en plus partie de la boîte à outils standard des entreprises. Si votre équipe de sécurité n'a pas de visibilité sur ce que font ces outils, vous avez une lacune. Claude Code et Cowork sont livrés avec le support OpenTelemetry qui fournit exactement le type de télémétrie dont les équipes de sécurité ont besoin : identité, contexte de la session, détails de l'invocation de l'outil, données sur les coûts et décisions de permission. Les capacités natives d'ingestion d'OTel d'Elastic, que ce soit via le point de terminaison Managed OTLP sur Elastic Cloud ou le collecteur EDOT dans un environnement autogéré, facilitent l'intégration de ces données dans Elasticsearch, où vous pouvez effectuer des recherches, créer des tableaux de bord et rédiger des règles de détection.

Si vous voulez commencer, inscrivez-vous à un essai gratuit d'Elastic Cloud et essayez le point de terminaison Managed OTLP, ou installez l'EDOT OTel Collector dans votre environnement existant.

Références

Partager cet article