Inhaltsverzeichnis

Benutzer mit Ansible verwalten

ist eine Open-Source-Software zur Automatisierung, Orchestrierung und Konfiguration von Serversystemen. Mit Ansible erfolgt die Verwaltung von Servern unter anderem über SSH und erfordert keinerlei zusätzliche Software auf dem zu verwaltenden System. Die Ausgabe erfolgt im JSON-Format und Module können in jeder beliebigen Programmiersprache geschrieben sein. Das System nutzt überwiegend YAML zur Konfiguration von wiederverwendbarer Beschreibungen der Systeme.

Ab hier werden ansible-Benutzerrechte zur Ausführung der nachfolgenden Befehle benötigt. Um der Benutzer ansible zu werden, geben Sie bitte nachfolgenden Befehl ein:

$ su - ansible
Password: 

Vorbereitung

Nachfolgend soll davon ausgegangen werden, dass

  1. Ansible installiert ist
    Siehe auch nachfolgenden internen Link: Ansible
  2. Ansible wie folgt eingerichtet ist
    Siehe auch nachfolgenden internen Link: Ansible mit Ansible einrichten
  3. Ein eigener Benutzer für die Nutzung von Ansible genutzt werden soll
  4. Die Authentifizierung des Ansible-Benutzers gegenüber allen Hosts durch Verwendung eines ssh-Schlüsselpaares erfolgen soll

Aufgaben

Aufbauend auf die Installation und Einrichtung von Ansible, soll nachfolgende role (Rolle) für

  1. die Erstellung von Benutzern, auf dem Ansible-Host und den Clients durchgeführt werden
  2. die Modifizierung von Benutzern, auf dem Ansible-Host und den Clients durchgeführt werden
  3. auf dem Ansible-Host und nur auf dem Ansible-Host sollen ssh-Schlüsselpaare für die einzelnen Benutzer erstellt werden.
  4. die auf dem Ansible-Host erstellten ssh-Schlüsselpaare für die einzelnen Benutzer, sollen auf die Clients verteilt werden.
  5. Mitglieder der Gruppe wheel haben die Möglichkeit root-Rechte, durch Eingabe des jeweiligen Passworts des Benutzers, zu erlangen.
  6. die Löschung von Benutzern, auf dem Ansible-Host und den Clients durchgeführt werden.

Konfiguration

Ausgehend davon, dass folgende Konfigurationen

  1. Ansible installiert ist
    Siehe auch nachfolgenden internen Link: Ansible
  2. Ansible wie folgt eingerichtet ist
    Siehe auch nachfolgenden internen Link: Ansible mit Ansible einrichten

bereits durchgeführt worden sind, erfolgen die weiteren Konfigurationen als role (Rolle).

Nachfolgende Dateien müssen dazu verändert:

  1. ~/ansible/inventories/production/hosts

bzw. nachfolgende Dateien sollen dazu mindestens neu erstellt:

  1. ~/ansible/inventories/production/host_vars/00_user.yml
  2. ~/ansible/00_user.yml
  3. ~/ansible/roles/00_user/tasks/main.yml

werden:

~/ansible/inventories/production/hosts

In nachfolgendem Aufruf wird die hosts-Datei unter nachfolgendem Pfad verwendet:

Der Inhalt, falls dies nicht schin geschen sein sollte, muss entsprechend mindestens wie folgt angepasst werden:

[ansible]
192.168.1.10
 
[all]
192.168.1.20
192.168.1.30

Erklärung:

Die Einträge sollte aus der nachfolgenden Ansible Einrichtung stammen:
Siehe auch nachfolgenden internen Link: Ansible mit Ansible einrichten

Die Gruppe - [all] muss, falls nicht schon vorhanden, entsprechend mit dem Gruppennamen und z.B. den IP-Adressen aller zu konfigurierenden Hosts versehen werden.

"vault"-Erstellung

Bevor mit der eigentlichen Konfiguration begonnen werden soll, sollen vorab die später benötigten vault verschlüsselten Zeichenkette generiert werden.

Zur Erstellung einer vault verschlüsselten Zeichenkette kann nachfolgender Befehl genutzt werden:

$ ansible-vault encrypt_string --stdin-name 'password'
New Vault password: 
Confirm New Vault password: 
Reading plaintext input from stdin. (ctrl-d to end input)
geheimpassword: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          35323839633331323063396362343163313632626634386366383961343632376636626335396564
          6461313461343538383738653365373036623837626136650a633961326533616133626262346133
          32653636343836303866303262653164326166356138356239333266616632646364343066306537
          3637623863373362660a626362653737623735623565343262333033323163386566376333393164
          3731
Encryption successful

bzw.

$ ansible-vault encrypt_string --stdin-name 'ssh_key_passphrase'
New Vault password: 
Confirm New Vault password: 
Reading plaintext input from stdin. (ctrl-d to end input)
geheimssh_key_passphrase: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          31653266333835333866323833643664363562323438333935303737383064346139306630396366
          6139336531393164643835353334346666623238336334330a623030353633666237343737326531
          66346338613735356131663035343632623238343331666566386639393231353061643862343961
          3361326130386664350a336538636238633638353730363935363339636632316135303635356138
          6330
Encryption successful

Nach absetzen des Befehls

muss zuerst ein Passwort für ALLE nachfolgende vault verschlüsselten Zeichenketten gesetzt werden, welches später wichtig zur Entschlüsselung benötigt wird!

New Vault password: 
Confirm New Vault password:

Nach Eingabe des Passwort für ALLE nachfolgende vault verschlüsselten Zeichenketten wird dann die eigentlich zu verschlüsselnde Zeichenkette eingegeben UND dann mit der

geheimpassword: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          35323839633331323063396362343163313632626634386366383961343632376636626335396564
          6461313461343538383738653365373036623837626136650a633961326533616133626262346133
          32653636343836303866303262653164326166356138356239333266616632646364343066306537
          3637623863373362660a626362653737623735623565343262333033323163386566376333393164
          3731
Encryption successful

generiert.

* Die vault verschlüsselte Zeichenkette ist hier geheim

~/ansible/inventories/production/host_vars/00_user.yml

:!: HINWEIS - Nachfolgende Variablen Definitionen sollen GLOBAL verfügbar sein!

:!: HINWEIS - Eine Beschreibung zur „vault“-Erstellung ist unter nachfolgendem internen Link verfügbar:

Die Konfigurationsdatei ~/ansible/inventories/production/host_vars/00_user.yml kann mit nachfolgendem Befehl neu erstellt werden, falls diese nicht bereits vorhanden sein sollte:

$ touch ~/ansible/inventories/production/host_vars/00_user.yml

Der Inhalt der Konfigurationsdatei ~/ansible/inventories/production/host_vars/00_user.yml, welche die benötigten Variablen für das Playbook bereit stellt, kann als Beispiel wie folgt aussehen:

--- ### Add, modifies and delete users, groups and ssh-key-pairs.
  #
  # Generate a encrypted password string: ansible-vault encrypt_string --stdin-name 'password'
  # To test the gernated password string: ansible localhost -m debug -a var="password" -e "@password.yml" --ask-vault-pass
  # (The encrypted string must be in a file in the same directory named 'password.yml')
  #
users:
  ansible:
    active: True
    gid: 65533
    group: 'ansible'
    comment: "Ansible User" 
    name: 'ansible'
    password: !vault |
      $ANSIBLE_VAULT;1.1;AES256
      35323839633331323063396362343163313632626634386366383961343632376636626335396564
      6461313461343538383738653365373036623837626136650a633961326533616133626262346133
      32653636343836303866303262653164326166356138356239333266616632646364343066306537
      3637623863373362660a626362653737623735623565343262333033323163386566376333393164
      3731
    shell: '/bin/bash'
    ssh_key_passphrase: !vault |
      $ANSIBLE_VAULT;1.1;AES256
      31653266333835333866323833643664363562323438333935303737383064346139306630396366
      6139336531393164643835353334346666623238336334330a623030353633666237343737326531
      66346338613735356131663035343632623238343331666566386639393231353061643862343961
      3361326130386664350a336538636238633638353730363935363339636632316135303635356138
      6330
    uid: 65533
    wheel: True

Erklärung:

Hier ist der Anfang der Konfigurationsdatei im YAML-Format, inklusive einer Kurzbeschreibung.

Ein Kommentar, welcher eine Beschreibung enthält, wie eine vault-verschlüsselte Zeichenkette erstellt und geprüft werden kann.

Name des dictionarys (Wörterbuchs) unter dem auf die nachfolgenden Inhalte zugegriffen werden kann.

Name des Benutzers im dictionary (Wörterbuch) unter dem die nachfolgenden Eigenschaften abgelegt werden.

Eigenschaft: Aktiv: (True|False) des Benutzers ansible im dictionary (Wörterbuch). Dies bewirkt, das des Benutzer durch Ansible

wird.

Eigenschaft: Gruppen-ID 65533 des Benutzers ansible im dictionary (Wörterbuch).

Eigenschaft: Gruppenname 'ansible' des Benutzers ansible im dictionary (Wörterbuch).

Eigenschaft: Kommentar „Ansible User“ des Benutzers ansible im dictionary (Wörterbuch).

Eigenschaft: Passwort als vault-verschlüsselte Zeichenkette des Benutzers ansible im dictionary (Wörterbuch).

Eigenschaft: shell /bin/bash des Benutzers ansible im dictionary (Wörterbuch).

Eigenschaft: Passphrase des ssh-Schlüssels als vault-verschlüsselte Zeichenkette des Benutzers ansible im dictionary (Wörterbuch).

Eigenschaft: Benutzer-ID 65533 des Benutzers ansible im dictionary (Wörterbuch).

Eigenschaft: wheel: True des Benutzers ansible im dictionary (Wörterbuch) ist eine eigene Definition und soll angeben, ob der Benutzer in die Gruppe wheel aufgenommen werden soll.

~/ansible/00_user.yml

Die Konfigurationsdatei ~/ansible/00_user.yml kann mit nachfolgendem Befehl neu erstellt werden:

$ touch ~/ansible/00_user.yml

Der Inhalt der Konfigurationsdatei ~/ansible/00_user.yml, welche das eigentliche Playbook darstellt, sollte mindestens wie folgt aussehen:

--- ### Add users, groups and creates ssh-key-pairs.
  #
  # # ansible-playbook -i /home/ansible/ansible/inventories/production/hosts --ask-pass --ask-vault-pass /home/ansible/ansible/00_user.yml
  #
- hosts: all
  vars_files:
    - inventories/production/host_vars/00_user.yml
  roles:
    - { role: 00_user }

Erklärungen:

Hier ist der Anfang der Konfigurationsdatei im YAML-Format, inklusive einer Kurzbeschreibung.

Ein Kommentar, welcher eine Beschreibung enthält, mit welchen Parametern das Playbook ausgeführt werden muss.

Auf welche hosts das Playbook angewendet werden soll.

Die Definition, das das Playbook nachfolgende Variablen Datei verwenden soll.

Die Definition, der Variablen Datei welche das Playbook verwenden soll.

Die Definition, das das Playbook aus nachfolgender role (Rolle) besteht.

Welche role (Rolle) das Playbook benutzen soll.

~/ansible/roles/00_user/tasks/main.yml

Die Verzeichnisstruktur für die role (Rolle) - 00_user, kann mit nachfolgendem Befehl erstellt werden:

$ mkdir -p ~/ansible/roles/00_user/tasks

Die Konfigurationsdatei ~/ansible/roles/00_user/tasks/main.yml kann mit nachfolgendem Befehl neu erstellt werden:

$ touch ~/ansible/roles/00_user/tasks/main.yml

Der Inhalt der Konfigurationsdatei ~/ansible/roles/00_user/tasks/main.yml, welche das eigentliche Playbook ist, kann als Beispiel wie folgt aussehen:

--- ### Add, modifies and delete users, groups and ssh-key-pairs.
  #
  # # ansible-playbook -i /home/ansible/ansible/inventories/production/hosts --ask-pass --ask-vault-pass /home/ansible/ansible/00_user.yml
  #
- name: Make sure group 'wheel' does exists.
  group:
    name: wheel
    state: present
- name: Allow 'wheel' group to have password accessed sudo.
  copy:
    content: '%wheel ALL=(ALL) ALL'
    dest: /etc/sudoers.d/020_passwd_all_for_wheel
    group: root
    mode: "0440"
    owner: root     
    validate: visudo -cf %s
- name: Ensure user NOT exists, if NOT active.
  user:
    name: "{{ item.value.name }}"
    remove: yes
    state: absent
  when: "item.value.active | bool != True"
  with_dict:
    - "{{ users }}"
  no_log: True
- name: Ensure group NOT exists, if NOT active.
  group:
    name: "{{ item.value.group }}"
    state: absent
  when: "item.value.active | bool != True"
  with_dict:
    - "{{ users }}"
  no_log: True    
- name: Ensure group exists, ONLY if active.
  group:
    gid: "{{ item.value.gid }}"
    name: "{{ item.value.group }}"
    state: present
  when: "item.value.active | bool == True"
  with_dict:
    - "{{ users }}"
  no_log: True
- name: Ansible-Host - Ensure user exists, ONLY if active.
  user:
    append: yes
    comment: "{{ item.value.comment }}"
    force: yes
    generate_ssh_key: yes
    group: "{{ item.value.group }}"
    name: "{{ item.value.name }}"
    password: "{{ item.value.password | password_hash('sha512', 65534 | random ) }}"
    shell: "{{ item.value.shell }}"
    ssh_key_comment: "{{ item.value.comment }}"
    ssh_key_file: ".ssh/id_ed25519_{{ item.value.name }}"
    ssh_key_passphrase: "{{ item.value.ssh_key_passphrase }}"
    ssh_key_type: ed25519
    state: present
    uid: "{{ item.value.uid }}"
  when: "item.value.active | bool == True"
  with_dict:
    - "{{ users }}"
  delegate_to: 127.0.0.1
  no_log: True
- name: Clients - Ensure user exists, ONLY if active.
  user:
    append: yes
    comment: "{{ item.value.comment }}"
    force: yes
    group: "{{ item.value.group }}"
    name: "{{ item.value.name }}"
    password: "{{ item.value.password | password_hash('sha512', 65534 | random ) }}"
    shell: "{{ item.value.shell }}"
    state: present
    uid: "{{ item.value.uid }}"
  when: "item.value.active | bool == True"
  with_dict:
    - "{{ users }}"
  no_log: True
- name: Set exclusive authorized key for users taken from file, ONLY if active.
  authorized_key:
    user: "{{ item.value.name }}"
    key: "{{ lookup('file', '/home/{{ item.value.name }}/.ssh/id_ed25519_{{ item.value.name }}.pub') }}"
    state: present
    exclusive: True
  when: "item.value.active | bool == True"
  with_dict:
    - "{{ users }}"
  no_log: True
- name: Add users to group 'wheel' if set to True.
  user:
    append: yes
    groups: wheel
    name: "{{ item.value.name }}"
  when: 
    - "item.value.active | bool == True"
    - "item.value.wheel | bool == True"
  with_dict:
    - "{{ users }}"
  no_log: True
- name: Remove users from all groups except the primary group, if set to False.
  user:
    append: no
    groups: ''
    name: "{{ item.value.name }}"
  when: 
    - "item.value.active | bool == True"
    - "item.value.wheel | bool != True"
  with_dict:
    - "{{ users }}"
  no_log: True     

Erklärungen:

Hier ist der Anfang der Konfigurationsdatei im YAML-Format, inklusive einer Kurzbeschreibung.

Ein Kommentar, welcher eine Beschreibung enthält, mit welchen Parametern das Playbook ausgeführt werden muss.

Es wird sicher gestellt, das ein Gruppe wheel auf allen Clients existiert.

Erstellt eine neue Konfigurationsdatei

mit dem Inhalt

welcher besagt, dass alle Mitglieder der Gruppe wheel auf allen Clients die Fähigkeit besitzen root-Rechte, durch Eingabe des Passworts des jeweiligen Benutzer, zu erlangen. Dazu Benötigt die Konfigurationsdatei nachfolgende Eigenschaften:

Es wird sicher gestellt, das ein Benutzer des Benutzers aus dem dictionary (Wörterbuch) - users

gelöscht wird, falls dieser NICHT als aktiv gekennzeichnet ist!

:!: HINWEIS - Dies bewirkt, das der Benutzer komplett gelöscht wird!

:!: ACHTUNG - Alle Dateien im und das $HOME-Verzeichnis des Benutzers werden ebenfalls gelöscht !!!

Es wird sicher gestellt, das eine Gruppe des Benutzers aus dem dictionary (Wörterbuch) - users - mit dem

gelöscht wird, falls dieser NICHT als aktiv gekennzeichnet ist!

:!: HINWEIS - Dies bewirkt, das die Gruppe komplett gelöscht wird!

Es wird sicher gestellt, das eine Gruppe des Benutzers aus dem dictionary (Wörterbuch) - users - mit der

durchgeführt wird.

Es wird sicher gestellt, das ein Benutzer des Benutzers aus dem dictionary (Wörterbuch) - users

hinzugefügt wird und nachfolgende Eigenschaften besitzt:

durchgeführt wird.

Es wird sicher gestellt, das ein Benutzer des Benutzers aus dem dictionary (Wörterbuch) - users

hinzugefügt wird und nachfolgende Eigenschaften besitzt:

durchgeführt wird.

Es wird sicher gestellt, das der öffentliche ssh-Schlüssel des Benutzers aus dem dictionary (Wörterbuch) - users

hinzugefügt wird und nachfolgende Eigenschaften besitzt:

durchgeführt wird.

Es wird sicher gestellt, das ein Benutzer des Benutzers aus dem dictionary (Wörterbuch) - users

der Gruppe wheel hinzugefügt wird, wenn die Varibale wheel: True gesetzt ist:

durchgeführt wird.

Es wird sicher gestellt, das ein Benutzer des Benutzers aus dem dictionary (Wörterbuch) - users

von allen Gruppen, auch wheel, außder dessen primärere Gruppe, entfernt wird, wenn die Varibale wheel: False gesetzt ist:

durchgeführt wird.

Playbook Ausführung

Ab hier werden root-Benutzerrechte zur Ausführung der nachfolgenden Befehle benötigt. Um der Benutzer root zu werden, geben Sie bitte nachfolgenden Befehl ein:

$ su -
Password: 

:!: HINWEIS - Dies ist aktuell noch erforderlich, da noch kein Benutzer außer root sich auf die entsprechenden Clients verbinden kann und sonst noch keine Benutzer angelegt sind!!!

Bevor das Playbbok ausgeführt werden kann, muss eine erste Verbindung mittels der ipv4-Adresse lokal auf und von demAnsible-Host und allen Clients aufgebaut werden, um den HOST-Key (HOST-Schlüssel) überpüfen zu können und dies dauerhaft zu speichern, was durch nachfolgenden Befehl erfolgen sollte:

# ssh root@192.168.1.20
The authenticity of host '192.168.1.30 (192.168.1.20)' can't be established.
ECDSA key fingerprint is SHA256:4j14DjWe5Vq5EP5aeQytzEZGx0phhhQK746jk6BJhIQ.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.1.20' (ECDSA) to the list of known hosts.
root@192.168.1.20's password: 
Last login: Sun Jan 12 13:07:20 2020 from 192.168.1.1

bzw.

# ssh root@192.168.1.30
The authenticity of host '192.168.1.30 (192.168.1.30)' can't be established.
ECDSA key fingerprint is SHA256:4j14DjWe5Vq5EP5aeQytzEZGx0phhhQK746jk6BJhIQ.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.1.30' (ECDSA) to the list of known hosts.
root@192.168.1.30's password: 
Last login: Sun Jan 12 13:07:20 2020 from 192.168.1.1

/home/ansible/ansible/00_user.yml

Nachfolgender Befehl führt eine detaillierte Überprüfung des angegeben Playbook durch:

# ansible-playbook --syntax-check -i /home/ansible/ansible/inventories/production/hosts --ask-pass --ask-vault-pass /home/ansible/ansible/00_user.yml 
Vault password: 

playbook: /home/ansible/ansible/00_user.yml

Nachfolgender Befehl für das Playbook, welches unter ~/ansible/00_user.yml gespeichert sein sollte aus:

# ansible-playbook -i /home/ansible/ansible/inventories/production/hosts --ask-pass --ask-vault-pass /home/ansible/ansible/00_user.yml
SSH password: 
Vault password: 
 
PLAY [all] *********************************************************************
 
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.20]
ok: [192.168.1.30]

TASK [00_user : Make sure group 'wheel' does exists.] **************************
ok: [192.168.1.20]
ok: [192.168.1.30]

TASK [00_user : Allow 'wheel' group to have password accessed sudo.] ***********
changed: [192.168.1.20]
changed: [192.168.1.30]

TASK [00_user : Ensure user NOT exists, if NOT active.] ************************
skipping: [192.168.1.20] => (item=None) 
skipping: [192.168.1.20] => (item=None) 
skipping: [192.168.1.20]
skipping: [192.168.1.30] => (item=None) 
skipping: [192.168.1.30] => (item=None) 
skipping: [192.168.1.30]

TASK [00_user : Ensure group NOT exists, if NOT active.] ***********************
skipping: [192.168.1.20] => (item=None) 
skipping: [192.168.1.20] => (item=None) 
skipping: [192.168.1.20]
skipping: [192.168.1.30] => (item=None) 
skipping: [192.168.1.30] => (item=None) 
skipping: [192.168.1.30]

TASK [00_user : Ensure group exists, ONLY if active.] **************************
ok: [192.168.1.20] => (item=None)
changed: [192.168.1.30] => (item=None)
changed: [192.168.1.20] => (item=None)
changed: [192.168.1.20]
changed: [192.168.1.30] => (item=None)
changed: [192.168.1.30]

TASK [00_user : Ansible-Host - Ensure user exists, ONLY if active.] ************
changed: [192.168.1.20 -> 127.0.0.1] => (item=None)
changed: [192.168.1.30 -> 127.0.0.1] => (item=None)
changed: [192.168.1.20 -> 127.0.0.1] => (item=None)
changed: [192.168.1.20]
changed: [192.168.1.30 -> 127.0.0.1] => (item=None)
changed: [192.168.1.30]

TASK [00_user : Clients - Ensure user exists, ONLY if active.] *****************
changed: [192.168.1.20] => (item=None)
changed: [192.168.1.30] => (item=None)
changed: [192.168.1.20] => (item=None)
changed: [192.168.1.20]
changed: [192.168.1.30] => (item=None)
changed: [192.168.1.30]

TASK [00_user : Set exclusive authorized key for users taken from file, ONLY if active.] ***
ok: [192.168.1.20] => (item=None)
changed: [192.168.1.30] => (item=None)
changed: [192.168.1.20] => (item=None)
changed: [192.168.1.20]
changed: [192.168.1.30] => (item=None)
changed: [192.168.1.30]

TASK [00_user : Add users to group 'wheel' if set to True.] ********************
ok: [192.168.1.20] => (item=None)
skipping: [192.168.1.20] => (item=None) 
ok: [192.168.1.20]
changed: [192.168.1.30] => (item=None)
skipping: [192.168.1.30] => (item=None) 
changed: [192.168.1.30]

TASK [00_user : Remove users from all groups except the primary group, if set to False.] ***
skipping: [192.168.1.20] => (item=None) 
skipping: [192.168.1.30] => (item=None) 
ok: [192.168.1.20] => (item=None)
ok: [192.168.1.20]
ok: [192.168.1.30] => (item=None)
ok: [192.168.1.30]
 
PLAY RECAP *********************************************************************
192.168.1.20               : ok=9    changed=5    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0   
192.168.1.30               : ok=9    changed=6    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0