microsoft / terraform-provider-azuredevops

Terraform Azure DevOps provider
https://www.terraform.io/docs/providers/azuredevops/
MIT License
385 stars 276 forks source link

Environment permissions for azuredevops_pipeline_authorization #923

Open hbuckle opened 1 year ago

hbuckle commented 1 year ago
resource "azuredevops_project" "project" {
  name               = var.name
  work_item_template = var.work_item_template
  version_control    = "Git"
  visibility         = "private"
}

resource "azuredevops_environment" "example" {
  project_id = azuredevops_project.project.id
  name       = "example"
}

resource "azuredevops_pipeline_authorization" "example" {
  project_id  = azuredevops_project.project.id
  resource_id = azuredevops_environment.example.id
  type        = "environment"
}

I get the following error from the azuredevops_pipeline_authorization resource

│ Error:  creating authorized resource: The resource doesn't exist or the user doesn't have admin permission for all resources of that type.

The user running Terraform is Administrator on the environment resource (as they just created it), and also Project Administrator (as they just created that also).

The only way I found to fix it is to make the user Administrator on all environments for the project, but that has to be done by a project collection administrator, as by default project administrators are only granted Creator permission on the Environment namespace.

So is there any way to grant all pipelines permissions to an environment without the user being project collection administrator?

jubr commented 8 months ago

I think I might be running into the same type of problem, but then for a cross-project repository authorization. So to add to the above example:

resource "azuredevops_project" "other-project" {
  name               = var.other_name
  work_item_template = var.work_item_template
  version_control    = "Git"
  visibility         = "private"
}

// This will have auto-created a repo with the same name
data "azuredevops_git_repository" "other-repo" {
  project_id = azuredevops_project.other-project.id
  name       = var.other_name
}

// Allow pipeline(s) in "project" to access "other-repo" in "other-project"
resource "azuredevops_pipeline_authorization" "to-other-repo" {
  project_id  = azuredevops_project.project.id
  resource_id = azuredevops_git_repository.other-repo.id
  type        = "repository"
  #pipeline_id = azuredevops_build_definition.in-first-project.id // not-set: allow all pipelines
}

Note the error is exacty the same (minus the "for all resources of that type"):

│ Error:  creating authorized resource:
          The resource doesn't exist or the user doesn't have admin permission.

And if I enable line pipeline_id the first part of the error is the same, but the underlying error is not:

│ Error:  creating authorized resource:
          The resource doesn't exist or the user doesn't have use permission.

Perhaps worth mentioning I already turned enforce_job_scope off for both projects with:

resource "azuredevops_project_pipeline_settings" "_" {
  for_each = toset(["project", "other-project"])
  project_id                           = azuredevops_project[each.key].id
  enforce_job_scope                    = false
  enforce_job_scope_for_release        = false
  //... other settings
}

I suspect this might be the same administrators-permission required. So this leads back to @hbuckle's original question:

So is there any way to grant all pipelines permissions [to an environment/repository] without the user being project collection administrator?

Can you please help us out @xuzhang3? 🙏

kerko commented 8 months ago

@jubr Since I hit the same problem as you. FYI: The problem ist that the resource will always prepend the project id to resource id for this type

The correct resource id for cross project repository authorization would be: "otherProjectId.repositoryId" but that can not be set atm

xuzhang3 commented 7 months ago

@jubr @kerko cross project authorization supported in #973 , will be available in v1.1.0

FRUCHTiii commented 3 months ago

I still get the error, even with version 1.2.0

Is there any fix for it @xuzhang3 ?

│ Error:  creating authorized resource: The resource doesn't exist or the user doesn't have admin permission for all resources of that type.
│ 
│   with module.cd-test.module.npm[0].azuredevops_pipeline_authorization.npm_auth,
│   on .terraform/modules/cd-test/npm/main.tf line 18, in resource "azuredevops_pipeline_authorization" "npm_auth":
│   18: resource "azuredevops_pipeline_authorization" "npm_auth" {
│ 
╵
╷
│ Error:  creating authorized resource: The resource doesn't exist or the user doesn't have admin permission for all resources of that type.
│ 
│   with module.cd-test.module.sonarqube[0].azuredevops_pipeline_authorization.sonarqube_auth,
│   on .terraform/modules/cd-test/sonarqube/main.tf line 19, in resource "azuredevops_pipeline_authorization" "sonarqube_auth":
│   19: resource "azuredevops_pipeline_authorization" "sonarqube_auth" {
xuzhang3 commented 2 months ago

@FRUCHTiii can you share your TF script?

FRUCHTiii commented 1 month ago

@xuzhang3 Unfortunately I don't have a Terraform Scirpt.

At first I thought i have this issue here but then recognized that I'm using a different type of this resource.

My issue is described here https://github.com/microsoft/terraform-provider-azuredevops/issues/1117

But IMHO for me it looks like a very similar issue within the api.

dzindzinj commented 1 month ago

Have the same error as @FRUCHTiii, I was able to create endpoint for acr and grant it all pipeline permission with old resource but not the new one.

resource "azuredevops_serviceendpoint_azurecr" "main" {
    project_id                             = data.azuredevops_project.main.id
    resource_group                         = azurerm_resource_group.acr.name
    service_endpoint_name                  = "example"
    service_endpoint_authentication_scheme = "WorkloadIdentityFederation"
    azurecr_spn_tenantid                   = data.azurerm_subscription.current.tenant_id
    azurecr_name                           = azurerm_container_registry.acr.name
    azurecr_subscription_id                = data.azurerm_subscription.current.subscription_id
    azurecr_subscription_name              = data.azurerm_subscription.current.display_name

    credentials {
      serviceprincipalid = azurerm_user_assigned_identity.acr.client_id
    }
}

resource "azurerm_federated_identity_credential" "main" {
    name                = "fed-wif"
    resource_group_name = azurerm_resource_group.acr.name
    parent_id           = azurerm_user_assigned_identity.acr.id # has to be managed identity
    audience            = ["api://AzureADTokenExchange"]
    issuer              = azuredevops_serviceendpoint_azurecr.main.workload_identity_federation_issuer
    subject             = azuredevops_serviceendpoint_azurecr.main.workload_identity_federation_subject
}

# Does not work - permission error / resource not found
# resource "azuredevops_pipeline_authorization" "pipeline_access" {
#  project_id  = data.azuredevops_project.main.id
#  resource_id = azuredevops_serviceendpoint_azurecr.main.id
#  type        = "endpoint"
#  #pipeline_id - all pipelines if not specified
#}

# works but deprecated
resource "azuredevops_resource_authorization" "pipeline_access" {
  project_id  = data.azuredevops_project.main.id
  resource_id = azuredevops_serviceendpoint_azurecr.main.id
  type        = "endpoint"
  authorized  = true
}

Edit: Worth to note that I am unable to make changes to the ACR service connection via Azure DevOps UI either with the error message that the service connection was created using Azure DevOps REST API

Endpoint of this type and scheme cannot be modified through the UI. Use Azure DevOps REST API instead. Learn more at https://aka.ms/azdo-rm-wif-docker-cross-tenant

The creator and owner of the ACR endpoint is "Project collection Build Service (Org)" - same pipeline and token.

Edit: Fixed by adding Endpoint Administrator permission to the service account that was running my terraform code.