Implementing Static & Dynamic RLS
This lesson walks through the step-by-step process of implementing both static and dynamic Row-Level Security.
Implementing Static RLS
Scenario: Create roles for East and West regions.
Step 1: Define Roles in Power BI Desktop
- Go to Modeling → Manage Roles
- Click Create → Name: "East Region"
- Select the Sales table
- Enter DAX filter:
[Region] = "East" - Click ✅ → Create another role: "West Region"
- DAX filter:
[Region] = "West" - Click Save
Step 2: Test Roles in Desktop
- Go to Modeling → View as Roles
- Select "East Region" → Click OK
- Verify: only East region data is visible
- Click Stop viewing to exit
Step 3: Publish & Assign Users
- Publish the report to Power BI Service
- Navigate to the dataset → ••• → Security
- Select "East Region" → Add users (e.g., alice@company.com)
- Select "West Region" → Add users (e.g., bob@company.com)
- Click Save
---
Implementing Dynamic RLS
Scenario: Sales representatives should see only their own orders.
Data Structure:
| OrderID | Product | Amount | SalesRepEmail |
|---|---|---|---|
| 1001 | Laptop | 50000 | alice@company.com |
| 1002 | Mouse | 500 | bob@company.com |
| 1003 | Monitor | 15000 | alice@company.com |
Step 1: Define Role in Desktop
- Modeling → Manage Roles
- Create role: "Sales Rep"
- Select Sales table
- DAX filter:
[SalesRepEmail] = USERPRINCIPALNAME() - Save
Step 2: Test in Desktop
- Modeling → View as Roles
- Check both "Sales Rep" role AND "Other user"
- Enter a test email (e.g., alice@company.com)
- Verify: only Alice's orders are visible
Step 3: Publish & Assign
- Publish to Power BI Service
- Dataset → Security → "Sales Rep" role
- Add all sales reps to this single role
- Each user automatically sees only their own data
---
Dynamic RLS with a Security Mapping Table
For complex scenarios, use a separate security table.
Security Table (UserAccess):
| UserEmail | Region |
|---|---|
| alice@company.com | East |
| alice@company.com | North |
| bob@company.com | West |
| charlie@company.com | East |
Relationship: UserAccess[Region] → Sales[Region] (Many-to-One)
Role DAX Filter (on UserAccess table):
[UserEmail] = USERPRINCIPALNAME()
How It Works:
- User alice@company.com logs in
- RLS filters UserAccess to Alice's rows (East, North)
- The relationship propagates the filter to Sales table
- Alice sees data for both East AND North regions
Benefits: • One role handles all users • Users can have access to multiple regions • Add/remove access by editing the UserAccess table (no DAX changes)
---
Dynamic RLS with Hierarchy (Manager Access)
Scenario: Managers should see their own data PLUS their team's data.
Employee Table:
| EmployeeEmail | ManagerEmail | Region |
|---|---|---|
| alice@company.com | manager@company.com | East |
| bob@company.com | manager@company.com | West |
| manager@company.com | director@company.com | All |
DAX Filter:
[EmployeeEmail] = USERPRINCIPALNAME() ||
[ManagerEmail] = USERPRINCIPALNAME()
Result: • Alice sees only her own data • Manager sees Alice's, Bob's, and their own data • Director sees everyone's data
Best Practices
• Prefer Dynamic RLS for scalability • Use security mapping tables for flexible access control • Always test with "View as Roles" before publishing • Use Azure AD security groups for efficient user management • Keep DAX filters simple for performance • Document your RLS design for future maintenance