Anmelden am Azure Resource Manager mit Zertifikat

Im alten Azure Portal gab es ja die Möglichkeit, sich ein Management-Zertifikat herunterzuladen und dieses für Logins zum Beispiel in PowerShell zu nutzen (.publishsettings hieß das Zauberwort). Mit dem Azure Resource Manager und dem neuen Azure Portal ist das nicht mehr möglich, hier kommt eine alternative Anmeldemöglichkeit über einen sogenannten "ServicePrincipal" ins Spiel, und so einen wollen wir hier mal anlegen, um uns künftig auch von PowerShell aus per Zertifikat anmelden zu können.

Mit dem Azure Resource Manager können wir Benutzer oder Gruppen, oder eben auch Applikationen oder Skripten Rechte an Ressourcen zuweisen. Hierzu müssen wir eine Identität erzeugen und dafür sorgen, dass sich die App mit den Credentials dieser Identität authentifiziert. In unserem Fall wäre die App quasi PowerShell, und die Identität eben der genannte ServicePrincipal.

Das Gute an diesem Prinzip ist, dass wir diesem "ServicePrincipal" (also dem Skript oder der Shell) ganz genau Rechte zuweisen können an Subscriptions, Ressourcengruppen oder Ressourcen, basierend auf RBAC, und auch das schauen wir uns an.

Wir brauchen für unser Vorhaben 3 Zutaten:

  • ein Zertifikat
  • eine ApplicationID für den ServicePrincipal, und
  •  notwendige Berechtigungen.

Fangen wir mal mit ein paar Voraussetzungen an…

Voraussetzungen

Applikationsregistrierungen können unter Umständen nur vom Tenant-Admin angelegt werden. Im Portal findet man diese Einstellung wie folgt:

  • Azure Active Directory wählen
  • User Settings
  • App Registrations

Ist diese Einstellung auf "No", dann kann nur ein Admin eine Applikation registrieren, und wenn wir keiner sind, dann müssen wir betteln gehen (ich mein natürlich, einen Change Request stellen und begründen). Nehmen wir mal an, wir dürfen oder wir sind sogar Admin, dann können wir weitermachen.

Zutat 1: Das Zertifikat

Wir brauchen ein Zertifikat, am einfachsten ein selbstsigniertes, es gehen aber auch offizielle. Auch hier der Einfachheit halber (wir wollen hier ja kein PKI Tutorial draus machen) erzeugen wir ein selbstsigniertes (selfsigned) Zertifikat. Als Profils machen wir das direkt in PowerShell:

[code gutter="false"]
$cert = New-SelfSignedCertificate -CertStoreLocation "cert:\CurrentUser\My" -Subject "CN=myServicePrincipalCert" -KeySpec KeyExchange
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())

Wir haben gerade lokal im Zertifikatsspeicher "My" (oder "Eigene Zertifikate") ein Zertifikat samt Schlüssel erstellt. Das können wir uns übrigens auch anschauen, entweder über den Zertifikatsmanager (certmgr.msc) oder wieder über PowerShell:

[code gutter="false"]
get-childitem -Path "Cert:\CurrentUser\My"

Unsere erste Zutat ist damit erledigt. Weiter geht's:

Zutat 2: Eine ApplicationID

Wie gelernt brauchen wir eine Applikationsregistrierung. Das können wir entweder via Portal oder auch wieder in der PowerShell machen:

[code gutter="false"]
$sp = New-AzureRMADServicePrincipal -DisplayName "myServicePrincipal" -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore

Das verwendet Variablen, die wir beim Anlegen des Zertifikats benutzt haben. Falls ein schon vorhandenes Zertifikat verwendet werden soll, dann müssen die Werte entsprechend ausgelesen werden. Als DisplayName bitte irgendwas Aussagekräftigeres wählen als ich hier, eventuell werden das im Laufe der Zeit ein paar mehr ServicePrincipals, und dann findet man die zum Beispiel wieder mittels:

[code gutter="false"]
Get-AzureADServicePrincipal -SearchString "myServicePrin"

Um Rechte zuweisen zu können, benötigen wir später die ApplicationID. Die bekommen wir mit:

[code gutter="false"]
$appID=$sp.ApplicationID

Zutat 3: Berechtigungen

Erstmal hat die Applikation bzw. der ServicePrincipal keine Rechte. Aber das können wir ändern, natürlich immer vorausgesetzt, wir selber haben die notwendigen Rechte… So detailliert müssen wir RBAC (Role Bases Access Control) hier nicht betrachten, da gibt es eine prima Doku dazu. Wir nehmen uns einfach die aktuelle SubscriptionID (und die Tenant-ID können wir uns auch bei der Gelegenheit gleich merken, die brauchen wir unten noch für's Login).

[code gutter="false"]
Get-AzureRmContext

Noch ein kleiner Hinweis: Zwischen dem Anlegen des ServicePrincipals und der Sichtbarkeit des Selbigen im AAD können ein paar Sekunden vergehen, also lieber mal ne Minute oder so warten. Dann aber geht's ab:

[code gutter="false"]
New-AzureRmRoleAssignment -Scope "/subscriptions/<sub-id>" -RoleDefinitionName Contributor -ServicePrincipalName $appID

So. Jetzt hat die Applikation bzw. der ServicePrinzipal "Contributor"-Rechte auf der Subscription. Soll es ein anderer Scope sein, einfach die entsprechende ResourceID verwenden, zum Beispiel für eine Resourcengruppe:

[code gutter="false"]
Get-AzureRmResourceGroup

Login per Zertifikat

Alle Zutaten wurden gut verrührt und bei 42 Grad gebacken. Dann können wir jetzt probieren. Wir brauchen die folgenden Angaben:

  • Den Thumbprint des Zertifikats
  • Die ApplicationID
  • Die TenantID

Ok, statt einem Passwort brauchen wir jetzt 3 Angaben, und das auch noch recht komplizierte. Wo liegt jetzt nochmal der Vorteil? Nun, diese Angaben bleiben immer gleich, also kein Problem, die in einem Skript zu verwenden. Niemand, der nicht auch gleichzeitig Zugriff auf das Zertifikat (genauer den privaten Schlüssel) hat, kann sich damit anmelden. In der Umkehrung heißt das auch, dass das Login erstmal nur auf dem Computer möglich ist, auf dem das Zertifikat erzeugt wurde. Nach einem Export (mit private Key) und Import auf einem anderen Computer würde es dann auch dort gehen.

Den Thumbprint bekommen wir ganz einfach:

[code gutter="false"]
$Thumbprint = (Get-ChildItem cert:\CurrentUser\My\ | Where-Object {$_.Subject -match "myServicePrincipalCert" }).Thumbprint

Als Subject verwenden wir hier die Angabe bei der Erstellung, siehe oben bei Zutat 1.

Das Login sieht dann so aus:

[code gutter="false"]
Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint <thumbprint> -ApplicationId <appID> -TenantId <TenantID>

Oder mit einem realen Beispiel:

[code gutter="false"]
Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint B007B51B911914E6CA5630137374A08648D02C8F -ApplicationId 919e6448-9c30-4481-ab5f-be29aa9021e4 -TenantId afa16547-9d30-4591-ac6f-be29aa9031e3

Zukünftig könnten wir also einfach beim Starten der PowerShell diese Zeile ausführen, und schon wären wir eingeloggt. Ganz ohne Passwort, denn das Zertifikat befindet sich ja in unserem Zertifikatsspeicher, und mit dem Windows-Login wird auch der Zugriff darauf erst freigegeben. Das heißt aber auch, wer das Zertifikat bekommt (mit dem privaten Schlüssel), und sich die restlichen Angaben beschafft, der kann sich solange anmelden, bis wir die Applikationsregistrierung wieder löschen (oder das Zertifikat abgelaufen ist). Also Aufpassen bei einem eventuellen Kopieren des Zertifikats auf andere Computer!

Microsoft Azure Deutschland

Für Azure Deutschland steht das alte Portal ja nicht mehr zur Verfügung, der hier beschriebene Weg ist damit der einzige (und auch generell der empfohlene) Weg, um sich mit Zertifikat anzumelden. Allerdings benötigt das Login noch zusätzlich die Angabe des Environments. Vollständig sieht das also so aus:

[code gutter="false"]
Login-AzureRmAccount -EnvironmentName "AzureGermanCloud" -ServicePrincipal -CertificateThumbprint <thumbprint> -ApplicationId <appID> -TenantId <TenantID>

Für Azure Deutschland gibt es übrigens hier ein kostenloses Testaccount…

Eine ausführlichere Beschreibung der Möglichkeiten gibt es übrigens bei AzureDocs.