-
Notifications
You must be signed in to change notification settings - Fork 257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow authentication in same manner as azurerm via azure cli login #419
Comments
Problem here is that the provider may work longer on a deployment than the life time of the access token. In that case the provider can use a refresh token to request a new access token. The problem is that we don't have anything in place right now to handle an expired login/access token, because the provider works with a (very) long living PAT. So implementing this would be a major effort. To make the situation even worse, the code that handles the authentication is hosted in a different repository https://github.com/microsoft/azure-devops-go-api. I successfully tested the OAuth 2.0 Resource Owner Password Credentials (ROPC) grant and Azure DevOps, where you use an application in Azure AD which impersonates a real user to access Azure DevOps. This flow is completely non-interactive and thus suitable for example CI/CD scenarios. The only drawback is that you need both the application secret and the passoword of the impersonated user.
|
@tedchamb @xuzhang3 I looked inside the code of I saw that development in the |
@goflores Can you help clarify this issue @tmeckel mentioned. |
@nechvatalp Hi Petr, good news. As I stated in my comment from 7/25 #419 (comment) we could fairly easy support the feature request of the original poster @haymansfield Problem is that, from what I know from @tedchamb, huge amount of the code in the repository is automatically generated by a tool which is not available in public. So before I, or someone else, would file a PR it must be clear that the parts of the code that must be changed to support the feature request are not generated by the tool and would thus be overwritten. Can you tell if the parts I mentioned in my comment are generated by the tool or not? |
@nechvatalp we have a feature request for the AzDO Terraform Provider which would need this implementation here as well: microsoft/azure-devops-go-api#105 |
@tmeckel that is correct. All the files in azuredevops/subfolder/*.go are generated, all the *.go files which are directly in azuredevops/ directory are not. So, the changes you are proposing should not be overwritten. |
@nechvatalp is there an ETA of v6.x or v7.x SDK? |
@xuzhang3 I started looking into the 6.0 version I want to have it this week. |
@nechvatalp Will |
@xuzhang3 it is not going as well as I expected so I won't be able to finish it this week, but I am continuing to work on it. As for the preview APIs, the preview APIs are 6.1 and I do not plan to do 6.1, however there will be upcoming release of ADO with API version 7.0 I do plan to release new go sdk for that version shortly after it is released and that should contain the APIs which are now in preview. |
@nechvatalp one concern, currently the API version is hardcoded in the source code. Once v7 released, will v5 still available? |
Hi, the Azure DevOps go API 6.0 has been released. Yes, the 5.1 is still available as |
What is the current status? I would like to execute azure devops terraform scripts from the commandline in the security context of my az cli user context without having to setup PATs. |
@cveld devops doesn't support non-interactive service access via service principals. Oauth flow is the potential way to do the authorization but we not verified that way. |
@xuzhang3 I know. You can circumvent this with OAuth 2.0 Resource Owner Password Credentials (ROPC) grant as @tmeckel confirmed. Az cli does the very same trick below the covers. And indeed it will fail when az cli is connected with Azure through a service principal. You will need to connect az cli with an AAD user. |
You can use Terraform external data sources to solve this, to call the token from the az cli. See below: variable "devops_org_name" {
type = string
default = "my_org_name"
}
# See here to create a personal access token for a user https://docs.microsoft.com/en-us/rest/api/azure/devops/tokens/pats/create?view=azure-devops-rest-7.1
# Below assumes that you have logged in via `az login` on Azure Cloud Shell
locals {
is_windows = substr(pathexpand("~"), 0, 1) == "/" ? false : true # Detects Windows or Linux - see https://stackoverflow.com/a/61392460
# Fixed scope for devops tokens comes from https://github.com/microsoft/azure-devops-auth-samples/blob/master/ManagedClientConsoleAppSample/Program.cs#L28
windows_pat_program = <<-EOWIN
$aztoken = az account get-access-token --scope "499b84ac-1321-427f-aa17-267ca6975798/user_impersonation" --query accessToken --output tsv;
$devopstokenheader = New-Object "System.Collections.Generic.Dictionary[[String],[String]]";
$devopstokenheader.Add("Authorization", 'Bearer '+ $aztoken);
$devopstokenbody = @{displayName='terraform_token';scope='app_token';validTo='9999-12-31 23:59:59Z';'allOrgs'='true'}|ConvertTo-Json;
((Invoke-WebRequest -Uri https://vssps.dev.azure.com/${var.devops_org_name}/_apis/tokens/pats?api-version=7.1-preview.1 -Method POST -ContentType 'application/json' -Headers $devopstokenheader -Body $devopstokenbody).Content | ConvertFrom-Json).patToken
EOWIN
linux_pat_program = <<-EOLINUX
#!/bin/bash -e
aztoken=$(timeout 30 az account get-access-token --scope "499b84ac-1321-427f-aa17-267ca6975798/user_impersonation" --query accessToken --output tsv);
timeout 30 curl --silent --request POST -H "Authorization: Bearer $aztoken" -H "Content-Type: application/json" -d '{"displayName": "terraform_token", "scope": "app_token", "validTo": "9999-12-31 23:59:59Z}", "allOrgs": true}' https://vssps.dev.azure.com/${var.devops_org_name}/_apis/tokens/pats?api-version=7.1-preview.1 | jq --compact-output --monochrome-output --ascii-output .patToken
EOLINUX
}
resource "local_file" "devops_pat_program" { # Must create a local file first
content = local.is_windows ? local.windows_pat_program : local.linux_pat_program
filename = "${path.module}/devops_pat_program"
}
data "external" "get_devops_pat" { program = local.is_windows ? ["Powershell.exe", local_file.devops_pat_program.filename] : ["bash", local_file.devops_pat_program.filename] }
terraform {
required_providers {
azuredevops = {
source = "microsoft/azuredevops"
version = "~>0.2"
}
}
}
provider "azuredevops" {
org_service_url = "https://dev.azure.com/${var.devops_org_name}"
personal_access_token = data.external.get_devops_pat.result["token"]
}
data "azuredevops_projects" "example" {
state = "all"
}
output "project_id" {
value = data.azuredevops_projects.example.projects.*.project_id
}
output "name" {
value = data.azuredevops_projects.example.projects.*.name
} |
I got an error when running your example:
When I leave out the data resource (and dependent outputs) the plan gets generated successfully. Terraform cli 1.3.6 providers: OS: Windows 11 The fix is to add Last line becomes: Additionally it seems the local file must have the extension Change the Unfortunately the flow seems still not complete. For now it seems I need to run the terraform configuration first without any usage of azuredevops data resources in order to populate the PAT with a sensible value for the data resources to be queryable by the provider. Is this a limitation of the provider? Or is this a limitation of Terraform semantics? Normally a provider would query a data resource during plan phase. A deferred approach is required. I.e., whenever the PAT is not yet computed, the data resources neither can be computed during plan phase and an apply needs to be run first. |
It's probable that my example in the above requires you to have logged in with Obviously this is all getting quite silly when you can provision a token once and solve the issue permanently. But all progress depends on the unreasonable. |
@dvasdekis did you see my comment? Not sure if it is applicable to your context as well:
|
Sorry for the misunderstanding. I never considered that someone wouldn't have the Devops org set up before using it. Is that the case here? In this case, does a depends_on = [your devops org resource] allow the script to work? |
@dvasdekis no that does not seem to be applicable. My experience tells me that the state file really needs to have a sensible value for the PAT upfront for the azure devops provider to pick it up. The provider seems to require a sensible value during plan phase and doesn't seem to pick up this value lazily during apply phase. In the smallest scenario at my side I am provisioning a service connection in an existing azure devops project. So my experience tells me that I first need to run |
Now that Azure Devops allows you to add service principals and managed identities to your organization, can anyone think of a workaround of using the The docs says that we can authenticate using a Azure AD access token in place of a PAT. But a PAT uses basic auth whereas the AD access token uses bearer. Would it be possible to update the provider in a way where we can specify the type of auth (`basic or bearer) and we can pass in the appropriate token? Looks like we'd probably have to add a new method somewhere here: https://github.com/microsoft/azure-devops-go-api/blob/c9e5fa06da2c96efdb063352524aa458e7733bb6/azuredevops/v7/connection.go#L18-L26 We'd still need to address the issue with the token expiring though. |
@AMoghrabi #747 will support SPN auth |
Now Service Principal oidc auth has landed (version 1.0.1), how can we make the configuration hybrid so that it also works through az cli in the context of a user? I.e. like the following workaround from @geekzter does: data external azdo_token {
program = [
"az", "account", "get-access-token",
"--resource", "499b84ac-1321-427f-aa17-267ca6975798", # Azure DevOps
"--query","{accessToken:accessToken}",
"-o","json"
]
}
provider azuredevops {
org_service_url = local.azdo_organization_url
personal_access_token = data.external.azdo_token.result.accessToken
} |
Any idea how to get this working successfully in an Azure DevOps pipeline? When I run this it requires az login to run first, however that doesn't work correctly in an external block.
|
Your principal must be added as a user with a license to the azure devops org. Is that done? The az cli does not always provide a meaningful error when it cannot obtain an access token. And I assume you are running from the az cli task? Obviously an entra authenticated az cli is required. |
Thanks for responding. My problem is I’m having a hard time figuring out how to get an Entra authenticated Az cli from within the terraform stage of my pipeline. The yaml file does the azure auth using a service connection to a federated app registration. It doesn’t need Az cli login inside the terraform stage from what I can see. But when I try and run Az login in an external block it throws the error that it doesn’t understand the json response, which kills the task. I’m fairly new to this, but this post is similar to what I’m trying to accomplish so I thought I’d ask the question. |
@JClarke90 you can ping me on discord username carlintveld. I wonder what task you are using. It is definitely arm related as you say you specify a service connection. You should be using the az cli task. |
Community Note
Description
I can create azure devops resources using the azure cli azure-devops extension without the need for managing PAT tokens. Could this provider be made to use the same authentication?
New or Affected Resource(s)
Potential Terraform Configuration
References
The text was updated successfully, but these errors were encountered: