Chapter 10 of 12

Power BI Data Analyst PL-300

Row-Level Security, Object-Level Security, and Data Protection

1. Foundations of Power BI Security Architecture

The Defense-in-Depth Model

Power BI security operates as concentric rings: tenant governance and Azure AD policies form the outer ring, workspace permissions (Admin, Member, Contributor, Viewer) control artifact access, dataset Build permission governs report creation, and the innermost rings — RLS, OLS, and sensitivity labels — govern the data itself. A critical production pitfall is assuming Workspace Viewer access implies row-level scoping; it does not. RLS must be explicitly configured, and users not assigned to any role see the full dataset.

Users with Power BI Dataset Build permission bypass RLS entirely when connecting via Analyze in Excel or live connections from Power BI Desktop. The architectural response is workspace separation — keep model builders in a development workspace with Build access and data consumers in a production workspace with Viewer-only access, using dataset sharing to bridge them without granting Build rights.

Security Role Artifacts and Lifecycle

RLS roles are model artifacts stored in the .pbix and published with the dataset — modifying a role definition requires republishing from Desktop. Role membership, however, is managed in the Power BI Service without republishing and is typically delegated to workspace admins or business owners. OLS configurations follow the same publication lifecycle; sensitivity labels are applied separately via Desktop, the Service, or automatic inheritance from labeled upstream sources.

Architecture diagram with three horizontal sections showing Power BI Desktop defining Static RLS with DAX filter expressions, Dynamic RLS using USERPRINCIPALNAME() with a dimension table lookup, and Object-Level Security hiding columns via Tabular Editor; Power BI Service managing role membership with Azure AD users and groups, View as Role testing, and Sensitivity Labels enforcing Microsoft Purview MIP policies; and a User Access Outcomes section showing Workspace Admins receiving full unfiltered data, Sales West role seeing only Region equals West rows, Analyst role with Salary column hidden by OLS, and a MIP label actions panel showing General, Confidential, and Highly Confidential label enforcement behaviors including encryption and export blocking.
Figure 10.1 — Power BI security layers: RLS, OLS, and MIP sensitivity label enforcement architecture

2. Static RLS: Role Definition and DAX Filter Expressions

Defining Static Roles in Power BI Desktop

Static RLS roles are defined in Modeling > Manage Roles. Each role is paired with a Boolean DAX table filter expression — Power BI returns only rows for which the expression evaluates to TRUE. Filters should target dimension tables rather than fact tables; Power BI propagates the dimension filter through relationships to downstream fact tables automatically. Filtering the fact table directly is a common mistake that prevents upstream filter propagation.

DAX Filter Expression Patterns

Common static filter patterns: single value ([Region] = "North America"), multi-value set ([Region] IN {"North America","EMEA"}), and substring match (CONTAINSSTRING([SalesRegionCodes],"NA")). Note that filter expressions cannot reference measures or columns from other tables without RELATED or RELATEDTABLE.

Important

RLS filter expressions are evaluated at query time on every row of the filtered table. Complex filters using RELATED or nested CALCULATE calls can add significant latency at scale. Profile with Performance Analyzer before deploying to high-concurrency environments.

Multiple Tables and Role Interaction

A single role can filter multiple tables simultaneously — each table entry adds an independent filter. When a user belongs to multiple roles, Power BI applies the union (OR) of all role filters, not the intersection. If AND semantics are required, merge the conditions into a single role with a compound DAX expression. Workspace Admins, Members, and Contributors bypass RLS entirely; only Viewers and users with direct Read permission are subject to role filters.

Note

Bidirectional cross-filter relationships can cause filter context leakage through RLS. Use unidirectional relationships in security-sensitive models and apply explicit filters to both sides when bidirectionality is functionally required.

A four-layer Power BI security architecture diagram showing: Layer 1 with Static RLS DAX role definitions and Dynamic RLS using USERPRINCIPALNAME with a DimEmployee dimension table for cross-table filter propagation; Layer 2 with Object-Level Security configuration states (Read, None, Error), column and table hiding examples, and key constraints requiring Tabular Editor; Layer 3 with Sensitivity Label application, inheritance to reports and exports, MIP policy enforcement actions, and license requirements; Layer 4 with testing workflows in Desktop using View as Role and in the Service using impersonation, role membership assignment, and RLS bypass rules for workspace admins.
Figure 10.2 — Power BI layered security: RLS, OLS, and Sensitivity Labels configuration architecture

3. Dynamic RLS with USERPRINCIPALNAME() and Dimension Tables

Dynamic RLS Architecture

Dynamic RLS uses a single role definition whose DAX filter expression evaluates differently per user at query time. The canonical pattern loads a security mapping table (e.g., UserSecurity) with columns [UserPrincipalName] and [Region], joins it to the Geography dimension via [Region], and sets the role filter on the security table to [UserPrincipalName] = USERPRINCIPALNAME(). The relationship propagates the per-user filter through Geography to the Sales fact table. The security mapping table should be sourced from a live data source — not an "Enter Data" table — so access changes take effect on dataset refresh without republishing the .pbix.

USERNAME() vs. USERPRINCIPALNAME()

USERPRINCIPALNAME() returns the Azure AD UPN (user@domain.com format) and is the recommended function for all modern cloud Power BI deployments. USERNAME() returns DOMAIN\username format — identical to UPN for cloud-only accounts, but different for hybrid AD accounts with mismatched SAM names. Always use USERPRINCIPALNAME() and store UPN values in the security mapping table.

Tip

Validate dynamic RLS using real authentication tokens in the Power BI Service with dedicated test accounts — the Desktop "View as" dialog uses a static string, not a real AAD token, and cannot replicate hybrid identity edge cases.

Implementing Dynamic RLS

Five-step pattern: (1) load the security mapping table from a governed live source; (2) create a many-to-one relationship from UserSecurity[Region] to Geography[RegionCode] with single-direction cross-filter; (3) define the role filter; (4) add all data consumers to this single role; (5) handle edge cases — unmatched users see no data (correct default), users with multiple rows see the union of their partitions.

dax
-- Dynamic RLS role filter on UserSecurity table
[UserPrincipalName] = USERPRINCIPALNAME()

-- Manager-subordinate variant (user sees own rows + reports)
[UserPrincipalName] = USERPRINCIPALNAME()
    || [ManagerUPN] = USERPRINCIPALNAME()

Warning

Never use the "Enter Data" feature for the security mapping table in production. Hard-coded security tables require dataset republication on every access change — use a live, refreshable data source instead.

4. Object-Level Security: Hiding Tables and Columns

OLS Architecture and Capacity Requirements

Object-Level Security hides tables or columns at the metadata level — hidden objects do not appear in the field list and cannot be referenced in DAX or report visuals by members of the restricted role. OLS requires Premium capacity (Premium Per User or Premium Per Capacity) and datasets using the enhanced metadata format. It is unavailable in shared-capacity Pro workspaces. OLS is configured exclusively through Tabular Editor (free TE2 or commercial TE3) — Power BI Desktop has no native OLS UI.

Configuring Column-Level OLS

In Tabular Editor, expand the table, select the column, open the Security tab in properties, and set MetadataPermission to None for the role to be denied. The valid values are Read (allowed), None (denied — object hidden), and ReadDesign. When a column is OLS-restricted, any measure that references it also becomes inaccessible to the denied role — users receive an error, not empty results.

Important

OLS denial returns an error to the user — not a blank visual or filtered row set. Report developers must build separate report pages for OLS-restricted roles to avoid confusing error states.

OLS vs. RLS Decision and Comparison

Use RLS when all users see the same columns but different rows (regional data, cost centers). Use OLS when certain users must not know a column or table exists (salary, PII, competitive intelligence). Combine both for fine-grained governance: RLS scopes rows, OLS scopes columns. OLS and RLS are independent — a table can have both applied to different aspects of the same role.

Security Control Scope Capacity Req. Where Configured Effect on Denied Users
Workspace PermissionsWorkspace artifactsShared or PremiumPower BI ServiceCannot view workspace reports
Dataset Build PermissionDatasetShared or PremiumPower BI ServiceCannot build reports against dataset
RLS (Static)Rows in tablesShared or PremiumPower BI DesktopSees only role-filtered rows
RLS (Dynamic)Rows in tablesShared or PremiumPower BI DesktopSees rows matching identity mapping
OLS (Column-Level)Specific columnsPremium (PPU or P-SKU)Tabular EditorError on any visual referencing column
OLS (Table-Level)Entire tablesPremium (PPU or P-SKU)Tabular EditorError on any visual referencing table
Sensitivity Labels (MIP)Dataset/Report artifactShared or PremiumDesktop or ServiceExport governed by MIP policy

5. Sensitivity Labels: Applying, Inheriting, and Enforcing MIP Policies

Microsoft Information Protection and Power BI Integration

MIP sensitivity labels (Confidential, Highly Confidential, Internal, etc.) classify data confidentiality and trigger downstream governance policies. Labels applied to Power BI datasets travel with data when exported — Excel, CSV, PowerPoint, and Analyze in Excel connections all inherit the source dataset's label, and the associated MIP policy (encryption, watermarking, access restrictions) is applied to the exported file. Labels are defined in the Microsoft Purview compliance portal and published to Power BI users via label policies.

Applying Labels in Desktop and the Service

In Power BI Desktop, the Sensitivity button in the Home ribbon opens the label picker. The selected label is embedded in the .pbix metadata and published with the dataset. In the Power BI Service, labels can be viewed and changed on datasets, reports, dashboards, and dataflows via artifact settings. Label downgrade (reducing classification) may require business justification and is logged to the Purview audit log for compliance traceability.

Note

Sensitivity label support requires Azure Information Protection Plan 1 or Plan 2 (included in M365 E3/E5). Users without AIP licenses cannot apply or change labels, and export operations may be blocked by label policy.

Label Inheritance and Downstream Enforcement

When "Automatically apply sensitivity labels from data sources" is enabled at the tenant level, Power BI datasets inherit the highest-classification label from their upstream data sources. This propagates to downstream reports, dashboards, and dataflows. Exported files receive the inherited label and associated Azure Rights Management policy — encryption, forwarding restrictions, and visual watermarks are applied transparently. This creates an auditable governance chain from source classification to exported artifact.

Warning

Sensitivity labels govern how data can be exported and forwarded — not who can view it within Power BI. Always combine labels with workspace permissions and RLS to achieve both access governance and export governance.

6. Testing RLS and Managing Role Membership

Testing with View as Role in Power BI Desktop

The View as feature (Modeling ribbon) renders the report through a selected role's filter. For static roles, check the role checkbox. For dynamic roles, check the role AND enter a test UPN in the "Other user" field — Power BI substitutes this string as the return value of USERPRINCIPALNAME(). Test with UPNs present in the security table (expect scoped data), absent UPNs (expect no data), and UPNs mapped to multiple partitions (expect union). Document each test case in a test matrix with expected vs. actual row counts.

Managing Role Membership in the Power BI Service

Navigate to the workspace dataset > three-dot menu > Security to add Azure AD users or security groups to each defined role. Adding Azure AD security groups is the recommended pattern — group membership in AAD drives access without requiring any dataset changes. Changes take effect within minutes due to AAD token caching. The Power BI REST API (POST .../datasets/{id}/roles/{role}/members) enables automated membership management integrated with HR and identity governance systems.

Important

Role membership and workspace permissions are independent. A user in an AAD group mapped to an RLS role must also have at least Viewer-level workspace access to see any reports. A Workspace Viewer not assigned to any role sees all data if no catch-all role filter is defined.

Validating RLS in the Power BI Service

Always validate published RLS using real test accounts in the Service — real AAD tokens and group memberships may differ from Desktop simulation. Create two test accounts: one with a role assignment (expects scoped data) and one outside all roles (expects no data or an access message). Verify slicers and drillthrough pages cannot expose out-of-scope data. For dynamic RLS, confirm that accounts absent from the security mapping table return zero rows, not all rows — a mismatch indicates a relationship or filter expression error.

7. Lab: Implementing Dynamic RLS and MIP Sensitivity Labels

19

CE-19: Dynamic RLS with Azure SQL Security Mapping Table

Provision an Azure SQL Database to host the dynamic RLS security mapping table, populate it with user-region mappings, and configure the Power BI dataset role membership via REST API.

bash
# CE-19: Provision Azure SQL and configure Dynamic RLS
RESOURCE_GROUP="rg-rls-ols-data-protection-prod-001"
SQL_SERVER_NAME="rls-ols-prod-eastus2-001"
SQL_DB_NAME="RLSSecurityMappingDB"

az group create --name "$RESOURCE_GROUP" --location "eastus2"
az sql server create --name "$SQL_SERVER_NAME" --resource-group "$RESOURCE_GROUP" \
  --location "eastus2" --admin-user "sqladmin" --admin-password "S3cur3Pa\$\$w0rd!"
az sql db create --resource-group "$RESOURCE_GROUP" --server "$SQL_SERVER_NAME" \
  --name "$SQL_DB_NAME" --service-objective S2
# ... see full script below for SQL table creation and REST API role assignment

Full script creates dbo.UserSecurityMapping table, seeds sample UPN-to-Region rows, and calls the Power BI REST API to assign an AAD security group to the DynamicSalesRegion role.

20

CE-20: Apply MIP Sensitivity Labels and Validate Export Governance

Apply a Confidential sensitivity label to a Power BI dataset via REST API, verify label inheritance on downstream reports, and query the Purview audit log for label activity.

bash
# CE-20: Apply MIP label to Power BI dataset via REST API
ACCESS_TOKEN=$(az account get-access-token \
  --resource "https://analysis.windows.net/powerbi/api" \
  --query accessToken -o tsv)

curl -s -X POST \
  "https://api.powerbi.com/v1.0/myorg/datasets/SetLabelAsAdmin" \
  -H "Authorization: Bearer \${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"datasets":[{"id":"<dataset-id>"}],"labelDetails":{"labelId":"<mip-label-id>"}}'
# Verify label on downstream report and query Purview audit log for label events

Full script verifies label on the downstream report, exports a label-coverage JSON for all workspace datasets, and queries Microsoft Graph for PowerBI audit log label events in the past 24 hours.

8. Chapter Summary

ConceptKey Point
Static RLSLiteral DAX filters per role; multiple roles are additive (OR); Workspace Admins/Members/Contributors bypass RLS.
Dynamic RLSSingle role using USERPRINCIPALNAME() matched to a security mapping table; scales without per-user roles; sourced from a live refreshable dataset.
Object-Level SecurityHides tables/columns at metadata level; Premium capacity required; configured via Tabular Editor; denial returns errors, not empty results.
Sensitivity LabelsInherited from upstream sources; travel with exported files; export enforcement (encryption, watermarks) governed by MIP policy.
Role MembershipManaged in Service without republishing; use AAD security groups; automate via Power BI REST API for IAM integration.
RLS Testing"View as role" + UPN in Desktop for development; real test accounts in Service for production validation before release.

Chapter: 10 of 12  |  Status: v0.1 Draft  |