OpenTelemetry OpenTelemetry

Telemetrie an Backends senden und die Pipeline absichern

Konfiguriere OTLP-Exporter für Tempo, Loki und Prometheus, plus TLS, Authentifizierung und Secrets.

14 min Fortgeschritten

Telemetrie zu sammeln ist die halbe Arbeit; die andere Hälfte ist, sie sicher an den richtigen Ort zu liefern. Diese Anleitung zeigt, wie du Exporter für die gängigen Open-Source-Backends konfigurierst (der Grafana-Stack dient für die Beispiele) und wie du Traffic in den und aus dem Collector mit TLS, Authentifizierung und Secrets absicherst, die aus deinen Konfigurationsdateien herausbleiben.

OTLP-Exporter: gRPC und HTTP

Zwei Exporter sprechen OTLP:

  • otlp nutzt gRPC. Der Endpunkt ist host:port ohne Schema, meist Port 4317.
  • otlphttp nutzt HTTP. Der Endpunkt ist eine URL, meist Port 4318, und der Exporter hängt den Signalpfad (/v1/traces, /v1/metrics, /v1/logs) an.

Nutze ein Namenssuffix, um mehrere vom selben Typ zu definieren:

exporters:
  otlp/tempo:
    endpoint: tempo.observability.svc.cluster.local:4317
    tls:
      insecure: true
  otlphttp/loki:
    endpoint: http://loki.observability.svc.cluster.local:3100/otlp
  otlphttp/prometheus:
    endpoint: http://prometheus.observability.svc.cluster.local:9090/api/v1/otlp

Wissenswerte Backend-Besonderheiten:

  • Tempo akzeptiert OTLP direkt auf seinen Receiver-Ports (4317 gRPC, 4318 HTTP), wenn der OTLP-Receiver in seiner Konfiguration aktiviert ist.
  • Loki akzeptiert OTLP-Logs unter /otlp auf seinem HTTP-Port, mit otlphttp wird die finale URL also /otlp/v1/logs.
  • Prometheus akzeptiert OTLP-Metriken unter /api/v1/otlp/v1/metrics, aber nur, wenn es mit aktiviertem OTLP-Receiver gestartet wurde (dem Flag --web.enable-otlp-receiver).

Bestätige diese Pfade in der Dokumentation jedes Produkts für die Version, die du betreibst. Route dann jedes Signal an sein Backend:

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp/tempo]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlphttp/loki]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlphttp/prometheus]

Eine Pipeline kann mehrere Exporter haben, um dieselben Daten an mehr als einen Ort zu senden, zum Beispiel ein primäres Backend und ein Archiv.

TLS an Exportern

Für alles, was ein nicht vertrauenswürdiges Netzwerk überquert, nutze TLS:

exporters:
  otlp/backend:
    endpoint: otlp.example.com:4317
    tls:
      ca_file: /etc/otel/certs/ca.crt        # um einer privaten CA zu vertrauen
      cert_file: /etc/otel/certs/client.crt  # für Mutual TLS
      key_file: /etc/otel/certs/client.key

Mit einer öffentlichen CA kannst du den gesamten tls-Block weglassen, da die System-Roots genutzt werden. insecure: true deaktiviert TLS und ist nur für die Entwicklung im Cluster. Vermeide insecure_skip_verify: true in der Produktion, da es den Schutz entfernt, den TLS bietet.

TLS und Authentifizierung an Receivern

Ein Collector, der auf einem Netzwerk-Port lauscht, sollte TLS und, wenn er von irgendetwas erreichbar ist, das du nicht kontrollierst, Authentifizierung verlangen.

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
        tls:
          cert_file: /etc/otel/certs/server.crt
          key_file: /etc/otel/certs/server.key
          client_ca_file: /etc/otel/certs/ca.crt   # Client-Zertifikate verlangen (mTLS)

Für tokenbasierte Authentifizierung nutze eine Authentifizierungs-Extension. Die Extension bearertokenauth kann ein Token sowohl senden als auch prüfen:

extensions:
  bearertokenauth/client:
    scheme: Bearer
    token: ${env:BACKEND_TOKEN}

exporters:
  otlphttp/backend:
    endpoint: https://otlp.example.com
    auth:
      authenticator: bearertokenauth/client

service:
  extensions: [bearertokenauth/client]

Um eingehende Anfragen zu validieren, gibt es andere Extensions, etwa basicauth und oidc, vom Receiver mit auth: { authenticator: <name> } referenziert. Verfügbare Optionen unterscheiden sich je nach Distribution und Version, prüfe also die Extension-README.

Für einfache Header-basierte Zugangsdaten kannst du auch Header an einem Exporter setzen:

exporters:
  otlphttp/saas:
    endpoint: https://otlp.vendor.example.com
    headers:
      api-key: ${env:VENDOR_API_KEY}

Secrets aus der Konfiguration heraushalten

Schreibe nie ein Token oder Passwort wörtlich in eine Konfigurationsdatei, die in Git liegt. Referenziere stattdessen eine Umgebungsvariable und liefere die Variable aus einem Secret Store:

exporters:
  otlphttp/backend:
    headers:
      authorization: Bearer ${env:BACKEND_TOKEN}

Auf Kubernetes injiziere die Variable aus einem Secret:

env:
  - name: BACKEND_TOKEN
    valueFrom:
      secretKeyRef:
        name: otel-backend
        key: token

Das Secret selbst sollte in Git verschlüsselt sein (zum Beispiel mit SOPS, wie in den Flux-Anleitungen) oder aus einem Secret Manager synchronisiert werden. Der Collector unterstützt außerdem einen file:-Provider (${file:/path/to/secret}), der eine gemountete Datei liest, was zu als Volumes gemounteten und von der Plattform rotierten Secrets passt. Welche Quelle du auch nutzt, bestätige, dass der Provider in deiner Distribution verfügbar ist; die Contrib-Builds enthalten mehrere.

Netzwerk-Exposition

Da der Collector oft im Cluster läuft, zählt seine Standardhaltung:

  • Binde bewusst. Neuere Versionen binden Receiver standardmäßig an localhost, was sicher, aber von anderen Containern aus unerreichbar ist. Nutze 0.0.0.0 nur für Ports, die erreichbar sein sollen, und schütze sie mit einer NetworkPolicy, TLS oder Authentifizierung.
  • Deaktiviere, was du nicht nutzt. Entferne ungenutzte Receiver und Service-Ports, damit die Angriffsfläche klein bleibt.
  • Debug-Endpunkte sind für Betreiber. Halte zpages und pprof auf localhost und exponiere sie nie öffentlich.
  • Schwärze vor dem Export. Nutze die Prozessoren attributes oder transform, um Zugangsdaten, Tokens und personenbezogene Daten zu löschen, bevor sie dein Netzwerk verlassen (siehe die Anleitung zur Produktionsreife).

Eine NetworkPolicy, die nur Anwendungs-Namespaces den Zugriff auf den Collector erlaubt:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-otlp-from-apps
  namespace: observability
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: opentelemetry-collector
  policyTypes: [Ingress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              telemetry: "enabled"
      ports:
        - protocol: TCP
          port: 4317
        - protocol: TCP
          port: 4318

Prüfen

  1. Führe otelcol validate --config=config.yaml aus, um YAML- und Schemafehler abzufangen.
  2. Starte den Collector und prüfe seine Logs auf Verbindungs- oder TLS-Fehler an den Exportern.
  3. Sende einen Test-Span und suche ihn dann im Backend. Kommt er nicht an, vergleiche Protokoll und Port des Exporters mit dem, worauf das Backend tatsächlich lauscht.
  4. Prüfe die eigenen Metriken des Collectors auf Zähler otelcol_exporter_send_failed_*, die steigen, wenn ein Backend Daten ablehnt.

Beliebte Anleitungen