databricks / terraform-provider-databricks

Databricks Terraform Provider
https://registry.terraform.io/providers/databricks/databricks/latest
Other
457 stars 393 forks source link

[ISSUE] `databricks_permission_assignment` doesn't admit empty `permissions` #3619

Open camilo-s opened 6 months ago

camilo-s commented 6 months ago

Configuration

terraform {
  required_providers {
    databricks = {
      configuration_aliases = [databricks.account, databricks.default]
      source                = "databricks/databricks"
    }
  }
}

data "databricks_group" "admin" {
  display_name = var.group_name

  provider = databricks.account
}

resource "databricks_permission_assignment" "this" {
  principal_id = data.databricks_group.admin.id
  permissions  = []

  provider = databricks.default
}

resource "databricks_entitlements" "this" {
  group_id              = data.databricks_group.admin.id
  workspace_access      = false
  databricks_sql_access = true

  depends_on = [databricks_permission_assignment.this]
  provider   = databricks.default
}

Expected Behavior

The group is assigned to the workspace (without entitlements), and the group's fine grained entitlements are created further downstream with databricks_entitlements.

Actual Behavior

terraform apply fails with the following error:

│ Error: cannot read permission assignment: <REDACTED> not found
│ 
│   with module.databricks_permission_assignment.databricks_permission_assignment.this,
│   on ../../modules/databricks-permission-assignment/main.tf line 16, in resource "databricks_permission_assignment" "this":
│   16: resource "databricks_permission_assignment" "this" {

Steps to Reproduce

  1. Provide input variables
  2. terraform apply

Terraform and provider versions

Terraform version: 1.8.3 terraform-provider-databricks_v1.44.0

Is it a regression?

To my knowledge, no.

Debug Output

See linked gist.

Important Factoids

I was unsure if this should be classified as an issue or a feature request. I opted for issue, since IMHO the provider behaves in an unexpected way.

Currently principal entitlements can be set with at least three different resources:

Ideally, they should interplay well with each other. For instance, databricks_group optionally admits entitlements as arguments, setting them to null if not provided, so you can set them downstream via databricks_entitlements.

In contrast, by assigning a principal to a workspace with databricks_permission_assignment, you are forced by the provider to assign either "USER" or "ADMIN" for permissions, which carry few workspace entitlements along, leaving you unable to define more fine graded entitlements with databricks_entitlements.

Two use-cases why such behaviour would be reasonable:

Another reason why the behavior is unexpected: the (account-level) Permission Assignment API admits doing assignments with empty permissions. Granted, I believe the Terraform resource databricks_permission_assignment uses a different API, but it would be just intuitive to expect it to work analogously.

Would you like to implement a fix?

With some guidance yes.

alexott commented 6 months ago

you're using a workspace-level provider for which the databricks_group data source will return the SCIM ID of the local group, while the permission assignment resource needs the account-level SCIM ID for the group. You need to use account-level provider to read group ID

camilo-s commented 6 months ago

I'm actually using the account-level provider to read the group's ID and Terraform can read it during plan:

module.databricks_permission_assignment.data.databricks_group.admin: Reading...
module.databricks_permission_assignment.data.databricks_group.admin: Read complete after 1s [id=<REDACTED>]

Anyhow, that shouldn't be an issue because, as of some time now, account-level IDs for group coincide with the workspace-level ones (can't tell for sure since when). E.g. the following outputs is_group_id_equal = true

terraform {
  required_providers {
    databricks = {
      configuration_aliases = [databricks.account, databricks.default]
      source                = "databricks/databricks"
    }
  }
}

data "databricks_group" "admin" {
  display_name = var.group_name

  provider = databricks.account
}

resource "databricks_permission_assignment" "this" {
  principal_id = data.databricks_group.admin.id
  permissions  = ["USER"]

  provider = databricks.default
}
data "databricks_group" "this" {
  display_name = var.group_name

  provider   = databricks.default
  depends_on = [databricks_permission_assignment.this]
}

output "is_group_id_equal" {
  value = data.databricks_group.admin.id == data.databricks_group.this.id
}
camilo-s commented 6 months ago

In any case, it seems setting only permissions = ["USER"] enables the group in the workspace without any entitlements. This is kind of confusing, as the entitlements documentation states that users get workspace and Databricks SQL access by default.

Do you think it would make sense to open a feature request to enable databricks_permission_assignment for the account provider? (for Azure workspaces it only works with the workspace provider at the moment, in contrast with databricks_mws_permission_assignment).

alexott commented 6 months ago

databricks_mws_permission_assignment should be used on account level

camilo-s commented 6 months ago

What I find more annoying is that restricting entitlements at group level has no effect on the actual user entitlements of the group members. If I define group entitlements as per the code below, the group's entitlements show in the Admin Settings UI as declared, however, any member of the group will have the default workspace access and Databricks SQL entitlements, so what's the point of doing databricks_entitlements at group granularity if they don't come to bear upon effective user's entitlements?

terraform {
  required_providers {
    databricks = {
      configuration_aliases = [databricks.account, databricks.default]
      source                = "databricks/databricks"
    }
  }
}

data "databricks_group" "admin" {
  display_name = var.group_name

  provider = databricks.account
}

resource "databricks_permission_assignment" "this" {
  principal_id = data.databricks_group.admin.id
  permissions  = ["USER"]

  provider = databricks.default
}
data "databricks_group" "this" {
  display_name = var.group_name

  provider   = databricks.default
  depends_on = [databricks_permission_assignment.this]
}

output "is_group_id_equal" {
  value = data.databricks_group.admin.id == data.databricks_group.this.id
}

resource "databricks_entitlements" "this" {
  group_id              = databricks_permission_assignment.this.principal_id
  workspace_access      = false
  databricks_sql_access = false

  depends_on = [databricks_permission_assignment.this]
  provider   = databricks.default
}

Group's entitlements: Screenshot 2024-05-27 at 11 22 18

Member's entitlements: Screenshot 2024-05-27 at 11 22 06