azurepowershellazure-devopscicdazure-bicep

What is the object properties for Get-AzAccessToken and its Token?


I have a script executed as bicep DeploymentScript in Azure DevOps. It executes Azure SQL Server commands and has worked up until the breaking changes made by Microsoft 5th June this year.

TLDR: The scripts below use the new MS Graph syntax for the June 5th breaking changes.

NOTE: I've tried both $token and $secureToken and neither worked.

The DeploymentScript commands is:

resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
  name: sqlAdminUmiName
}

var sqlServerHostname = environment().suffixes.sqlServerHostname
var tokenResourceUrl = 'https://${substring(sqlServerHostname, 1)}'
      
resource deploymentScriptServerGroupAssignment 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
  name: name
  location: location
  kind: 'AzurePowerShell'
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${identity.id}': {}
    }
  }
  properties: {
    azPowerShellVersion: '8.3'
    arguments: '-dbHost "${dbHost}" -tokenResourceUrl "${tokenResourceUrl}" -dbName "${dbName}" -fxaName "${fxaName}" '
    scriptContent: '''
      param(
        [string] $dbHost,
        [string] $tokenResourceUrl,
        [string] $dbName,
        [string] $fxaName,
        [string] $dbRoleNames
      )
      
      echo "Step 0: about to Install-Module Microsoft.Graph -Force"
      Install-Module -Name SqlServer -Force
      Import-Module -Name SqlServer
      $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token
      echo "Step 1: token - $token"

      $secureToken = ConvertTo-SecureString $token -AsPlainText -Force
      echo "Step 2: secureToken - $secureToken"
      
      
      $query = @()
      $query += "DROP USER IF EXISTS `"$fxaName`""
      $query += "CREATE USER `"$fxaName`" FROM external provider"
      $query += "ALTER ROLE db_owner ADD MEMBER `"$fxaName`""
      $query += "ALTER ROLE db_datareader ADD MEMBER `"$fxaName`""
      $query += "ALTER ROLE db_datawriter ADD MEMBER `"$fxaName`""
      $query += "ALTER ROLE db_ddladmin ADD MEMBER `"$fxaName`""

      $query = $query -join ";"
      Invoke-Sqlcmd -ServerInstance $dbHost -Database $dbName -AccessToken "$secureToken" -Query $query
    '''
    retentionInterval: 'PT1H'
    cleanupPreference: 'OnSuccess'
    forceUpdateTag: currentTime
  }
}

The Error in the Deployment plan in Azure portal is:

Microsoft.Data.SqlClient.SqlException (0x80131904): Login failed for user '<token-identified principal>'.

and

Microsoft.SqlTools.ServiceLayer.BatchParser.BatchParserException: Incorrect syntax was encountered while parsing

I asked a similar question this week for PowerShell execution and the recent MS Graph breaking changes per here

The both the older version of my code with the breaking change, and the syntax that worked for the previous question both still given the same errors. For reference, the new syntax I'm using is:

  $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token

I have another script which has the same line and is not working (same type of Bicep DeploymentScript wrapper as the one above - sub snippet for conciseness):

  $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token
  echo "Step 1: token - $token"
  
  $secureToken = ConvertTo-SecureString $token -AsPlainText -Force
  echo "Step 2: secureToken - $secureToken"
  
  Write-Host "##vso[task.setvariable variable=dbToken;isOutput=true]$secureToken"
  
  $DeploymentScriptOutputs = @{}
  $DeploymentScriptOutputs['dbAccess'] = $secureToken

It returns the error:

The template output 'dbToken' is not valid: The provided value for the template output 'dbToken' is not valid. Expected a value of type 'String, Uri', but received a value of type 'Object'.

Solution

  • I found a very helpful article that discusses the inability of Invoke-SqlCmd to accept a SecureString object.

    https://github.com/Azure/azure-powershell/issues/25533

    One contributor (dadthiele) share the magic code that solves the question about returned object error not being a string (half points to me!):

    $accessToken = (ConvertFrom-SecureString $token -AsPlainText)
    

    Note the Convert**From**SecureString instead of Convert**To**SecureString

    However, this still does not solve the error on authenticating to Invoke-SqlCmd.

    Microsoft.Data.SqlClient.SqlException (0x80131904): Login failed for user ''.

    To solve that I read the full article and there was the answer already in the above post.

    Instead of getting the token with:

      $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token
    

    it needed this:

      $token = (Get-AzAccessToken -ResourceUrl https://database.windows.net -AsSecureString).Token