Jede nützliche OpenTelemetry-Collector-Konfiguration braucht irgendwann ein Secret. In dem Moment, in dem Sie einen Exporter hinzufügen, brauchen Sie ein Credential, um sich gegenüber dem Ziel zu authentifizieren: einen Datadog-API-Key, ein Splunk-HEC-Token, einen Grafana-Cloud-Benutzernamen und ein Access-Policy-Token, ein Client-Zertifikat für mTLS zu Ihrem eigenen Gateway. Die Collector-Konfiguration ist nur YAML, und der naheliegende Ort für diesen Key ist direkt dort neben dem Exporter, der ihn verwendet – was genau der Fehler ist.
Das Problem ist nicht, dass der Collector kein Secret halten kann. Es ist, dass Collector-Konfiguration in die Versionskontrolle gehört, und die Versionskontrolle ist der eine Ort, an dem ein Klartext-Credential niemals landen darf. In diesem Beitrag geht es darum, diese Spannung aufzulösen: wie Sie Secrets aus dem YAML heraushalten, das Sie committen, während Sie dem laufenden Collector dennoch die Credentials übergeben, die er braucht, wie Sie sie ohne Ausfallzeit rotieren und wo die ehrlichen Grenzen der eingebauten Handhabung des Collectors liegen.
Für wen dieser Leitfaden ist
Platform-Engineers, SREs und Security-Teams, die OpenTelemetry Collectors betreiben und ihre
Konfiguration in Git speichern. Wenn Sie je einen API-Key in einen exporters:-Block
eingefügt und dann vor git commit gezögert haben, ist das hier für Sie. Voraussetzungen: ein
Collector-Fleet (oder ein Plan dafür) und Zugriff auf den Secret-Store, den Ihre Plattform
bereits verwendet.
Wo Secrets in einer Collector-Konfiguration auftauchen
Secrets sammeln sich an ein paar vorhersehbaren Stellen, fast alle in Exportern und Receivern, die mit etwas Authentifiziertem sprechen:
- Backend-API-Keys und -Tokens – Datadog
api::key, Splunk-HEC-token, einotlphttp-Exporter mit einem Bearer Token inheaders, Grafana-Cloud-Basic-Auth. - TLS-Material – Client-Zertifikate und Private Keys für mTLS, CA-Bundles, die
Pfade
tls::key_fileundtls::cert_filesowohl auf Exportern als auch auf Receivern. - Upstream-Credentials – ein Kafka-Receiver oder -Exporter mit SASL-Benutzernamen und -Passwort, ein Prometheus-Remote-Write-Endpunkt hinter Auth.
Jedes davon ist ein Wert, der Zugriff auf ein System gewährt. Die Konfiguration, die auf sie verweist, ist etwas, das Sie in Git haben wollen – reviewt, versioniert, diffbar – aus all den Gründen, aus denen jedes Infrastructure-as-Code-Artefakt dorthin gehört. Das ist die gesamte GitOps-Spannung in einem Satz: die Konfiguration muss committet werden; die Secrets dürfen es nicht.
Die Regel: niemals hardcoden, niemals committen
Ein Secret in committetes YAML zu hardcoden, ist schlimmer, als es aussieht, denn Git
vergisst nicht. Sobald ein Key in einem Commit landet, ist er in der Historie auf jedem
Clone, jedem Fork, jedem CI-Cache und jedem Entwickler-Laptop – und ihn aus der
aktuellen Datei herauszurotieren, ändert nichts an den zwanzig Stellen, an denen der
alte Wert noch lebt. Ein geleaktes Credential in der Git-Historie ist ein
Alles-rotieren-Incident, kein git revert.
Die Disziplin ist also absolut: Die committete Konfiguration enthält niemals ein Klartext-Secret. Was sie stattdessen enthält, ist eine Referenz – ein Platzhalter, der in dem Moment, in dem der Collector startet, aus einer Quelle, die nicht Ihr Git-Repository ist, zum echten Wert aufgelöst wird.
Umgebungsvariablen-Substitution: das eingebaute Primitiv
Der native Mechanismus des Collectors dafür ist Substitution. Überall in der Konfiguration
können Sie ${env:VAR_NAME} schreiben, und der Collector expandiert es zur Ladezeit aus der
Prozessumgebung – und dieselbe Maschinerie löst ${file:/path/to/secret} aus einer
gemounteten Datei auf, was sich natürlich mit Kubernetes Secrets oder einem Vault-CSI-Volume
paart. Ihr committetes YAML hält nur den Platzhalter:
exporters:
datadog:
api:
key: ${env:DD_API_KEY}
otlphttp/vendor:
endpoint: https://otlp.vendor.example
headers:
authorization: ${env:VENDOR_BEARER_TOKEN}
Der echte DD_API_KEY taucht niemals in der Datei auf. Er muss in der Umgebung des Collectors
vorhanden sein, wenn der Prozess startet, und dort erledigt der Rest der Plattform die Arbeit.
Das ist bewusst grundlegend – es ist String-Substitution, kein Secrets-System. Der Collector
vertraut darauf, dass alles, was die Umgebungsvariable gesetzt hat, dies sicher getan hat, und
bietet selbst nichts für Speicherung, Rotation oder Zugriffskontrolle. Diese Ehrlichkeit
zählt: Sie komponieren den Collector mit einem echten Secret-Manager; Sie verlassen sich
nicht darauf, dass der Collector einer ist.
Kubernetes Secrets als Umgebungsvariablen
Auf Kubernetes ist das gängige Muster, das Credential in einem Secret zu speichern und
es als Umgebungsvariable in den Collector-Container zu projizieren, die die
${env:...}-Syntax dann aufgreift:
env:
- name: DD_API_KEY
valueFrom:
secretKeyRef:
name: otel-backend-credentials
key: dd-api-key
Nun sagt die Konfiguration in Git ${env:DD_API_KEY}, das Deployment verweist per Name auf
ein Secret, und der tatsächliche Wert lebt nur im Kubernetes Secret – verwaltet mit seinem
eigenen RBAC, idealerweise durch Encryption at Rest abgesichert. Seien Sie klarsichtig über
die Grenzen: Ein Standard-Kubernetes-Secret ist Base64-kodiert, nicht verschlüsselt, und
jeder, der Secrets im Namespace lesen kann, kann es lesen. Aktivieren Sie Encryption at Rest,
sperren Sie RBAC ab und greifen Sie für stärkere Garantien zu einem externen Manager.
Externe Secret-Manager und Injection
Für echte Rotation, Auditing und Least-Privilege-Zugriff lebt das Credential in einem dedizierten Secret-Manager – HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault – und wird zur Deploy-Zeit in die Umgebung des Collectors injiziert. Zwei gängige Formen:
- Sync in ein Kubernetes Secret. Tools wie der External Secrets Operator ziehen aus Vault oder einem Cloud-Manager und materialisieren ein Kubernetes Secret, das Sie dann genau wie oben als Umgebungsvariablen mounten. Die Source of Truth ist Vault; das Secret ist eine kurzlebige Projektion.
- Sidecar-/Agent-Injection. Ein Vault Agent (oder CSI-Treiber) holt das Secret und
schreibt es in eine gemountete Datei (die die Konfiguration direkt mit
${file:...}lesen kann) oder in die Prozessumgebung, sodass es etcd überhaupt nicht berührt.
So oder so liest der Collector weiterhin nur ${env:DD_API_KEY} – die Raffinesse liegt
vollständig darin, wie diese Variable befüllt wurde. Der Collector weiss nicht und kümmert
sich nicht darum, ob der Wert von einem statischen Secret oder einem frisch geprägten
Vault-Lease kam, was genau der Grund ist, warum diese Komposition sauber ist.
Secrets ohne Ausfallzeit rotieren
Rotation ist der Ort, an dem hardgecodete Secrets am meisten wehtun und referenzierte Secrets glänzen. Weil der Collector sein Credential beim Start aus der Umgebung liest, ist Rotation: Aktualisieren Sie den Wert im Secret-Manager, dann starten Sie den Collector neu, damit er den neuen aufgreift. Ein paar praktische Hinweise:
- Rollen, nicht stoppen. In Kubernetes ersetzt ein Rolling Restart des Collector-Deployments oder -DaemonSets die Pods einen nach dem anderen, sodass die Telemetrie weiterfliesst, während jeder Pod den rotierten Wert aufgreift. Nichts geht dunkel.
- Alt und neu überlappen. Wenn das Backend zwei aktive Keys unterstützt, fügen Sie den neuen Key hinzu, bevor Sie den alten widerrufen. Rollen Sie das Fleet auf den neuen Wert, bestätigen Sie, dass die Exporte erfolgreich sind, und ziehen Sie dann den alten Key aus dem Verkehr. Das vermeidet das Zeitfenster, in dem ein halb ausgerolltes Fleet sich mit einem Key authentifiziert, den Sie bereits abgeschaltet haben.
- Die Konfiguration ändert sich nie. Das committete YAML sagt durch die gesamte
Rotation hindurch weiterhin
${env:DD_API_KEY}. Das ist der Punkt – Rotation berührt den Secret-Store, nicht die versionierte Konfiguration, also hinterlässt sie keinen Diff und braucht kein Config-Review.
Der Collector reloaded Umgebungsvariablen nicht mitten im Prozess, also rechne damit, dass ein Neustart Teil jeder Rotation ist. Das ist eine milde Einschränkung, keine echte, wenn man bedenkt, dass Rolling Restarts günstig sind.
Wo eine Control Plane hineinpasst
Das über ein Fleet hinweg von Hand zu verwalten, ist machbar, aber fummelig, und es ist leicht, dass die Konfiguration eines Nodes dahin driftet, einen literalen Key zu halten, „nur um etwas zu testen”. Hier verdient sich eine Control Plane ihren Platz: Mit LinkMesh geben Sie ein Backend-Credential einmal, zentral ein, auf dem Ziel, das es verwendet – niemand fügt einen Key von Hand in das YAML auf einem einzelnen Node ein. Rotation hört auf, eine fleet-weite Schnitzeljagd zu sein: Aktualisieren Sie das Credential auf dem Ziel, und jeder Collector, der an dieses Backend ausliefert, erhält den neuen Wert automatisch, ohne Änderung pro Node.

Der Teil, der für die Spannung zählt, um die es in diesem Beitrag geht: LinkMesh macht
denselben Trick «Referenz statt Wert» wie ${env:...}, aber durchgängig und serverseitig. Ein
Credential liegt als benanntes Secret in einem verschlüsselten Speicher (AES-256-GCM, der
Schlüssel gehört Ihnen und verlässt nie die Grenze Ihrer Datenbank), und die Ziel-Konfiguration
referenziert es per Name – ${secret:grafana-cloud-token}. Diese Referenz ist das, was in Git
committet, von der API zurückgegeben und in einem Diff angezeigt wird; der Klartextwert ist
nie eines davon. Der echte Wert wird erst bei der Auslieferung eingesetzt – in dem Moment,
in dem die Konfiguration über den authentifizierten Kanal an einen Collector gepusht wird –,
sodass der laufende Collector genau die Bytes erhält, die er braucht, während Ihr GitOps-Repo,
Ihre Konfigurationshistorie und ein PVC-Backup nichts als die Referenz enthalten. Rotieren Sie
das Secret einmal, und LinkMesh rendert die Konfiguration neu und liefert sie an jeden
Collector aus, der es referenziert.
Das bewahrt die Eigenschaften, die Sie tatsächlich wollen: Jede Konfigurationsänderung ist versioniert und auditierbar (das Modell hinter GitOps für Collector-Konfiguration), der Zugriff auf die verwaltete Konfiguration ist berechtigungsgesteuert, Credentials werden auf jedem Lesepfad geschwärzt und – weil LinkMesh selbst gehostet ist und Pipeline-Telemetrie niemals durch es fliesst – bleiben Ihre Daten und Ihre Credentials auf Ihrer eigenen Infrastruktur. Es komponiert mit demselben Enforcement-Modell, das jede andere Policy über das Fleet hinweg konsistent hält.
Wo anfangen
Sie brauchen Vault nicht am ersten Tag. Die Progression, die funktioniert:
- Hören Sie jetzt auf, Secrets zu committen. Ersetzen Sie jedes literale Credential in Ihrer Konfiguration durch
${env:VAR}und verschieben Sie den Wert in die Umgebung. Dann scrubben Sie die Git-Historie, falls bereits etwas geleakt ist. - Sichern Sie es mit Kubernetes Secrets ab (Encryption at Rest an, RBAC eng), sodass der Wert ein verwaltetes Zuhause hat, kein Shell-Export.
- Steigen Sie auf einen externen Manager um – Vault oder einen Cloud-Secret-Manager mit Injection –, wenn Sie Rotation, Auditing und Least-Privilege-Zugriff brauchen.
- Referenzieren Sie zentral per Name, sodass die committete Konfiguration keines Nodes je Klartext hält und Rotation den Secret-Store berührt statt der Pipeline.
Die eigene Secret-Handhabung des Collectors ist bewusst dünn: ${env:...}- und
${file:...}-Substitution und nichts weiter. Das ist in Ordnung, solange Sie daran denken,
dass es ein Referenz-Mechanismus ist, und einen echten Secret-Manager dahinterstellen.
Halten Sie den Klartext aus Git heraus, lösen Sie ihn beim Start auf, rotieren Sie ihn im
Store – und Ihre sensibelsten Credentials fahren niemals in der Konfiguration mit, die Ihre
Pipeline beschreibt.
Müde davon, API-Keys von Hand in per-Node-YAML einzufügen?
LinkMesh speichert ein Backend-Credential einmal als benanntes, verschlüsseltes Secret und referenziert es in der Konfiguration per Name – so enthalten Ihr committetes YAML, Ihre Diffs und Ihre Historie nur die Referenz, nie den Key. Der echte Wert wird bei der Auslieferung eingesetzt; einmal rotieren, und das gesamte Fleet erhält die Konfiguration neu. Selbst gehostet, sodass Ihre Telemetrie und Ihre Credentials auf Ihrer eigenen Infrastruktur bleiben. Stellen Sie eine auf in Minuten, oder sehen Sie sich an, was sie leistet.
