5
votes

I have a VSTS project connected via a Service Principal to an Azure subscription through an Azure Resource Manager endpoint. This works fine for my builds that configure ARM resources via templated, parameter driven deployments.

I have an additional requirement to set up Azure AD groups as part of the build. I have a script that works fine from my local machine. When I deployed it via the build and it executed on the hosted build controller, the script could initially not find the AzureAD module. I got around this by including the script in git Repo and accessing it through:

$adModulePath = $PSScriptRoot + "\PsModules\AzureAD\2.0.0.131\AzureAD.psd1"
Import-Module $adModulePath 

However, I now have another problem when it comes to running New-AzureADGroup. The script requires Connect-AzureAD to be run before the command is issued. This works fine by hardcoding a credential but I don't want to do this, I want it to run under the context of the SPN created, which is running the scripts on the hosted build controller.

So, the question is, can I get the current context of the Azure PowerShell execution SPN and pass that to Connect-AzureAD to avoid storing credential in plain text? Am I missing a trick? Are there any alternatives?

My current code is as below, the commented connection works fine from the command like with hard coded values. The call with no parameters presents the login UI which terminates the build since it is obviously not interactive.

## Login to Azure
#$SecurePassword = ConvertTo-SecureString $AdminPassword -AsPlainText -Force
#$AdminCredential = New-Object System.Management.Automation.PSCredential ($AdminUserEmailAddress, $SecurePassword)
#Connect-AzureAD -Credential $AdminCredential

Connect-AzureAD

Write-Output "------------------ Start: Group Creation ------------------"

$TestForAdminGroup = Get-AzureADGroup -SearchString $AdminGroup
$TestForContributorGroup = Get-AzureADGroup -SearchString $ContributorGroup
$TestForReaderGroup = Get-AzureADGroup -SearchString $ReaderGroup

Thanks

3
No, you need to call Connect-AzureAD with credential script, you can store the credential in secret variable (click the lock icon, it is hardcoding)starian chen-MSFT
Thanks - that is an option, I was hoping there would be a better way.Murray Foxcroft
The Connect-AzureAD is required too if do it manually in local machine. I tried to use principal key and ID to generate credential, but can't be used for Connect-AzureAD. Do you have a way to do it with principal key and ID?starian chen-MSFT
No, unfortunately not. I appreciate that Azure AD is independent of an Azure subscription but it would be good if the Poweshell modules could share the same context. It's no biggie but now I have to manage two sets of credentials to run my azure builds for a single subscription.Murray Foxcroft

3 Answers

8
votes

This is possible. Got it working today for my own VSTS extension that I released a while ago. My extension is using a Azure Resource Manager endpoint as input.

Running it now on a Microsoft Hosted Visual Studio 2017 agent pool using the below code. See for more information my post on how to use AzureAD PowerShell cmdlets on VSTS agent.

Write-Verbose "Import AzureAD module because is not on default VSTS agent"
$azureAdModulePath = $PSScriptRoot + "\AzureAD\2.0.1.16\AzureAD.psd1"
Import-Module $azureAdModulePath 

# Workaround to use AzureAD in this task. Get an access token and call Connect-AzureAD
$serviceNameInput = Get-VstsInput -Name ConnectedServiceNameSelector -Require
$serviceName = Get-VstsInput -Name $serviceNameInput -Require
$endPointRM = Get-VstsEndpoint -Name $serviceName -Require

$clientId = $endPointRM.Auth.Parameters.ServicePrincipalId
$clientSecret = $endPointRM.Auth.Parameters.ServicePrincipalKey
$tenantId = $endPointRM.Auth.Parameters.TenantId

$adTokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/token"
$resource = "https://graph.windows.net/"

$body = @{
    grant_type    = "client_credentials"
    client_id     = $clientId
    client_secret = $clientSecret
    resource      = $resource
}

$response = Invoke-RestMethod -Method 'Post' -Uri $adTokenUrl -ContentType "application/x-www-form-urlencoded" -Body $body
$token = $response.access_token

Write-Verbose "Login to AzureAD with same application as endpoint"
Connect-AzureAD -AadAccessToken $token -AccountId $clientId -TenantId $tenantId
2
votes

To conclude, the Powershell module can’t share the same context and you need to store the credential in secret variable in VSTS.

-2
votes

To take this further, it is possible to use the Service Principal by following example 3 here:

https://docs.microsoft.com/en-us/powershell/module/azuread/connect-azuread?view=azureadps-2.0

Once you have created a self-signed cert and attached it, you can connect to the Azure AD by passing in the thumbprint of the cert along with a couple of other parameters:

Connect-AzureAD -TenantId $tenantId -ApplicationId $sp.AppId -CertificateThumbprint $thumb