Ansible - erweitertes Konfigurationsbeispiel 7: Ansible Vault
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:
- Sensible Informationen werden verschlüsselt (krypted) und niemals im Klartext vorgehalten!
- 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.
- 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)!
- 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.
- 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.
Dokumentation - Beschreibung
Was das Python3-Script ansible-vault
nun alles kann und leistet, entnehmen wir einfach den Hilfe-Optionen des Scripts bzw. der zugehörigen Manpage.
Hilfeseite des Scripts
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)
Manpage
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)
ansible-vault - Praxis-Beispiele
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!
Inhalte/Datei Verschlüsseln
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
Inhalte anzeigen
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
Inhalte editieren
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
Inhalte/Datei entschlüsseln
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!
weitere Optionen und Hinweise
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!
ansible-vault in Verbindung mit ansible-playbook
ask-vault-pass
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:
- Der Admin muss den SSH-Privat-Key besitzen und von dessen Passphrase Kenntnis haben.
- 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. - 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!
vault-password-file
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!
ansible-vault mit Passwortmanager pass
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:
- Ein Wrapper-Skript, um das Passwort vom Benutzer abzufragen um es ggf. für kurze Zeit für weitere
ansible-playbook
-Läufe zwischenzuspeichern. - 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.
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.
become_pass und vault-password aus einem Ansible-Vault
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:
- Er muss den SSH-Privat-Key besitzen, diesen laden und die zugehörige Passphrase eingeben.
- Der Admin muss ferner das
BECOME password:
beim Starten eines Playbooks eingeben, damit er Root-Rechte auf den Zielsystemen erlangen kann. - 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 …
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
Im ersten Beispiel wollen wir nun die Anzahl der Verzeichnisse und Dateien im$HOME
Verzeichnis des Benutzersroot
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 zuansible_become_pass
kommen! - Aufruf mit PGP Schlüssel
Im zweiten Beispiel werden wir nun erneut versuchen Anzahl der Verzeichnisse und Dateien im$HOME
Verzeichnis des Benutzersroot
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 zuansible_become_pass
aus dem Ansible-Vault erfolgreich mit Hilfe des PGP-Schlüssels temporär entschlüsselt werden konnte.
Beim 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:
- 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!
- 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.
Fazit und Ausblick
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.