Inhaltsverzeichnis

Ansible - einfaches Playbook-Beispiel: mehrere Benutzer anlegen

Bild: Ansible Logo

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:

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

Links