DefaultAzureCredential lokal statt Verbindungszeichenfolgen

DefaultAzureCredential lokal statt Verbindungszeichenfolgen

- Matt

Eine Verbindungszeichenfolge mit Kontoschlüssel im Klartext ist die bequemste und die unangenehmste Art, lokal an einen Azure-Dienst zu kommen. Bequem, weil sie sofort funktioniert. Unangenehm, weil sie irgendwann in einer appsettings-Datei landet, dann versehentlich im Repository, und weil ihr nie ansieht, wer sie schon einmal kopiert hat. Zugangsdaten aus dem Repository herauszuhalten hatte ich schon einmal mit User Secrets beschrieben. Der Schlüssel selbst bleibt dabei aber ein Schlüssel. Angenehmer ist, lokal gar keinen zu haben.

Die Kette

DefaultAzureCredential aus dem Paket Azure.Identity ist eine vorkonfigurierte Kette von Anmeldearten. Sie probiert der Reihe nach durch, bis eine ein Token liefert: Umgebungsvariablen, Workload Identity, Managed Identity, Visual Studio, Visual Studio Code, Azure CLI, Azure PowerShell, Azure Developer CLI und zuletzt der Browser. Der Reiz ist, dass derselbe Code lokal und in Azure funktioniert. Auf meinem Rechner greift die Anmeldung aus Visual Studio oder aus az login, in der Cloud die Managed Identity des App Service.

var client = new BlobServiceClient(
    new Uri($"https://{konto}.blob.core.windows.net"),
    new DefaultAzureCredential());

Kein Schlüssel, keine Verbindungszeichenfolge, nur der Endpunkt. Der Dienst muss mich stattdessen als Benutzer kennen, also braucht mein Konto die passende Rolle, etwa Storage Blob Data Contributor. Das ist der eigentliche Umbau: weg vom Schlüssel, hin zur Rollenzuweisung.

Wo es hakt

Genau hier habe ich Zeit verloren. Der erste Aufruf lief lokal mehrere Sekunden, bevor überhaupt etwas passierte. Grund war, dass Managed Identity in der Kette vor der Azure CLI steht und auf meinem Rechner erst in einen Timeout laufen muss, bevor die nächste Anmeldeart drankommt. Sichtbar wird das nur, wenn man das Protokoll über einen AzureEventSourceListener mitschreibt. Ohne das rätselt man, warum ein leerer Aufruf hängt.

Die Lösung ist, die Kette lokal zu kürzen. Über die Umgebungsvariable AZURE_TOKEN_CREDENTIALS lässt sich seit Azure.Identity 1.15 eine einzelne Anmeldeart erzwingen, etwa AzureCliCredential, oder mit dem Wert dev alles Serverseitige ausschließen. Alternativ setzt man die Exclude-Eigenschaften in den DefaultAzureCredentialOptions.

Was es kostet

Umsonst ist der Komfort nicht. Die Kette verschleiert, welche Anmeldeart am Ende greift, und beim Fehlersuchen ist das lästig. In Produktion sollte deshalb nicht DefaultAzureCredential stehen, sondern die konkrete Klasse, also ManagedIdentityCredential. Sonst hängt das Verhalten der Anwendung an Umgebungsvariablen, die jemand global auf dem Host gesetzt haben könnte, und niemand rechnet damit. Lokal nehme ich die Kette gern, deployt lieber die eindeutige Variante.