When using Azure Devops functions such as creating a new Repo or starting a pipeline is there any way to authenticate the user without an Access token through Powershell? The only other solution that I found is Azure CLI though I would prefer to Invoke the web API calls.
Actually, indeed you can auth the Azure DevOps REST API without using a PAT(personal access token), but you could not auth it without any access token. Even if you use the user account to auth, essentially it will generate an access token to auth.
For your requirement, if you want to use powershell to auth the REST API, you could use the script below.
Make sure you have installed the Az powershell module, and login with a user account which has the permission in your devops org via Connect-AzAccount.
Here is a sample to start the pipeline with Runs - Run Pipeline. This sample uses the Azure AD access token to auth, please note don't change the 499b84ac-1321-427f-aa17-267ca6975798 in the script, it is the well-known resource id of the DevOps REST API, it works for me.
$token = (Get-AzAccessToken -ResourceUrl "499b84ac-1321-427f-aa17-267ca6975798").Token
$URL = 'https://dev.azure.com/orgname/testpro1/_apis/pipelines/52/runs?api-version=6.0-preview.1'
$header = #{
'Authorization' = 'Bearer ' + $token
'Content-Type' = 'application/json'
}
$body = #"
{
"resources": {
"repositories": {
"self": {
"refName": "refs/heads/main"
}
}
}
}
"#
Invoke-RestMethod -Method Post -Uri $URL -Headers $header -Body $body | ConvertTo-Json
Related
I can connect to MS Graph to get a Bearer token using Powershell but not with a Web Acvtivity in ADFv2 using the same credentials.
I'm getting the TenantId, ApplicationId and ClientSecret from an existing App in Azure.
This is what I'm doing in Powershell - Works
# Authenticate to Microsoft Graph
Write-Host "Authenticating to Microsoft Graph via REST method"
$url = "https://login.microsoftonline.com/$tenantId/oauth2/token"
$resource = "https://graph.microsoft.com/"
$restbody = #{
grant_type = 'client_credentials'
client_id = $applicationID
client_secret = $clientSecret
resource = $resource
}
# Get the return Auth Token
$token = Invoke-RestMethod -Method POST -Uri $url -Body $restbody
Write-Host "Authenticated - token retrieved of type " $($token.token_type)
Result
This is the Web Activity - Fails
Input
{
"url": "https://login.microsoftonline.com/<tenantId>/oauth2/token",
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"body": "grant_type=client_credentials&client_id=\"<applId>\"&client_secret=\"<client_secret>\"&resource=\"https://graph.microsoft.com/\"",
"authentication": {
"type": "MSI",
"resource": "https://graph.microsoft.com/"
}
}
Error
Application with identifier '{appIdentifier}' was not found in the
directory '{tenantName}'. This can happen if the application has not
been installed by the administrator of the tenant or consented to by
any user in the tenant. You may have sent your authentication request
to the wrong tenant.
The error doesn't make sense as it works in powershell.
The difference here is that I'm executing the powershell with my own account and with a System Assigned MI in ADF. What permission am I missing? How do I troubleshoot this?
I tried to reproduce same thing in my environment got below results:
PowerShell with Bearer token :
To resolve the error .Please follow below steps:
Step1: Created AD application added permission as below:
Step2: Create a web activity to get the Access Token from ADF
URL: https://login.microsoftonline.com/<Tenant ID>/oauth2/token
Method : POST
Body: grant_type=client_credentials&client_id=<client_id>&client_secret=<client_secret>&resource=https://graph.microsoft.com/
Header: Content-Type:application/x-www-form-urlencoded
Step3: Create Set variable :
Add dynamic content -> #activity('Web1').output.access_token
Response
In Azure Pipeline Releases, I have one task "Azure PowerShell".
This script will do a deployment of another release. In my code, I use a System.AutenticantionToken: "$AzureDevOpsToken = $env:SYSTEM_ACCESSTOKEN" and my headers for a call rest API is:
$basicAuthValue = "Bearer $AzureDevOpsToken"
$headers = #{
Authorization = $basicAuthValue
}
When I ran this code :
$deploymentBody = #{
status = "inProgress"
} | ConvertTo-Json
$urlDeployment = "https://vsrm.dev.azure.com/$Organization/$ProjectName/_apis/Release/releases/$ReleaseId/environments/$EnvironmentId`?api-version=5.1-preview.6"
$deployment = Invoke-WebRequest -Uri $urlDeployment -Method Patch -ContentType "application/json" -Headers $header -UseBasicParsing -Body $deploymentBody
I received an error:
2022-06-01T14:53:15.4901741Z {"$id":"1","customProperties":{"Descriptor":null,"IdentityDisplayName":null,"Token":null,"RequestedPermissions":0,"NamespaceId":"00000000-0000-0000-0000-000000000000"},"innerException":null,"message":"VS402904: Access denied: User e3b793c5-a512-44b7-a704-878e8adb62e9 does not have manage deployments permission. Contact your release manager.","typeName":"Microsoft.VisualStudio.Services.Security.AccessCheckException, Microsoft.VisualStudio.Services.WebApi","typeKey":"AccessCheckException","errorCode":0,"eventId":3000}
This happened when I use a System.AccessToken.
But when I use a Personal Access Token it goes well. But I don't want to use it because I need to put the password in plain sight in the pipeline. So I want to use a System.AccessToken.
In my pipeline, on the agent pool, I have this check: "Allow scripts to access the OAuth token"
Can you help me?
You do not have to use the password plaintext for the personal access token. You can set a variable lets call it PAT on your pipeline with the value as a secret and then inject this variable on your powershell script.
$connectionToken="$(PAT)"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
Then you have to use as a header
-Headers #{authorization = "Basic $base64AuthInfo"}
VS402904: Access denied: User e3b793c5-a512-44b7-a704-878e8adb62e9 does not have manage deployments permission.
Based on the error message, it means that the service account has no access to manage the deployment.
The variable: $(system.accesstoken) will create a token based on the permissions of the service account: {Project Name} Build Service ({Org Name}).
Refer to this doc: Scoped build identities
To solve this issue, you need to navigate to Piplines -> Release -> Security and grant the Manage Deployments permission to the service account: {Project Name} Build Service ({Org Name}).
For example:
I am trying to run a shellscript program to connect tfs by using tfsapi service.
Jenkins run on logged user but i want to connect tfs with different user (not with windows logged user)
How can i add credential to my powershell code? I use UseDefaultCredentials but need to use different user to connect tfs. how can i do that?
$tfsServerURL = "https://test.tfs.siemens.net/test"
$BuildDefinition = "test.rgs.project"
$URL = "$($tfsServerURL)"
#Get ID of Builddefinition
$buildDefinitionID = (Invoke-RestMethod -Uri ($URL + '/_apis/build/definitions?api-version=2.0&name=' + $BuildDefinition) -Method GET -UseDefaultCredentials).value.id
We can use this official Rest API: Definitions - List to get specific build definition with additional parameter name. And this API supports Oauth2 authentication. However, OAuth 2.0 is not supported on Azure DevOps Server. So we need to use PAT authentication with below least scope: vso.build.
Therefore, if you want to connect tfs with different user using this API, please provide their corresponding PAT, and then below script should work as expected.
$tfsServerURL = "https://test.tfs.siemens.net/test"
$BuildDefinition = "test.rgs.project"
$URL = "$($tfsServerURL)"
$connectionToken="PAT here"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$AzureDevOpsAuthenicationHeader = #{authorization = "Basic $base64AuthInfo"}
#Get ID of Builddefinition
$buildDefinitionID = (Invoke-RestMethod -Uri ($URL + '/_apis/build/definitions?api-version=5.0&name=' + $BuildDefinition) -Method GET -Headers $AzureDevOpsAuthenicationHeader).value[0].id
Write-host $buildDefinitionID
I automate processes for certain colleagues. In one use case, a ps1 script is to be executed which gets its required secrets from azure kezvault.
This works really well if the powershell az module or the az cli is installed on the pc, because user-log in is required only initially. This is the case on my machine.
But on the machine of my colleagues, installing the az cli or the az powershell module might not be available as an option.
How would I best authenticate them (for getting a keyvault access token) without having them manually enter credentials everytime at runtime?
Cheers
Simplest approach for getting key vault secret is by using rest api by service principal authentication.
Here are the steps to achieve the same:
Create Azure AD and then add that app in the access policies of the key vault.
Send a request to Azure AD for getting token:
https://login.microsoftonline.com/{{directoryId}}/oauth2/v2.0/token
https://vault.azure.net/.default
Create a new GET request “Get Secret” with the URL similar to the one below:
https://yourkeyvaultname.vault.azure.net/secrets/Secret1?api-version=2016-10-01
Here is a detailed article for achieving this , which you can find here :
https://medium.com/#anoopt/accessing-azure-key-vault-secret-through-azure-key-vault-rest-api-using-an-azure-ad-app-4d837fed747
https://github.com/anoopt/GetKeyVaultData
For getting the Azure AD token using powershell, you can simply refer this code:
$tenantId = "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"
$clientId = "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"
$clientSecret = "MYCLENTSECRETHERE"
$TokenEndpoint = {https://login.windows.net/{0}/oauth2/token} -f $tenantId
$resourceURL = "https://management.core.windows.net/";
$Body = #{
'resource'= $resourceURL
'client_id' = $clientId
'grant_type' = 'client_credentials'
'client_secret' = $clientSecret
}
$params = #{
ContentType = 'application/x-www-form-urlencoded'
Headers = #{'accept'='application/json'}
Body = $Body
Method = 'Post'
URI = $TokenEndpoint
}
$token = Invoke-RestMethod #params
Write-Output $token.access_token
https://social.msdn.microsoft.com/Forums/en-US/f98e029a-8c3e-417b-830b-9157bcbecc1e/getting-access-tokenjwt-token-for-azure-ad-using-powershell?forum=WindowsAzureAD
Hope it helps.
Requirements
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:
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!
There is the example for the build tasks: Use a PowerShell script to customize your build pipeline
You have to enable access to token (option Allow Scripts to Access OAuth Token)
Then use it in your script. Script from the example:
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=5.0"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"