Azure Entra ID automatisieren: Benutzer, Gruppen und Apps mit Ansible
Fabian Peter 11 Minuten Lesezeit

Azure Entra ID automatisieren: Benutzer, Gruppen und Apps mit Ansible

Azure Entra ID automatisieren: Benutzer, Gruppen und App-Registrierungen mit Ansible und Polycrate

TL;DR

  • Ansible kann Azure Entra ID (ehem. Azure AD) über die azure.azcollection vollständig automatisieren: Benutzer, Gruppen, App-Registrierungen und sogar die Dokumentation Ihrer Conditional Access Policies.
  • Mit Polycrate laufen alle Playbooks in einem reproduzierbaren Container: keine lokale Ansible-/Python-Installation, kein Versionschaos, kein “funktioniert bei mir”-Problem – die komplette Azure-Toolchain ist im Dockerfile.poly definiert.
  • Ein dedizierter Service Principal dient als Automatisierungs-Account – mit klar begrenzten Rechten (Least Privilege) und sicher verschlüsselten Zugangsdaten im Workspace.
  • Jede Änderung an Entra ID wird zu Code: Pull-Requests, Reviews und Git-History dienen als technischer Audit-Trail für Compliance, z.B. im Kontext von DSGVO oder internen Richtlinien.
  • ayedo unterstützt Sie mit Polycrate, Best Practices und einem spezialisierten Azure-Automatisierungs-Workshop, in dem wir Ihr Entra-ID-Management gemeinsam industrialisieren.

Warum Entra ID automatisieren?

Für Windows-Admins und Azure-Admins hat sich das Zentrum der Identitätsverwaltung längst von klassischem On-Prem-AD zu Azure Entra ID verschoben. Benutzer, Gruppen und App-Registrierungen werden heute immer häufiger direkt dort gemanagt – oft aber noch per Portal-Klick.

Das funktioniert, bis eine der folgenden Situationen eintritt:

  • Jemand ändert spontan eine Conditional Access Policy – und drei Wochen später weiß niemand mehr warum.
  • Ein Kollege legt in der Nacht Benutzer an “damit es schnell geht” – ohne Change-Request, ohne Dokumentation.
  • Das Onboarding neuer Mitarbeiter dauert, weil immer noch manuell Benutzer und Gruppenmitgliedschaften gepflegt werden.

Automatisierung mit Ansible löst genau diese Probleme:

  • Alle Änderungen sind deklarativ beschrieben.
  • Idempotenz sorgt dafür, dass der Zielzustand wiederholbar hergestellt wird.
  • Git-Workflows liefern nachvollziehbare Change-Historie.

Mit Polycrate liegt diese Automatisierung nicht als lose Playbooksammlung auf mehreren Laptops, sondern als strukturierter Workspace, inklusive verschlüsselten Secrets und reproduzierbarer Container-Umgebung.


Polycrate + Ansible: saubere Umgebung für Azure-Automation

Bevor wir Benutzer und Gruppen in Entra ID anfassen, lohnt sich ein Blick auf das “Wie”.

Container statt lokaler Ansible-Installation

Das klassische Ansible-Problem für Azure kennen Sie vermutlich:

  • Python-Versionen unterscheiden sich zwischen Teammitgliedern.
  • azure.azcollection zieht eine halbe Azure-SDK-Landschaft nach sich.
  • Auf einem Host ist noch die alte Azure CLI, auf einem anderen gar keine.

Polycrate nimmt diesen Schmerz weg:

  • Jede Action läuft im Polycrate-Container; optional erweitern Sie das Image per Dockerfile.poly – dabei leiten Sie immer vom offiziellen Image ab (siehe unten).
  • Zusätzliche Ansible-Collections (wie azure.azcollection) installieren Sie in genau dieser Erweiterung; Python und ansible-core kommen aus dem Basis-Image.
  • Das gesamte Team arbeitet damit auf derselben Toolchain – egal ob Linux-, Mac- oder Windows-Workstation.

Details dazu finden Sie in der Ansible-Integration und den Best Practices.

azure.azcollection im Polycrate-Container installieren

Ein Dockerfile.poly muss immer vom offiziellen Polycrate-Image ausgehen (cargo.ayedo.cloud/library/polycrate), nicht von einem nackten python:-Image: Polycrate erwartet die mitgelieferte Toolchain, Mounts und Umgebung. Ein reines Python-Image würde als Action-Runtime nicht funktionieren. Hintergrund: Der Polycrate Container.

Zusätzliche Collections installierst du in einer dünnen Schicht darauf. Minimal könnte das so aussehen:

FROM cargo.ayedo.cloud/library/polycrate:latest

# requirements.yml für Collections (z. B. neben Dockerfile.poly im Workspace)
COPY requirements.yml /workspace/requirements.yml

# Azure Collection installieren (Ansible ist bereits im Polycrate-Base-Image)
RUN ansible-galaxy collection install -r /workspace/requirements.yml

WORKDIR /workspace

Die zugehörige requirements.yml:

---
collections:
  - name: azure.azcollection
    version: 1.18.0

Damit steht azure.azcollection im Polycrate-Container für alle Blöcke bereit – keine lokale Installation mehr nötig.


Workspace und Block für Entra-ID-Automation

Wir nutzen das Beispiel-Setup acme-corp-automation und legen einen dedizierten Block für Entra ID an.

workspace.poly: Block einbinden

name: acme-corp-automation
organization: acme

blocks:
  - name: entra-id-mgmt
    from: registry.acme.corp/blocks/entra-id-mgmt:0.1.0
    config:
      default_domain: "acme-corp.com"
      azure_credentials_file: "artifacts/secrets/azure-sp.json"

Wichtig:

  • from: zeigt hier die Registry-Notation eines Blocks (<registry>/<pfad>:<version>). registry.acme.corp ist nur ein fiktives Beispiel; in der Praxis nutzt du z. B. polycrate blocks pull … oder eure eigene OCI-Registry.
  • In workspace.poly und block.poly gibt es kein Jinja2 – azure_credentials_file ist ein fester Pfad zur Datei unter artifacts/secrets/ (nach Entschlüsselung im Container nutzbar). Im Ansible-Playbook greifst du weiter mit {{ block.config.azure_credentials_file }} zu.
  • Die Struktur und Arbeitsweise von Workspaces ist in den Workspace-Dokumentation beschrieben.

block.poly: Aktionen für Benutzer, Gruppen, Apps, Policies

Im Block-Verzeichnis blocks/entra-id-mgmt legen wir eine block.poly an:

name: entra-id-mgmt
version: 0.1.0
kind: ansible

config:
  default_domain: ""
  azure_credentials_file: ""

actions:
  - name: users
    description: "Benutzer in Entra ID verwalten"
    playbook: users.yml

  - name: groups
    description: "Gruppen und Mitgliedschaften verwalten"
    playbook: groups.yml

  - name: apps
    description: "App-Registrierungen und Service Principals verwalten"
    playbook: apps.yml

  - name: policies
    description: "Conditional Access Policies dokumentieren (read-only)"
    playbook: policies.yml

Unter config: stehen nur die erwarteten Schlüssel (hier mit leeren Defaults); kein Jinja2 in .poly-Dateien. Die konkreten Werte setzt du bei der Block-Instanz in workspace.poly (siehe oben).

Damit haben wir klare Guardrails:

  • Jede Aufgabe ist eine klar benannte Action.
  • Keine lose wachsende Playbook-Sammlung.
  • Für Ihr Team entsteht eine einfache UX: polycrate run entra-id-mgmt users statt komplexer Ansible-CLI-Aufrufe.

Mehr zu Blöcken und Actions finden Sie unter Blöcke und Actions.


Service Principal als Automatisierungs-Account

Für Entra-ID-Automation brauchen wir einen dedizierten Service Principal.

Rollen und Least Privilege

Je nachdem, was Sie automatisieren, benötigen Sie unterschiedliche Entra-Rollen. Ein gängiges Setup:

  • Benutzer-Management: Rolle User Administrator
  • Gruppen-Management: Rolle Groups Administrator
  • App-Registrierungen: Rolle Application Administrator oder feiner granulierte App-Registration-Berechtigungen

Best Practice:

  • Einen eigenen “Automation”-Service-Principal anlegen.
  • Nur die minimal notwendigen Rollen zuweisen.
  • Zugangsdaten ausschließlich im Polycrate-Workspace verwenden (nicht lokal herumliegen lassen).

Zugangsdaten in einem Secret speichern

Legen Sie im Workspace die Datei artifacts/secrets/azure-sp.json an:

{
  "client_id": "00000000-0000-0000-0000-000000000000",
  "client_secret": "SUPER-GEHEIMER-WERT",
  "tenant_id": "11111111-1111-1111-1111-111111111111",
  "subscription_id": "22222222-2222-2222-2222-222222222222"
}

Konfigurieren Sie diese Datei über secrets.poly als zu verschlüsselndes Secret (Details in der Workspace-Verschlüsselung) und verschlüsseln Sie den Workspace anschließend:

polycrate workspace encrypt

Damit:

  • Liegt die Datei verschlüsselt im Git-Repository.
  • Stellt Polycrate sie im Container am konfigurierten Pfad (z. B. artifacts/secrets/azure-sp.json) bereit.
  • Müssen Sie kein externes Tool wie Vault betreiben.

Benutzer verwalten mit azure_rm_aduser

Jetzt wird es konkret: Wir verwalten Entra-ID-Benutzer mit azure.azcollection.azure_rm_aduser.

users.yml: Benutzer anlegen, deaktivieren, löschen

Die Datei blocks/entra-id-mgmt/users.yml:

---
- name: Benutzer in Entra ID verwalten
  hosts: localhost
  connection: local
  gather_facts: false

  vars:
    azure_credentials_file: "{{ block.config.azure_credentials_file }}"
    default_domain: "{{ block.config.default_domain }}"

  tasks:
    - name: Azure Service Principal Credentials laden
      ansible.builtin.include_vars:
        file: "{{ azure_credentials_file }}"
        name: azure

    - name: Benutzer anlegen oder aktualisieren
      azure.azcollection.azure_rm_aduser:
        state: present
        user_principal_name: "alice@{{ default_domain }}"
        display_name: "Alice Example"
        password: "InitialPassw0rd!"
        account_enabled: true
        force_password_change: true
        tenant: "{{ azure.tenant_id }}"
        client_id: "{{ azure.client_id }}"
        secret: "{{ azure.client_secret }}"
        auth_source: client_secret
      register: alice_result

    - name: Benutzer deaktivieren (Beispiel)
      azure.azcollection.azure_rm_aduser:
        state: present
        user_principal_name: "bob@{{ default_domain }}"
        display_name: "Bob Example"
        account_enabled: false
        tenant: "{{ azure.tenant_id }}"
        client_id: "{{ azure.client_id }}"
        secret: "{{ azure.client_secret }}"
        auth_source: client_secret

    - name: Benutzer löschen (Beispiel)
      azure.azcollection.azure_rm_aduser:
        state: absent
        user_principal_name: "temp.user@{{ default_domain }}"
        tenant: "{{ azure.tenant_id }}"
        client_id: "{{ azure.client_id }}"
        secret: "{{ azure.client_secret }}"
        auth_source: client_secret

    - name: Kurze Zusammenfassung ausgeben
      ansible.builtin.debug:
        msg: "Benutzerverwaltung abgeschlossen. Alice-Änderung: {{ alice_result.changed }}"

Wichtig:

  • hosts: localhost und connection: local sind hier korrekt – das Playbook läuft im Polycrate-Container und spricht die Azure-APIs, nicht einen SSH-Host.
  • Die Credentials werden aus der verschlüsselten Datei geladen und nicht in der block.poly oder im Playbook hinterlegt.

Ausführen der Action:

polycrate run entra-id-mgmt users

Mit plain Ansible müssten Sie dafür sorgen, dass lokal:

  • Python, Ansible, azure.azcollection und alle Abhängigkeiten installiert sind.
  • Die Pfade zu Credential-Dateien auf jedem Admin-Laptop stimmen.

Mit Polycrate reicht es, den Workspace zu clonen, polycrate run zu nutzen, und alles läuft im definierten Container.


Gruppen und Mitgliedschaften mit azure_rm_adgroup

Gruppen sind das Herzstück von Berechtigungen in Entra ID. Das Prinzip ist identisch: deklarativ beschreiben, welche Gruppen existieren und welche Mitglieder dazugehören.

groups.yml: Gruppen und Mitglieder

---
- name: Gruppen in Entra ID verwalten
  hosts: localhost
  connection: local
  gather_facts: false

  vars:
    azure_credentials_file: "{{ block.config.azure_credentials_file }}"
    default_domain: "{{ block.config.default_domain }}"

  tasks:
    - name: Azure Service Principal Credentials laden
      ansible.builtin.include_vars:
        file: "{{ azure_credentials_file }}"
        name: azure

    - name: Sicherheitsgruppe "HR-Staff" sicherstellen
      azure.azcollection.azure_rm_adgroup:
        state: present
        display_name: "HR-Staff"
        mail_nickname: "hr-staff"
        security_enabled: true
        description: "HR Mitarbeiter"
        tenant: "{{ azure.tenant_id }}"
        client_id: "{{ azure.client_id }}"
        secret: "{{ azure.client_secret }}"
        auth_source: client_secret
      register: hr_group

    - name: Mitglieder in HR-Staff pflegen
      azure.azcollection.azure_rm_adgroup:
        state: present
        display_name: "HR-Staff"
        security_enabled: true
        members:
          # Beispiel UPNs, in der Praxis besser Object IDs verwenden
          - "alice@{{ default_domain }}"
        tenant: "{{ azure.tenant_id }}"
        client_id: "{{ azure.client_id }}"
        secret: "{{ azure.client_secret }}"
        auth_source: client_secret

    - name: Gruppe "Legacy-Group" löschen (falls noch vorhanden)
      azure.azcollection.azure_rm_adgroup:
        state: absent
        display_name: "Legacy-Group"
        tenant: "{{ azure.tenant_id }}"
        client_id: "{{ azure.client_id }}"
        secret: "{{ azure.client_secret }}"
        auth_source: client_secret

Ausführen:

polycrate run entra-id-mgmt groups

So entsteht ein reproduzierbarer Zielzustand für Ihre Gruppen. Änderungen laufen über Pull-Requests und die Git-History dokumentiert, wann welche Gruppen angepasst wurden.


App-Registrierungen und Service Principals automatisieren

Viele Windows-/Azure-Teams haben Dutzende App-Registrierungen: Skripte, Automatisierungs-Accounts, Drittanbieter-Anwendungen. Diese manuell im Portal anzulegen, ist fehleranfällig.

apps.yml: App-Registrierung + Service Principal

---
- name: App-Registrierungen in Entra ID verwalten
  hosts: localhost
  connection: local
  gather_facts: false

  vars:
    azure_credentials_file: "{{ block.config.azure_credentials_file }}"

  tasks:
    - name: Azure Service Principal Credentials laden
      ansible.builtin.include_vars:
        file: "{{ azure_credentials_file }}"
        name: azure

    - name: Anwendung "acme-hr-portal" registrieren
      azure.azcollection.azure_rm_adapplication:
        state: present
        display_name: "acme-hr-portal"
        identifier_uris:
          - "api://acme-hr-portal"
        reply_urls:
          - "https://hr.acme-corp.com/auth/callback"
        available_to_other_tenants: false
        tenant: "{{ azure.tenant_id }}"
        client_id: "{{ azure.client_id }}"
        secret: "{{ azure.client_secret }}"
        auth_source: client_secret
      register: hr_app

    - name: Service Principal für "acme-hr-portal" sicherstellen
      azure.azcollection.azure_rm_adserviceprincipal:
        state: present
        app_id: "{{ hr_app.object_id }}"
        tenant: "{{ azure.tenant_id }}"
        client_id: "{{ azure.client_id }}"
        secret: "{{ azure.client_secret }}"
        auth_source: client_secret

    - name: App-Details anzeigen
      ansible.builtin.debug:
        msg: "App acme-hr-portal registriert mit Object ID {{ hr_app.object_id }}"

Ausführen:

polycrate run entra-id-mgmt apps

Damit können Sie:

  • App-Registrierungen für eigene Anwendungen konsistent anlegen.
  • Service Principals gezielt für Automatisierung oder externe Integrationen bereitstellen.
  • Änderungen sauber versionieren: z.B. neue Redirect-URLs oder zusätzliche Scopes.

Conditional Access Policies dokumentieren (read-only)

Conditional Access Policies sind sicherheitskritisch. Änderungen daran sollten nachvollziehbar und dokumentiert sein. Anstelle von manuellen Screenshots oder Excel-Listen können Sie diese mit Ansible auslesen und als JSON im Repository ablegen.

Ein vereinfachtes Beispiel für policies.yml, das die bestehenden Policies per Microsoft Graph ausliest und in einer Datei dokumentiert. Hier gehen wir davon aus, dass Sie ein Access-Token außerhalb des Playbooks erzeugen und im Secret ablegen (z.B. per kleinem Hilfsskript).

---
- name: Conditional Access Policies dokumentieren
  hosts: localhost
  connection: local
  gather_facts: false

  vars:
    azure_credentials_file: "{{ block.config.azure_credentials_file }}"

  tasks:
    - name: Azure Service Principal Daten laden (inkl. access_token)
      ansible.builtin.include_vars:
        file: "{{ azure_credentials_file }}"
        name: azure

    - name: Conditional Access Policies via Microsoft Graph abrufen
      ansible.builtin.uri:
        url: "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies"
        method: GET
        headers:
          Authorization: "Bearer {{ azure.access_token }}"
          Content-Type: "application/json"
        return_content: true
      register: ca_policies

    - name: Policies in Datei schreiben
      ansible.builtin.copy:
        dest: "artifacts/entra-id/conditional-access-policies.json"
        content: "{{ ca_policies.content }}"

Ausführen:

polycrate run entra-id-mgmt policies

Der wichtige Punkt:

  • Sie haben eine maschinenlesbare Momentaufnahme Ihrer Conditional Access Policies.
  • Diese Datei landet im Git-Repo und jede Änderung ist differenzierbar.
  • Bei Audits oder internen Reviews können Sie klar zeigen, wie sich Policies über die Zeit entwickelt haben.

Git als Audit-Trail für Entra-ID-Änderungen

Compliance-Anforderungen (z.B. aus der DSGVO, die seit dem 25.05.2018 gilt, oder aus internen Richtlinien) verlangen nachvollziehbare Prozesse:

  • Wer hat wann welche Berechtigung geändert?
  • Wie sah die Konfiguration zu einem bestimmten Stichtag aus?
  • Welche Policies galten, als ein sicherheitsrelevantes Ereignis auftrat?

Mit Polycrate + Ansible + Git bekommen Sie das quasi “by design”:

  • Jede Änderung an Benutzern, Gruppen, Apps oder Policies ist ein Commit.
  • Pull-Requests, Reviews und Approvals bilden den Freigabeprozess ab.
  • Durch die Workspace-Verschlüsselung bleiben Secrets geschützt, während der Rest offen revisioniert werden kann.

Statt manueller Excel-Listen oder Screenshots erhalten Sie eine saubere, technische Nachvollziehbarkeit.


Häufige Fragen

Brauche ich für diese Lösung zwingend Linux-Know-how?

Nein. Als Windows- oder Azure-Admin müssen Sie kein Linux-Experte sein. Polycrate kapselt die Linux-/Container-Seite in Dockerfile.poly. Sie arbeiten hauptsächlich mit YAML (Ansible-Playbooks, workspace.poly, block.poly) und führen Aktionen mit einfachen Befehlen wie:

polycrate run entra-id-mgmt users

Die Container-Laufzeit kümmert sich um Python, Ansible, azure.azcollection und alle Abhängigkeiten.

Was passiert, wenn Microsoft an den APIs oder Modulen etwas ändert?

Weil Ihre Automatisierung:

  • Im Container läuft und
  • azure.azcollection mit einer konkreten Version in requirements.yml gepinnt ist,

haben Sie einen stabilen Stand. Updates passieren kontrolliert:

  1. Sie passen die Collection-Version im Branch an.
  2. Sie bauen das neue Container-Image.
  3. Sie testen in einem Test-Tenant.
  4. Erst dann wird in Produktion gemerged.

So vermeiden Sie Überraschungen bei spontanen Modul- oder API-Änderungen.

Wie passt Polycrate in unsere bestehende Azure- und AD-Landschaft?

Polycrate ersetzt weder Ihr AD noch Azure selbst. Es ist die Schicht darüber, die:

  • Ansible-Playbooks strukturiert (Block-Modell statt Playbook-Wildwuchs).
  • Eine einheitliche Toolchain liefert (Container statt manueller Setups).
  • Secrets handhabbar und verschlüsselt macht.
  • Actions und Workflows bereitstellt, die auch Kolleg:innen ohne tiefes Ansible-Wissen ausführen können.

Sie können Polycrate schrittweise einführen – z.B. zunächst nur für Entra-ID-User-Management, später für weitere Azure- oder On-Prem-Aufgaben.

Weitere Fragen? Siehe unsere FAQ


Compliance in der Praxis

In diesem Beitrag haben Sie gesehen, wie Sie Entra ID mit Ansible und Polycrate strukturiert automatisieren:

  • Benutzer, Gruppen und App-Registrierungen werden als Code beschrieben und wiederholbar angewendet.
  • Die azure.azcollection läuft in einem klar definierten Container, der das klassische Dependency-Problem von Ansible auflöst.
  • Zugangsdaten Ihres Service Principals liegen verschlüsselt im Workspace, ohne dass zusätzliche Secret-Manager-Infrastruktur nötig ist.
  • Conditional Access Policies lassen sich regelmäßig auslesen und als JSON im Repository dokumentieren – eine solide Basis für Audits und Sicherheitsreviews.
  • Git wird zu Ihrem Audit-Trail: Pull-Requests, Reviews und die Commit-Historie machen Änderungen an Ihrer Identitätslandschaft nachvollziehbar.

Bei ayedo kombinieren wir genau diese Bausteine regelmäßig in Kundenprojekten: Polycrate-Workspaces, Ansible-Playbooks mit azure.azcollection, verschlüsselte Secrets und Git-basierte Prozesse. Für Windows- und Azure-Teams entsteht so ein Werkzeugkasten, mit dem sie eigenständig und sicher ihr Entra-ID-Management modernisieren können – ohne sich erst durch die komplette Cloud-Native-Welt kämpfen zu müssen.

Wenn Sie Ihre bestehende Entra-ID-Landschaft aufnehmen, automatisieren und gleichzeitig Compliance-Anforderungen sauber adressieren möchten, unterstützen wir Sie dabei in einem fokussierten Azure-Automatisierungs-Workshop – mit Ihrem Tenant, Ihren Richtlinien und Ihren Tools.

Azure-Automatisierung Workshop

Ähnliche Artikel