Contact us
Leave a message

Computerverwaltung

Inzwischen werden all unsere Linux-basierten PCs (wir haben keine anderen mehr ;) per Ansible verwaltet -- was es deutlich erleichtert, alle Geräte auf dem gleichen Stand zu halten oder neu zu installieren. Hier ein paar Kniffe, die ich im Rahmen der Familien-PC-Verwaltung anwende.

Host-spezifische Userverwaltung

In unserem Inventar können Computer die Gruppe family_boxes zugewiesen bekommen, wodurch auf ihnen eine Reihe von Accounts angelegt werden, die in einer users-Liste mit Dictionaries definiert sind, die jeweils benutzer*innen-spezifische Konfigurationswerte enthalten (Auszug; bei uns es gibt pro User in Wirklichkeit noch mehr Konfigurationsparameter):

users:
  - name: homer
    full_name: Homer
    password: $6$D'oh
    is_kid: false
    manage_desktop: true
  - name: marge
    full_name: Marge
    password: $6$Hrmmm
    is_kid: false
    manage_desktop: false
  - name: bart
    full_name: Bart
    password: $6$EatMyShorts
    is_kid: true
    manage_desktop: true
  - name: lisa
    full_name: Lisa
    password: $6$IfAnyoneWantsMe,I'llBeInMyRoom
    shell: /usr/bin/zsh
    is_kid: true
    manage_desktop: false
  - name: maggie
    full_name: Maggie
    password: $6$SuckSuck
    is_kid: true
    manage_desktop: true

Nun kann es für einzelne Hosts nötig sein, manche dieser Default-Werte zu verändern oder gar neue Benutzer*innen hinzuzufügen. Um nicht die gesamte users-Liste neu explizit hinschreiben zu müssen, wird eine Rolle user_management definiert, die die users-Liste entsprechend einem host-spezifischen host_users-Dictionary aktualisiert und/oder ergänz. Ein solches Dictionary könnte z. B. wie folgt aussehen:

host_users:
  marge:
    manage_desktop: false
  lisa:
    shell: /bin/bash
    manage_desktop: false
  guest:
    full_name: Guest
    manage_desktop: false
    password: $6$guest

Hier der Task, in dem die Magie passiert:

---
# Tasks for user_management role

  - name: get list of default user names
    set_fact:
      # Creates a list of all the 'name' values of all dictionaries
      # contained in the default users list.
      _default_user_names: "{{ 
        users 
        | map(attribute='name') 
        | list 
      }}"

  - name: get list of host user_names
    set_fact:
      # Creates a list of all keys of the host_users dictionary, which are
      # the names of all users to be configured specifically for this host.
      _host_user_names: "{{ 
        (host_users | default({}, true))
        | dict2items
        | map(attribute='key') 
        | list
      }}"

  - name: determine additional user names
    set_fact:
      # Excludes all default user names from the set of host-specific user names.
      _additional_user_names: "{{
        _host_user_names 
        | difference(_default_user_names) 
      }}"

  - name: append additional users to default users
    set_fact:
      # For each host-specific user not yet contained in the default users dictionaries list,
      # add a dicionary containing 'name' as key and the additional user's name as value.
      users: "{{
        (users | default([]))
        + [{
          'name': item
        }]
      }}"
    loop: "{{ _additional_user_names}}"

  - name: process users' configuration
    set_fact:
      # For all users (both default and host-specific users, additional or not), merge/overwrite
      # host-specific user configuration into the user's cohnfiguration dictionary.
      _all_users: "{{ 
        (_all_users | default([])) 
        + [
            item 
            | combine(
                host_users[item.name] | default({}), 
                recursive = True
            )
        ]
      }}"
    loop: "{{ users }}"

  - name: get default user groups
    set_fact:
      # Ensures we have a list of default groups user are to assigned to.
      _default_user_groups: "{{ default_user_groups | default([]) }}"
  
  - name: show default user groups
    debug:
      # For debugging purposes.
      msg: "{{ _default_user_groups }}"

  - name: complete users' configuration
    set_fact:
      # Re-build the list of user dictionaries, ensuring all expected keys are present
      # and have default values, if not specified otherwise in the configuration data
      # gathered thus far.
      _users: "{{ 
        (_users | default([])) 
        + [
            item 
            | combine(
                {
                  'groups': (_default_user_groups + (item.addidional_groups | default([]))),
                  'full_name': (item.full_name | default(item.name)),
                  'shell': (item.shell | default('/bin/bash')),
                  'is_system_user': (item.is_system_user | default(false)),
                  'home': (item.home | default('/home/' + item.name)),
                  'id_rsa': (item.id_rsa | default('id_rsa')),
                  'is_kid': (item.is_kid | default(false)),
                  'manage_home': (item.is_kid | default(false)),
                  'manage_desktop': (item.is_kid | default(false)),
                  'record_session': (item.is_kid | default(false))
                }
            )
        ]
      }}"
    loop: "{{ _all_users }}"

  - name: apply users configuration
    set_fact:
      # Re-assign the newly created user configuration list to the users variable.
      users: "{{ _users}}"

  - name: show users
    debug:
      # For debugging purposes.
      msg: "{{ users }}"
  

Hier die effektive user-Liste, die auf dem betreffenden Host zum Tragen kommt (Änderungen hervorgehoben):

users:
  - name: homer
    full_name: Homer
    password: $6$D'oh
    is_kid: false
    manage_desktop: true
  - name: marge
    full_name: Marge
    password: $6$Hrmmm
    is_kid: false
    manage_desktop: true
  - name: bart
    full_name: Bart
    password: $6$EatMyShorts
    is_kid: true
    manage_desktop: true
  - name: lisa
    full_name: Lisa
    password: $6$IfAnyoneWantsMe,I'llBeInMyRoom
    shell: /bin/bash
    is_kid: true
    manage_desktop: true
  - name: maggie
    full_name: Maggie
    password: $6$SuckSuck
    is_kid: true
    manage_desktop: true
  - name: guest
    full_name: Guest
    password: $6$guest
    is_kid: false
    manage_desktop: true