Skip to content
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

azuread_group is broken in v1.6.0 with use_microsoft_graph = true #478

Closed
ibacalu opened this issue Jul 7, 2021 · 43 comments · Fixed by #503 or #519
Closed

azuread_group is broken in v1.6.0 with use_microsoft_graph = true #478

ibacalu opened this issue Jul 7, 2021 · 43 comments · Fixed by #503 or #519

Comments

@ibacalu
Copy link

ibacalu commented Jul 7, 2021

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritise this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritise the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform (and AzureAD Provider) Version

➜ terraform -v                 
Terraform v1.0.1
on darwin_amd64
terraform {
  required_providers {
    azuread = {
      source  = "hashicorp/azuread"
      version = "1.6.0"
    }
  }
  required_version = ">= 0.15"
}

Affected Resource(s)

  • azuread_group

Terraform Configuration Files

# Copy-paste your Terraform configurations here - for large Terraform configs,
# please use a service like Dropbox and share a link to the ZIP file. For
# security, you can also encrypt the files using our GPG public key: https://keybase.io/hashicorp
provider "azuread" {
  use_microsoft_graph = true
}
resource "azuread_group" "this" {
  description             = local.description
  display_name            = local.display_name
  members                 = local.members
  owners                  = local.owners
  prevent_duplicate_names = local.prevent_duplicate_names

  depends_on = [
    var.module_depends_on
  ]
}

Debug Output

│ Error: Creating group "azuread_group-test"
│ 
│   with azuread_group.this,
│   on main.tf line 11, in resource "azuread_group" "this":
│   11: resource "azuread_group" "this" {
│ 
│ GroupsClient.BaseClient.Post(): unexpected status 400 with OData error:
│ Request_BadRequest: Request contains a property with duplicate values.

Panic Output

Expected Behavior

New group created in AzureAD

Actual Behavior

Nothing gets created and error is thrown.
Azure Log:

Status: failure
Status reason: Microsoft.Online.DirectoryServices.DirectoryValueExistsException

Steps to Reproduce

  1. terraform apply

Important Factoids

Setting use_microsoft_graph = false creates the group without any issues.

References

  • #0000
@ju-la-berger
Copy link

I have the feeling (sorry, cannot say for sure) that it worked a couple of days ago with the same version. Maybe Microsoft changed (broke) something?!

As a workaround, I am now using an alternate provider config (via alias) just for managing groups:

terraform {
  required_version = ">= 1.0"

  required_providers {
    azuread = {
      source  = "hashicorp/azuread"
      version = "1.6.0"
    }
  }
}

provider "azuread" {
  tenant_id           = "..."
  use_microsoft_graph = true
}

provider "azuread" {
  alias               = "groups"
  tenant_id           = "..."
  use_microsoft_graph = false
}

resource "azuread_group" "foo" {
  display_name = "foo"
}

resource "azuread_group" "bar" {
  provider = azuread.groups

  display_name = "bar"
}
$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azuread_group.bar will be created
  + resource "azuread_group" "bar" {
      + display_name            = "bar"
      + id                      = (known after apply)
      + mail_enabled            = (known after apply)
      + members                 = (known after apply)
      + name                    = (known after apply)
      + object_id               = (known after apply)
      + owners                  = (known after apply)
      + prevent_duplicate_names = false
      + security_enabled        = (known after apply)
    }

  # azuread_group.foo will be created
  + resource "azuread_group" "foo" {
      + display_name            = "foo"
      + id                      = (known after apply)
      + mail_enabled            = (known after apply)
      + members                 = (known after apply)
      + name                    = (known after apply)
      + object_id               = (known after apply)
      + owners                  = (known after apply)
      + prevent_duplicate_names = false
      + security_enabled        = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azuread_group.bar: Creating...
azuread_group.foo: Creating...
azuread_group.bar: Still creating... [10s elapsed]
azuread_group.bar: Creation complete after 10s [id=a8341fce-6014-431a-a54b-b1ad0e9bf9ec]
╷
│ Error: Creating group "foo"
│ 
│   with azuread_group.foo,
│   on main.tf line 23, in resource "azuread_group" "foo":
│   23: resource "azuread_group" "foo" {
│ 
│ GroupsClient.BaseClient.Post(): unexpected status 400 with OData error: Request_BadRequest: Request contains a property with duplicate values.
╵

Hope this helps at least until the fix arrives.

@ju-la-berger
Copy link

Oh, this seems to be related to or even a duplicate of #464 although I do not see how this is related to the owners:

data "azuread_client_config" "current" {}

resource "azuread_group" "foo" {
  display_name = "foo"
}

resource "azuread_group" "foo_with_owners_current_caller" {
  display_name = "foo_with_owners_current_caller"
  owners       = [data.azuread_client_config.current.object_id]
}

resource "azuread_group" "foo_with_different_owner" {
  display_name = "foo_with_different_owner"
  owners       = ["31812e0a-0cfd-4d42-a6d5-99076f0cf2f7"] # different from data.azuread_client_config.current.object_id
}
$ terraform apply
azuread_group.bar: Refreshing state... [id=a8341fce-6014-431a-a54b-b1ad0e9bf9ec]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azuread_group.foo will be created
  + resource "azuread_group" "foo" {
      + display_name            = "foo"
      + id                      = (known after apply)
      + mail_enabled            = (known after apply)
      + members                 = (known after apply)
      + name                    = (known after apply)
      + object_id               = (known after apply)
      + owners                  = (known after apply)
      + prevent_duplicate_names = false
      + security_enabled        = (known after apply)
    }

  # azuread_group.foo_with_different_owner will be created
  + resource "azuread_group" "foo_with_different_owner" {
      + display_name            = "foo_with_different_owner"
      + id                      = (known after apply)
      + mail_enabled            = (known after apply)
      + members                 = (known after apply)
      + name                    = (known after apply)
      + object_id               = (known after apply)
      + owners                  = [
          + "31812e0a-0cfd-4d42-a6d5-99076f0cf2f7",
        ]
      + prevent_duplicate_names = false
      + security_enabled        = (known after apply)
    }

  # azuread_group.foo_with_owners_current_caller will be created
  + resource "azuread_group" "foo_with_owners_current_caller" {
      + display_name            = "foo_with_owners_current_caller"
      + id                      = (known after apply)
      + mail_enabled            = (known after apply)
      + members                 = (known after apply)
      + name                    = (known after apply)
      + object_id               = (known after apply)
      + owners                  = [
          + "06ee5fa0-7a61-4313-bae7-4d1bf50cbb03",
        ]
      + prevent_duplicate_names = false
      + security_enabled        = (known after apply)
    }

Plan: 3 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azuread_group.foo_with_different_owner: Creating...
azuread_group.foo_with_owners_current_caller: Creating...
azuread_group.foo: Creating...
╷
│ Error: Creating group "foo"
│ 
│   with azuread_group.foo,
│   on main.tf line 25, in resource "azuread_group" "foo":
│   25: resource "azuread_group" "foo" {
│ 
│ GroupsClient.BaseClient.Post(): unexpected status 400 with OData error: Request_BadRequest: Request contains a property with duplicate values.
╵
╷
│ Error: Creating group "foo_with_owners_current_caller"
│ 
│   with azuread_group.foo_with_owners_current_caller,
│   on main.tf line 35, in resource "azuread_group" "foo_with_owners_current_caller":
│   35: resource "azuread_group" "foo_with_owners_current_caller" {
│ 
│ GroupsClient.BaseClient.Post(): unexpected status 400 with OData error: Request_BadRequest: Request contains a property with duplicate values.
╵
╷
│ Error: Creating group "foo_with_different_owner"
│ 
│   with azuread_group.foo_with_different_owner,
│   on main.tf line 40, in resource "azuread_group" "foo_with_different_owner":
│   40: resource "azuread_group" "foo_with_different_owner" {
│ 
│ GroupsClient.BaseClient.Post(): unexpected status 400 with OData error: Request_BadRequest: Request contains a property with duplicate values.
╵

@manicminer
Copy link
Contributor

Hi @ibacalu, thanks for reporting this. There is at least one known recent upstream issue with groups management (see #464 and #473), however before concluding this is the same issue, I'm trying to reproduce the error you are seeing. I'm starting with the assumption that the owners or members are the likely cause. If you could check the following it will be helpful:

  1. Are you sure there are no duplicates in your members or owners values? It may be that the API previously accepted duplicates but now it does not?
  2. How many members and/or owners are you attaching for the group that fails?
  3. Does this definitely only occur with MS Graph enabled?
  4. Are you able to have a look at the Audit Logs for the tenant to see if the errors are logged there? (e.g. Portal > Azure Active Directory > Audit Logs)

@manicminer
Copy link
Contributor

Ha you beat me to a reply!

That's helpful thanks, it may be that the provider is attaching the calling principal twice, if it's also specified in the configuration.

@manicminer
Copy link
Contributor

@ibacalu Could you try the same configuration, but ensuring that the calling principal is not included in the list of owners and/or members (narrowing it down to the correct property will also help). Thanks!

@ibacalu
Copy link
Author

ibacalu commented Jul 7, 2021

Hi guys. Thanks for looking into this!

@manicminer I was trying to create this group with one principal and with a different principal in the owners.
If I try to create it without any owners defined, still doesn't work, and throws the same error:

No Owners:

Terraform will perform the following actions:

  # azuread_group.this will be created
  + resource "azuread_group" "this" {
      + description             = "Test azuread_group Module"
      + display_name            = "azuread_group-test"
      + id                      = (known after apply)
      + mail_enabled            = (known after apply)
      + members                 = (known after apply)
      + name                    = (known after apply)
      + object_id               = (known after apply)
      + owners                  = (known after apply)
      + prevent_duplicate_names = false
      + security_enabled        = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + config = {
      + description             = "Test azuread_group Module"
      + display_name            = "azuread_group-test"
      + members                 = []
      + owners                  = []
      + prevent_duplicate_names = null
    }
  + this   = (sensitive value)
azuread_group.this: Creating...
│ Error: Creating group "azuread_group-test"
│ 
│   with azuread_group.this,
│   on main.tf line 11, in resource "azuread_group" "this":11: resource "azuread_group" "this" {
│ 
│ GroupsClient.BaseClient.Post(): unexpected status 400 with OData error:
│ Request_BadRequest: Request contains a property with duplicate values.

Different owner

Terraform will perform the following actions:

  # azuread_group.this will be created
  + resource "azuread_group" "this" {
      + description             = "Test azuread_group Module"
      + display_name            = "azuread_group-test"
      + id                      = (known after apply)
      + mail_enabled            = (known after apply)
      + members                 = (known after apply)
      + name                    = (known after apply)
      + object_id               = (known after apply)
      + owners                  = [
          + "********-****-****-****-********fc56",
        ]
      + prevent_duplicate_names = false
      + security_enabled        = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  ~ config = {
      ~ owners                  = [
          + "********-****-****-****-********fc56",
        ]
        # (4 unchanged elements hidden)
    }
  + this   = (sensitive value)
azuread_group.this: Creating...
╷
│ Error: Creating group "azuread_group-test"
│ 
│   with azuread_group.this,
│   on main.tf line 11, in resource "azuread_group" "this":11: resource "azuread_group" "this" {
│ 
│ GroupsClient.BaseClient.Post(): unexpected status 400 with OData error:
│ Request_BadRequest: Request contains a property with duplicate values.
➜ az account show                          
{
  "environmentName": "AzureCloud",
  "id": "********-****-****-****-********6d29",
  "isDefault": true,
  "name": "N/A(tenant level account)",
  "state": "Enabled",
  "tenantId": "********-****-****-****-********6d29",
  "user": {
    "name": "*@*.com",
    "type": "user"
  }
}

The error is the same in Azure Portal:

Microsoft.Online.DirectoryServices.DirectoryValueExistsException

@ju-la-berger
Copy link

@manicminer Thx for your quick reply!

I tried all combinations I could come up with:

resource "azuread_group" "just_name" {
  display_name = "just_name"
}

resource "azuread_group" "owner_current_caller_only" {
  display_name = "owner_current_caller_only"
  owners       = [data.azuread_client_config.current.object_id]
}

resource "azuread_group" "owner_different_only" {
  display_name = "owner_different_only"
  owners       = ["31812e0a-0cfd-4d42-a6d5-99076f0cf2f7"] # different from data.azuread_client_config.current.object_id
}

resource "azuread_group" "owner_both" {
  display_name = "owner_both"
  owners       = [data.azuread_client_config.current.object_id, "31812e0a-0cfd-4d42-a6d5-99076f0cf2f7"]
}

resource "azuread_group" "member_owner_current_caller_only" {
  display_name = "member_owner_current_caller_only"
  members      = [data.azuread_client_config.current.object_id]
  owners       = [data.azuread_client_config.current.object_id]
}

resource "azuread_group" "member_owner_different_only" {
  display_name = "member_owner_different_only"
  members      = ["31812e0a-0cfd-4d42-a6d5-99076f0cf2f7"] # different from data.azuread_client_config.current.object_id
  owners       = ["31812e0a-0cfd-4d42-a6d5-99076f0cf2f7"] # different from data.azuread_client_config.current.object_id
}

resource "azuread_group" "member_owner_both" {
  display_name = "member_owner_both"
  members      = [data.azuread_client_config.current.object_id, "31812e0a-0cfd-4d42-a6d5-99076f0cf2f7"]
  owners       = [data.azuread_client_config.current.object_id, "31812e0a-0cfd-4d42-a6d5-99076f0cf2f7"]
}

resource "azuread_group" "member_empty_owner_different_only" {
  display_name = "member_empty_owner_different_only"
  members      = []
  owners       = ["31812e0a-0cfd-4d42-a6d5-99076f0cf2f7"] # different from data.azuread_client_config.current.object_id
}

All fail when using Microsoft Graph API and succeed otherwise.

@ju-la-berger
Copy link

I have no access to our AAD's audit log to look for error messages there.

@manicminer
Copy link
Contributor

manicminer commented Jul 7, 2021

Thanks for the info, that's super helpful. In the combination testing you did, was the other principal a service principal or a user?

When you say the error is the same in the portal, do you mean you're unable to create a group in the portal too, or that you're seeing the error logged there?

@manicminer
Copy link
Contributor

Also, just to note that I have not yet been able to reproduce the error you're getting. It might be that the tenant you're using has different semantics, possibly due to location, generation or SKU.

@ju-la-berger
Copy link

Oh, that sounds bad for us. ;-)

Unfortunately, I am not an admin for our AD. I can only see the following info:

License: Azure AD Premium P2
Country or region: Germany
Location: EU Model Clause compliant datacenters

I am using my personal user (not SP) authenticated via Azure CLI for running Terraform. I can create groups via the Azure Portal.

I will try with a SP instead later (but this requires some "work" as I need an admin's consent for the SP's API permissions).

@manicminer
Copy link
Contributor

Thanks again, I'll continue trying to repro whilst authenticating as some user principals via Azure CLI

@ju-la-berger
Copy link

I was trying to see anything helpful in the TRACE logs but I could not spot the requests which are sent to MS Graph API. Did I just miss it or is there any way I can help by providing logs?

@manicminer
Copy link
Contributor

manicminer commented Jul 7, 2021

The MS Graph requests are unfortunately not yet included in the debug log, this will be fixed in v2.0.

Do you have a MITM proxy you could run to grab the failed request(s)? Something like Proxyman or Charles?

@ibacalu
Copy link
Author

ibacalu commented Jul 14, 2021

@manicminer When you say the error is the same in the portal, do you mean you're unable to create a group in the portal too, or that you're seeing the error logged there?

I meant the error I see in the portal is the same if i try to create it with the same principal or with a different principal in the owners (both through terraform).
The same code works just fine when I configure the provider with

provider "azuread" {
  use_microsoft_graph = false
}

My tenant is also in Germany, so that could be something...

Country or region: Germany
Location: EU Model Clause compliant datacenters

@manicminer
Copy link
Contributor

manicminer commented Jul 14, 2021

That's useful context, thanks @ibacalu 👍

We're still following up with the service team to get to the bottom of this and/or create a workaround.

For anyone affected by this, can you confirm which permissions you have effectively granted Terraform when accessing MS Graph, i.e. API roles such as Group.Create or Group.ReadWrite.All and/or any assigned directory roles such as Groups Administrator? And also whether you are using a user principal or a service principal?

@cparkins
Copy link

cparkins commented Jul 14, 2021

@manicminer I was running into the exact same issue as @ibacalu using a User Principal with the exact same error in the audit logs and enabling the Groups Administrator role resolved the issue for me. @ibacalu this may resolve your issue as well. It appears that the error message:

│ GroupsClient.BaseClient.Post(): unexpected status 400 with OData error:
│ Request_BadRequest: Request contains a property with duplicate values.

Is a generic response. I did notice that if I updated existing resources I did not need the Groups Administrator role assigned to my User though. And I also got a different error when attempting to set a Group as an Owner on a Group (This isn't allowed in the Portal either).

@manicminer
Copy link
Contributor

Thanks @cparkins! Do you know which other roles/permissions you had assigned before granting Groups Admin?

@cparkins
Copy link

@manicminer I had no Azure AD Roles previously but do have the owner role at the Subscription level.

@ju-la-berger
Copy link

I do not get the point of the whole roles & permissions stuff because I do not have any problems via the Azure Portal or via the Azure CLI:

$ az account show
{
  "environmentName": "AzureCloud",
  "homeTenantId": "xxx",
  "id": "xxx",
  "isDefault": true,
  "managedByTenants": [],
  "name": "xxx",
  "state": "Enabled",
  "tenantId": "xxx",
  "user": {
    "name": "[email protected]",
    "type": "user"
  }
}
$ az rest --uri 'https://graph.microsoft.com/v1.0/groups' --method 'POST' --body '{"displayName": "foo_bar_baz", "mailEnabled": "false", "mailNickname": "foo_bar_baz", "securityEnabled": true}'
{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
  "@odata.id": "https://graph.microsoft.com/v2/xxx/directoryObjects/78bf4882-9b63-47f3-a8b7-dff8e1ddde53/Microsoft.DirectoryServices.Group",
  "classification": null,
  "createdDateTime": "2021-07-14T20:25:34Z",
  "creationOptions": [],
  "deletedDateTime": null,
  "description": null,
  "displayName": "foo_bar_baz",
  "expirationDateTime": null,
  "groupTypes": [],
  "id": "78bf4882-9b63-47f3-a8b7-dff8e1ddde53",
  "isAssignableToRole": null,
  "mail": null,
  "mailEnabled": false,
  "mailNickname": "foo_bar_baz",
  "membershipRule": null,
  "membershipRuleProcessingState": null,
  "onPremisesDomainName": null,
  "onPremisesLastSyncDateTime": null,
  "onPremisesNetBiosName": null,
  "onPremisesProvisioningErrors": [],
  "onPremisesSamAccountName": null,
  "onPremisesSecurityIdentifier": null,
  "onPremisesSyncEnabled": null,
  "preferredDataLocation": null,
  "preferredLanguage": null,
  "proxyAddresses": [],
  "renewedDateTime": "2021-07-14T20:25:34Z",
  "resourceBehaviorOptions": [],
  "resourceProvisioningOptions": [],
  "securityEnabled": true,
  "securityIdentifier": "S-1-12-1-2025801858-1207147363-4175411112-1407114721",
  "theme": null,
  "visibility": null
}

As I am using Azure CLI as authentication mechanism for the Terraform provider, the issue seems to be unrelated to my role & permissions. Basically, the provider should execute "the same" request as via az rest ...!?

@manicminer
Copy link
Contributor

manicminer commented Jul 14, 2021

Hi @ju-la-berger, unfortunately there's a bit more complexity involved. In your Terraform config you can specify any number of owners, which not only have to be applied in the same operation, but unlike a fire-and-forget CLI command, Terraform needs to ensure that it can continue to manage and update a group after it has been created and the owners manipulated per a user's configuration.

Unlike Azure CLI, which is a first party MS application and has special privileges that Terraform can never have, Terraform has to cater for a range of auth scenarios including accessing the API on behalf of a user (acquiring a token via az-cli), or as a service principal, and each of these have their own considerations in terms of how the API determines your permissions. The root of this issue appears likely to be a service change which, if we work around, forces us to break users with certain auth setups, which is why I'm trying to gather more information from affected users. Note that when you run az rest, you're sending your az-cli access token in the request which is specially bestowed to be able to bypass permissions in many cases. The portal has similar privileges.

I'm going to guess that maybe you don't have any directory roles granted to your "[email protected]" user? If that's the case, any workaround we put in place would preclude you from using Terraform to manage your groups without acquiring an administrative role, which is something we'd like to avoid if at all possible.

@ibacalu
Copy link
Author

ibacalu commented Jul 16, 2021

Found another related issue.
Sometimes removing the group works, and other times it doesn't.
When it fails to remove the group, I think what happens is that first the user that created the group gets removed from the owners(in the same apply run), and of course, afterward terraform can't remove the group.

│ Error: Deleting group with object ID: "********-****-****-****-********1350"
│ 
│ graphrbac.GroupsClient#Delete: Failure responding to request:StatusCode=403 -- Original Error: autorest/azure: Service returned an
│ error. Status=403 Code="Unknown" Message="Unknown service error"Details=[{"odata.error":{"code":"Authorization_RequestDenied","date":"2021-07-16T08:27:08","message":{"lang":"en","value":"Insufficient
│ privileges to complete the
│ operation."},"requestId":"********-****-****-****-********12b5"}}]

@manicminer
Copy link
Contributor

@ibacalu Thanks for reporting. I think I'd probably consider that a separate issue, and it looks like you're not using MS Graph there? Could you open a new issue for that? Thanks!

@manicminer manicminer added this to the v2.0.0 milestone Jul 21, 2021
@ju-la-berger
Copy link

@manicminer Sorry for the late reply. It's holiday season. Regarding your question: My user "[email protected]" has elevated rights ("Directory Reader" and "Application Developer"). I can enable these roles via Azure PIM. Does not make any difference regarding this issue though.

Thanks for your explanations regarding the app-specific rights. I am just beginning to explore this whole topic.

Maybe we can track this issue down once we have more logging in place (what is actually sent to the Graph API including the token).

However, I am pretty sure (99%; based on my Git commit logs) that group creation worked the week before. So, something in our tenant has changed which is causing this issue. I can even imagine that maybe our AD admins (accidentally) blocked us somehow.

@manicminer
Copy link
Contributor

Additional fixes to follow

@manicminer manicminer reopened this Aug 12, 2021
@manicminer
Copy link
Contributor

Draft fixes for the identified issues above are in #519

Anyone with knowledge of the codebase and/or Go who has experienced any of the above, is welcome to review

@manicminer
Copy link
Contributor

manicminer commented Aug 16, 2021

@ibacalu, @ju-la-berger, @patrickmarabeas, @huwjeffries - thanks all for reporting these groups bugs and helping to narrow down the root causes. We've worked with the service team to try and get some more insight, and have implemented better logic around group ownership on which I'm hoping to get your feedback whether this helps in your respective cases. I've published a test build to the TF Registry which you can consume with the following provider config:

terraform {
  required_providers {
    azuread = {
      source = "manicminer/azuread"
      version = "11.0.6"
    }
  }
}

This is effectively a 2.0 RC build despite the nonsense version number I used. For a brief breakdown of most of the behavioral changes see #519. Any feedback will be gratefully received and will help us move closer to the next release. Thanks!

Ed: build number bumped to 11.0.6

@patrickmarabeas
Copy link
Contributor

"Swapping" owners now works as expected, i.e. adding and removing a single own at the same time works.

Service principals are still not respected as being a valid single group owner, however. The following is the error when a user and a service principal have both been applied as a group's owners, and then the user is subsequently removed leaving only the service principal.

GroupsClient.BaseClient.Delete(): unexpected status 400 with OData error:
Request_BadRequest: The group must have at least one owner, hence this owner
cannot be removed.

I'm not sure if this is a big deal, but it is odd.

Anpother oddity -

owners = []

Returns error Attribute requires 1 item minimum, but config has only 0 declared.

However, removing owners field entirely, regardless of previous contents returns No changes. Infrastructure is up-to-date.

Owner shouldn't be enforced, as the API does allow for groups with no owners, however, once there are assigned owners there MUST, from that point on, be an owner. This really needs to be picked up by the plan, as well.

@manicminer
Copy link
Contributor

manicminer commented Aug 17, 2021

@patrickmarabeas Thanks for testing! That is super helpful feedback and although you have still encountered some errors, that is actually the expected behavior end-to-end at this point.

"Swapping" owners now works as expected, i.e. adding and removing a single own at the same time works.

Great!

Service principals are still not respected as being a valid single group owner, however. The following is the error when a user and a service principal have both been applied as a group's owners, and then the user is subsequently removed leaving only the service principal.

...

I'm not sure if this is a big deal, but it is odd.

This is unfortunately an API behavior/bug and we have no choice but to document this and live with it.

Anpother oddity -


owners = []

Returns error Attribute requires 1 item minimum, but config has only 0 declared.

However, removing owners field entirely, regardless of previous contents returns No changes. Infrastructure is up-to-date.

Owner shouldn't be enforced, as the API does allow for groups with no owners, however, once there are assigned owners there MUST, from that point on, be an owner. This really needs to be picked up by the plan, as well.

Actually it's not possible to create a group with no owners. The API always assigns the caller as the owner, effectively stamping permanent ownership on the group, since as you note owners can never be totally removed.

When you omit owners, during group creation the provider assigns itself as owner. But the API does this anyway even if we don't. And it's impossible to specify an empty list of owners or otherwise say "no owners for this new group".

Removing the owners property from your config for an existing group does nothing because it's necessarily a computed property. You must specify a different set of owners in order to remove currently assigned owners.

@patrickmarabeas
Copy link
Contributor

Ahh, understood. Thanks!

@github-actions
Copy link

This functionality has been released in v2.0.0 of the Terraform Provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template. Thank you!

@ilya-git
Copy link

ilya-git commented Sep 9, 2021

I still get this error in 2.1.0:

Request_BadRequest: Request contains a property with duplicate values.

I created a group

resource "azuread_group" "sql_admins" {
  display_name            = "admins-sql-<my-app>"
  security_enabled        = true
  prevent_duplicate_names = true
}

and I get this error still. I tried with owners and depending on owners I get either the same error or some other one. What is weird that I have 2 modules and both have this group and it works in one case, but not the other! (names are different). So I am completely lost as to what is going on

P.S. I have tried later and it just started working...

@manicminer
Copy link
Contributor

Hi @ilya-git, there's a fix going out later today in v2.2.0 (changelog) which should hopefully resolve that error for you.

@ilya-git
Copy link

ilya-git commented Sep 9, 2021

Sounds great, thanks for the update!

@iulianmarius
Copy link

iulianmarius commented Sep 10, 2021

i still have the same error with v2.2.0 . this worked with 1.2.2
GroupsClient.BaseClient.Post(): unexpected status 400 with OData error: Request_BadRequest: Request contains a property with duplicate values.

it looks like the error is occuring only when i include the current user as owner. If i put another user it works like expected. maybe is the current user(creator) added by default and conflicts with the owners block if the owners block also contains the current user?

@manicminer
Copy link
Contributor

H @iulianmarius, thanks for reporting. Please could you post a reproducible config in full, and a debug log? In all our test configurations this is no longer occurring, it seems likely that something about your configuration may be triggering this incorrect behavior. Thanks!

@nfeltrin-dkb
Copy link

Hi I'm also getting the "GroupsClient.BaseClient.Post(): unexpected status 400 with OData error:" error. I've managed to isolate some cases where it happens and where it doesn't, hope it's helpful.

Setup:

  • group_admin: Groups administrator, User administrator
  • app_admin: Application administrator
  • user: no assigned role

Errors out:

  • tf run as app_admin, no owner set
  • tf run as app_admin, owner = app_admin

Succeeds:

  • tf run as app_admin, owner = group_admin => owners are app_admin, group_admin
  • tf run as app_admin, owner = user => owners are app_admin, user
  • tf run as group_admin, owner = user => owners are user
  • tf run as group_admin, no owner set => owners are group_admin
  • tf run as group_admin, owner = group_admin => owners are group_admin
  • tf run as group_admin, owner = app_admin => owners are app_admin
  • creating the group as app_admin from the Azure UI obviously works every time

At this point I'd guess it's some weird issue within Azure itself; for the time being setting group_admin as default owner solves it for us (although it might not fit everybody's use case).

@manicminer
Copy link
Contributor

Thanks @nfeltrin-dkb, there are ongoing known service issues with group ownership and I agree what you've documented looks like an API bug.

At this time, we're fairly confident that the provider is doing the right thing with regards to group ownership and the following (misleading) errors, are very likely to be caused by known API bugs:

  • Request contains a property with duplicate values
  • The group must have at least one owner, hence this owner cannot be removed

@manicminer
Copy link
Contributor

manicminer commented Sep 16, 2021

Thanks again to all who helped debug this issue, your help is greatly appreciated. Since it seems that what remains of this issue is due to an API bug, I've reported this upstream at microsoftgraph/msgraph-metadata#92 and will be closing this issue for now. If you're still experiencing this issue, I encourage you to report your observations on the upstream issue to give the service team the best possible set of evidence. Thanks!

@kyrios

This comment has been minimized.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.