Secrets in Ansible maskieren
Ansible-Playbooks benötigen häufig Passwörter und API-Tokens, um sich mit Servern zu verbinden und Anwendungen bereitzustellen. Diese Werte können auch in der Aufgabenausgabe auftauchen, etwa wenn ein Befehl einen Fehler zurückgibt, der ein Passwort enthält.
Ansible führt dafür die Maskierung von Secrets ein. Bekannte geheime Werte werden in der Ausgabe durch $REDACTED$ ersetzt, während der Rest der Meldung lesbar bleibt. Die Aufgaben verwenden weiterhin die ursprünglichen Werte.
Die Funktion wurde mit dem Pull Request für die Secret Masking API hinzugefügt, der am 10. September 2026 zusammengeführt wurde. Zum Zeitpunkt dieses Beitrags ist sie in Entwicklungsbuilds von ansible-core 2.22 verfügbar. Sie ist noch nicht Teil einer stabilen Version.
Sehen wir uns ein einfaches Playbook an und anschließend, wie wir diese Funktion in Semaphore UI einsetzen wollen.
Zuerst ein Secret registrieren
Ansible muss wissen, welche Werte maskiert werden sollen. Die neue API registriert Werte aus bekannten Secret-Quellen, etwa mit Vault verschlüsselte Variablen und mit no_log markierte Modulparameter.
Für eine gewöhnliche Variable können wir den Filter register_secret verwenden. Auch eine über --extra-vars übergebene Variable muss registriert werden. Der Name db_password allein reicht nicht aus.
Für dieses Beispiel verwenden wir ein fiktives Datenbankpasswort. Erstelle ein Playbook namens masking.yml:
- name: Try secret masking
hosts: localhost
gather_facts: false
vars:
db_password: "example-db-password-123456"
tasks:
- name: Register the password before using it
ansible.builtin.set_fact:
db_password: "{{ db_password | ansible.builtin.register_secret }}"
- name: Show a message containing the password
ansible.builtin.debug:
msg: "Connecting to db.internal with password={{ db_password }}"
Die erste Aufgabe registriert das Passwort. Der Filter gibt den ursprünglichen Wert zurück, sodass das Playbook ihn weiterhin für die Verbindung zur Datenbank nutzen kann. Die Registrierung muss stattfinden, bevor eine Aufgabe den Wert ausgibt.
Führe das Playbook mit einem Entwicklungsbuild von ansible-core 2.22 aus:
ansible-playbook -i localhost, -c local masking.yml
Die zweite Aufgabe zeigt diese Meldung an:
Connecting to db.internal with password=$REDACTED$
Wir geben das Passwort hier nur aus, um die Maskierung zu demonstrieren. Beziehe es in einem echten Playbook aus deiner Secret-Quelle und vermeide es, Zugangsdaten absichtlich auszugeben.
Integration mit Semaphore UI
Semaphore UI weiß bereits, welche Variablen du als geheim markiert hast. Wir planen, diese Information in künftigen Versionen zu nutzen, um die Werte automatisch bei Ansible zu registrieren.
Dafür werden wir Ansibles Option _SECRETS_INPUT_FILES verwenden. Sie wird über die Umgebungsvariable _ANSIBLE_SECRETS_INPUT_FILES konfiguriert und ermöglicht es Ansible, vor dem Start eines Playbooks eine Liste von Secrets einzulesen.
Die Eingabe kann als YAML oder JSON vorliegen. Ein Dokument mit unserem Beispielpasswort sieht so aus:
version: 1
secrets:
- example-db-password-123456
Diese Liste teilt Ansible mit, was maskiert werden soll. Die Variablen selbst werden dem Playbook weiterhin separat übergeben.
Die geplante Integration wird geheime Werte aus folgenden Quellen abdecken:
- Variablengruppen (Variable Groups) — Secrets, die zur Verwendung in deinen Aufgaben gespeichert sind.
- Abfragen (Surveys) — geheime Antworten, die beim Start einer Aufgabe eingegeben werden.
Für diese Werte müsstest du nicht jedem Playbook eine Aufgabe mit register_secret hinzufügen.
Wir haben diesen Ansatz mit einem Entwicklungsbuild von ansible-core 2.22 getestet. Registrierte Werte wurden in debug-Meldungen, Befehlsergebnissen, Fehlermeldungen, ausführlichen Ausgaben und der Ansible-Protokolldatei maskiert. Auch die Übergabe der Liste über eine Pipe funktionierte, ohne eine separate Secret-Datei auf die Festplatte zu schreiben.
Die Option ist derzeit intern und kann sich ändern. Die Unterstützung in Semaphore UI ist für eine künftige Version geplant und wird eine kompatible Ansible-Version voraussetzen.
Beispiel: Eine Anwendung bereitstellen
Angenommen, wir haben eine Aufgabenvorlage (Task Template), die eine Anwendung bereitstellt. Das Deployment-Skript verwendet ein API-Token, das als Secret in einer Variablengruppe gespeichert ist.
Mit der geplanten Integration wird die Aufgabe wie folgt ablaufen:
- Semaphore UI übergibt das Token an das Playbook.
- Vor der Ausführung übergibt es das Token außerdem über
_SECRETS_INPUT_FILESan Ansibles Maskierungsliste. - Das Playbook führt das Deployment-Skript mit dem echten Token aus.
- Falls das Skript dieses Token in seine Ausgabe aufnimmt, maskiert Ansible es im angezeigten Ergebnis.
Ein abgelaufenes Token könnte beispielsweise diese Meldung im Aufgabenprotokoll erzeugen:
Deployment rejected: service=payments environment=staging token=$REDACTED$ reason=token expired
Wir sehen, welches Deployment fehlgeschlagen ist und warum, ohne das Token allen Lesern des Protokolls zu zeigen. Derselbe Ablauf wird für ein temporäres Token gelten, das über ein geheimes Survey-Feld eingegeben wurde.
Einschränkungen
Die Maskierung arbeitet mit registrierten Werten. Die Entwicklungsimplementierung überspringt Secrets mit weniger als vier Zeichen. Ein kodierter oder anderweitig umgewandelter Wert muss möglicherweise separat registriert werden.
Sie schützt auch keine Zugangsdaten in Prozessargumenten, in Dateien, die ein Playbook schreibt, oder in Protokollen außerhalb von Ansible. Verwende weiterhin no_log: true für Aufgaben, deren gesamte Ausgabe vertraulich bleiben soll.
Mit dieser Integration werden die in Semaphore UI markierten Secrets auch Ansibles Maskierungssystem bekannt sein. So lassen sich Zugangsdaten aus Aufgabenprotokollen fernhalten, während nützliche Informationen zur Fehlerdiagnose erhalten bleiben.

