auth0 / terraform-provider-auth0

The Auth0 Terraform Provider is the official plugin for managing Auth0 tenant configuration through the Terraform tool.
https://registry.terraform.io/providers/auth0/auth0/latest/docs
Mozilla Public License 2.0
157 stars 73 forks source link

Auth0 Terraform Provider not handling the state for `auth0_role_permissions` resources #954

Closed hectorhuol closed 1 month ago

hectorhuol commented 2 months ago

Checklist

Description

I am creating some resources using the Auth0 Terraform provider and I am noticing this strange behavior with the auth0_role_permissions, and I am not sure if it is expected or not.

What is happening to me, is that the first time I ran my Terraform, I got an error saying that one permission didn’t exist. I added the depends_on and the terraform worked fine and all my Auth0 resources are being created.

Now what happens is that every time I run a terraform plan(without making any change to the terraform code) it says that it will update my role permissions, and the update is that it will delete the assigned permissions, like this:

# module.iq_saas_admin[0].auth0_role_permissions.iq_saas_admin_support["staging"] will be updated in-place
  ~ resource "auth0_role_permissions" "iq_saas_admin_support" {
        id      = "rol_v0XKG2RYOinLzPtZ"
        # (1 unchanged attribute hidden)

      - permissions {
          - description                = "Permission to generate support zip files" -> null
          - name                       = "create:support-zip" -> null
          - resource_server_identifier = "https://dev.mtiq-admin-service.cloudy.sonatype.dev/" -> null
          - resource_server_name       = "dev-iq-saas-admin-api" -> null
        }
      - permissions {
          - description                = "Permission to read IQ SaaS tenants" -> null
          - name                       = "read:tenants" -> null
          - resource_server_identifier = "https://dev.mtiq-admin-service.cloudy.sonatype.dev/" -> null
          - resource_server_name       = "dev-iq-saas-admin-api" -> null
        }

        # (2 unchanged blocks hidden)
    }

If apply the terraform plan, then the role permissions are deleted, and if I run again the terraform plan(Again without making any change to the terraform code), what happens is that my role permissions will be updated again, but now all the permissions will be added, something like this:

# module.iq_saas_admin[0].auth0_role_permissions.iq_saas_admin_support["dev"] will be updated in-place
  ~ resource "auth0_role_permissions" "iq_saas_admin_support" {
        id      = "rol_v0XKG2RYOinLzPtZ"
        # (1 unchanged attribute hidden)

      + permissions {
          + description                = (known after apply)
          + name                       = "create:support-zip"
          + resource_server_identifier = "https://dev.mtiq-admin-service.cloudy.sonatype.dev/"
          + resource_server_name       = (known after apply)
        }
      + permissions {
          + description                = (known after apply)
          + name                       = "read:tenants"
          + resource_server_identifier = "https://dev.mtiq-admin-service.cloudy.sonatype.dev/"
          + resource_server_name       = (known after apply)
        }
    }

I can keep doing the same all day, and I always get the same behavior, it first deletes the permissions, then adds them again. So in the end I never get the No Changes message I expect from Terraform.

And if I try to put the next block on the auth0_resource_server resource:

# Until we remove the ability to operate changes on
  # the scopes field it is important to have this
  # block in the config, to avoid diffing issues.
  lifecycle {
    ignore_changes = [scopes]
  }

I am getting the next error from Terraform:

 Error: Unsupported attribute
│
│   on iq-saas-admin\apis.tf line 18, in resource "auth0_resource_server" "iq_saas_admin_apis":
│   18:     ignore_changes = [ scopes ]
│
│ This object has no argument, nested block, or exported attribute named "scopes".

Expectation

I expect auth0_role_permissions resources to be saved on terraform state always, and I can get the No Changes message from TerraformTerraform

Reproduction

  1. Use this Terraform Code as a reference:

    
    resource "auth0_resource_server" "iq_saas_admin_apis" {
    for_each = var.configuration.environments
    
    name                                            = each.value.api.name
    identifier                                      = each.value.api.identifier
    signing_alg                                     = "RS256"
    token_lifetime                                  = 86400
    token_lifetime_for_web                          = 7200
    enforce_policies                                = true
    skip_consent_for_verifiable_first_party_clients = true
    allow_offline_access                            = false
    token_dialect                                   = "access_token"
    }

resource "auth0_resource_server_scopes" "iq_saas_admin_api_scopes" { for_each = var.configuration.environments

resource_server_identifier = auth0_resource_server.iq_saas_admin_apis[each.key].identifier

scopes { name = "create:tenants" description = "Permission to create IQ SaaS tenants" }

scopes { name = "update:tenants" description = "Permission to update IQ SaaS tenants" }

scopes { name = "read:tenants" description = "Permission to read IQ SaaS tenants" }

scopes { name = "delete:tenants" description = "Permission to delete IQ SaaS tenants" }

scopes { name = "create:support-zip" description = "Permission to generate support zip files" } }

resource "auth0_role" "iq_saas_admin_support" { description = "Support access for the IQ SaaS Admin App" name = "IQ SaaS Admin App - Support" }

resource "auth0_role_permissions" "iq_saas_admin_support" { for_each = var.configuration.environments

role_id = auth0_role.iq_saas_admin_support.id

permissions { name = "create:support-zip" resource_server_identifier = auth0_resource_server.iq_saas_admin_apis[each.key].identifier } permissions { name = "read:tenants" resource_server_identifier = auth0_resource_server.iq_saas_admin_apis[each.key].identifier }

depends_on = [ auth0_resource_server_scopes.iq_saas_admin_api_scopes ] }



2. Run `terraform apply` -> Resources are created successfully 
3. Run `terraform plan` -> Terraform says it has some changes to apply(Deleting all permissions assigned to role)
4. Run `terraform apply` -> Permissions are deleted
5. Run `terraform plan` -> Terraform says it has some changes to apply(Now it wants to add back all permissions assigned to role)
6. Run `terraform apply` -> Permissions are added back

Continue with the `terraform plan` and `terraform apply` all the times you want the permissions are always deleted and then added back

### Auth0 Terraform Provider version

1.2.0

### Terraform version

1.7.4
sergiught commented 1 month ago

Hey @hectorhuol 👋🏻

Thanks for taking the time to put such a detailed issue together ⭐ and apologies for the time it took to get back to you. I'm no longer working on the provider but going forward the community should expect much faster replies as we're onboarding new team members to the project.

I was able to reproduce your issue and understand what's causing it. I'll attempt at clarifying this for you, but please don't hesitate to follow up with further questions if something's not clear.


From the HCL configuration snippet you provided above I can see that you're:

Now the issue you're encountering is caused by the fact that when you're using the auth0_role_permissions resource, you're actually effectively creating 2 separate resources behind the scenes through the use of the for_each at the resource level.

The auth0_role_permissions resource manages all the permissions assigned to a role in bulk and you can only ever have 1 instance of this resource within your config, otherwise if you have multiple and they have different permissions, only the last resource that gets applied will have any effect, as that will overwrite the changes from a previous resource.

If you want the permissions to get added in an append only style you'll need to switch your config to use the 1 to 1 resource relationship instead auth0_role_permission or use dynamic permission blocks if you want to use the auth0_role_permissions that manages everything in bulk through a 1 to many relationship. Does this make sense?

So you're effectively seeing a constant change because the 2 auth0_role_permissions resources, that get created because of the for_each block on the resource level, will overwrite each other. Please also check the warning inside the docs: https://registry.terraform.io/providers/auth0/auth0/latest/docs/resources/role_permissions for this.

So you have 2 options to fix your configuration: A) Use for_each at a resource level but with the auth0_role_permission resource instead (1:1 relationship) B) Use dynamic permissions blocks and use the for_each inside there to manage everything with only 1 auth0_role_permissions resource.

This is only if you truly want to use 1 role for both APIs created. It would be great to understand from your side if that's intended or there's a missed for_each block on the auth0_role resource so you have a dedicate role for each environment.

If you want to use 1 role for both APIs and only use the auth0_role_permissions resource, you'd have to modify your configuration as follows, so that you only have 1 auth0_role_permissions resource created that won't overwrite others:

resource "auth0_role_permissions" "iq_saas_admin_support" {
    role_id = auth0_role.iq_saas_admin_support.id

    dynamic "permissions" {
        for_each = var.configuration.environments
        content {
            name                       = "create:support-zip"
            resource_server_identifier = auth0_resource_server.iq_saas_admin_apis[permissions.key].identifier
        }
    }

    dynamic "permissions" {
        for_each = var.configuration.environments
        content {
            name                       = "read:tenants"
            resource_server_identifier = auth0_resource_server.iq_saas_admin_apis[permissions.key].identifier
        }
    }
}

The above will attach 4 permissions to the auth0_role, create:support-zip from the first API, create:support-zip from the second API, read:tenants from the first API and read:tenants from the second API.

hectorhuol commented 1 month ago

Hi @sergiught

Thanks for the detailed response, now I understand better how the auth0_role_permission works, what you explained there makes a lot of sense. I tested with your suggestion, and the error I saw disappeared, thanks for the help!

Regards