In einem meiner letzten Azure Deployments bin ich über einen komischen Fehler gestoßen. Das Deployment nutzt Deployment Scripts, um während des Deployments Anpassungen in einer SQL Datenbank zu machen. Damit das sauber funktioniert wird das Deployment-Skipt im Scope einer Managed Identity ausgeführt und nutzt die Azure PowerShell Modules.
Der PowerShell-Code sieht in etwa so aus:
$connectionString = "Server=sql-my-awesome-azure-sql-server.database.windows.net;Database=sqldb-awesome"
$sqlAccessToken = (Get-AzAccessToken -ResourceUrl $tokenResourceUrl).Token
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString)
$connection.AccessToken = $sqlAccessToken
try {
$connection.Open()
# ... do sql stuff ...
}
finally {
$connection.Close()
}
So weit so gut. Ist eigentlich ein gewöhnliches Setup. Das Deployment lief bisher immer. Doch plötzlich kam es zu diesem Fehler:
System.Management.Automation.MethodInvocationException: Exception calling "Open" with "0" argument(s): "Login failed for user '<token-identified principal>'."
-> System.Data.SqlClient.SqlException (0x80131904): Login failed for user '<token-identified principal>'
Nach einigen Tests in verschiedenen Umgebungen und Azure Regionen hat sich für mich herausgestellt, dass der Fehler sehr sporadisch auftritt. Ich teste gerne in der Region Poland Central. Hier gab es den Fehler nicht. In Germany West Central hingegen schon.
Nochmal einige Tests später habe ich das Problem gefunden. In einigen Regionen wurde das Deployment-Skript mit den Az PowerShell Modules in Version 12 ausgeführt, in anderen Region mit der Version 14. Warum das so ist konnte ich nicht herausfinden. Es könnte aber sein, dass Microsoft ein Update für Deployment Scripts ausrollt.
Und hier kommt die Krux an der Sache!
Microsoft hat mit der Version 14 der Az PowerShell Modules die Funktion Get-AzAccessToken
angepasst. Im Vergleich zur Version 12 gibt die Funktion im Token
-Feld nun keinen einfachen String zurück, sondern ein SecureString-Objekt.
In der Dokumentation gibt es dazu diese Info:

Damit mein Code funktioniert, brauche ich einen ganz normalen Access Token String. Also habe ich meinen Code um eine kleine Typenprüfung erweitert. Falls der Typ meines Token-Objekts ein System.Security.SecureString
-Objekt ist, wird kurzerhand wieder ein normaler String
daraus gemacht:
if ($sqlAccessToken -is [System.Security.SecureString]) {
$sqlAccessToken = ConvertFrom-SecureString -SecureString $sqlAccessToken -AsPlainText
}
Der Code aus meinem Beispiel sieht damit wie folgt aus:
1$connectionString = "Server=sql-my-awesome-azure-sql-server.database.windows.net;Database=sqldb-awesome"
2$sqlAccessToken = (Get-AzAccessToken -ResourceUrl $tokenResourceUrl).Token
3
4if ($sqlAccessToken -is [System.Security.SecureString]) {
5 $sqlAccessToken = ConvertFrom-SecureString -SecureString $sqlAccessToken -AsPlainText
6}
7
8$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString)
9$connection.AccessToken = $sqlAccessToken
10
11try {
12 $connection.Open()
13 # ... do sql stuff ...
14}
15finally {
16 $connection.Close()
17}
Fazit
Die Umstellung von Get-AzAccessToken
auf die Rückgabe eines SecureString
-Objekts kann in bestehenden Deployment Scripts zu unerwarteten Fehlern führen. Mit einer einfachen Typprüfung und Konvertierung lässt sich das Problem jedoch schnell beheben.