Ansible - erweitertes Konfigurationsbeispiel 7: Ansible Vault

Bild: Ansible Logo

Im Eingangskapitel Grundlagen haben wir uns mit der Installation bereits befasst. Mit den Hintergrundinformationen haben wir uns auch schon in den beiden Kapiteln Playbooks und YAML - was ist das? eingehend beschäftigt, sowie erste Erfahrungen mit Playbooks gesammelt.

Beim ersten Playbook-Beispiel Benutzer anlegen ist uns bereits ein wesentlicher Umstand ins Auge gestossen. Das Ablegen von Passwörtern in einem Playbook ist alles andere als sicher:

Doch Achtung: Es zeigt sehr anschaulich, dass es keine gute Idee sein kann, Passworte und ähnliches direkt in einem Playbook und/oder Inventory unverschlüsselt vor zuhalten - kann doch so jeder, der Zugriff auf das Playbook/Inventory hat, unberechtigter Weise Kenntnis von vertraulichen Informationen erlangen!

Das Passwort M31nP4p4157d3r4113r83573! des Nutzers ruben ist in diesem Beispiel für jedermann lesbar in dem Playbook gespeichert. Das ist natürlich alles andere als sicher! Jeder oder jede, die auf diese Datei lesend zugreifen kann, kennt nun das Passwort dieses Users. :-? Was also tun? Nun, im Grunde verfahren wir wie sonst auch:

  1. Sensible Informationen werden verschlüsselt (krypted) und niemals im Klartext vorgehalten!
  2. Benötigt man Zugriff auf den Inhalt der verschlüsselten Informationen, müssen wir diese temporär entschlüsselt werden (dekrypt). Hierzu müssen wir in Besitz eines entsprechenden Schlüssels und ggf. dessen Sicherungspassphrase sein! Optional wäre auch noch denkbar über einen Access-Token bei einem Agenten, das betreffende Passwort zu erfragen.
  3. Wir wollen möglichst wenig Aussenanbindungen, wenn es um die Verwaltung und den Zugriff auf vertrauliche Informationen geht. Zum einen können diese ausfallen und unsere Ansible-Umgebung wäre inoperabel und zum anderen trauen wir nur möglichst unserem eigenen System(en)!
  4. Wir sind uns dabei einig und sicher, dass im RAM des Rechners bzw. über einen Agent, dass Passwort zur Laufzeit vorgehalten und ggf. dort unberechtigter Weise ausgelesen werden könnte - kurzum eine 100% sichere Lösung gibt es nicht, nicht einmal wenn sich ein entsprechendes Passwort ausschliesslich im Gehirn des Admin befände.
  5. Bei einem Security-Audit wollen wir nicht sofort durch Auswahl, Nutzung und Handling von unsicheren Lösungen auffallen.

Wir benötigen also eine Lösung, die sowohl als ausreichend sicher Bestand hat und auch eine entsprechende Akzeptanz bei der Nutzung gewährleistet. Hier greifen wir nun auf Ansible-Vault aus dem Paket ansible zurück.

Was das Python3-Script ansible-vault nun alles kann und leistet, entnehmen wir einfach den Hilfe-Optionen des Scripts bzw. der zugehörigen Manpage.

Rufen wir das Script ansible-vault mit der Option -h bzw –help auf, erhalten wir eine entsprechende Kurzbeschreibung.

 $ ansible-vault --help
usage: ansible-vault [-h] [--version] [-v] {create,decrypt,edit,view,encrypt,encrypt_string,rekey} ...

encryption/decryption utility for Ansible data files

positional arguments:
  {create,decrypt,edit,view,encrypt,encrypt_string,rekey}
    create              Create new vault encrypted file
    decrypt             Decrypt vault encrypted file
    edit                Edit vault encrypted file
    view                View vault encrypted file
    encrypt             Encrypt YAML file
    encrypt_string      Encrypt a string
    rekey               Re-key a vault encrypted file

optional arguments:
  --version             show program's version number, config file location, configured module search path, module location,
                        executable location and exit
  -h, --help            show this help message and exit
  -v, --verbose         Causes Ansible to print more debug messages. Adding multiple -v will increase the verbosity, the builtin
                        plugins currently evaluate up to -vvvvvv. A reasonable level to start is -vvv, connection debugging might
                        require -vvvv.

See 'ansible-vault <command> --help' for more information on a specific command.

Wollen wir eine Kurz-Hilfe z.B. zur Option encrypt, fragen wir entsprechend nach dessen beschreibende Option bzw. Kurz-Hilfe.

 $ ansible-vault encrypt --help
usage: ansible-vault encrypt [-h] [--vault-id VAULT_IDS] [--ask-vault-password | --vault-password-file VAULT_PASSWORD_FILES] [-v]
                             [--output OUTPUT_FILE] [--encrypt-vault-id ENCRYPT_VAULT_ID]
                             [file_name [file_name ...]]

positional arguments:
  file_name             Filename

optional arguments:
  -h, --help            show this help message and exit
  --vault-id VAULT_IDS  the vault identity to use
  --ask-vault-password, --ask-vault-pass
                        ask for vault password
  --vault-password-file VAULT_PASSWORD_FILES, --vault-pass-file VAULT_PASSWORD_FILES
                        vault password file
  -v, --verbose         Causes Ansible to print more debug messages. Adding multiple -v will increase the verbosity, the builtin
                        plugins currently evaluate up to -vvvvvv. A reasonable level to start is -vvv, connection debugging might
                        require -vvvv.
  --output OUTPUT_FILE  output file name for encrypt or decrypt; use - for stdout
  --encrypt-vault-id ENCRYPT_VAULT_ID
                        the vault id used to encrypt (required if more than one vault-id is provided)

Werfen wir nun also auch noch einen Blick in die Manpage von ansible-vault.

 $ man ansible-vault
ANSIBLE-VAULT(1)                                  System administration commands                                 ANSIBLE-VAULT(1)

NAME
       ansible-vault - encryption/decryption utility for Ansible data files

SYNOPSIS
       usage: ansible-vault [-h] [--version] [-v]
              {create,decrypt,edit,view,encrypt,encrypt_string,rekey} ...

DESCRIPTION
       can  encrypt  any  structured  data file used by Ansible.  This can include group_vars/ or host_vars/ inventory variables,
       variables loaded by include_vars or vars_files, or variable files passed on the ansible- playbook  command  line  with  -e
       @file.yml or -e @file.json.  Role variables and defaults are also included!

       Because Ansible tasks, handlers, and other objects are data, these can also be encrypted with vault.  If you'd like to not
       expose what variables you are using, you can keep an individual task file entirely encrypted.

COMMON OPTIONS
       --version
          show program's version number, config file location, configured module search path, module location,  executable  loca‐
          tion and exit

       -h, --help
          show this help message and exit

       -v, --verbose
          verbose mode (-vvv for more, -vvvv to enable connection debugging)

ACTIONS
       create create and open a file in an editor that will be encrypted with the provided vault secret when closed

              --ask-vault-pass
                 ask for vault password

              --encrypt-vault-id 'ENCRYPT_VAULT_ID'
                 the vault id used to encrypt (required if more than vault-id is provided)

              --vault-id
                 the vault identity to use

              --vault-password-file
                 vault password file

       decrypt
              decrypt the supplied file using the provided vault secret

              --ask-vault-pass
                 ask for vault password

              --output 'OUTPUT_FILE'
                 output file name for encrypt or decrypt; use - for stdout

              --vault-id
                 the vault identity to use

              --vault-password-file
                 vault password file

       edit   open and decrypt an existing vaulted file in an editor, that will be encrypted again when closed

              --ask-vault-pass
                ask for vault password

              --encrypt-vault-id 'ENCRYPT_VAULT_ID'
                 the vault id used to encrypt (required if more than vault-id is provided)

              --vault-id
                 the vault identity to use

              --vault-password-file
                 vault password file

       view   open, decrypt and view an existing vaulted file using a pager using the supplied vault secret

              --ask-vault-pass
                 ask for vault password

              --vault-id
                 the vault identity to use

              --vault-password-file
                 vault password file

       encrypt
              encrypt the supplied file using the provided vault secret

              --ask-vault-pass
                 ask for vault password

              --encrypt-vault-id 'ENCRYPT_VAULT_ID'
                 the vault id used to encrypt (required if more than vault-id is provided)

              --output 'OUTPUT_FILE'
                 output file name for encrypt or decrypt; use - for stdout

              --vault-id
                 the vault identity to use

              --vault-password-file
                 vault password file

       encrypt_string
              encrypt the supplied string using the provided vault secret

              --ask-vault-pass
                 ask for vault password

              --encrypt-vault-id 'ENCRYPT_VAULT_ID'
                 the vault id used to encrypt (required if more than vault-id is provided)

              --output 'OUTPUT_FILE'
                 output file name for encrypt or decrypt; use - for stdout

              --stdin-name 'ENCRYPT_STRING_STDIN_NAME'
                 Specify the variable name for stdin

              --vault-id
                 the vault identity to use

              --vault-password-file
                 vault password file

              -n,   --name
                 Specify the variable name

              -p,   --prompt
                 Prompt for the string to encrypt

       rekey  re-encrypt a vaulted file with a new secret, the previous secret is required

              --ask-vault-pass
                 ask for vault password

              --encrypt-vault-id 'ENCRYPT_VAULT_ID'
                 the vault id used to encrypt (required if more than vault-id is provided)

              --new-vault-id 'NEW_VAULT_ID'
                 the new vault identity to use for rekey

              --new-vault-password-file 'NEW_VAULT_PASSWORD_FILE'
                 new vault password file for rekey

              --vault-id
                 the vault identity to use

              --vault-password-file
                 vault password file

ENVIRONMENT
       The following environment variables may be specified.

       ANSIBLE_CONFIG -- Specify override location for the ansible config file

       Many more are available for most options in ansible.cfg

       For a full list check https://docs.ansible.com/. or use the ansible-config command.

FILES
       /etc/ansible/ansible.cfg -- Config file, used if present

       ~/.ansible.cfg -- User config file, overrides the default config if present

       ./ansible.cfg  -- Local config file (in current working directory) assumed to be 'project specific' and overrides the rest
       if present.

       As mentioned above, the ANSIBLE_CONFIG environment variable will override all others.

AUTHOR
       Ansible was originally written by Michael DeHaan.

COPYRIGHT
       Copyright © 2018 Red Hat, Inc | Ansible.  Ansible is released under the terms of the GPLv3 license.

SEE ALSO
       ansible (1), ansible-config (1), ansible-console (1), ansible-doc (1), ansible-galaxy (1),  ansible-inventory  (1),  ansi‐
       ble-playbook (1), ansible-pull (1),

       Extensive documentation is available in the documentation site: <https://docs.ansible.com>.  IRC and mailing list info can
       be found in file CONTRIBUTING.md, available in: <https://github.com/ansible/ansible>

Ansible 2.9.6                                                                                                    ANSIBLE-VAULT(1) 

Nehmen wir in nachfolgendem Beispiel an, dass Passwort Früh übt sich, wer ein Meister werden will! des Admin-Users christoph legen wir im Inventory ab:

 $ echo "admin_password: Frueh_uebt_51ch_wer_31n_Meister_werden_will!" > ~/ansible/inventory/produktion/group_vars/all/secrets.yml

Wir haben also eine Datei, mit folgendem Inhalt, die jeder (aus-)lesen kann der Zugriff auf unseren Rechner hat:

 $ cat ~/ansible/inventory/produktion/group_vars/all/secrets
admin_password: Frueh_uebt_51ich_wer_31n_Meister_werden_will!

Wir wollen also diese Datei mit Hilfe von ansible-vault verschlüsseln, dazu rufen wir folgenden Befehl auf:

 $ ansible-vault encrypt ~/ansible/inventory/produktion/group_vars/all/secrets.yml

Wir werden nun nach einem hinreichend sicheren Passwort 2x gefragt - hier geben wir also Schleichi, der aufstrebende Stern am Ansible-Himmel! ein.

New Vault password: Schleichi, der aufstrebende Stern am Ansible-Himmel!
Confirm New Vault password: Schleichi, der aufstrebende Stern am Ansible-Himmel!
Encryption successful

Unsere Datei mit dem Passwort ist nun verschlüsselt, versuchen wir nun das Passwort „auszulesen“ erhalten wir nur einen entsprechenden „Zahlensalat“.

 $ less ~/ansible/inventory/produktion/group_vars/all/secrets
$ANSIBLE_VAULT;1.1;AES256
39303364346439623430643364306438353034663962646364376362626665373862623335323361
3531626233656330646563656262383638336666633363340a356361353938613534623539353937
66366633323936333731653234386363336336376261373632613063663536663931356333303331
3164363837383636650a323630666265363262346662623231636536306532353963323332373932
65376637363362346161376665313231383562643164616332363636363630626264373665313837
32373965393266323231313033613732636438623538616439616364643332366535653230386263
316365393035626461383535613761343365

Wie wir gerade gesehen haben, kommen wir nun nicht mehr so ohne weiteres an die verborgene Information. Wollen wir den Inhalt einsehen, benutzen wir die Option view beim Aufruf von ansible-vault.

 $ ansible-vault view ~/ansible/inventory/produktion/group_vars/all/secrets.yml

Wir werden nun aufgefordert unser Vault-Passphrase/-Passwort einzugeben, damit für die Anzeige der Datei diese temporär entschlüsselt werden kann. Wir geben also hier Schleichi, der aufstrebende Stern am Ansible-Himmel! ein.

Vault password: Schleichi, der aufstrebende Stern am Ansible-Himmel!

Als Ergebnis erhalten wir:

admin_password: Frueh_uebt_51ch_wer_31n_Meister_werden_will!

Die Datei selbst ist immer noch verschlüsselt:

 $ less ~/ansible/inventory/produktion/group_vars/all/secrets.yml
$ANSIBLE_VAULT;1.1;AES256
39303364346439623430643364306438353034663962646364376362626665373862623335323361
3531626233656330646563656262383638336666633363340a356361353938613534623539353937
66366633323936333731653234386363336336376261373632613063663536663931356333303331
3164363837383636650a323630666265363262346662623231636536306532353963323332373932
65376637363362346161376665313231383562643164616332363636363630626264373665313837
32373965393266323231313033613732636438623538616439616364643332366535653230386263
316365393035626461383535613761343365

Möchten wir eine Anpassung am Inhalt der Datei vornehmen, nutzen wir einfach die Option edit.

 $ ansible-vault view ~/ansible/inventory/produktion/group_vars/all/secrets.yml

Wir werden auch hier nun aufgefordert unser Vault-Passphrase/-Passwort einzugeben, damit die Datei entschlüsselt und im vim zum editieren angeboten werden kann. Wir geben also hier wiederum unsere Passphrase Schleichi, der aufstrebende Stern am Ansible-Himmel! ein.

Vault password: Schleichi, der aufstrebende Stern am Ansible-Himmel!

Wir fügen einfach mal eine weitere Zeile am Anfang der Datei an und definieren dort den Admin-User:

admin_user: christoph
admin_password: Frueh_uebt_51ch_wer_31n_Meister_werden_will!

Anschliessend verlassen wir den Editor und speichern unsere Änderungen mit dem altbekannten :x!. Die Datei liegt nun wieder verschlüsselt mit den geänderten Inhalten vor.

 $ less ~/ansible/inventory/produktion/group_vars/all/secrets
$ANSIBLE_VAULT;1.1;AES256
62376535393830663233323630313962613831356261333336326439613962346132383439363833
6639653032633564373531376263306165306664653939300a313333323632623037373834663033
62363364393231613964363730323065313166306431633338393365333732373637316332643139
3662346632613430310a393437313062393031623435376630643735363364363361316137666261
31643461386563383465663766386464303465653761663738313562663361636237613038313662
31663061643835653339616433323939313130613862323739336261656637336366663636323035
39656238616232386530653161343632626637373238613530666330613139313037633534643132
65373030386236613130383939346361346165343034386532363363656230343935623064653434
3963

Mit view können wir uns vergewissern, ob die neuen Inhalte auch wirklich vorliegen.

 $ ansible-vault view ~/ansible/inventory/produktion/group_vars/all/secrets.yml
Vault password: Frueh_uebt_51ch_wer_31n_Meister_werden_will!
admin_user: christoph
admin_password: Frueh_uebt_51ch_wer_31n_Meister_werden_wil

Wollen wir die Verschlüsselung unserer Datei wieder entfernen, entschlüsseln wir diese mit der Option decrypt.

 $ ansible-vault decrypt ~/ansible/inventory/produktion/group_vars/all/secrets.yml

Auch hier geben wir unsere Passphrase ein, damit die Datei entschlüsselt werden kann.

Vault password: 
Decryption successful

Die Datei liegt nun wieder entschlüsselt in plaintext vor.

 $ cat ~/ansible/inventory/produktion/group_vars/all/secrets.yml
admin_user: christoph
admin_password: Frueh_uebt_51ch_wer_31n_Meister_werden_will!

Die weiteren Optionen, wie z.B. create oder rekey sind soweit selbsterklärend und werden hier in diesem Konfigurationsbeispiel nicht noch extra ausführlich beschrieben.

Bei der Verschlüsselung von Inhalten sind wir keinesfalls auf Dateien und Variabeln beschränkt. Wir könnten bei Bedarf auch jedwede Projeketdateien, wie Playbooks, Rollen, Templates oder auch ganze Inventories verschlüsseln!

Beim Aufruf eines Ansible-Playbooks liest ansible-playbook alle benötigten Dateien ein. Zum Abarbeiten benötigt Ansible natürlich die temporär entschlüsselten Informationen. Damit Ansible nun die verschlüsselten Informationen herankommt, benötigt Ansible natürlich vorübergehend das Vault-Passwort/-Passphrase. Hier kommt die Option --ask-vault-pass ins Spiel.

Der Aufruf des Scripts 01_create-user.ym aus Beispiel 1 würde dann lauten:

 $ ansible-playbook -v 01_create-user.yml --limit=demo --ask-vault-pass

Nach der Abfrage des BECOME password: wird dann nach dem Vault-Passwort gefragt Vault password:.

Aus dem Blickwinkel Sicherheit haben wir nun zum einen erreicht, dass schützenswerte Informationen nicht mehr als plain-text in unserer Ansible-Entwicklungsumgebnung ungeschützt herumliegen. Darüber hinaus haben wir nun quasi einen zweiten Faktor bei der Abarbeitung unserer Ansible-Playbooks eingeführt - genauer gesagt sind es ja eher drei Dinge, über die der Admin verfügen muss:

  1. Der Admin muss den SSH-Privat-Key besitzen und von dessen Passphrase Kenntnis haben.
  2. Der Admin muss das BECOME password: kennen, mit dessen Hilfe die Rechteerweiterung, gemäss unserer initialen Konfiguration zur Rechteerweiterung mit Passwort auf den Zielsystemen erlangt werden kann.
  3. Der Administrator muss nun auch noch Vault password: eingeben, damit die verschlüsselten Inhalte, die im Inventory abgelegt sind, entschlüsselt werden können und das bzw. die Playbooks auch ordnungsgemäss und vollständig abgearbeitet werden können.

Aus Sicht von IT-Security doch schon mal ein erheblicher Mehrwert, der natürlich zugegebener Maßen mit einem Komfortverlust erkauft wird!

Ja, es gäbe auch die Option --vault-password-file, aber diese Option streichen wir gleich mal aus unserem Gedächtnis, da es erwiesener Maßen keine gute Idee sein kann, das zum Entschlüsseln von vertraulichen Informationen benötigte Passwort, in Dateisystem wieder für alle lesbar abzulegen!

Nein, so 'was machen wir hier definitiv nicht! Never ever! Ein absolutes no go!

Will oder muss man ansible-playbook öfters und mehrmals ausführen, ist es doch zuweilen mehr als mühsam, bei jedem Aufruf neben dem become (früher auch bekannt als sudo) bei Verwendung von ansible-vault nunmehr zusätzlich das ansible-vault-Passwort einzugeben.

Wie im vorangegangenen Abschnitt bereits angeschnitten, verwerfen wir die Option „Übergabe der Passworte auf der Kommandozeile“ bzw. „Vorhalten von Passworten in (Konfig-)Files“ sofort wieder.

Vorüberlegungen

Was wir nun brauchen ist zum einen eine Möglichkeit das Vault-Passwort sicher zu speichern bzw. vor zuhalten und zum anderen bei Bedarf eine Möglichkeit das Vault-Passwort irgendwie zu „cachen“, so dass man Ansible schnell ausführen kann, ohne die Anmeldedaten für kleine Änderungen im Playbook erneut eingeben zu müssen.

Sowohl die Option --extra-vars=„ansible_become_pass=Frueh_uebt_51ch_wer_31n_Meister_werden_will!“ wie auch --vault-password-file haben entscheidende Nachteile, wären doch die Passworte in der History-Datei der Shell verstreut, in der Prozessliste ps aux sichtbar oder gar in den betreffenden plaintext Dateien im Dateisystem auffindbar. Alles in allem nachvollziehbar: definitiv eine sehr schlechte und unsichere Lösung!

Die Vault-Funktion von Ansible bietet zwar eine Option, das Passwort aus einer Datei bzw. aus der zugehörigen Konfigurationsvariable zu holen. Aber wie wir bereits wissen: Plaintext-Passworte im Dateisystem, eine furchtbar schlechte und definitiv keine sichere Lösung!

Aber: Die Option vault-password-file in der Ansible-Konfigurationsdatei ~/.ansible.cfg kann auch ein (Wrapper-)Script sein. Wir brauchen also nun zwei Dinge bzw. gehen in zwei Schritte vor:

  1. Ein Wrapper-Skript, um das Passwort vom Benutzer abzufragen um es ggf. für kurze Zeit für weitere ansible-playbook-Läufe zwischenzuspeichern.
  2. Ein Tool, das das Vault-Passwort von Ansible auf stdin zurückgibt. Glücklicherweise bietet der Passwort-Manager pass genau diese Funktion. pass ist ein Passwort-Manager, der die Passwörter in einer Verzeichnisstruktur organisiert und sie (in Klartextdateien) mit GPG verschlüsselt und über ein CLI1) verfügt..

Der Zugriff nach dem benötigten Passwort könnte nun so ablaufen: Als erstes hinterlegen wir in dem ausführbaren Wrapper-Script pass show ansible-vault-password. Dadurch frägt GPG nach dem Passwort, entschlüsselt die Passwortdatei und gibt das entschlüsselte Passwort auf stdout aus. Je nach dem wie lange der GPG-Agent den gecachten persönlichen privaten Schlüssel aus dem Speicher entfernt hat, geben nachfolgende Aufrufe von pass show ansible-vault-password das Passwort aus, ohne dass das Passwort des privaten PGP-Schlüssels erneut abgefragt wird.

Passwortmanager pass

Als erstes befassen wir uns mit dem Standard UNIX Passwort-Manager pass. Der Passwort-Manager pass haben wir ein einfach zu bedienendes wie auch strukturiertes Tool. Bei pass wird jedes Passwort in einer PGP-verschlüsselten Datei abgelegt, deren Dateiname der Titel der Website oder Ressource ist, für die das Passwort benötigt wird. Diese verschlüsselten Dateien können in sinnvollen Ordnerhierarchien organisiert, bei Bedarf von Host zu Host kopiert und im Allgemeinen mit Standard-Kommandozeilen-Dienstprogrammen für die Dateiverwaltung bearbeitet werden. Ferner kann der Passwortmanager einfach über sein CLI angesprochen und bedient werden.

Bei der Nutzung von pass gehen wir davon aus, dass man bereits über einen eigenen PGP-Key verfügt und mit dessen Verwendung vertraut ist. Falls nicht, wird in diesem Kapitel die Erstellung und Verwendung ausführlich beschrieben. Besonders sicherheitsbewussten Administratoren ist auch die Verwendung einer Kryptographie-Hardware z.B. eines Nitrokey Start empfohlen. Die Erstellung von passenden Schlüsselmaterial wie ECDSA-basierten SSH-Schlüssel und PGP-Schlüssel ist z.B. in diesem Kapitel in Djangos WIKI ausführlich beschrieben und erklärt.

Bevor wir uns nun eingehender mit pass beschäftigen installieren wir das Programm-Paket mit Hilfe des Paketverwaltungs-Tools unserer Distribution.

  • Arch :
     $ pacman -S pass
  • Fedora / RHEL :
     # yum install pass
  • Gentoo :
     # emerge -av pass
  • openSUSE :
     $ sudo zypper in password-store
  • Ubuntu / Debian :
     $ sudo apt-get install pass

Was das Programm pass alles an Befehlsoptionen mitbringt, offenbart uns die der Programmaufruf mit der Option help.

 $ pass --help
============================================
= pass: the standard unix password manager =
=                                          =
=                  v1.7.4                  =
=                                          =
=             Jason A. Donenfeld           =
=               Jason@zx2c4.com            =
=                                          =
=      http://www.passwordstore.org/       =
============================================

Usage:
    pass init [--path=subfolder,-p subfolder] gpg-id...
        Initialize new password storage and use gpg-id for encryption.
        Selectively reencrypt existing passwords using new gpg-id.
    pass [ls] [subfolder]
        List passwords.
    pass find pass-names...
    	List passwords that match pass-names.
    pass [show] [--clip[=line-number],-c[line-number]] pass-name
        Show existing password and optionally put it on the clipboard.
        If put on the clipboard, it will be cleared in 45 seconds.
    pass grep [GREPOPTIONS] search-string
        Search for password files containing search-string when decrypted.
    pass insert [--echo,-e | --multiline,-m] [--force,-f] pass-name
        Insert new password. Optionally, echo the password back to the console
        during entry. Or, optionally, the entry may be multiline. Prompt before
        overwriting existing password unless forced.
    pass edit pass-name
        Insert a new password or edit an existing password using editor.
    pass generate [--no-symbols,-n] [--clip,-c] [--in-place,-i | --force,-f] pass-name [pass-length]
        Generate a new password of pass-length (or 25 if unspecified) with optionally no symbols.
        Optionally put it on the clipboard and clear board after 45 seconds.
        Prompt before overwriting existing password unless forced.
        Optionally replace only the first line of an existing file with a new password.
    pass rm [--recursive,-r] [--force,-f] pass-name
        Remove existing password or directory, optionally forcefully.
    pass mv [--force,-f] old-path new-path
        Renames or moves old-path to new-path, optionally forcefully, selectively reencrypting.
    pass cp [--force,-f] old-path new-path
        Copies old-path to new-path, optionally forcefully, selectively reencrypting.
    pass git git-command-args...
        If the password store is a git repository, execute a git command
        specified by git-command-args.
    pass help
        Show this text.
    pass version
        Show version information.

More information may be found in the pass(1) man page.

Zunächst müssen wir einmalig den Passwort-Safe initialisieren. Wichtig ist dabei, dass wir hier (der dritte Wert beim Aufruf) genau den Namen angeben, den wir bei der Generierung des PGP-Schlüssels verwendet hatten. Im folgenden Konfigurationsbeispiel gehen wir davon aus, dass hier die eMail-Adresse christoph@mailserver.guru unseres Admins christoph verwendet wird.

 $ pass init christoph@mailserver.guru

Anschliessend hinterlegen wir das Vault-Passwort Schleichi, der aufstrebende Stern am Ansible-Himmel! mit welchem wir unsere zu schützende Datei ~/ansible/inventory/produktion/group_vars/all/secrets verschlüsselt hatten.

 $ pass insert ansible-vault-password
Enter password for ansible-vault-password
Schleichi, der aufstrebende Stern am Ansible-Himmel!

Im Homeverzeichnis unseres Admins findet sich nun das zugehörige verschlüsselte Dokument.

/home/christoph/.password-store/
└── ansible-vault-password.gpg

Dies zeigt uns auch die Abfrage von pass.

 $ pass
 Password Store
└── ansible-vault-password

Den Inhalt des Passwort-Store können wir mit Hilfe des folgenden Befehls anzeigen lassen.

 $ pass ansible-vault-password
Schleichi, der aufstrebende Stern am Ansible-Himmel!

Den Inhalt des Passwort-Stores können wir auch in die Zwischenablage kopieren um dessen Inhalt dann an geeigneter stelle einzufügen.

 $ pass -c ansible-vault-password 
Copied ansible-vault-password to clipboard. Will clear in 45 seconds.

WrapperScript

Der zweite der Aufgabenstellung ist schnell und einfach umgesetzt. Wir legen uns das Wrapper-Script im ~/bin-Verzeichnis unseres Admin-Account an.

Sollte das betreffende Verzeichnis noch nicht existieren, legen wir es erst einmal an.

 $ mkdir ~/bin/

Nun legen wir das benötigte Wrapper-Script an.

 $ vim ~/bin/ansible_vault_password
~/bin/ansible_vault_password
#!/bin/bash
/usr/bin/pass show ansible-vault-password

Abschliessend statten wir das Script mit x-Rechten aus.

 $ chmod +x ~/bin/ansible_vault_password

Ansible-Konfiguration

Was nun noch fehlt ist die Konfiguration von Ansible. Dazu setzen wir in der Sektion [defaults] die Option vault_password_file entsprechend.

 $ vim ~/.ansible.cfg
~/.ansible.cfg
...
 
# If set, configures the path to the Vault password file as an alternative to
# specifying --vault-password-file on the command line.
# Django : 2022-08-09
# default: #vault_password_file = /path/to/vault_password_file
vault_password_file = ~/bin/ansible_vault_password
 
...

Ansible-Playbook

Dank unserer Konfiguration wird ab sofort beim Aufruf von ansible, ansible-playbook oder auch ansible-lint, dass Passwort unseres PGP-Schlüssels abgefragt, damit das wiederum mit dem PGP-Schlüssel verschlüsselte Vault-Passwort entschlüsselt und benutzt werden kann.
Bild: Ansible NitroKey Start Verwenden wir ein Security-Hardware-Geräte wie z.B. einen Nitrokey Start werden wir aufgefordert, den USB-Stick anzustecken uns die zugehörige PIN einzugeben.

Wie bereits im Abschnitt ask-vault-pass im Kapitel ansible-vault in Verbindung mit ansible-playbook aufgezeigt haben wir nun eine, mit der Security-Brille betrachtete, optimale Lösung gefunden, die natürlich zugegebener Maßen nicht gerade bequem und komfortabel anmuten kann.

Wir werden uns hierzu gleich noch eine Konfiguration ansehen, die in gewisser Art und Weise ähnliche Sicherheit beim doch mehr Bequemlichkeit für den Admin mit sich bringen kann, doch hierzu mehr in nachfolgendem Abschnitt.

Beispiel mit zwei Passwortabfragen

Bei der Grundkonfiguration zur Rechteerweiterung unserer Ansible-Umgebung, hatten wir in der ansible.cfg in der Sektion [privilege_escalation] unter anderem folgendes definiert.

 $ vim ~/.ansible.cfg
ansible.cfg
...
 
[privilege_escalation]
# Django : 2020-01-04
# default: unset
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False
become=True
become_method=sudo
become_user=root
become_ask_pass=True
 
...

Das hat zur Folge, dass wir nach dem Aufruf eines Ansible Playbooks stets nach dem become_password gefragt werden. In Abschnitt Ansible Konfiguration in diesem WIKI-Artikel hatten wir das vault_password_file mit unserem Wrapper-Script verknüpft.

 $ vim ~/.ansible.cfg
ansible.cfg
...
 
# If set, configures the path to the Vault password file as an alternative to
# specifying --vault-password-file on the command line.
# Django : 2022-08-09
# default: #vault_password_file = /path/to/vault_password_file
vault_password_file = ~/bin/ansible_vault_password
 
...

Dank dieser beiden Definitionen haben wir nun erreicht, dass beim Starten eines Ansible-Playbooks nach der Abfrage des BECOME password: zusätzlich noch das Vault password: abgefragt wird. Natürlich müssen wir den SSH-Key auch noch geladen haben und dessen Passphrase eingegeben haben!

Zur Abarbeitung eines Ansible-Playbooks muss der Admin über drei Dinge verfügen:

  1. Er muss den SSH-Privat-Key besitzen, diesen laden und die zugehörige Passphrase eingeben.
  2. Der Admin muss ferner das BECOME password: beim Starten eines Playbooks eingeben, damit er Root-Rechte auf den Zielsystemen erlangen kann.
  3. Zusätzlich muss er auch noch das Vault password: eingeben, damit die verschlüsselten Inhalte, die im Inventory abgelegt sind, entschlüsselt werden können und das bzw. die Playbooks auch ordnungsgemäss und vollständig abgearbeitet werden können.

Aus Sicht der IT-Sicherheit ein anpeilbares Zielszenario, welches zugegebener Maßen dem Admin einiges an manuellen Tätigkeiten abverlangt.

Beispiel mit nur einer Passwortabfrage

Jede Lösung und Anwendung in der IT-Welt steht und fällt mit der Akzeptanz der Anwender. In unserem speziellen Fall ist das der Admin und für ihn kann es mitunter helfen, wenn man bei der Lösungsfindung eine akzeptable Mischung aus Sicherheit und Bequemlichkeit der Lösung finden kann. Und genau solch ein Beispiel wollen wir uns nun noch abschliessend genauer ansehen. Was werden wir nun machen? Nun, wir verlagern die Information zum become_passord weg von einer interaktiven Abfrage beim Starten eines Playbooks hin zur Datenvorhaltung in einem ansible-vault!

Nein, wir werden nicht den Admin-Aser in eine Gruppe sudo oder wheels packen und auf den Zielsystemen in der sudoers auf die Abfrage des Passwortes verzichten! NOPASSWD: ALL ist keine erstrebenswerte Idee! Übrigens genau so wenig wie das Vorhaben allen Admins einen direkten root-Access auf Zielsystemen zu geben. Aus Sicherheitsaspekten quasi der Super-GAU schlechthin - wenn auch in gewissen Kreisen seit Jahren Usus, aber das ist ein anders Thema … :-X

Wir werden nun als erstes die Konfiguration in der ansible.cfg, die wir bei der Ansible-Ersteinrichtung ggf vorgenommen hatten wieder entfernen.

 $ vim ~/.ansible.cfg
ansible.cfg
...
 
[privilege_escalation]
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False
 
...

Die Konfiguration des become-Optionen verlagern wir nun in unser Inventory. Hierzu legen wir im Inventory ein Variablen-Verzeichnis für alle Hosts an.

 $ mkdir ~/ansible/inventories/production/group_vars/all/

Dort hinterlegen wir zunächst die Optionen, die wir früher in der ansible.cfg vermerkt hatten.

 $ vim ~/ansible/inventories/production/group_vars/all/ansible_environment.yml
ansible_environment.yml
ansible_become:          True
ansible_become_method:   sudo
ansible_become_user:     root
ansible_become_ask_pass: False

Unser become_password legen wir dann in einer zweiten Datei im Inventory ab.

 $ vim ~/ansible/inventories/production/group_vars/all/vault.yml
vault.yml
ansible_become_pass:  Frueh_uebt_51ch_wer_31n_Meister_werden_will!

Anschliessend verschlüsseln wir diese Datei mit dem Vault-Passwort, welches wir ja mit Hilfe von pass mit unserem PGP-Key verschlüsselt vorhalten.

 $ ansible-vault encrypt inventories/production/group_vars/all/vault.yml

Tests

Für einen ersten Test bemühen wir das Ansible adhoc Aufruf und Ermitteln mit Hilfe des shell-Moduls wie viele Dateien und Verzeichnisse sich im $HOME-Verzeichnis des Benutzers root befinden. Der Test zeigt uns unmittelbar, ob der Zugriff auf die vault.yml-Datei klappt in dem sich das become_pasword befindet.

  • Aufruf ohne PGP Schlüssel :DOWN:
    Im ersten Beispiel wollen wir nun die Anzahl der Verzeichnisse und Dateien im $HOME Verzeichnis des Benutzers root erfragen. Hierzu sind natürlich Root-Rechte von nöten, die unser Admin-Account natürlich per se nicht hat.

     $ ansible localhost -m shell -a "ls -l /root | wc -l"

    gpg: decryption failed: No secret key
    [WARNING]: Error in vault password file loading (default): Vault password script /home/django/bin/ansible_vault_password returned non-zero (2): None
    ERROR! Vault password script /home/django/bin/ansible_vault_password returned non-zero (2): None
    
    Der Versuch scheitert natürlich, da wir ohne den PGP-Schlüssel nicht an die per Ansible-Vault verschlüsselte Info zu ansible_become_pass kommen!

  • Aufruf mit PGP Schlüssel :UP:
    Im zweiten Beispiel werden wir nun erneut versuchen Anzahl der Verzeichnisse und Dateien im $HOME Verzeichnis des Benutzers root zu erfragen. Nur dieses mal werden wir unseren PGP-Schüssel laden und die zugehörige Passphrase richtig eingeben.

     $ ansible localhost -m shell -a "ls -l /root | wc -l"

    localhost | CHANGED | rc=0 >>
    2
    
    Die Abfrage liefert hier natürlich nun das gewünschte Ergebnis, da die Info zu ansible_become_pass aus dem Ansible-Vault erfolgreich mit Hilfe des PGP-Schlüssels temporär entschlüsselt werden konnte.

Bild: Ansible NitroKey StartBeim Aufruf eines Ansible-Playbooks liest das Programm ansible-playbook alle benötigten Dateien ein inklusive aller Hostdefinitionen aus dem Inventory ein, auch wenn diese gerade nicht zum Abarbeiten des Playbooks benötigt werden. Zum Abarbeiten benötigt Ansible natürlich die temporär entschlüsselten Informationen. Damit Ansible nun die verschlüsselten Informationen herankommt, benötigt Ansible natürlich vorübergehend das Vault-Passwort/-Passphrase, welches sich nun selbst verschlüsselt in einem Ansible-Vault befindet. Durch den Passwortmanager pass und unserem PGP-Schlüssel kommen wir nun direkt zu dem Ansible Vault Passwort. Wir brauchen also nur einmal das für den PGP zugehörige Passwort oder im Falle der Verwendung eines Security-Hardware-Devices wie eines Nitrokey Start.

Der Aufruf des Scripts 01_create-user.ym aus Beispiel 1 würde dann lauten:

 $ ansible-playbook -v 01_create-user.yml --limit=demo

Nach der Abfrage des PGP-Passwortes bzw. der PIN bei Verwendung eines Nitrokey Start wird dann sofort das Playbook ausgeführt. Eine zusätzliche Eingabe eines become_password ist nunmehr nicht mehr nötig.

Aus dem Blickwinkel Sicherheit haben wir nun zum einen erreicht, dass schützenswerte Informationen nicht mehr als plain-text in unserer Ansible-Entwicklungsumgebnung ungeschützt herumliegen. Darüber hinaus haben wir nun quasi einen zweiten Faktor bei der Abarbeitung unserer Ansible-Playbooks eingeführt - genauer gesagt sind es ja eher drei Dinge, über die der Admin verfügen muss:

  1. Der Admin muss den SSH-Privat-Key besitzen und von dessen Passphrase Kenntnis haben. Wird ein Nitrokey Start USB-Schlüssel verwendet, kann bei Bedarf auch der SSH-Key bei Verwendung der SSH benutzt werden. Die Zusätzliche Eingabe einer Passphrase erübrigt sich dadurch auch hier, wenn der SSH-Key auf dem Kryptostick verwendet wird!
  2. Der Administrator muss beim Aufruf der Playbooks nunmehr nur noch den PGP-Schlüssel durch Eingabe der zugehörigen Passphrase entsperren. Das become_password Passwort für die Rechteerweiterung wird nun auch von Ansible aus dem Vault gelesen.

Aus Sicht von IT-Security haben wir auch hier einen erheblicher Zugewinn an Sicherheit. Die Akzeptanzschwelle ist durch Minimierung von mehrfachen Eingaben diverser Passworte durchaus niedrig, so dass für den Admin durchaus ein Mehrwert bei der täglichen administrativen Tätigkeit ausgemacht werden kann.

Wir können nun mit Ansible-Vault vertrauliche Informationen in unseren Playbooks bzw. im Inventory ablegen. Diese werden als krypted AES256 Daten abgelegt und können dadurch auch jederzeit in einem verteiltem Versionskontrollsystem wie git vorgehalten werden. Durch Nutzung des Passwort-Manager pass wird die Handhabung soweit vereinfacht, so dass der Admin auch ohne grosse Not mehrmals hintereinander Ansible-Playbooks ausführen kann, ohne sich durch zigfache Eingabe von Passworten sich selbst das Leben allzu schwer zu machen!

All die in diesem WIKI-Artikel aufgezeigten Konfigurationsschritte müssen wir aber nicht manuell nachvollziehen und auf jedem Administrations-Knoten/-Host via cut'n'paste nachtragen. Wir werden diese Punkte ganz einfach mit Hilfe von Ansible selbst ausrollen, wie genau das gemacht werden kann, werden wir uns im nächsten Kapitel Ansible mit Hilfe von Ansible einrichten/konfigurieren genauer ansehen.

Links


1)
CommandLineInterface
Diese Website verwendet Cookies. Durch die Nutzung der Website stimmen Sie dem Speichern von Cookies auf Ihrem Computer zu. Außerdem bestätigen Sie, dass Sie unsere Datenschutzbestimmungen gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website.Weitere Information
  • linux/ansible/playbook_example_07.txt
  • Zuletzt geändert: 22.07.2023 08:08.
  • von django