Microsoft Fabric OneLake Security: RBAC, Row-Level Security, and Purview Governance at Scale

The question that killed Fabric adoption in 2025 was simple: "How do I prevent Team A from seeing Team B's data?" Workspace-level permissions were the only option, and they were too coarse for any organization with sensitive data.

OneLake security went GA in early 2026 with granular folder-level and table-level RBAC, shortcuts-aware governance policies, and REST APIs for automated role management. This is the missing piece that makes Fabric viable for enterprises.

The OneLake Security Model

┌──────────────────────────────────────────────────┐
│                  OneLake                          │
│  ┌────────────────────────────────────────────┐  │
│  │  Fabric Workspace                          │  │
│  │  ┌──────────────┐  ┌──────────────────┐   │  │
│  │  │ Lakehouse A   │  │ Lakehouse B       │   │  │
│  │  │               │  │                   │   │  │
│  │  │ Folder: /raw  │  │ Folder: /sensitive│   │  │
│  │  │ (team-shared) │  │ (restricted)      │   │  │
│  │  │               │  │                   │   │  │
│  │  │ ACL: Team A   │  │ ACL: Team B only  │   │  │
│  │  └──────────────┘  └──────────────────┘   │  │
│  │                                            │  │
│  │  Workspace ACL: Analysts (read)            │  │
│  │  Folder ACL: Override workspace (restricted)│ │
│  └────────────────────────────────────────────┘  │
│                                                   │
│  ┌────────────────────────────────────────────┐  │
│  │  Shortcut: /lakehouse-a/external-data      │  │
│  │  → Points to ADLS Gen2 / S3 bucket         │  │
│  │  → Inherits governance from Lakehouse       │  │
│  │  → Can have independent ACL                │  │
│  └────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────┘

Key Design Principles

  1. Inheritance with override. Folder ACLs inherit from workspace ACLs but can be overridden at any level. A user with workspace-level read access can be denied access to a specific folder.
  2. Shortcuts respect governance. When you create a shortcut to external data (ADLS Gen2, S3), the shortcut inherits the governance policy of the parent Lakehouse. You can also apply independent ACLs to the shortcut itself.
  3. REST API for CI/CD. All role assignments are manageable via REST API, enabling automated governance in your deployment pipelines.

RBAC Implementation

Built-in Roles

Role Scope Permissions
Admin Workspace Full control, manage permissions
Contributor Workspace/Lakehouse Read, write, create artifacts
Member Workspace Read, write (no permission management)
Viewer Workspace/Folder Read-only
None No access (explicit deny)

Custom Role via REST API

# Grant folder-level access via OneLake Security REST API
curl -X POST "https://api.fabric.microsoft.com/v1/workspaces/{workspace-id}/lakehouses/{lakehouse-id}/security/permissions" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "principal": {
      "id": "{security-group-id}",
      "type": "SecurityGroup"
    },
    "role": "Viewer",
    "scope": {
      "type": "Folder",
      "path": "/sensitive/financial-data"
    }
  }'

# Grant table-level access
curl -X POST "https://api.fabric.microsoft.com/v1/workspaces/{workspace-id}/lakehouses/{lakehouse-id}/security/permissions" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "principal": {
      "id": "{user-id}",
      "type": "User"
    },
    "role": "Contributor",
    "scope": {
      "type": "Table",
      "name": "customer_pii"
    }
  }'

Terraform Automation

# Automate OneLake security via Fabric REST API + Terraform null_resource
resource "null_resource" "onelake_security" {
  for_each = var.folder_permissions

  triggers = {
    folder_path = each.value.folder_path
    principal   = each.value.principal_id
    role        = each.value.role
  }

  provisioner "local-exec" {
    command = <<-EOT
      curl -X POST "${var.fabric_api_url}/workspaces/${var.workspace_id}/lakehouses/${var.lakehouse_id}/security/permissions" \
        -H "Authorization: Bearer ${var.fabric_token}" \
        -H "Content-Type: application/json" \
        -d '${jsonencode({
          principal = { id = each.value.principal_id, type = each.value.principal_type }
          role      = each.value.role
          scope     = { type = "Folder", path = each.value.folder_path }
        })}'
    EOT
  }
}

variable "folder_permissions" {
  type = map(object({
    folder_path     = string
    principal_id    = string
    principal_type  = string
    role            = string
  }))
  default = {
    "finance-team-raw" = {
      folder_path    = "/finance/raw-data"
      principal_id   = "sec-group-finance"
      principal_type = "SecurityGroup"
      role           = "Contributor"
    }
    "finance-team-sensitive" = {
      folder_path    = "/finance/sensitive"
      principal_id   = "sec-group-finance-leads"
      principal_type = "SecurityGroup"
      role           = "Viewer"
    }
  }
}

Row-Level and Column-Level Security

OneLake security handles folder and table access. For finer-grained control within tables, use T-SQL security features in Fabric Data Warehouse:

-- Row-Level Security: Users see only their region's data
CREATE FUNCTION security.fn_region_access(@region NVARCHAR(50))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS result
WHERE @region = SYSTEM_USER_CONTEXT() OR IS_MEMBER('db_owner');

CREATE SECURITY POLICY region_filter
ADD FILTER PREDICATE security.fn_region_access(region)
ON dbo.sales_data
WITH (STATE = ON);

-- Column-Level Security: Hide sensitive columns from non-privileged users
GRANT SELECT ON dbo.sales_data(region, product, amount) TO analyst_role;
GRANT SELECT ON dbo.sales_data(region, product, amount, customer_ssn, customer_email) TO compliance_role;

Purview Integration for Automated Compliance

Microsoft Purview classifies data automatically and applies governance policies:

from azure.purview.scanning import PurviewScanningClient
from azure.identity import DefaultAzureCredential

# Register a Fabric Lakehouse as a Purview data source
purview_client = PurviewScanningClient(
    endpoint="https://your-purview.purview.azure.com/",
    credential=DefaultAzureCredential()
)

# Create a scan rule for PDPA classification
scan_rule = {
    "name": "PDPA-Classification",
    "type": "SystemScanRuleset",
    "dataSourceType": "AzureDataLakeStorage",
    "customRules": [
        {
            "ruleName": "Malaysian-IC",
            "columnName": "*",
            "regexPattern": "\\d{6}-\\d{2}-\\d{4}",
            "sensitivityLabel": "Highly Confidential"
        },
        {
            "ruleName": "Email-Address",
            "columnName": "*",
            "regexPattern": "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}",
            "sensitivityLabel": "Confidential"
        }
    ]
}

The compliance pipeline:

OneLake Data → Purview Scan → Classification → Sensitivity Labels →
  └── Auto-apply RBAC based on label
       ├── "Highly Confidential" → Restricted folder + encrypted
       ├── "Confidential" → Team-only folder
       └── "Public" → Workspace-wide access

Comparison with Databricks Unity Catalog and Snowflake

Feature Fabric OneLake Security Databricks Unity Catalog Snowflake
Granularity Folder, Table, Column Catalog, Schema, Table, Column Database, Schema, Table, Column
Shortcuts awareness ✅ Native ❌ External locations only
Row-level security T-SQL native Row filters Row access policies
Column masking T-SQL GRANT Dynamic views Dynamic data masking
CI/CD API REST API (GA) Terraform provider Terraform provider
Purview/DLP integration Native Purview External (Microsoft Purview) External
Cross-platform Fabric only Databricks only Snowflake only
Cost Included in Fabric Included in Databricks Included in Snowflake

Common Anti-Patterns

Anti-Pattern 1: Over-granting at workspace level

# BAD: Giving everyone Contributor at workspace level
# Then trying to restrict individual folders
az fabric workspace access add --role Contributor --principal everyone

# GOOD: Give minimal workspace access, restrict at folder level
az fabric workspace access add --role Viewer --principal everyone
# Then grant Contributor on specific folders

Anti-Pattern 2: Ignoring shortcuts

Shortcuts to external data inherit the parent Lakehouse's governance, but the external data itself may not be governed. Always apply explicit ACLs to shortcuts pointing to sensitive external data.

Anti-Pattern 3: Manual governance at scale

Do not manage permissions through the Fabric UI for more than 10 folders. Use the REST API and automate via Terraform or CI/CD pipelines.

Key Takeaways

  1. OneLake security is the critical missing piece that makes Fabric enterprise-viable. Folder-level and table-level RBAC with shortcuts-aware governance means you can finally enforce least-privilege access.
  2. Inheritance with override is the design pattern. Start with minimal workspace access, then grant granular permissions at folder and table level.
  3. Automate governance via REST API and Terraform. Manual permission management does not scale. Build governance into your deployment pipelines.
  4. Purview integration enables automated classification and compliance. Data sensitivity labels drive RBAC decisions — classify first, then govern.
  5. Compare with Databricks Unity Catalog before committing. Both platforms offer similar governance features; the choice depends on your broader ecosystem (Microsoft vs Databricks/Spark).

Resources