The Power BI Fellowship
Patterns & Playbooks · Guide

BI security field guide

Workspace roles, Build and app permissions, sharing, static and dynamic RLS, OLS, sensitivity labels, tenant settings, export controls, service principals, guest users and least privilege, with an RLS testing checklist and a 'why can this user see this row?' guide.

BI DeveloperSenior BI DeveloperBI EngineerBI Architect / LeadPower BI ServicePower BI DesktopTabular EditorChecked 2 Oct 2026Download .md
On this page (12)

The warning everyone learns the hard way

Warning: RLS restricts data only for users with Viewer access to the workspace, or who get the content through an app or sharing. Workspace Admins, Members and Contributors can edit the semantic model, so RLS doesn't restrict them. Never test RLS from a developer's account, and never give people who must be restricted a Contributor role "so they can see the report".

The layers of access

LayerControlsTypical use
Tenant settingsWhat anyone in the organisation can do: export, publish to web, share externally, service principals, CopilotSet by Fabric admins; least privilege by default
Workspace rolesAdmin, Member, Contributor, Viewer on everything in a workspaceDevelopers get Contributor/Member; consumers ideally get nothing here and use an app
App permissionsWho sees which content in an app (audiences)The normal way to distribute to consumers
Item sharingDirect access to one report or modelExceptions, not the norm
Build permissionCreate new reports on a semantic model, analyse in ExcelSelf-service authors on a certified model
RLSWhich rows a user seesRegion managers see their region
OLSWhich tables and columns a user sees at allHide salary columns from most roles
Sensitivity labelsClassification that travels with the content and exportsConfidential data stays labelled in Excel and PDF
Export controlsWhether data can leave Power BI (Excel, CSV, PDF, PowerPoint)Restrict for sensitive models

Static and dynamic RLS

Static: one role per audience with a fixed filter, such as [RegionName] = "West". Simple, but a new region means a new role.

Dynamic: one role whose filter looks up the signed-in user in a mapping table:

dax
-- role filter on UserRegionMapping (related to DimRegion, which filters the facts)
[UserEmail] = USERPRINCIPALNAME ()

With a mapping table like the course's UserRegionMapping, a user with two rows sees two regions, and a user with an "ALL" access level needs a rule that returns true for every region. Build and test this in Row-level security.

Things to know:

Object-level security

OLS hides tables or columns from a role entirely: they don't appear in the field list and queries that reference them fail. Define it in Tabular Editor (or TMDL) on roles. Use it for columns like salary or national ID that most people must not know exist, and combine with RLS for rows.

Sensitivity labels, tenant settings and exports

Practise: Sensitivity labels, OLS, export controls and tenant settings.

Service principals and guest users

Least privilege

Default to the smallest access that lets someone do their job: Viewer through an app rather than a workspace role, Build only for authors, Contributor only for developers, Admin for two people per workspace. Review access quarterly; remove leavers through group membership, not by hunting individual shares.

Why can this user see this row?

Work through these in order, for the specific user:

  1. Which access path? App, workspace role, direct share or Build permission. If they have Admin, Member or Contributor on the workspace, RLS doesn't apply: that's your answer.
  2. Which roles are they in? Including through groups. Two roles = union of both.
  3. What does USERPRINCIPALNAME() return for them? Show it in a card under View as.
  4. What does the mapping table say for that value? Duplicates, an "ALL" row, a stale entry after they moved team?
  5. Does the role's filter reach the table being shown? Relationship direction, inactive relationships, or a table unrelated to the security table (which RLS therefore doesn't filter).
  6. Is the visual using a different model? A report built on a copy of the model without the roles.

RLS testing checklist

Security matrix template

Keep one row per role and representative user: what they must see, what they must not see, the access path, and the last test result. That's the RLS / OLS test matrix.

Security architecture patterns

PatternWhen
One certified model with dynamic RLS, consumed through appsMost organisations; one model, many audiences
RLS + OLS on one modelMost users see some rows; few see sensitive columns
Separate models per legal entity or data residencyLegal or contractual separation that RLS can't prove
Aggregated public model + detailed restricted modelBroad audiences see summaries; a few see detail

Incident scenarios

A manager sees other regions' payroll: what do you do in the first hour? Sprint 03 is that incident, end to end. The short version: contain access first, confirm the scope from audit logs, fix and test, then write the incident report and tell the data owner.

Something missing or out of date? Open an issue or edit content/toolkit/guides/security-field-guide.md.