Ansible - einfaches Playbook-Beispiel: mehrere Benutzer anlegen
Im Eingangskapitel Grundlagen haben wir uns mit der Installation bereits befasst. Auch haben wir uns schon in den beiden Kapiteln Playbooks und YAML - was ist das? eingehend mit den Hintergrundinformationen beschäftigt, so dass wir uns nun mit unsere Playbooks beschäftigen können.
Beispiel 3: mehrere Benutzer anlegen und SSH-Schlüssel kopieren
Beim dritten Playbook-Beispiel wollen wir mit Hilfe von Ansible nicht nur ein Admin-Konto sondern gleich mehrere anlegen. Dabei kopieren wir dann auch noch gleich die zugehörigen öffentlichen SSH-Schlüssel an Ort und Stelle. Zu guter Letzt stellen wir noch sicher dass der Eintrag %wheel ALL=(ALL) ALL
gesetzt ist, hierzu binden wird das YAML-Playbook von Beispiel 02 ein.
Bevor wir unser erstes Script schreiben, wechseln wir in unser zuvor angelegtes Zielverzeichnis:
$ cd ~/ansible
Script anlegen
Nun legen wir nun unser erstes Script ab.
$ vim 03_create-admins.yml
- 03_create-admins.yml
--- - hosts: centos8 become: true vars: sudoers: ansible tasks: - name: add several users to the system user: name: "{{ item.name }}" comment: "{{ item.fullname }}" uid: "{{ item.uid }}" groups: "{{ item.groups }}" state: present with_items: - { name: bofh, fullname: "Bastard Operator from Hell", uid: 1020, groups: "wheel, users" } - { name: ruben, fullname: "Ruben Nausch", uid: 1010, groups: wheel } - { name: ansible, fullname: "Ansible Systemuser", uid: 2003, groups: wheel } - name: Initial password generation for each user shell: usermod -p $(echo '{{ item.secret }}' | openssl passwd -1 -stdin) {{ item.name }} with_items: - { name: bofh, secret: "/ImTAxBwi++W2Y26195+Q72GbH73i/zQyaq12wsx" } - { name: ruben, secret: "lop5YtypT+E6qhOjpZEoAlnyiLH7HlIF1k212qyo" } - { name: ansible, secret: "X4z3AEx6WZ2+DDzvuzjx0mBERQ-o03f12qwPOSyx" } - name: Set authorized keys for each user authorized_key: user: "{{ item.name }}" state: present key: "{{ lookup('file', '/home/django/ansible/authkeys/{{ item.name }}.pub') }}" with_items: - {name: bofh } - {name: ruben } - {name: ansible } - include_tasks: 02_passwd_sudo_wheel.yml ...
WICHTIG
WICHTIG: Auch hier gilt die Warnung aus Beispiel 1: Es zeigt sehr anschaulich, dass es definitiv keine gute Idee ist, Passworte und Schlüsselmaterial direkt in einem Playbook und/oder Inventory unverschlüsselt vor zuhalten. Dies gilt um so mehr, wenn man seine Ansible bei GitHub oder GitLab vorhält! Jeder der dort Zugriff auf die Repositories hat, gelangt so ohne grosse Mühe an vertraulichen Informationen!
Wie wir dieses Thema elegant und sicher lösen können und auch werden, betrachten wir eingehend in dem Ansible - erweitertes Konfigurationsbeispiel 7: Ansible Vault.
Script Beschreibung
Das Script ist soweit selbsterklärend, werden doch der Reihe nach vier Tasks abgearbeitet:
- Task 1 : Drei Userkonten anlegen - die betreffenden Daten für unsere User holen wir uns dabei aus einer Liste (array)
- Task 2 : Setzen der initialen Passwörter je Userkonto
- Task 3 : Kopieren der jeweiligen öffentlichen SSH-Schlüssel der User. In diesem Konfigurationsbeispiel liegen diese im Verzeichnis
/home/django/ansible/authkeys/
.$ ~/ansible/authkeys/
insgesamt 12 -rw-r--r--. 1 django django 100 4. Jan 22:12 ansible.pub -rw-r--r--. 1 django django 108 4. Jan 22:13 bofh.pub -rw-r--r--. 1 django django 98 4. Jan 22:16 ruben.pub
- Task 4 : Das Anpassen der sudoers-Eigenschaften haben wir in diesem Konfigurationsbeispiel in eine separate YAML-Datei ausgelagert. Hierzu nutzen wir das YAML-Modul include. Das entsprechende Include-Verzeichnis legen wir gleich mal an.
$ mkdir ~/ansible/includes
Hier legen wir uns eine YAML-Datei an, die nur den entsprechenden
task
beinhaltet.$ vim includes/sudoers.yml
- includes/sudoers.yml
--- - name: All users from groub 'wheel' are allowed sudo users copy: content: "# Allows people in group wheel to run all command\n%wheel ALL=(ALL) ALL\n" dest: /etc/sudoers.d/10_passwd_sudo_wheel owner: root group: root mode: "0440" validate: visudo -cf %s
Script ausführen
Nun wollen wir unser Playbook ausführen, um auf dem Zielhost den gewünschten Benutzer anzulegen; hierzu rufen wir unser Script wie folgt auf:
$ ansible-playbook -v 03_create-admins.yml03_create-admins.yml
Using /etc/ansible/ansible.cfg as config file BECOME password: PLAY [centos8] **************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************** ok: [www8.dmz.nausch.org]
TASK [add several users to the system] ************************************************************************************************* changed: [www8.dmz.nausch.org] => (item={'name': 'bofh', 'fullname': 'Bastard Operator from Hell', 'uid': 1020, 'groups': 'wheel, users'}) => {"ansible_loop_var": "item", "changed": true, "comment": "Bastard Operator from Hell", "create_home": true, "group": 1020, "groups": "wheel, users", "home": "/home/bofh", "item": {"fullname": "Bastard Operator from Hell", "groups": "wheel, users", "name": "bofh", "uid": 1020}, "name": "bofh", "shell": "/bin/bash", "state": "present", "system": false, "uid": 1020} changed: [www8.dmz.nausch.org] => (item={'name': 'ruben', 'fullname': 'Ruben Nausch', 'uid': 1010, 'groups': 'wheel'}) => {"ansible_loop_var": "item", "changed": true, "comment": "Ruben Nausch", "create_home": true, "group": 1010, "groups": "wheel", "home": "/home/ruben", "item": {"fullname": "Ruben Nausch", "groups": "wheel", "name": "ruben", "uid": 1010}, "name": "ruben", "shell": "/bin/bash", "state": "present", "system": false, "uid": 1010} ok: [www8.dmz.nausch.org] => (item={'name': 'ansible', 'fullname': 'Ansible Systemuser', 'uid': 500, 'groups': 'wheel'}) => {"ansible_loop_var": "item", "append": false, "changed": false, "comment": "Ansible Systemuser", "group": 500, "groups": "wheel", "home": "/home/ansible", "item": {"fullname": "Ansible Systemuser", "groups": "wheel", "name": "ansible", "uid": 500}, "move_home": false, "name": "ansible", "shell": "/bin/bash", "state": "present", "uid": 500}
TASK [Initial password generation for each user] *************************************************************************************** changed: [www8.dmz.nausch.org] => (item={'name': 'bofh', 'secret': '/ImTAxBwi++W2Y26195+Q72GbH73i/zQyaq12wsx'}) => {"ansible_loop_var": "item", "changed": true, "cmd": "usermod -p $(echo '/ImTAxBwi++W2Y26195+Q72GbH73i/zQyaq12wsx' | openssl passwd -1 -stdin) bofh", "delta": "0:00:00.389066", "end": "2020-01-05 17:04:51.991293", "item": {"name": "bofh", "secret": "/ImTAxBwi++W2Y26195+Q72GbH73i/zQyaq12wsx"}, "rc": 0, "start": "2020-01-05 17:04:51.602227", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} changed: [www8.dmz.nausch.org] => (item={'name': 'ruben', 'secret': 'lop5YtypT+E6qhOjpZEoAlnyiLH7HlIF1k212qyo'}) => {"ansible_loop_var": "item", "changed": true, "cmd": "usermod -p $(echo 'lop5YtypT+E6qhOjpZEoAlnyiLH7HlIF1k212qyo' | openssl passwd -1 -stdin) ruben", "delta": "0:00:00.382204", "end": "2020-01-05 17:04:53.167841", "item": {"name": "ruben", "secret": "lop5YtypT+E6qhOjpZEoAlnyiLH7HlIF1k212qyo"}, "rc": 0, "start": "2020-01-05 17:04:52.785637", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} changed: [www8.dmz.nausch.org] => (item={'name': 'ansible', 'secret': 'X4z3AEx6WZ2+DDzvuzjx0mBERQ-o03f12qwPOSyx'}) => {"ansible_loop_var": "item", "changed": true, "cmd": "usermod -p $(echo 'P1r473np4r731' | openssl passwd -1 -stdin) ansible", "delta": "0:00:00.386751", "end": "2020-01-05 17:04:54.313829", "item": {"name": "ansible", "secret": "X4z3AEx6WZ2+DDzvuzjx0mBERQ-o03f12qwPOSyx"}, "rc": 0, "start": "2020-01-05 17:04:53.927078", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [Set authorized keys for each user] *********************************************************************************************** hanged: [www8.dmz.nausch.org] => (item={'name': 'bofh'}) => {"ansible_loop_var": "item", "changed": true, "comment": null, "exclusive": false, "follow": false, "item": {"name": "bofh"}, "key": "ssh-ed25519 AAAAC3NzaC2lZDI1NTE5AAAAILxi47aZOS3tfvNFxVVqkJAfSKXjpvemB3kRZEQ5q/kf Bastard Operator from Hell", "key_options": null, "keyfile": "/home/bofh/.ssh/authorized_keys", "manage_dir": true, "path": null, "state": "present", "user": "bofh", "validate_certs": true} changed: [www8.dmz.nausch.org] => (item={'name': 'ruben'}) => {"ansible_loop_var": "item", "changed": true, "comment": null, "exclusive": false, "follow": false, "item": {"name": "ruben"}, "key": "ssh-ed25519 AAAAC3TzaC2lZ60DI1NTE5AAILxi47aZOS3tfvNFxq16293SKXjp4tsB3kRZffQ5q/kf ruben@nausch.org", "key_options": null, "keyfile": "/home/ruben/.ssh/authorized_keys", "manage_dir": true, "path": null, "state": "present", "user": "ruben", "validate_certs": true} ok: [www8.dmz.nausch.org] => (item={'name': 'ansible'}) => {"ansible_loop_var": "item", "changed": false, "comment": null, "exclusive": false, "follow": false, "item": {"name": "ansible"}, "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILti47aZOSetfvNFxVVqkJAfSKXjyvemB3kRZEQ5q/kf Ansible Systemuser", "key_options": null, "keyfile": "/home/ansible/.ssh/authorized_keys", "manage_dir": true, "path": null, "state": "present", "user": "ansible", "validate_certs": true} TASK [All users from groub 'wheel' are allowed sudo users] ***************************************************************************** included: /home/django/ansible/includes/sudoers.yml for www8.dmz.nausch.org
TASK [All users from groub 'wheel' are allowed sudo users] ***************************************************************************** ok: [www8.dmz.nausch.org] => {"changed": false, "checksum": "b51f017f799aca0d0aef9fa29b7da87006ea5c29", "dest": "/etc/sudoers.d/10_passwd_sudo_wheel", "gid": 0, "group": "root", "mode": "0440", "owner": "root", "path": "/etc/sudoers.d/10_passwd_sudo_wheel", "secontext": "system_u:object_r:etc_t:s0", "size": 80, "state": "file", "uid": 0} PLAY RECAP *************************************************************************************************************************************** www8.dmz.nausch.org : ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Ergebnis
Auf dem Zielhost findet sich nun unsere gewünschte Datei mit dem zugehörigen Inhalt.
# cat /etc/sudoers.d/10_passwd_sudo_wheel
- /etc/sudoers.d/10_passwd_sudo_wheel
# Allows people in group wheel to run all command %wheel ALL=(ALL) ALL
Auch unsere drei Nutzer-/Admin-Konten sind angelet und deren öffentlicher SSH-Schlüssel in diue Datei .ssh/authorized_keys
im jeweiligen Homeverzeichnis der User kopiert.
/home/ ├── ansible │ ├── .bash_logout │ ├── .bash_profile │ ├── .bashrc │ ├── .ssh │ │ └── authorized_keys ├── bofh │ ├── .bash_logout │ ├── .bash_profile │ ├── .bashrc │ └── .ssh │ └── authorized_keys └── ruben ├── .bash_logout ├── .bash_profile ├── .bashrc └── .ssh └── authorized_keys