11.1 Row-Level Security (RLS)

Key Takeaways

  • RLS filters rows by role: define roles with DAX filter expressions in Desktop (Manage roles), then assign users or security groups to roles in the service.
  • Static RLS hard-codes filter values and needs one role per value; dynamic RLS uses USERPRINCIPALNAME() with a mapping table so a single role serves everyone and scales.
  • Workspace Admins and Members always bypass RLS, so you must test with Modeling -> View as (entering a test UPN for dynamic RLS); only Viewers/Contributors/app consumers are subject to RLS.
  • A user assigned to multiple roles sees the union of all their roles' filters, and a user in no role sees all data.
  • Object-Level Security (OLS) hides entire tables or columns from a role and complements RLS, which filters rows.
Last updated: June 2026

Quick Answer: Row-Level Security (RLS) filters which rows a user sees based on their assigned role. Define roles in Desktop (Modeling -> Manage roles) with DAX filter expressions, then assign users/groups to roles in the service. Static RLS hard-codes filter values ([Region] = "West"); dynamic RLS uses USERPRINCIPALNAME() plus a mapping table so one role serves everyone. Workspace Admins/Members bypass RLS entirely. RLS is one of the most heavily tested PL-300 topics.

What RLS does

Two users open the same report and see different data: the West manager sees only West rows, the East manager only East rows, the VP sees everything. RLS enforces this through roles — named sets of DAX filters applied to tables.

Creating roles in Desktop

Modeling tab -> Manage roles -> Create -> name the role -> pick a table -> write a DAX filter.

Static RLS

Hard-coded values, one role per value:

// Role "West Region", table Sales
[Region] = "West"

Simple, but it does not scale — 50 regions means 50 roles to build and maintain.

Dynamic RLS

One role that filters by the signed-in user's identity. USERPRINCIPALNAME() returns the user's UPN (usually their email, e.g., john@contoso.com). Pair it with a mapping table:

Two common patterns:

// Pattern A - filter the data table directly via LOOKUPVALUE
[Region] = LOOKUPVALUE(UserRegion[Region], UserRegion[Email], USERPRINCIPALNAME())
// Pattern B - filter the security (mapping) table; the relationship propagates the filter
// Role on the UserRegion table:
[Email] = USERPRINCIPALNAME()

Pattern B is preferred at scale: build a relationship from the mapping table to Sales so the filter propagates automatically. Permission changes mean editing one table, not re-publishing roles. USERNAME() returns domain\user (and behaves like UPN in the service), but USERPRINCIPALNAME() is the standard choice for cloud RLS.

Testing RLS

In Desktop: Modeling -> View as -> select role(s), and for dynamic RLS also enter Other user (a test UPN) so USERPRINCIPALNAME() resolves to that value. Verify users see only allowed rows, totals reflect only visible data, all visuals respect the filter, cross-filtering still works, and measures honor the RLS filter context.

Assigning users in the service

Workspace -> semantic model -> Security -> pick role -> add members (emails or Azure AD/Entra security groups). Using groups centralizes management and auditing.

Role assignment rules (exam-critical)

  • A user in no role sees all data (RLS does not apply to them — assign every consumer to a role).
  • Admins and Members of the workspace always see all data, regardless of RLS — so you cannot test RLS by viewing as yourself; use View as.
  • Only Viewers/Contributors and app consumers are subject to RLS.
  • A user in multiple roles sees the union of all their roles' filters (access is additive, not intersected).

RLS with other configurations

  • DirectQuery: the RLS filter is pushed into every source query; complex filters can affect performance.
  • Live connection to Analysis Services: RLS lives in the SSAS/AAS model; Power BI passes the user identity through.
  • Shared semantic model: RLS defined on the dataset is inherited by every report built on it — enforcement is at the model level, not per report.

Object-Level Security (OLS)

OLS hides entire tables or columns from a role (defined via Tabular Editor or the XMLA endpoint). It complements RLS (which filters rows). Example: hide the Salary column from the Manager role while HR keeps it.

Manager hierarchies with PATH (advanced dynamic RLS)

A frequent advanced scenario: a sales VP should see their own data and everyone who rolls up to them. A flat email-to-region map can't express a hierarchy, so you use a parent-child pattern. Add a PATH column to the employee/security table: Hierarchy Path = PATH(Employee[EmployeeID], Employee[ManagerID]), which stores each employee's chain of ancestors (e.g., 1|7|42). Then the dynamic RLS role filters with PATHCONTAINS:

// Role on Employee table - a user sees themselves and all reports beneath them
PATHCONTAINS(
  Employee[Hierarchy Path],
  LOOKUPVALUE(Employee[EmployeeID], Employee[Email], USERPRINCIPALNAME())
)

This returns every employee whose path contains the logged-in user's ID — i.e., the user and their entire downline — which is exactly the org-chart filtering pattern the exam describes as "managers see their team's data."

Common RLS mistakes the exam probes

  • Testing as yourself with Admin/Member access shows all data because Admins/Members bypass RLS — always use View as.
  • Forgetting to assign users to any role means they see everything, not nothing.
  • Bidirectional relationships can leak rows across an RLS filter; Power BI may require you to enable "Apply security filter in both directions" deliberately, and over-using bidirectional filters is a common RLS bug.
  • A user in two roles sees the union, so adding a broad role to someone who also has a narrow role widens their access — never assume roles intersect.
  • Measures must respect filter context: a measure using ALL() can blow past RLS for totals if written carelessly; verify totals in View as.

On the exam

Expect: choose dynamic RLS + mapping table for 50 managers and PATH/PATHCONTAINS for an org-chart hierarchy; recall USERPRINCIPALNAME() returns the user's email/UPN; know Admins/Members bypass RLS so you must use View as; understand multiple roles = union of filters and that an unassigned user sees all data; and distinguish RLS (rows) from OLS (tables/columns).

Test Your Knowledge

A company has 50 regional managers, each of whom should only see data for their region. What is the most scalable RLS approach?

A
B
C
D
Test Your Knowledge

A workspace Admin opens a report that has RLS configured. The Admin is not assigned to any RLS role. What data do they see?

A
B
C
D
Test Your Knowledge

In a dynamic RLS setup, which DAX function returns the email address of the currently logged-in user?

A
B
C
D
Test Your Knowledge

You need to hide the entire Salary column from users in the Manager role while keeping rows visible. Which feature should you use?

A
B
C
D