SO FUNKTIONIERT ES
TerraProvider in deinem Tenant und deiner Pipeline einrichten.
Was der Engineer, der TerraProvider einrichtet, wissen muss: wie die Anmeldung funktioniert, welche Berechtigungen benötigt werden, wie der erste Plan aussieht und wie ein bestehender Tenant unter Code kommt.
- terraprovider/microsoft365wp
- Terraform and OpenTofu
- 10 Builds
- Version 0.20.2
Dein erster Plan in vier Schritten
Ungefähr so aufwendig wie das Einrichten eines anderen Azure-Providers, denn die Anmeldung funktioniert auf dieselbe Weise.
Eine App in Entra ID registrieren.
Single Tenant, keine Redirect-URI erforderlich. Notiere die Application (Client) ID und die Directory (Tenant) ID.Graph-Berechtigungen erteilen.
Füge die Anwendungsberechtigungen für die Objekte hinzu, die du verwalten möchtest (siehe die Tabelle unten), und erteile die Admin-Zustimmung.Den Provider deklarieren.
SetzeARM_TENANT_IDundARM_CLIENT_IDsowieARM_CLIENT_SECRETfür einen ersten Test. In einer Pipeline verwende stattdessen OpenID Connect (siehe unten).terraform { required_providers { microsoft365wp = { source = "terraprovider/microsoft365wp" } }}provider "microsoft365wp" {}
Planen.
Schreibe eine Ressource, zum Beispiel eine Compliance-Richtlinie, und führeterraform planodertofu planaus. Im Tenant ändert sich nichts, bis du applyst.resource "microsoft365wp_device_compliance_policy" "windows_defender" { display_name = "Windows - Defender for Endpoint" windows10 = { device_threat_protection_enabled = true } scheduled_actions_for_rule = [{ scheduled_action_configurations = [{ action_type = "block" grace_period_hours = 6 }] }] assignments = [{ target = { all_licensed_users = {} } }]}
Beispieldaten.
Die Graph-Berechtigungen, die benötigt werden
Anwendungsberechtigungen, erteilt per Admin-Zustimmung. Erteile nur die Berechtigungen für die Objekte, die du verwaltest; eine Ressource, die hier nicht aufgeführt ist, nennt ihre Berechtigungen auf ihrer Dokumentationsseite.
| Berechtigung | Was sie erlaubt |
|---|---|
| DeviceManagementConfiguration.ReadWrite.All | Intune-Gerätekonfiguration und -Richtlinien |
| DeviceManagementApps.ReadWrite.All | Intune-Apps |
| DeviceManagementServiceConfig.ReadWrite.All | Intune-Dienstkonfiguration, z. B. Enrollment |
| Policy.ReadWrite.ConditionalAccess | Conditional Access-Richtlinien |
| Policy.Read.All | Lesen der Richtlinien deiner Organisation |
| Application.ReadWrite.All | Anwendungen |
| Directory.ReadWrite.All | Verzeichnisdaten |
| Group.ReadWrite.All | Gruppen |
| User.ReadWrite.All | Vollständige Benutzerprofile |
| CloudPC.ReadWrite.All | Windows 365-Konfiguration |
Quelle: Leitfaden des Providers „Configuring a Service Principal for managing EntraID".
Dieselben Anmeldeeinstellungen wie beim azuread-Provider
Der Provider liest dieselben ARM_*-Einstellungen wie der azuread-Provider. Setze ARM_TENANT_ID und ARM_CLIENT_ID, dann wähle eine Methode.
| Methode | Wann sie passt | Aktivieren |
|---|---|---|
| OpenID Connect, GitHub Actions | Workflows ohne gespeichertes Secret | ARM_USE_OIDC=true |
| OpenID Connect, Azure DevOps | Pipelines mit einer Service Connection | ARM_USE_OIDC=trueARM_ADO_PIPELINE_SERVICE_CONNECTION_ID |
| OpenID Connect, beliebiger Issuer | Andere CI-Systeme, die ein ID-Token ausstellen | ARM_USE_OIDC=trueARM_OIDC_TOKEN / ARM_OIDC_TOKEN_FILE_PATH |
| Client-Zertifikat | Runner, die ein Zertifikat besitzen | ARM_CLIENT_CERTIFICATE / ARM_CLIENT_CERTIFICATE_PATH |
| Client Secret | Ein erster Test, ein Lab | ARM_CLIENT_SECRET / ARM_CLIENT_SECRET_FILE_PATH |
| Managed Identity | Runner auf Azure | ARM_USE_MSI=true |
| AKS Workload Identity | Runner auf Kubernetes in Azure | ARM_USE_AKS_WORKLOAD_IDENTITY=true |
| Azure CLI | Dein Laptop | standardmäßig aktiv; ARM_USE_CLI=false deaktiviert es |
Jede Einstellung existiert auch als Provider-Argument (use_oidc, client_certificate_path usw.). Der OpenID-Connect-Leitfaden des Providers zeigt, wie man Entra ID dazu bringt, einem GitHub-Repository zu vertrauen. Kurz zusammengefasst: OpenID Connect (GitHub Actions, Azure DevOps, beliebiges OIDC-Token), Client-Zertifikat, Client Secret, Managed Identity, AKS Workload Identity, Azure CLI.
Vier Clouds
Setze environment oder ARM_ENVIRONMENT. Der Provider kommuniziert dann mit dem Microsoft Graph-Endpunkt der jeweiligen Cloud: global, US Government L4, US Government L5 (DoD), China.
Environment
- global (auch public)
- Die kommerzielle Cloud, der Standard
- usgovernmentl4 (auch usgovernment)
- US Government L4
- usgovernmentl5 (auch dod)
- US Government L5 (DoD)
- china
- Microsofts Cloud in China
- Eigener Endpunkt
metadata_hostoderARM_METADATA_HOSTNAME
Was der Plan beobachtet
- Collections, die du weglässt, werden standardmäßig als leer behandelt, sodass ein hinzugefügtes Mitglied, eine Ausnahme oder eine App sichtbar wird.
- Eine neue Conditional Access-Richtlinie ohne Status wird als
enabledForReportingButNotEnforcederstellt. - Der Standardwert jedes Attributs steht auf der Dokumentationsseite der Ressource, gekennzeichnet als Provider-Standard.
Die Kehrseite: Eine Einstellung, die jemand in einem Portal ein- und wieder ausgeschaltet hat, kann als false statt als nicht gesetzt zurückkommen und erscheint einmalig als Änderung. Ein Apply behebt das.
Im Portal: Keine Änderungen seit dem letzten Apply.
microsoft365wp_conditional_access_policy.require_mfa_admins: Refreshing state... [id=2b7f9c3e-8d41-4f6a-b0e2-5c9a1d7e3f80]No changes. Your infrastructure matches the configuration.
resource "microsoft365wp_conditional_access_policy" "require_mfa_admins" { display_name = "Require MFA for admins" state = "enabled" conditions = { users = { include_roles = ["62e90394-69f5-4237-9190-012177145e10"] } applications = { include_applications = ["All"] } } grant_controls = { operator = "OR" built_in_controls = ["mfa"] }}
Einen bestehenden Tenant in zwei Phasen exportieren und importieren
Das Quickstart-Repository enthält eine Referenzkonfiguration mit Modulen, GitHub Actions-Workflows und einem PowerShell-Export. Der Export läuft in zwei Phasen ab, weil Richtlinien auf Gruppen und Filter verweisen.
Gruppen, Filter und Benachrichtigungsvorlagen exportieren.
Sie werden in die Module des Quickstarts geschrieben, mit einer Mapping-Datei pro Typ. Mail-aktivierte Gruppen werden ausgelassen, sofern du sie nicht explizit anforderst.Importieren.
Das Tool ruft Terraform oder OpenTofu auf, um jedes exportierte Objekt in den State zu importieren.Compliance- und Konfigurationsrichtlinien exportieren.
Settings-Catalog- und Endpoint-Security-Richtlinien gelten als Konfigurationsrichtlinien. Jeder Export enthält außerdem einen rohen JSON-Dump dessen, was Graph zurückgegeben hat.Importieren.
Dasselbe Tool, zweite Phase.Planen.
Der Plan zeigt, was noch abweicht. Nicht jedes Attribut lässt sich exportieren, daher ist vor dem ersten sauberen Plan eine kurze Nacharbeit zu erwarten.
Ein Objekt nach dem anderen
Für alles, was der Export nicht abdeckt, schreibt ein kleines Skript eine Terraform-Datei für ein einzelnes Objekt eines beliebigen Ressourcentyps, gegeben dessen id. Es verwendet Terraforms eigene Konfigurationsgenerierung, sodass die Datei genau das enthält, was der Provider selbst aus dem Tenant liest.
Der Quickstart auf GitHubEine Ressource enthält die App, ihr Paket und ihre Zuweisungen
microsoft365wp_mobile_app deckt 21 App-Typen ab. Bei .intunewin, MSI, APPX/MSIX, DMG, PKG Paketen verschlüsselt der Provider die Datei und lädt sie in Intune hoch, und zwar erneut nur dann, wenn sich source_sha256 ändert. Zuweisungen liegen in derselben Ressource: alle Geräte, alle lizenzierten Benutzer, eine Gruppe oder eine Ausschlussgruppe, jeweils mit einem Include- oder Exclude-Filter.locals { agent_package = "${path.module}/packages/contoso-agent-4.2.1.intunewin" agent_meta = provider::microsoft365wp::parse_intunewin_metadata(local.agent_package)}resource "microsoft365wp_mobile_app" "contoso_agent" { display_name = "Contoso Agent" publisher = "Contoso" win32_lob = { file_name = local.agent_meta.file_name setup_file_path = local.agent_meta.setup_file install_command_line = "setup.exe /quiet" uninstall_command_line = "setup.exe /uninstall /quiet" detection_rules = [{ filesystem = { detection_type = "exists" path = "C:\\Program Files\\Contoso\\Agent" file_or_folder_name = "agent.exe" } }] source_file = local.agent_package source_sha256 = filesha256(local.agent_package) } assignments = [{ target = { group = { group_id = "3d9b2f61-7a4e-4c18-9e05-6f2a8b1c4d93" } } settings = { win32_lob = {} } }]}
microsoft365wp_mobile_app.contoso_agent: Refreshing state... [id=5e0c8a17-2d94-4b6f-a3e1-9c7d0f2b8a46]No changes. Your infrastructure matches the configuration.
# microsoft365wp_mobile_app.contoso_agent will be updated in-place ~ resource "microsoft365wp_mobile_app" "contoso_agent" { ~ win32_lob = { ~ source_file = "./packages/contoso-agent-4.2.1.intunewin" -> "./packages/contoso-agent-4.3.0.intunewin" ~ source_sha256 = "9f2c41d0…" -> "b71e05aa…" # (6 unchanged attributes hidden) } # (4 unchanged attributes hidden) }Plan: 0 to add, 1 to change, 0 to destroy.
Beispieldaten.
Windows
Win32 (.intunewin), MSI, APPX/MSIX, Microsoft Store (neu, über WinGet), Microsoft Store (Legacy), Microsoft Edge, Microsoft 365 Apps, Weblinks.
macOS
DMG, PKG, Microsoft Edge, Microsoft Defender, Microsoft 365 Apps, Web-Clips.
iOS und iPadOS
App-Store-Apps, verwaltete iOS-Store-Apps, Web-Clips.
Android
Google-Play-Store-Apps, verwaltete Google-Play-Apps, verwaltete Android-Store-Apps.
Jede Plattform
Weblinks.
Mehrere Tenants aus einem Repository
tenant_id, schreibst die Baseline als Modul und rufst es einmal pro Tenant auf. Jeder Block meldet sich eigenständig an, sodass jeder Tenant sein eigenes Service Principal mit eigenen Berechtigungen haben kann.- Unterschiede zwischen Tenants sind Modulvariablen und im Review sichtbar.
- Ein neuer Tenant bedeutet einen Provider-Block, einen Modulaufruf und einen Plan.
provider "microsoft365wp" { alias = "contoso" tenant_id = "8a1f3c2e-5b7d-4e90-a6c4-2d9e7f1b0c35"}provider "microsoft365wp" { alias = "fabrikam" tenant_id = "e4c27b91-0d3a-4f86-b5e2-7a1c9d0f6b48"}module "baseline_contoso" { source = "./baseline" providers = { microsoft365wp = microsoft365wp.contoso }}module "baseline_fabrikam" { source = "./baseline" providers = { microsoft365wp = microsoft365wp.fabrikam } allow_byod = true}
Beispieldaten.
Wie Graph-Throttling behandelt wird
Microsoft Graph begrenzt die Anzahl der Anfragen, die ein Client senden darf, und ein Plan über einen großen Tenant sendet viele. Der Provider wartet und wiederholt die Anfragen selbstständig.
Wiederholungen
- Wiederholungen pro Anfrage
- bis zu 10
- Wartezeit zwischen Wiederholungen
- 3 bis 60 Sekunden
- Retry-After von null
- Auf das Backoff-Intervall ausgedehnt, weil Graph häufig so antwortet und ein sofortiger Wiederholungsversuch selten hilft
Mit dem Quickstart anfangen.
Klone ihn, richte ihn auf einen Test-Tenant aus und führe einen Plan aus. Die Community Edition ist für Organisationen mit bis zu 99 Benutzern kostenlos.