Als Konfigurationsmanagement-System muss Ansible sogenannte Geheimnisse verwalten können, die einen weitreichenden Zugriff auf die zu verwaltenden Systeme erlauben. Dieser Artikel zeigt, wie du Geheimnisse mit GnuPG sicher speichern und komfortabel verwenden kannst.

Interaktive Password-Eingabe: Sicher, aber unbequem

Ansible bietet mit Ansible Vault eine Möglichkeit, in Playbooks verwendete Geheimnisse (secrets) zu verschlüsseln. Bei den Geheimnissen kann es sich um Passwörter, Zugriffstoken, private Schlüssel oder auch um das Playbook selbst handeln. Diese Daten werden von Vault mit einem Hauptpasswort, dem Vault-Passwort, verschlüsselt. Um ein Playbook auszuführen, das auf verschlüsselte Daten zugreift, erwartet Ansible das Vault-Passwort beim Aufruf. Dazu gibst du die Option --ask-vault-pass an und tippst das Passwort interaktiv ein. Ansible entschlüsselt die Daten transparent im Hintergrund: Verschlüsselte Variablen verhalten sich für das Playbook genauso wie unverschlüsselte.

Auch der Zugriff auf die Zielsysteme muss abgesichert werden, oft kommt noch ein Passwort für sudo oder für einen anderen Mechanismus zur Erlangung erhöhter Rechte hinzu. Der Zugriff auf die Zielsysteme erfolgt in der Regel mit SSH-Schlüsseln. Diese verwaltet der SSH-Agent. Der Agent fragt die Passphrase ab und erlaubt für eine festgelegte Zeit die Verwendung des privaten Schlüssels. Anders sieht es mit dem Passwort für die Erlangung höherer Rechte aus. Dieses gibst du, genau wie das Vault-Passwort, interaktiv bei jedem Aufruf des Playbooks ein. Du rufst Ansible dazu mit der Option --ask-become-pass auf.

Passwort-Dateien: Bequem, aber unsicher

Die manuelle Eingabe der beiden Passwörter bei jedem Aufruf des Playbooks kann schnell mühsam werden. Stattdessen kannst du in der Ansible-Konfigurationsdatei ansible.cfg des Projekts für beide Passwörter Dateien angeben, aus denen Ansible dann die Passwörter liest.

[defaults]
vault_password_file = passwords/vault-password
become_password_file = passwords/sudo-password

Diese Vorgehensweise hat allerdings den Nachteil, dass die Passwörter jetzt unverschlüsselt im Dateisystem herumliegen. Da mit diesen Passwörtern in der Regel weitreichender Zugriff auf wichtige Systeme möglich ist, ist das keine gute Idee.

Passwort-Skripte: Sicher und bequem

Zum Glück gibt es eine bessere Möglichkeit: Anstelle von herkömmlichen Textdateien kannst du auch Skripte verwenden, die das jeweilige Passwort zurückgeben. Für Passwort-Skripte gibt es keine eigenen Parameter, Ansible nutzt hier dieselben Parameter (vault_password_file, become_password_file) wie für Passwort-Dateien. Zur Unterscheidung prüft Ansible das Executable-Bit der Datei: Ist dieses gesetzt, handelt es sich um ein Passwort-Skript. Ansible führt das Skript aus und verwendet dessen Standardausgabe als Passwort.

 

Diese Funktion lässt sich zunutze machen, um Passwörter bei Verwendung automatisch per GnuPG zu entschlüsseln. Dafür brauchst du ein PGP-Schlüsselpaar und musst die Passwörter verschlüsselt im System ablegen. Der GnuPG-Agent sorgt anschließend dafür, dass du das Passwort nicht bei jedem Aufruf neu eingeben musst. Die Geheimnisse liegen jedoch trotzdem verschlüsselt im System.

PGP-Schlüssel erstellen und Passwörter verschlüsseln

Falls du keinen vorhandenen PGP-Schlüssel nutzen möchtest, kannst du einen neuen erstellen. Für den Schlüsseltyp und die elliptische Kurve sind die Standardwerte eine gute Wahl. Wenn du bei der Gültigkeitsdauer 0 eingibst, ist der Schlüssel zeitlich unbeschränkt gültig.

$ gpg --full-gen-key

Please select what kind of key you want:
(1) RSA and RSA
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(9) ECC (sign and encrypt) *default*
(10) ECC (sign only)
(14) Existing key from cardYour selection? 9
Please select which elliptic curve you want:
(1) Curve 25519 *default*
(4) NIST P-384
(6) Brainpool P-256
Your selection? 1
Please specify how long the key should be valid.
      0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years Key is valid for? (0) 0 Key does not expire at all Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: Jens Meißner Email address: Comment: You are using the 'utf-8' character set. You selected this USER-ID: "Jens Meißner" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o We need to generate a lot of random bytes. It is a good idea to performsome other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random numbergenerator a better chance to gain enough entropy. We need to generate a lot of random bytes. It is a good idea to performsome other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random numbergenerator a better chance to gain enough entropy. gpg: revocation certificate stored as '/home/jens/.gnupg/openpgp-revocs.d/3B91358E2B949CDB9D33A6F77F53C4D9F50B05D0.rev' public and secret key created and signed. pub ed25519 2026-06-14 [SC]3B91358E2B949CDB9D33A6F77F53C4D9F50B05D0 uid Jens Meißner sub cv25519 2026-06-14 [E]

GnuPG fragt zweimal nach einer Passphrase. Diese dient künftig als Generalschlüssel.

Mit dem PGP-Schlüssel lässt sich jetzt das Vault-Passwort sicher verschlüsseln. Das verschlüsselte Passwort wird in der Datei vault-password.gpg im Ordner secretsgespeichert. Falls der Ordner noch nicht existiert, musst du ihn zuerst erstellen. Mit dem Parameter --recipient gibst du die Schlüssel-ID des PGP-Schlüssels an. Der Parameter -s des read-Befehls sorgt dafür, dass das Passwort während der Eingabe nicht sichtbar ist.

$ read -s PASSWORD$ echo "$PASSWORD" | gpg --recipient 3B91358E2B949CDB9D33A6F77F53C4D9F50B05D0 --output secrets/vault-password.gpg$ unset PASSWORD

Wenn du Ansible Vault bisher noch nicht verwendet hast, kannst du auch ein neues, zufälliges Vault-Passwort erzeugen und es gleich verschlüsselt speichern:

$ pwgen -s 20 | gpg --encrypt --recipient 3B91358E2B949CDB9D33A6F77F53C4D9F50B05D0 --output secrets/vault-password.gpg

Für das sudo-Passwort kannst du analog verfahren und es verschlüsselt in der Datei sudo-password.gpg speichern.

$ read -s PASSWORD $ echo "$PASSWORD" | gpg --recipient 3B91358E2B949CDB9D33A6F77F53C4D9F50B05D0 --output secrets/sudo-password.gpg $ unset PASSWORD

Entschlüsselungsskripte einrichten und Ansible konfigurieren

Als Nächstes erstellst du die beiden Skripte für die Entschlüsselung der Passwörter und legst sie im Ordner bin im Projekt-Verzeichnis ab. Auch diesen Ordner musst du gegebenenfalls zuerst erstellen.

bin/vault-password.sh
---------------------
#!/bin/sh
gpg --quiet --decrypt ./secrets/vault-password.gpg
bin/sudo-password.sh
--------------------
#!/bin/sh
gpg --quiet --decrypt ./secrets/sudo-password.gpg

Die so erstellten Skripte machst du ausführbar:

$ chmod +x bin/vault-password.sh bin/sudo-password.sh

Beim ersten Aufruf der Skripte wird der GnuPG-Agent nun nach der Passphrase des PGP-Schlüssels fragen, anschließend gibt das Skript das entschlüsselte Passwort auf der Standard-Ausgabe aus. Wird das Skript in den nächsten 10 Minuten erneut aufgerufen, ist keine erneute Eingabe der Passphrase notwendig.

Wenn du die Skripte erfolgreich getestet hast, kannst du Ansible so konfigurieren, dass es sie automatisch verwendet, wenn die Passwörter benötigt werden. Dafür setzt du die Optionen vault_password_file und become_password_file im Abschnitt defaults in der Ansible-Konfigurationsdatei ansible.cfg:

[defaults]
vault_password_file = ./bin/vault-password.sh
become_password_file = ./bin/sudo-password.sh

Hast du Ansible Vault bereits mit dem gespeicherten Passwort verwendet, kannst du ansible-playbook nun ohne den Parameter --ask-vault-pass aufrufen. Die Eingabe des Vault-Passworts entfällt. Die Passphrase des GnuPG-Agents musst du nur eingeben, falls seit der letzten Verwendung mehr als 10 Minuten vergangen sind. Ansonsten kannst du Ansible Vault wie bisher weiter verwenden. Der einzige Unterschied ist die Eingabe der PGP-Passphrase anstelle des Vault-Passworts.

Hast du Ansible Vault noch nicht verwendet, kannst du jetzt eine Variable mit dem Befehl ansible-vault encrypt_string verschlüsseln. Eventuell fragt der GnuPG-Agent nach der Passphrase, Ansible sollte aber kein Vault-Passwort erfragen. Zu beachten ist, das etwaige abschließende Zeilenumbrüche mit verschlüsselt werden. Soll die Variable nicht mit einem Zeilenumbruch enden, musst du die Eingabe nach dem letzten Buchstaben durch zweimaliges Drücken von Strg+D beenden.

$ ansible-vault encrypt_string
Reading plaintext input from stdin. (ctrl-d to end input, twice if your content does not already have a newline)
<Geheimnis>
Encryption successful
!vault |
    $ANSIBLE_VAULT;1.1;AES256
    37303964353931656336336435626462663430623562653730336565353937306237643730636134
    6431313136313637323936386564616532623131623162370a303861353531373234326235346365
    37666661383235393065326564336533356432326230373432343335303032656264316132373161
    3632623964633338350a323139623834343435353037613638656631323435653934366632386265
    31363266383065386636663565383566326130323464656632383338303437343335

Es wird eine mit !vault beginnende mehrzeilige Zeichenkette ausgegeben. Diese kannst du überall dort einsetzen, wo Variablen in Ansible definiert werden können, zum Beispiel im Inventory oder in den group_vars.

Die Praxis

Beispielhaft siehst du hier die Verwendung direkt im Playbook:

- hosts: localhost
  vars:
      password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          37303964353931656336336435626462663430623562653730336565353937306237643730636134
          6431313136313637323936386564616532623131623162370a303861353531373234326235346365
          37666661383235393065326564336533356432326230373432343335303032656264316132373161
          3632623964633338350a323139623834343435353037613638656631323435653934366632386265
          31363266383065386636663565383566326130323464656632383338303437343335
  tasks:
  - name: Show encrypted password
    ansible.builtin.debug:
        msg: "Das Passwort ist {{ password }}"

Beim Aufruf des Playbooks wird die verschlüsselte Variable zuerst entschlüsselt und dann ausgegeben. Wichtig ist, dass du den Befehl im Verzeichnis mit der Ansible-Konfigurationsdatei ansible.cfg ausführst und dass die Pfade in der Datei und den Skripten korrekt sind.

$ ansible-playbook test.yaml

Abschließend lässt sich noch die Zeit konfigurieren, nach welcher der GnuPG-Agent die Passphrase „vergisst“. Dabei gibt es zwei Werte: Über default-cache-ttl wird die Zeitspanne festgelegt, nach der GnuPG die Passphrase bei Nicht-Verwendung vergisst. Über max-cache-ttl legst du die Zeit fest, die nach Eingabe der Passphrase vergehen muss, bis diese vergessen wird, auch wenn der Schlüssel verwendet wird.

Soll der Agent die Passphrase nach einer Stunde Nicht-Verwendung und spätestens nach vier Stunden insgesamt vergessen, sehen die entsprechenden Einträge in der Datei ~/.gnupg/gpg-agent.conf so aus:

default-cache-ttl 3600
max-cache-ttl 14400

Damit die Änderungen wirksam werden, muss der GnuPG-Agent neu geladen werden:

$ gpgconf --reload gpg-agent

Damit ist die Einrichtung von GnuPG als Hilfswerkzeug für Ansible Vault abgeschlossen.

Sicher und bequem – kein Widerspruch

Ein PGP-Schlüsselpaar, zwei Skripte und ein paar Anpassungen in zwei Konfigurationsdateien – das ist alles was man braucht, um Geheimnisse für Ansible sicher zu speichern und trotzdem bequem verwenden zu können. Jetzt gibt es keinen Grund mehr für unverschlüsselte Passwörter in Ansible-Playbooks.

Jens Meißner
Jens Meißner arbeitet seit 2018 als Linux-Consultant bei B1 Systems und beschäftigt sich mit den Themen Netzwerk, Virtualisierung, Automatisierung und Monitoring. Am liebsten benutzt er Debian, interessiert sich neben Linux aber auch für FreeBSD und OpenBSD.