microsoft / azure-pipelines-tasks

Tasks for Azure Pipelines
https://aka.ms/tfbuild
MIT License
3.49k stars 2.61k forks source link

Authenticate Azure Powershell task against Azure DevOps REST API #9604

Closed Jokab closed 5 years ago

Jokab commented 5 years ago

Hello,

My requirement is that for my Azure devops release pipeline I want to tag a specific commit with an annotated tag which contains the build number and the date (which is auto-set on an annotated tag).

Proposed solution

My solution to this is to use a the Azure Powershell pipeline task, the one shown here: enter image description here

The task (ignore what's in the script box right now) will use the Azure Subscription that I have set in order to authenticate towards the Azure DevOps REST API. I have successfully been able to perform the task I want using a personal access token (PAT) but this is not stable long-term for a whole team and I want to use our Azure Subscription.

The problem

My problem is that I'm not sure how to use the authentication of the Azure Subscription correctly. I seem to get some data using Get-AzureRmContext (see current code below) and then I found a GitHub issue which seems to do sort of the same thing. The code gets some kind of OAuth token but using the code below, Azure still returns to me that I need to sign in, so I assume it's not the correct token. I don't understand how things hatch into each other.

Note that my subscription should have all the permissions it needs to do what I want.

Code so far:

Function Get-AccessToken($tenantId) {
    $cache = [Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache]::DefaultShared
    $cacheItem = $cache.ReadItems() | Where-Object { $_.TenantId -eq $tenantId } | Select-Object -First 1
    return $cacheItem.AccessToken
}

$context = Get-AzureRmContext
$uri = "https://dev.azure.com/<my_org>/<my_area>/_apis/git/repositories/<project_sha>/annotatedtags?api-version=5.0-preview.1"
$token = Get-AccessToken $context.tenantID

$body = @"
{
    "taggedObject": {
        "objectId": "$(BUILD.SOURCEVERSION)"
    },
    "name": "D-$(Build.BuildNumber)",
    "message": "dummy"
}
"@
$header = @{"Authorization" = "Bearer" + $token}

Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Body $body -Headers $header

Any help is greatly appreciated!

JohannesDrexler commented 5 years ago

The buildpipeline has a setting called 'Allow scripts to use OAuth token' on phase-level. If this is checked the build expose a token (secret variable 'system.accesstoken') that can be used to authenticate against DevOpsApi.

You might need to give the build-service account (which exposes the token) contribute rights on the git repo. as far as i know the buildservice account only has "read" on most resources in devops

Jokab commented 5 years ago

The buildpipeline has a setting called 'Allow scripts to use OAuth token' on phase-level. If this is checked the build expose a token (secret variable 'system.accesstoken') that can be used to authenticate against DevOpsApi.

You might need to give the build-service account (which exposes the token) contribute rights on the git repo. as far as i know the buildservice account only has "read" on most resources in devops

Thanks, it worked. That was way simpler than what I tried...