microsoft / terraform-provider-azuredevops

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

Managing user permissions for environment: azuredevops_environment_user_permissions #974

Open asinitson opened 6 months ago

asinitson commented 6 months ago

Community Note

Description

There does not seem to be any way to control environment user permissions. It is already possible to control Pipeline permissions. Can we have also have a resource for managing user permissions for an environment?

image

New or Affected Resource(s)

Potential Terraform Configuration

resource "azuredevops_environment_user_permissions" "example-permissions" {
  project_id     = azuredevops_git_repository.example.project_id
  environemnt_id = azuredevops_environment.example.id
  principal      = data.azuredevops_group.example-group.id
  role           = "User" # Other options: "Administrator", "Reader"
}
asinitson commented 5 months ago

Hey, guys! While we are waiting for the fix, here is a workaround (just tested it, it's a copy-paste with minimal modifications). It's made with a for_each, but you can easily rewrite to a single instance:

resource "azuredevops_group" "example" {
  display_name = "Example"
  members = [
    #
  ]
}

# Workaround until proper Terraform resource is implemented:
# https://github.com/microsoft/terraform-provider-azuredevops/issues/974
resource "terraform_data" "services_deployments_permissions" {
  for_each = local.deployments

  triggers_replace = [
    azuredevops_environment.services_deployments[each.key].id,
  ]
  provisioner "local-exec" {
    command = <<EOT
      curl $URL \
          --user ':${var.azuredevops_personal_access_token}' \
          --request PUT \
          --header 'Content-Type: application/json' \
          --data $DATA \
EOT
    interpreter = ["/bin/bash", "-c"]
    environment = {
      URL = join("", [
        "https://dev.azure.com/${local.azure_devops_organization}/_apis",
        "/securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/",
        data.azuredevops_project.example.id,
        "_",
        azuredevops_environment.services_deployments[each.key].id,
        "?api-version=5.0-preview.1"
      ])
      DATA = jsonencode([{
        userId   = resource.azuredevops_group.example.origin_id
        roleName = "User"
      }])
    }
  }
}
gittyNico commented 4 months ago

Make sure to use the correct userId (at least for me), by creating an entitlement for the azuredevops_group first.

userId = azuredevops_group_entitlement.azdo_group.id

ChristianPejrup commented 2 weeks ago

I suspect that the issue with environment user permission is that there is no official Azure DevOps API for configuring this. I would expect this to be a feature request to the Azure DevOps Team/Azure DevOps Api team.

Just like many other features in the Azure DevOps they are not supported by official API's but but some manipulation of the Odata subtypes (i think). I was at least able to reverse engineer something similar to this (great example by the way) but was unable to find any official documentation about the api.

Did you (@asinitson) also do a feature request with the Go api that this library is based on?

asinitson commented 2 weeks ago

@ChristianPejrup: I did not do much except reworking this StackOverflow answer into a cURL/Bash version. This is the only feature request I filed so far.

There is one more method to workaround bad API documentation: doing the manipulation through UI and just inspecting the network requests in your browser of choice (I might have used it during debugging that Terraform snippet above, I don't remember exactly at this point). It's not great, but better than nothing.

asinitson commented 2 weeks ago

Hey, everyone! I see that there is a new resource in terraform-provider-azuredevops 1.1.0 called azuredevops_securityrole_assignment. Judging by example given in the documentation it is doing just what my snippet above is doing:

resource "azuredevops_securityrole_assignment" "example" {
  scope       = "distributedtask.environmentreferencerole"
  resource_id = format("%s_%s", azuredevops_project.example.id, azuredevops_environment.example.id)
  identity_id = azuredevops_group.example.origin_id
  role_name   = "Administrator"
}

If I will find some time I will give it a go, but at first glance it seems like a more generic solution to this feature request.