Using pipeline identity for Connect-AzureAD, Graph and other endpoints

Azure Pipelines and Azure Functions (and Automation Accounts) can have managed identities, in other words, a service principal. This service principal can be assigned to Azure AD roles (e.g. to modify users / devices) or graph / Azure RM resources. A service principal could even be a global admin, and Service Principals don’t have to do MFA…. 🙂

In both Pipelines and Functions the new Az module is enabled and logged into your tenant by default as the service principal, how cool would it be to use that identity to do those (hopefully few) things that are still only supported by e.g. the AzureAD module?

Here’s an example on getting tokens for Azure AD and for Graph, obviously you could also get tokens for other audiences the same way:

$context = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
$graphToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, "https://graph.microsoft.com").AccessToken
$aadToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, "https://graph.windows.net").AccessToken

Write-Output "Hi I'm $($context.Account.Id)"

Connect-AzureAD -AadAccessToken $aadToken -AccountId $context.Account.Id -TenantId $context.tenant.id

get-azureaduser -Top 5

If you want to do this from an old fashioned Azure Runbook (please move to functions!) then you’ll have to log in to Az first:

try
{
    $servicePrincipalConnection = Get-AutomationConnection -Name "AzureRunAsConnection"
    Connect-AzAccount -Tenant $servicePrincipalConnection.TenantID `
        -ApplicationId $servicePrincipalConnection.ApplicationID   `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint `
        -ServicePrincipal
}catch {
    Write-Error -Message $_.Exception
    throw $_.Exception
}

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

16 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Andreas
Andreas
5 years ago

Thank you for providing this info. Works pretty well.

What I’m trying to achieve is, connecting to ExchangeOnline with a Bearer-Token.

The thing is, there’s a token generated by my second commandline. But then, with the command New-PSSession I get the message, I’m not authorized.

If I catch with Fiddler the token generated by the command Connect-ExchangeOnline and insert it into $exoToken, I can connect with the following code.

Any idea how I make this code work?

$context = Get-AzContext
    
# Build the auth information
$exoToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, "https://outlook.office365.com").AccessToken
$Authorization = "Bearer {0}" -f $exoToken

$UserId = $context.Account.Id
    
# create the "basic" token to send to O365 EXO
$Password = ConvertTo-SecureString -AsPlainText $Authorization -Force
$Credtoken = New-Object System.Management.Automation.PSCredential -ArgumentList $UserId, $Password
    
# Create and import the session
$Session = New-PSSession -Name EXO -ConfigurationName Microsoft.Exchange -ConnectionUri 'https://outlook.office365.com/PowerShell-LiveId?BasicAuthToOAuthConversion=true' -Credential $Credtoken -Authentication Basic -AllowRedirection -ErrorAction Stop
Import-Module (Import-PSSession $Session -AllowClobber) -Global -WarningAction 'SilentlyContinue'
Ivan Ignatiev
5 years ago

Hi Jos,

It seems you have forgot the parameter:

-MsAccessToken $graphToken

in your

Connect-AzureAD

to fully authenticate in AzureAD

some command does not work without this

Vishnu
Vishnu
5 years ago

Hi Jos,

I am following the same process did the following :

created the SPN
Added the Graph Permissions for create Group and Group readwrite
Acquired the token also during the process.
When it tried to connect it throws out the error.
]Error occurred while executing GetUsers
Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.

Permissions on Graph:

Group.Create
Group.Read.All
User.Read
Application.ReadWrite.Owned
Directory.Read.All

all are admin consent for the tenant

Any advice would be great as i can run the same script from the local it works.From the pipeline it throws the Error as i did created the SPN access on subscription to “Contributor” also.

The SPN is set manually targeting the TennatID and Client secret. The connection is verified also.

Thanking you
Vishnu

Last edited 5 years ago by Vishnu
frasier
frasier
5 years ago

Hi Jos,

Thank you for this!
This appears to work for almost all the AzureAD cmdlets but today I stumbled across one that didn’t work.

New-AzureADMSInvitation

Would you have any idea on why this command would not work using the above authentication approach?
Any thoughts on this would be appreciated.

The error I’m getting is Object reference not set to an instance of an object.

Last edited 5 years ago by frasier
Lindy
Lindy
4 years ago

Hi. Thanks for your approach with example script.
I am trying to apply the same concept in order to apply it on Connect-MsolService, so it should be something like the script below,

$context = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
$graphToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, “https://graph.microsoft.com”).AccessToken
$aadToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, “https://graph.windows.net”).AccessToken
 
Write-Output “Hi I’m $($context.Account.Id)

Connect-MsolService -AdGraphAccessToken $aadToken -MsGraphAccessToken $graphToken

However, I got the error: Connect-MsolService: IDX10703: Unable to decode the ‘header’: ‘eyJ0e….<the jwt token>’.

Have everyone tried to Connect-MsolService in this way?
Anny idea how to make this work?

Thanks a million, any help appreciated.

Henrique
Henrique
4 years ago

Hi Jos,

Thanks for this post.

I’ve been trying to use this to login to graph and do some Intune automation but when I see the tokens that are generated I don’t get anything from DeviceManagementManagedDevices permissions

Is there a way to point to an ApplicationID on this process or anything that can help me authenticate with Delegated permissions without creating App Secrets?