Skip to content

Instantly share code, notes, and snippets.

@abij
Last active June 13, 2025 08:00
Show Gist options
  • Save abij/e2515f4275f46902dc26a46811e708e6 to your computer and use it in GitHub Desktop.
Save abij/e2515f4275f46902dc26a46811e708e6 to your computer and use it in GitHub Desktop.
All in one terraform example to manage Azure SCIM-app and Account-level groups.
terraform {
required_providers {
azuread = {
source = "hashicorp/azuread"
# Latest version selected
}
databricks = {
source = "databricks/databricks"
# Latest version selected
}
}
}
# === Providers ===============================================================
# Permissions required:
# - Add groups to SCIM-app: `Owner` on SCIM App + `Application.ReadWrite.OwnedBy` on calling SPN app.
# - Lookup groups: `Group.Read.All` or `Directory.Read.All` on calling SPN-app.
provider "azuread" {
}
# Permission required:
# - Add groups: `Account Admin`
provider "databricks" {
# Note: Account-level (not pointing to a Workspace)
host = "https://accounts.azuredatabricks.net"
account_id = "<here your Azure Databricks Account Id>" # found in Account-console (url)
auth_type = "azure-cli"
}
# === Variables ===============================================================
variable "input_group_names" {
type = list(string)
description = "EntraID group names to add in Databricks Account-level and SCIM-app for automatic user synchronization."
default = [
"group1",
"group2"
]
}
# === Data lookups ============================================================
# Check the groups that are available in Azure AD:
data "azuread_groups" "included" {
# This is more efficient then using "azuread_group" with a for_each.
# Only the object_id and display_name are returned, not all the members and many other properties.
display_names = var.input_group_names
}
# Lookup "Azure Databricks SCIM Provisioning Connector"
data "azuread_service_principal" "scim" {
client_id = "<here your SCIM app Client Id>"
}
# === Locals ==================================================================
locals {
# Make a mapping of the group name => object_id
included_groups = {
for i in range(length(data.azuread_groups.included.display_names)) :
data.azuread_groups.included.display_names[i] => data.azuread_groups.included.object_ids[i]
}
# Filter the app_role if there the display_name is "User" return its id
scim_app_user_role_id = [for r in data.azuread_service_principal.scim.app_roles: r.id if r.display_name == "User"][0]
}
# === Resources ===============================================================
# Create (empty) external groups in the Databrick Account-level.
resource "databricks_group" "scim" {
for_each = local.included_groups
display_name = each.key
external_id = each.value
force = true # don't fail when the group already exists.
}
# Create groups in SCIM-app for synchronization
resource "azuread_app_role_assignment" "scim_group" {
for_each = local.included_groups
app_role_id = local.scim_app_user_role_id
principal_object_id = each.value
resource_object_id = data.azuread_service_principal.scim.object_id
}
# Assign a non-user as owner of the SCIM-app:
#
# 0. Lookup the client-id of the SCIM-app
# 1. Lookup the object-id of the Service Principal to add as Owner.
# 2. Use Azure-CLI to assign the Owner
az rest --method post \
--url "https://graph.microsoft.com/v1.0/servicePrincipals(appId='SCIM_APP_CLIENT_ID')/owners/\$ref" \
--body '{"@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/OBJECT-ID-OF-THE-SPN"}'
@jijosg
Copy link

jijosg commented Jun 13, 2025

Thanks this was really helpful.

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