terraform-provider-azuread icon indicating copy to clipboard operation
terraform-provider-azuread copied to clipboard

azuread_invitation: support same properties as in azuread_user

Open ppanyukov opened this issue 3 years ago • 13 comments

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

Description

The azuread_user resource supports many properties like department, company etc, and most notably account_enabled -- pretty much all fields I can set manually in AAD.

The azuread_invitation doesn't have any of these at all. And again most notably it doesn't have account_enabled. At the same time, we can edit and populate all these fields manually in AAD.

We use many external users in our AAD and we use the metadata extensively to document their roles and why they are in our AAD at all.

The proposal is to "beef up" azuread_invitation to support all the same properties as azuread_user (except there is no need for password of course).

Looking at the graph SDK, the Invitation struct does have the *User member, and it is the same type being used by azuread_user, so in theory this should be just a matter of exposing the properties and fill out this object in azuread_invitation?

type Invitation struct {
	ID                      *string          `json:"id,omitempty"`
	InvitedUserDisplayName  *string          `json:"invitedUserDisplayName,omitempty"`
	InvitedUserEmailAddress *string          `json:"invitedUserEmailAddress,omitempty"`
	SendInvitationMessage   *bool            `json:"sendInvitationMessage,omitempty"`
	InviteRedirectURL       *string          `json:"inviteRedirectUrl,omitempty"`
	InviteRedeemURL         *string          `json:"inviteRedeemUrl,omitempty"`
	Status                  *string          `json:"status,omitempty"`
	InvitedUserType         *InvitedUserType `json:"invitedUserType,omitempty"`

	InvitedUserMessageInfo *InvitedUserMessageInfo `json:"invitedUserMessageInfo,omitempty"`
	InvitedUser            *User                   `json:"invitedUser,omitempty"`  // <== THIS
}

Of course if this is possible and is implemented, then we'd want azuread_invitation to return extra attributes too.

ppanyukov avatar Oct 28 '21 18:10 ppanyukov

Hi @ppanyukov, thanks for requesting this. Whilst the Invitation object contains a User container, this is read-only and only the user's ID is returned by the API.

We could potentially implement this by updating the guest user separately after the invitation is created, but I'd first like to experiment and see if this can be done with the existing user resource, and also investigate to see which properties are updateable for guest users yet to accept their invitation.

manicminer avatar Nov 03 '21 14:11 manicminer

Hmm, I really hoped this wouldn't be the case but oh well...

Would it be breaking "tf resource best practice" if we do two operations (create and then update) on a single resource? Say create succeeds but update fails for some reason (network issue), what happens with the tf state? Tainted? Although azurerm provider does lots of these "combined operations", e.g. azurerm_app_service is full of them.

Another alternative is to have separate resource say azuread_invitation_metadata which will just update these meta properties and will take an object_id as required parameter?

Of course having all these just in azuread_invitation resource is much more convenient from the usage perspective.

Judging from the Azure Portal, we can edit all the same properties for invited users as for the regular ones. I don't know if this helps?

ppanyukov avatar Nov 05 '21 16:11 ppanyukov

Performing multiple operations for a single logical operation in Terraform is fine, as you say we do this in lots of places. If the create operation gets far enough to assign a resource ID, then it is in fact tainted on failure.

manicminer avatar Nov 05 '21 20:11 manicminer

Oh, while we are at it, this makes me very sad :(

This resource does not support importing.

ppanyukov avatar Nov 10 '21 13:11 ppanyukov

There's no way to read back invitations as it's a POST only endpoint - however you can import guest users into an azuread_user resource! :)

manicminer avatar Nov 10 '21 14:11 manicminer

What we struggle with not having any way to set the First and Last names for the created object, this is an issue with things like AAD SCIM sync to sync the guests to other 3rd party apps, (AWS SSO for example) that require First and Last name attributes.

I understand this is likely limitation on the azure api but still my 2 cents

TheMacStack avatar Nov 16 '21 15:11 TheMacStack

Seems like it should be possible to support the attributes in the Azure Portal when inviting a New User. Looking at the code there is an update of the newly created user that takes place following the actual invitation so this could support updating attributes like the First Name and Last Name, etc. (I guess at least should be able to set the First Name, Last Name, Job Title, Department, Company name and possibly Usage location).

The resource is already reading the Email from the existing user in the read hook which would be able to update these attributes, this would trigger a change in the resource if there are differences. I guess the question is whether these additional attributes trigger an update (not currently implemented) or whether they force a new resource.

Proposed changes:

  • add the attributes First Name, Last Name, Job Title, Department, Company name to the resource
    • should these attributes be defined with forceNew: true??
  • change the second update in the create hook to pass these values (if present)
  • update read hook to update these attributes from the User object retrieved from AD
  • add an update dependent on the answer of the forceNew question above

I don't mind looking at making the changes and creating pull request, that is if the suggested changes are appropriate!

This would at least provide the same level of functionality as the Invite user form in Azure AD (excluding Groups, Roles and Manager)

StickNitro avatar Jul 07 '22 14:07 StickNitro

I'm unsure why you need this as the user_id is an output variable of azuread_invitation, we do e.g.

locals {
invited_folks = yamldecode(file("${path.module}/../invited_folks.yml"))  
}

resource "azuread_invitation" "invite" {
  for_each           = local.invited_folks
  user_email_address = each.key
  redirect_url       = "https://example.com"
  message {
    additional_recipients = [each.value.inviter]
    body                  = <<-EOT
    Hello ${each.key}
    You have been invited to example.com
    Please accept this invite to get access.
    Have a nice day!
    EOT
  }
}

resource "azuread_group_member" "example" {
  group_object_id  = "<an object id>"
  for_each         = local.invited_folks
  member_object_id = azuread_invitation.invite[each.key].user_id
}

with a invited_folks.yml looking like this:

---
[email protected]:
  inviter: [email protected]
[email protected]:
  inviter: [email protected]

bufferoverflow avatar Apr 22 '23 15:04 bufferoverflow

We intend to approach this by incorporating invite functionality into the azuread_user resource rather than expand the azuread_invitation resource.

manicminer avatar Jul 25 '23 21:07 manicminer

Any updates on this? This is quite and urgent requirement for out needs as we manage ALL our users through terraform using the azuread_invitation resource and we are currently unable to set any of the additional attributes

old-guy-coder avatar Mar 21 '24 11:03 old-guy-coder