Active Directory automatisieren: Benutzer, Gruppen und OUs mit Ansible
Fabian Peter 11 Minuten Lesezeit

Active Directory automatisieren: Benutzer, Gruppen und OUs mit Ansible

Active Directory automatisieren: Benutzer, Gruppen und OUs mit Ansible und Polycrate

TL;DR

  • Active-Directory-Änderungen per GUI oder unversionierten PowerShell-Skripten sind fehleranfällig, schlecht nachvollziehbar und kollaborativ kaum nutzbar – mit Ansible und Polycrate werden sie reproduzierbar, versioniert und teamfähig.
  • Wir bauen einen Polycrate-Block für AD-Management, der Benutzer, Gruppen und OUs mit den Modulen community.windows.win_domain_user, community.windows.win_domain_group und community.windows.win_domain_ou verwaltet – inklusive CSV-basiertem Bulk-Onboarding und Offboarding-Playbook mit Audit-Log.
  • Jeder Lauf hinterlässt Spuren im Git-Repository (CSV, Playbooks, Audit-Logs) und wird mit polycrate workspace sync automatisch committet: Ein sauberer Audit-Trail für Compliance-Anforderungen wie die DSGVO, die seit dem 25.05.2018 gilt.
  • Polycrate kapselt Ansible komplett im Container, inklusive aller Windows-/AD-Dependencies; kein Python-/Ansible-Chaos mehr auf Admin-Notebooks und klar strukturierte Blöcke statt Playbook-Wildwuchs.
  • ayedo unterstützt Sie dabei, solche AD-Automatisierungen als wiederverwendbare, compliance-fähige Bausteine in Ihrer Organisation zu etablieren – von der Konzeption bis zur Integration in bestehende Prozesse.

Warum AD-Automatisierung bisher so mühsam war

Wenn Sie heute ein klassisches Active Directory verwalten, sieht der Alltag oft so aus:

  • Benutzer werden in der MMC per Hand angelegt
  • Gruppenmitgliedschaften werden „mal eben“ angepasst
  • Gelegentlich existieren PowerShell-Skripte – aber ohne zentrale Versionierung, ohne Tests, oft nur auf einem Admin-Laptop

Das funktioniert, solange Sie wenige Changes haben und die gleichen zwei Personen alles machen. Spätestens wenn Teams wachsen, Audits dazukommen oder mehrere Standorte entstehen, wird es schwierig:

  • Keine Nachvollziehbarkeit: Wer hat wann welche Gruppe geändert? Warum ist dieser Benutzer in der „Domain Admins“-Gruppe?
  • Kein Audit-Trail: Für Compliance (z. B. DSGVO, interne Richtlinien, ISO 27001) brauchen Sie nachvollziehbare Änderungen – GUI-Klicks sind schwer nachweisbar.
  • Skript-Wildwuchs: Jeder schreibt eigene PowerShell-Skripte, mit minimalen Variationen. Fehler lassen sich kaum reproduzieren.
  • Dependency-Chaos: Das PowerShell-Skript vom Kollegen läuft bei Ihnen nicht, weil Module fehlen oder Versionen nicht passen.

Mit plain Ansible wird zwar einiges besser – Sie bekommen Idempotenz, verständliche YAML-Playbooks und ein mächtiges Ökosystem. Aber:

  • Sie müssen Ansible, Python und die passenden Collections (z. B. community.windows) auf jeder Maschine sauber installieren.
  • Versionen unterscheiden sich von Admin zu Admin.
  • Geteilte Playbooks landen „irgendwo“ in Git ohne klare Struktur – der nächste Wildwuchs.

Genau hier setzt Polycrate an.


Polycrate + Ansible: strukturiertes AD-Management mit Audit-Trail

Polycrate macht aus Ihren Ansible-Playbooks versionierte, teilbare Blöcke und löst dabei mehrere typische Probleme:

  • Dependency-Problem gelöst: Ansible läuft immer in einem Polycrate-Container. Die benötigten Collections (z. B. community.windows) werden im Container-Image definiert. Kein lokales Ansible, kein Python-Wirrwarr, weniger Supply-Chain-Risiko. Mehr dazu in der Ansible-Integration von Polycrate.
  • Sharable Automation: Ihr AD-Block ist ein eigenständiges Artefakt, das Sie in einer OCI-Registry oder im PolyHub teilen können. Teams binden ihn per vollständiger Registry-Referenz in from: ein (siehe Workspace-Beispiel unten).
  • Guardrails statt Playbook-Wildwuchs: Durch das Block-Modell sind Actions (Onboarding, Offboarding, OU-Setup) klar getrennt. Kein „alles in einem riesigen Playbook“ mehr.
  • Compliance-ready:
    • Git-Versionierung des gesamten Workspaces, inklusive Audit-Logs.
    • Automatische Commits über polycrate workspace sync (siehe Git-Integration von Polycrate).
    • Workspace-Verschlüsselung mit age, um Passwörter und Inventories geschützt abzulegen (siehe Workspace-Verschlüsselung).

Wir bauen im Folgenden einen Workspace mit einem AD-Management-Block, der:

  • OUs anlegt
  • Benutzer aus einer CSV-Datei importiert
  • Gruppen anlegt und Mitglieder pflegt
  • Offboarding mit Deaktivierung, Gruppenentfernung und Audit-Log automatisiert

Workspace für AD-Management vorbereiten

Zuerst legen wir den Workspace acme-corp-automation an und definieren unseren AD-Block sowie das Inventory.

workspace.poly

name: acme-corp-automation
organization: acme

blocks:
  - name: ad-mgmt
    from: registry.acme-corp.com/acme/infra/ad-mgmt:1.0.0
    config:
      domain_name: "acme-corp.com"
      default_ou: "OU=Users,DC=acme-corp,DC=com"

from: enthält die vollständige OCI-Registry-Referenz inklusive Versions-Tag am Ende der Zeile (wie bei Container-Images); ein separates version-Feld unter der Block-Instanz gibt es nicht. Im Block-Paket trägt block.poly denselben logischen Namen (ad-mgmt). Die Registry registry.acme-corp.com ist ein Beispiel (kein Bezug zu ayedos Produkt-Registry). Fehlt der Block lokal, kann Polycrate ihn beim ersten polycrate run … aus der Registry nachziehen; ausgepackt liegt er unter blocks/registry.acme-corp.com/acme/infra/ad-mgmt/. Mehr dazu im Beitrag Multi-Server-Management mit Ansible-Inventories.

Mehr zu Workspaces finden Sie in der Dokumentation zu Polycrate Workspaces.

Inventory für den Domain Controller

Polycrate erwartet ein YAML-Inventory im Workspace-Root als inventory.yml. Alle Hosts stehen unter all.hosts; unter children verweist die Gruppe domain_controllers nur noch per Hostname – gemeinsame WinRM-Einstellungen liegen in vars der Gruppe. Keine Passwörter im Inventoryansible_password setzen Sie in den Playbooks aus secrets.poly / workspace.secrets.* (siehe Workspace-Verschlüsselung). Für einen Domain Controller dc01.acme-corp.com kann das so aussehen:

all:
  hosts:
    dc01.acme-corp.com: {}

  children:
    domain_controllers:
      hosts:
        dc01.acme-corp.com:
      vars:
        ansible_user: Administrator
        ansible_connection: winrm
        ansible_port: 5986
        ansible_winrm_transport: credssp
        ansible_winrm_server_cert_validation: ignore

Wichtig:

WinRM-Passwort für die Playbooks: In secrets.poly legen Sie z. B. ad_dc_password ab; in jedem Play gegen domain_controllers setzen Sie darunter vars: zusätzlich ansible_password: "{{ workspace.secrets.ad_dc_password }}" (die folgenden Beispiele enthalten das).


Der AD-Block: block.poly definieren

Unser Block blocks/registry.acme-corp.com/acme/infra/ad-mgmt/block.poly (nach dem Pull aus der Registry) kapselt alle AD-Aktivitäten:

name: ad-mgmt
version: 0.1.0
kind: generic

config:
  domain_name: "acme-corp.com"
  default_ou: "OU=Users,DC=acme-corp,DC=com"
  users_csv: "users.csv"
  audit_log: "audit.log"

actions:
  - name: setup_ou_and_groups
    playbook: setup_ou_and_groups.yml

  - name: onboarding
    playbook: onboarding.yml

  - name: offboarding
    playbook: offboarding.yml
  • config.*-Werte können Sie im Workspace bei Bedarf überschreiben.
  • Die Playbooks liegen im Block-Verzeichnis (Registry-Pfad unter blocks/…). Laufzeitdaten wie CSV und Audit-Log legen Sie nicht im Block ab, sondern unter artifacts/blocks/<Block-Instanzname>/ im Workspace – z. B. artifacts/blocks/ad-mgmt/users.csv. In Ansible zeigt block.artifacts.path auf genau dieses Verzeichnis (im Container: /workspace/artifacts/blocks/<name>/).

Weitere Details zu Blocken finden Sie in den Polycrate Blocke-Docs.


CSV-basiertes Bulk-Onboarding von AD-Benutzern

Beispiel-CSV für Benutzer

Legen Sie die Datei im Workspace unter artifacts/blocks/ad-mgmt/users.csv an (nicht im Block-Verzeichnis unter blocks/…). Polycrate stellt den Pfad in Playbooks als {{ block.artifacts.path }} bereit (entspricht artifacts/blocks/ad-mgmt/ im Workspace).

username;givenName;sn;password;enabled;ou_dn;groups
jdoe;John;Doe;Start123!;true;OU=IT,OU=Users,DC=acme-corp,DC=com;IT-Admins,VPN-Users
mroe;Maria;Roe;Start123!;true;;Sales,VPN-Users
  • ou_dn ist optional – fehlt er, verwenden wir default_ou.
  • groups ist eine durch Komma getrennte Liste.

Playbook: Onboarding mit win_domain_user und win_domain_group

Das Onboarding besteht aus zwei Plays:

  1. CSV im Polycrate-Container einlesen (localhost, erlaubt, weil nur Dateien gelesen werden)
  2. Benutzer und Gruppen auf dem Domain Controller pflegen
# blocks/registry.acme-corp.com/acme/infra/ad-mgmt/onboarding.yml
- name: Load users from CSV in Polycrate container
  hosts: localhost
  gather_facts: false
  vars:
    users_csv: "{{ block.artifacts.path }}/{{ block.config.users_csv }}"
  tasks:
    - name: Read users from CSV
      community.general.read_csv:
        path: "{{ users_csv }}"
        delimiter: ";"
      register: csv_users

    - name: Normalize user list
      ansible.builtin.set_fact:
        ad_users: "{{ csv_users.list }}"

- name: Create OUs and groups on domain controllers
  hosts: domain_controllers
  gather_facts: false
  vars:
    ansible_password: "{{ workspace.secrets.ad_dc_password }}"
    domain_name: "{{ block.config.domain_name }}"
    default_ou: "{{ block.config.default_ou }}"
  tasks:
    - name: Ensure base OU exists
      community.windows.win_domain_ou:
        name: "{{ default_ou }}"
        state: present

    - name: Ensure department OUs from CSV exist
      community.windows.win_domain_ou:
        name: "{{ item.ou_dn }}"
        state: present
      loop: "{{ hostvars['localhost'].ad_users | map(attribute='ou_dn') | list | unique }}"
      when: item.ou_dn is defined and item.ou_dn | length > 0

    - name: Collect all group names from CSV
      ansible.builtin.set_fact:
        all_groups: >-
          {{ hostvars['localhost'].ad_users
             | map(attribute='groups')
             | select('defined')
             | map('split', ',')
             | sum(start=[])
             | map('trim')
             | reject('equalto', '')
             | list }}
      run_once: true

    - name: Ensure groups exist
      community.windows.win_domain_group:
        name: "{{ item }}"
        scope: global
        state: present
      loop: "{{ all_groups | default([]) }}"
      run_once: true

    - name: Ensure AD users exist and are in the right groups
      community.windows.win_domain_user:
        name: "{{ item.username }}"
        upn: "{{ item.username }}@{{ domain_name }}"
        given_name: "{{ item.givenName }}"
        surname: "{{ item.sn }}"
        password: "{{ item.password }}"
        enabled: "{{ (item.enabled | default('true')) | bool }}"
        path: "{{ item.ou_dn | default(default_ou) }}"
        state: present
        groups: >-
          {{ (item.groups | default(''))
             | split(',')
             | map('trim')
             | reject('equalto', '')
             | list }}
      loop: "{{ hostvars['localhost'].ad_users }}"
      run_once: true

Was passiert hier?

  • CSV-Einlesen im Container: community.general.read_csv läuft auf localhost im Polycrate-Container. Es verändert keine Zielsysteme, daher ist hosts: localhost hier korrekt.
  • OU-Management: Mit community.windows.win_domain_ou legen wir zunächst eine Basis-OU an und dann ggf. zusätzliche OUs aus den CSV-Daten.
  • Gruppenverwaltung: community.windows.win_domain_group erstellt alle in der CSV referenzierten Gruppen.
  • Benutzerverwaltung: community.windows.win_domain_user legt Benutzer an oder aktualisiert sie idempotent, inklusive OU, Passwort, Status und Gruppen.

Mit plain Ansible ohne Polycrate müssten Sie:

  • Ansible und alle Collections lokal installieren.
  • Sicherstellen, dass community.windows überall gleich verfügbar ist.
  • Playbooks und CSV manuell mit Git verknüpfen.

Mit Polycrate reicht ein strukturierter Block und ein reproduzierbarer Container.

Onboarding ausführen

Vom Workspace-Root aus:

cd ~/workspaces/acme-corp-automation
polycrate run ad-mgmt onboarding

Polycrate kümmert sich um:

  • Start des Containers mit der richtigen Ansible- und Collection-Version
  • Bereitstellung des Workspaces im Container
  • Übergabe des Inventories

Offboarding-Playbook mit Audit-Log

Beim Offboarding wollen Sie:

  • Benutzer deaktivieren
  • Aus Gruppen entfernen
  • Optional in eine „Disabled Users“-OU verschieben
  • Einen nachvollziehbaren Audit-Eintrag schreiben

Offboarding-Playbook

# blocks/registry.acme-corp.com/acme/infra/ad-mgmt/offboarding.yml
- name: Disable AD user and clean up group memberships
  hosts: domain_controllers
  gather_facts: false
  vars:
    ansible_password: "{{ workspace.secrets.ad_dc_password }}"
    domain_name: "{{ block.config.domain_name }}"
    disabled_ou: "OU=Disabled Users,DC=acme-corp,DC=com"
    username: "{{ username }}"
  tasks:
    - name: Ensure OU for disabled users exists
      community.windows.win_domain_ou:
        name: "{{ disabled_ou }}"
        state: present

    - name: Disable user and move to disabled OU
      community.windows.win_domain_user:
        name: "{{ username }}"
        upn: "{{ username }}@{{ domain_name }}"
        enabled: false
        path: "{{ disabled_ou }}"
        state: present

    - name: Remove user from sensitive groups
      community.windows.win_domain_group:
        name: "{{ item }}"
        state: present
        members:
          - "{{ username }}"
        members_state: absent
      loop:
        - "IT-Admins"
        - "Domain Admins"
        - "VPN-Users"

- name: Write audit log entry in Polycrate workspace
  hosts: localhost
  gather_facts: false
  vars:
    audit_log: "{{ block.artifacts.path }}/{{ block.config.audit_log }}"
  tasks:
    - name: Append audit log entry
      ansible.builtin.lineinfile:
        path: "{{ audit_log }}"
        line: "{{ lookup('ansible.builtin.pipe', 'date -u +%Y-%m-%dT%H:%M:%SZ') }};{{ username }};offboarded"
        create: yes
        insertafter: EOF

Hinweise:

  • Der erste Play läuft auf den Domain Controllern und nutzt Windows-spezifische Module.
  • Der zweite Play läuft wieder im Polycrate-Container (localhost) und schreibt ins audit.log unter {{ block.artifacts.path }} (Workspace: artifacts/blocks/ad-mgmt/). Dieses File ist Teil des Workspaces und wird damit versioniert und verschlüsselt.

Offboarding für einen Benutzer ausführen

Den Benutzer über ein Extra-Var übergeben:

cd ~/workspaces/acme-corp-automation
polycrate run ad-mgmt offboarding -- -e "username=jdoe"

Der Doppelstrich -- trennt die Polycrate-Argumente von den Argumenten, die an ansible-playbook gehen.


Änderungen versionieren und Audit-Trail sicherstellen

Die eigentliche Stärke für Compliance entsteht durch die Kombination:

  • Playbooks + CSV + Audit-Logs im Git-Repository
  • Automatisierte Commits mit Polycrate

Nach einem Onboarding- oder Offboarding-Lauf:

  • Wurde ggf. users.csv geändert (z. B. neue Benutzer).
  • Wurde audit.log um einen Eintrag erweitert.
  • Sind Ihre Playbooks und Block-Definitionen unverändert oder angepasst.

Mit Polycrate halten Sie den Workspace synchron zu Git, z. B.:

cd ~/workspaces/acme-corp-automation
polycrate workspace sync

Polycrate:

  • Erkennt Änderungen im Workspace.
  • Erstellt einen Commit mit sinnvollem Commit-Text.
  • Optional pusht es in Ihr zentrales Git-Repository (je nach Konfiguration).

Details dazu finden Sie in der Git-Integration von Polycrate.

Der Compliance-Vorteil gegenüber GUI-Klicks oder losen PowerShell-Skripten:

  • Jede AD-Änderung ist über Playbooks und CSV-Daten nachvollziehbar.
  • Jeder Lauf hinterlässt einen Commit mit Timestamp und Diff.
  • Das audit.log bietet eine zusätzliche, menschenlesbare Übersicht („wann wurde welcher Benutzer offboarded?“).

In Audits oder bei forensischen Analysen ist das Gold wert.


Block teilen und im Unternehmen standardisieren

Sie entwickeln den Block im Workspace unter dem registry-kompatiblen Verzeichnis, das zu Ihrer späteren from:-Referenz passt – z. B. blocks/registry.acme-corp.com/acme/infra/ad-mgmt/ (Registry-Host und Pfad wie in der OCI-Referenz ohne Versionstag), nicht unter einem verkürzten Pfad wie ./blocks/ad-mgmt/. Anschließend veröffentlichen Sie ihn in Ihrer OCI-Registry oder im PolyHub – andere Workspaces beziehen ihn dann mit vollständiger from:-Referenz und Versionstag, wie im ersten workspace.poly-Beispiel. Dasselbe Verzeichnisprinzip gilt für die Polycrate-Registry cargo (blocks/cargo.ayedo.cloud/…). Alternativ (oder zusätzlich) nutzen Sie z. B. cargo in from: – Beispiel:

blocks:
  - name: ad-mgmt
    from: cargo.ayedo.cloud/acme/infra/ad-mgmt:0.1.0
    config:
      domain_name: "acme-corp.com"
      default_ou: "OU=Users,DC=acme-corp,DC=com"

Dadurch:

  • Nutzen andere Teams exakt denselben, getesteten AD-Block.
  • Sie können neue Versionen (z. B. 0.2.0) ausrollen, ohne bestehende Workspaces zu brechen.
  • Automatisierung wird zu einem unternehmensweiten Standardbaustein, nicht zu einer Sammlung individueller Skripte.

Mehr dazu in der Dokumentation zu Registry und PolyHub.


Häufige Fragen

Muss ich auf meinem Admin-Notebook noch Ansible oder zusätzliche Python-Pakete installieren?

Nein. Polycrate bringt ein Container-Image mit, in dem Ansible, Python und benötigte Collections wie community.windows bereits installiert sind. Sie führen nur polycrate run ... aus, Polycrate startet den Container, bindet den Workspace ein und ruft ansible-playbook im Container auf.

Vorteile:

  • Alle Admins nutzen dieselbe Toolchain – keine Versions-Konflikte.
  • Sie reduzieren das Risiko, dass jemand „mal eben“ ein Modul auf einem Notebook aktualisiert und damit Playbooks bricht.
  • Sie haben eine klare Supply-Chain: Das Container-Image ist Ihr definierter „Control Node“.

Wie schütze ich Passwörter und sensible Daten im Workspace?

Der Workspace kann mit polycrate workspace encrypt über age verschlüsselt werden. Damit lassen sich Dateien wie:

  • secrets.poly und verschlüsselte Artefakte (AD-Credentials, keine Klartext-Passwörter im inventory.yml)
  • CSV-Dateien mit temporären Initialpasswörtern
  • zusätzliche Secret-Files

verschlüsselt im Git-Repository ablegen. Nur berechtigte Personen mit den passenden Schlüsseln können den Workspace entschlüsseln.

Details finden Sie in der Dokumentation zur Workspace-Verschlüsselung.

Kann ich den AD-Block in mehreren Domains oder Umgebungen (z. B. Test/Prod) nutzen?

Ja. Über blocks.config im workspace.poly können Sie pro Workspace (oder sogar pro Umgebung) andere Parameter setzen, z. B.:

  • domain_name
  • default_ou
  • andere CSV-Dateien

Für Test- und Produktionsumgebungen legen Sie einfach getrennte Workspaces an, die denselben Block aus der Registry referenzieren, aber andere Konfigurationen und Inventories haben. So bleibt die Logik identisch, während Ziele und Daten je Umgebung variieren.

Weitere Fragen? Siehe unsere FAQ


Compliance in der Praxis

Mit dem hier gezeigten AD-Block haben Sie einen wichtigen Schritt getan:

  • AD-Benutzer, Gruppen und OUs werden deklarativ beschrieben, nicht per Hand geklickt.
  • Bulk-Onboarding aus CSV, Offboarding mit Deaktivierung und Gruppenbereinigung – alles nachvollziehbar und wiederholbar.
  • Durch Git-History, polycrate workspace sync und das Audit-Log entstehen prüfbare Spuren, die bei Audits, Pen-Tests oder internen Kontrollen überzeugen.
  • Polycrate nimmt Ihnen den operativen Ballast: keine lokale Ansible-Installation, keine unkontrollierten Skripte, klare Struktur durch das Block-Modell.

Als ayedo begleiten wir Organisationen dabei, genau solche Automatisierungen systematisch aufzubauen – von der ersten AD-Action bis zu ganzen Landschaften aus standardisierten Polycrate-Blöcken. Ob Sie „nur“ das Onboarding/Offboarding verbessern oder ein umfassendes Policy-as-Code-Modell für Ihr Active Directory etablieren wollen: Wir bringen die Erfahrung aus Platform Engineering, Windows- und Compliance-Projekten zusammen.

Wenn Sie sehen möchten, wie dieses Setup in Ihrer Umgebung aussehen kann und welche Erweiterungen (z. B. automatische GPO-Zuordnung oder Integration in Ihr HR-System) sinnvoll sind, lohnt sich ein gemeinsamer Blick auf Ihre Anforderungen:

AD-Management Demo

Ähnliche Artikel