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
- 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.
- 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.
- 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
- 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.
- Inheritance with override is the design pattern. Start with minimal workspace access, then grant granular permissions at folder and table level.
- Automate governance via REST API and Terraform. Manual permission management does not scale. Build governance into your deployment pipelines.
- Purview integration enables automated classification and compliance. Data sensitivity labels drive RBAC decisions — classify first, then govern.
- Compare with Databricks Unity Catalog before committing. Both platforms offer similar governance features; the choice depends on your broader ecosystem (Microsoft vs Databricks/Spark).