Bei der Nutzung von ansible muss man ab und an auch sensible Daten (z.B. Passwörter) in Variablen hinterlegen. Diese werden dann in einem Repository zum Beispiel dem gesamten Team zur Verfügung gestellt. Da will man die sensiblen Daten natürlich nicht im Klartext ablegen, sondern man muss sie verschlüsselt speichern können. Und genau hier kommt ansible vault zum Einsatz.

Methoden

Es gibt zwei Möglichkeiten, Daten in ansible zu verschlüsseln. Entweder man verschlüsselt einzelne Werte und hinterlegt diese in einer Datei zusammen mit anderen Variablen die im Klartext erfasst sind oder man verschlüsselt den gesamten Inhalt einer Datei. Beide Methoden können natürlich auch gleichzeitig verwendet werden. Unter Umständen ist es manchmal sogar sinnvoll, zwei oder mehr Vaults zu verwenden. Ein denkbares Szenario wäre zum Beispiel, das man einen Vault für die Production-Umgebung, einen anderen Vault für die Development-Umgebung verwendet. So können unterschiedliche Teams mit verschiedenen Passwörtern arbeiten. Oder aber jede Rolle enthält einen eigenen Vault. Viele Möglichkeiten mit verschiedenen Vor- und Nachteilen, dass sollte bei der Konzeption des ansible-Repositories vorab berückstichtig werden.

Vault-IDs

Wenn man mehrere Vaults mit verschiedenen Passwörtern verwendet, dann muss man die Vaults irgendwie unterscheiden können. Hierzu verwendet man IDs. Diese IDs sind in Vaults nicht verschlüsselt hinterlegt und im Klartext einsehbar. Sie können daher auch als eine Art "Hinweis" verstanden werden, der angibt, welches Kennwort hier verwendet werden muss. Bei jedem Vorgang (erstellen, ansehen oder bearbeiten) eines Vaults gibt man die ID mit dem Parameter --vault-id an. Es folgt als erstes die ID (z.B. prod) gefolgt von der Angabe, wo das Passwort zu finden ist (z.B. der Pfad zur Datei, zu einem Skript). Es kann statt der Datei auch prompt verwendet werden, dann wird man aufgefordert, ein Passwort einzugeben.

Natürlich kann man sich die Passwörter einfach merken, aber das will ja keiner. Daher speichere ich meine Passwörter in einer Datei (diese Datei wird NIE in das Repository eingecheckt und darüber verteilt). Hier gibt es zwei Optionen:

  • Die Datei enthält nur ein Passwort für ein Vault. Jeder Vault nutzt eine eigene Datei.
  • Die Datei enthält mehrere Passwörter zu verschiedenen Vaults. Dann muss jedem Passwort die ID des zugehörigen Vaults vorangestellt werden.

How to

So viel zur Theorie, nun zur Praxis. Erstell dir einen Ordner ansible-vault und darin einen Unterordner repository. Im Unterordner repository erstellst du noch einen Ordner group_vars. Damit hast du die grundlegende Ordnerstruktur für dieses Beispiel erstellt.

Nun erstellst du die Passwort-Datei. Dazu legst du im Ordner ansible-vault eine Datei namens ansible.pass an und hinterlegst dort zuerst die Vault-IDs und dann, durch einen Tabulator getrennt, das jeweilige Passwort.

prod    OhM4aiHe
dev     Oogh4Ach

Erstellen eines neuen Vaults

Jetzt erstellst du dir den ersten Vault prod_vault.yml im Ordner group_vars mit dem unten folgenden Befehl. Zur Verschlüsselung verwenden wir das von uns in der Datei ansible.pass vorher festgelegte Passwort zu der Vault-ID prod:

ansible-vault create --vault-id prod@ansible.pass --encrypt-vault-id prod repository/group_vars/prod_vault.yml

Der Parameter --vault-id gibt an, welche ID und welches zugehörige Passwort aus der Datei geladen werden sollen, der Parameter --encrypt-vault-id legt fest, welches Passwort für die Verschlüsselung verwendet wird und abschließend wird der Pfad zur Vault-Datei angegeben.

Es öffnet sich ein Editor, in dem wir die folgenden Einträge vornehmen:

vault_db_password: 'MeinDatenbankPasswort'
vault_auth_password: 'MeinAuthPasswort'

Nach dem Schließen des Editors befindet sich im Ordner group_vars die neu erstellte Datei *prod_vault.yml**. Diese sieht in etwa so aus:

$ANSIBLE_VAULT;1.2;AES256;prod
36613635356566643962353836303433353464643862633234376338373961613733316166613336
3861306462333964633938383762343737653239353837350a363138333037323862656661643366
34373564613233613235626439316538323737363433313865613639366536396536303466613161
6436663666643066370a373662326438303038363366353538663361646632353362653130386438
34633661626138333534626538383637643630303730626134643162623665343933386562613066
63623138353533383062663866653334393731653736386331323939393537333338323731383432
32653263316230613666396162373338363030366362653038313561666135663531343938396237
34323237353265396465386434306264633536636134386463666238363633303536333434363431
3434

Verschlüsseln einer bestehenden Datei

Es gibt noch die zweite Option, eine bereits vorhandene Datei zu verschlüsseln. Dazu legst du dir im Ordner group_vars die Datei dev_vault.yml an und trägst die folgenden Zeilen ein:

vault_db_password: 'MeinDevDatenbankPasswort'
vault_auth_password: 'MeinDevAuthPasswort'

Jetzt verschlüsseln wir den Inhalt dieser Datei.

ansible-vault encrypt --vault-id dev@ansible.pass --encrypt-vault-id dev repository/group_vars/dev_vault.yml

Dieser Befehl lädt aus der Datei ansible.pass die ID dev sowie das zugehörige Passwort. Dieses Passwort wird zur Verschlüsselung verwendet. Die erfolgreiche Verarbeitung der Datei wird mit dem Hinweis "encryption successful" quitiert und der gesamte Inhalt der Datei ist nun verschlüsselt:

$ANSIBLE_VAULT;1.2;AES256;dev
66633530306261376437336163393238343033353236653937316365663762323733643261393331
6261363964613962316638363031643830303836366635310a653437356337633839313962356431
66633332353534316236313930323034633731346533333736343038363732666465366638383630
3663623737386431310a313638613634323062656162333063363832373033373032336237663961
36363535333038643761373865303461343933326236373131373630366561363338653462346662
31353963373962633935313736346436646336623931373132383236636337306235343565353436
66373331353234393334346635663038633234396662663164333261373566336134363763393133
64633938363037663032656262393738396566386166336337623839346539643631366233323433
6634

Verwendung der Vaults

Jetzt wechseln wir in den Ordner repository und legen dort die folgenden Dateien an.

  • ansible.cfg
[defaults]
inventory             = inventory.ini
host_key_checking     = False
retry_files_enabled   = False
vault_password_file   = ../ansible.pass
  • inventory.ini
[prod]
127.0.0.1  ansible_connection=local

[dev]
127.0.0.1  ansible_connection=local
  • provision-prod.yml
- hosts: prod

  pre_tasks:
    - name: include vault
      include_vars: "group_vars/prod_vault.yml"
      tags: ["always"]

  tasks:
    - name: "Print db password from vault"
      debug:
        msg: "DB: {{ vault_db_password }}"

    - name: "Print auth password from vault"
      debug:
        msg: "DB: {{ vault_auth_password }}"
  • provision-dev.yml
- hosts: dev

  pre_tasks:
    - name: include vault
      include_vars: "group_vars/dev_vault.yml"
      tags: ["always"]

  tasks:
    - name: "Print db password from vault"
      debug:
        msg: "DB: {{ vault_db_password }}"

    - name: "Print auth password from vault"
      debug:
        msg: "DB: {{ vault_auth_password }}"

Damit haben wir das Inventar inventory.yml angelegt mit zwei Hosts, eine Konfigurationsdatei ansible.cfg, über die die Passwort-Datei eingebunden wird und jeweils ein Playbook für die beiden Hosts prod und dev.

Jetzt lassen wir jedes Playbooks einmal durchlaufen.

ansible-playbook provision-prod.yml
ansible-playbook provision-dev.yml

Bei der Ausgabe der beiden Playbooks sollten euch zuerst die Passwörter aus dem Vault prod_vault.yml ausgegeben werden, beim Provisionieren des Dev-Systems die Kennwörter aus dem Vault dev_vault.yml.

Optimierung

Ein Manko des o.a. Setups ist, dass kein Editor die Vault-Datei auslesen kann und somit die Variablen vault_db_password und vault_auth_password bei der automatischen Vervollständigung nicht verfügbar sind. Um das Problem zu lösen, erstellt man im Ordner group_vars eine Datei all.yml. Dort trägt man die folgenden Zeilen ein.

db_password:    "{{ vault_db_password }}"
auth_password:  "{{ vault_auth_password }}"

Nun nimmt man sich die Playbooks und ändert dort die Variable von vault_db_password auf db_password und von vault_auth_password auf auth_password. Die beiden neuen Variablen aus der Datei all.yml sind nun in der Autovervollständigung des Editors vorhanden.

Ansehen und bearbeiten von verschlüsselten Dateien

Um die verschlüsselten Werte im Klartext ansehen zu können gibt es bei ansible-vault das Kommando view, zum Bearbeiten verwendet man das Kommando edit.

# Ansehen der verschlüselten Daten im Klartext
ansible-vault view --vault-id dev@ansible.pass repository/group_vars/dev_vault.yml

# Bearbeiten der verschlüsselten Daten
ansible-vault edit --vault-id dev@ansible.pass repository/group_vars/dev_vault.yml

Verschlüsselung einer einzelnen Variable

Nur der Vollständigkeit halber möchte ich noch kurz die Verschlüsselung einer einzelnen Variablen aufzeigen. Ich verwende hier wieder die bereits angelegte Datei ansible.pass. Die Variable soll support_user_password heißen und das Passwort lautet Ki3lahTh.

ansible-vault encrypt_string --vault-id dev@../ansible.pass --encrypt-vault-id dev 'Ki3lahTh' --name 'support_user_password'

Den so erzeugten Eintrag hinterlegt man in der Datei all.yml im Ordner group_vars.

db_password:    "{{ vault_db_password }}"
auth_password:  "{{ vault_auth_password }}"

support_user_password: !vault |
          $ANSIBLE_VAULT;1.2;AES256;dev
          30643232643939363937643366666664623132313337313231363465653631316563316465613766
          3237363165333663646434633733333130643232386235660a616266343461666231383438346137
          64623435353765343064663630613035643437353565353931336262303134363062306238303363
          3436653965366230360a383361666230323231396230646230396135356432626133373661646631
          3839

Im Playbook *provision-dev.yaml fügt man folgenden Task hinzu:

- name: "Print password for support user"
  debug:
    msg: "Support user: {{ support_user_password }}"

Bei einem erneuten Lauf des Playbooks wird das Kennwort des Support-Benutzers ausgegeben.

Hier die Ordnerstruktur inklusive der erstellten Datein zum Herunterladen und vergleichen: ansible-vault.tar.gz

Vorheriger Beitrag