hashicorp / terraform-provider-azuread

Terraform provider for Azure Active Directory
https://registry.terraform.io/providers/hashicorp/azuread/latest/docs
Mozilla Public License 2.0
432 stars 300 forks source link

Terraform destroy on azuread_service_principal returns 403, but is destroyed #538

Open avinashpancham opened 3 years ago

avinashpancham commented 3 years ago

Currently I am using the Terraform's azurerm and azuread provider to create the same resources as az ad sp create-for-rbac would do. For this I apply the following code:

provider "azurerm" {
  features {}
}

data "azurerm_client_config" "current" {}

data "azurerm_resource_group" "rg" {
  name = "my_rg"
}

resource "azuread_application" "app-registration" {
  display_name = "my-app-registration"
  owners       = [data.azurerm_client_config.current.object_id]
}

resource "azuread_service_principal" "service-principal" {
  application_id = azuread_application.app-registration.application_id
}

resource "azuread_application_password" "password" {
  application_object_id = azuread_application.app-registration.object_id
  end_date              = "2022-01-01T00:00:00Z"
}

resource "azurerm_role_assignment" "role" {
  principal_id         = azuread_service_principal.service-principal.id
  role_definition_name = "Contributor"
  scope                = data.azurerm_resource_group.rg.id
}

For now I authenticate via a User principal (i.e. az login) to an Azure subscription of which I am the Owner. In AAD I am a regular User (with no additional assigned roles such as Application Administrator or Global Administrator). Applying the above code with terraform apply works and creates the app registration, service principal and service principal secret.

When I, however, use terraform destroy on this code I get the following error

│ Error: Deleting service principal with object ID "XXX", got status 403
│ 
│ ServicePrincipalsClient.BaseClient.Delete(): unexpected status 403 with OData error: Authorization_RequestDenied: Insufficient privileges to complete the operation.

At that moment the following resources are left in my terraform state:

data.azurerm_client_config.current
azuread_application.app-registration
azuread_service_principal.service-principal

If I then again use terraform destroy, the azuread_application.app-registration is destroyed. Meaning that the service principal is deleted in Azure and not accessible anymore, but azuread_service_principal.service-principal is still present in my terraform state.

Terraform (and AzureAD Provider) Version

Terraform v1.0.5 on linux_amd64

Affected Resource(s)

Terraform Configuration Files

See above

# 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

Debug Output

Panic Output

Expected Behavior

Either the azuread_application.app-registration and azuread_service_principal.service-principal should both be deletable from my Terraform state, or they should both be not deletable from my Terraform state.

Actual Behavior

azuread_application.app-registration and azuread_service_principal.service-principal are deleted from Azure, but azuread_service_principal.service-principal is still present in my Terraform state.

Steps to Reproduce

  1. terraform apply
  2. terraform destroy (throws error)
  3. terraform destroy (on the remaining resources)

    Important Factoids

References

manicminer commented 3 years ago

May be related to #535

dimbleby commented 3 years ago

I also hit this before reaching #535 - I think that it can be resolved by adding owners to the service principal, just as on the application.

I think that the reason that the service principal is destroyed is that, although destroying it as a standalone object failed, it goes when the application goes.

Would be nice if there's anything that can be done to make the terraform behaviour better, but I'm not sure what.

manicminer commented 3 years ago

This would usually be taken care of by the DAG if you reference the application_id in the service principal resource, from the application resource - I'll play around with this and see what can be improved.

avinashpancham commented 3 years ago

@dimbleby thanks for your solution, that indeed works! But I agree with @manicminer if the parent resource (in this case azuread_application.app-registration) is owned by my object-id then I would expect that you can delete the child resource (azuread_service_principal.service-principal) without specifying the owner.

manicminer commented 3 years ago

@avinashpancham Given the authentication setup you describe, I suspect this is down to API/object permissions. There is a useful Azure docs page describing the default permissions for users when no additional directory roles are assigned - which states that a regular (non-guest) user can register applications and read service principals (noting that service principals are referred to as 'enterprise applications' versus 'registered applications' which are app registrations).

I agree with @dimbleby that specifying yourself in the owners list for both the application and service principal may resolve the deletion issue for you. There is a bug in 2.0.0/2.0.1 with service principal owners so I'd suggest waiting for 2.1.0 to confirm that.

Failing that, the service principal resource has a new property use_existing. When you set this to true, the provider will first look for an existing service principal that might have been auto-created and will use that instead of creating a new one - and subsequently it will ignore any permissions errors when deleting/destroying that same service principal. It's not ideal behavior but does work around SPs for first-party applications and cases such as this where you don't have permission to delete but you can delete the linked app registration.

slyons commented 3 years ago

Just as a heads up this is still an issue in 2.2.1

manicminer commented 3 years ago

Hi @avinashpancham, @dimbleby, @slyons

Thanks for reporting on this issue. I have not observed this error myself however it's likely in my testing I don't have the same configurations of principals and API/directory roles which would cause this to occur.

I would suggest checking that the following conditions are being met by your Azure and Terraform configurations:

If you are confident these conditions are met, and you still receive the error, feel free to post HTTP traces for both the apply and the destroy operations to this issue, and I'll be happy to verify that Terraform is sending the correct request(s). Should Terraform be demonstrated to be doing the right thing, I'll pass the evidence to the service team for further investigation. Thanks!