Cos’è la Row-Level Security e quando serve

La Row-Level Security (RLS) limita l’accesso ai dati a livello di riga all’interno di un semantic model di Power BI: due utenti aprono lo stesso report ma vedono solo le righe di loro competenza (il responsabile vendite Nord non vede le righe della regione Sud). La RLS filtra i dati, non nasconde visual o pagine: per quello servono altri meccanismi (object-level security, permessi sull’area di lavoro). Opera applicando filtri DAX su una o più tabelle quando un utente appartiene a un dato ruolo.

Punto chiave: la RLS vincola solo gli utenti in sola lettura (ruolo Viewer sul workspace o accesso tramite app). Chi ha ruolo Admin/Member/Contributor o permessi di Build/Edit bypassa i filtri.

RLS statica vs dinamica

RLS statica

Più ruoli, ciascuno con un filtro DAX fisso. Esempio, ruolo “Nord”:

[Region] = "Nord"

Semplice ma poco scalabile: con 40 regioni servono 40 ruoli e altrettante assegnazioni. Adatta a perimetri pochi e stabili.

RLS dinamica

Un unico ruolo con un filtro che identifica l’utente a runtime tramite USERPRINCIPALNAME() (consigliata: restituisce l’UPN/email, coerente con l’identità Microsoft Entra ID) oppure USERNAME(). Il filtro si appoggia a una tabella di mapping utente→perimetro. Il pattern più comune applica sulla tabella di sicurezza:

[Email] = USERPRINCIPALNAME()

e lascia che la relazione propaghi il filtro verso la fact table. Vantaggio: si aggiungono utenti o perimetri modificando i dati, non il modello. Ideale per centinaia di utenti.

Definire i ruoli in Desktop, assegnarli nel Service

  • Power BI Desktop (Modeling → Manage roles): si crea il ruolo e si scrive l’espressione di filtro sulle tabelle. Qui si definisce cosa filtra il ruolo, non si assegnano gli utenti.
  • Test in Desktop con View as → si seleziona il ruolo; per la RLS dinamica si compila anche “Other user” con un UPN per verificare cosa vede quell’identità.
  • Power BI Service: dopo la pubblicazione, sul semantic model → Security, si assegnano utenti o gruppi di sicurezza Entra ID ai ruoli. Best practice: assegnare gruppi, non singoli utenti.

La trappola: direzione dei filtri nelle relazioni

Il filtro RLS parte dalla tabella su cui è scritto e si propaga secondo la direzione delle relazioni. In uno star schema la dimensione filtra la fact (relazione one-to-many, direzione single dal lato “one”): il filtro su DimRegion raggiunge naturalmente FactSales.

I problemi nascono quando:

  • Il filtro è scritto sulla tabella sbagliata: se applicato dal lato many o su una tabella non collegata alla fact, può non propagarsi — l’utente vede tutto (o nulla).
  • Si usano relazioni bidirezionali (both): possono aprire falle, facendo trapelare righe attraverso percorsi non previsti, oppure produrre propagazioni incoerenti. Per questo esiste l’opzione di relazione “Apply security filter in both directions”, da attivare consapevolmente solo quando il filtro dinamico deve attraversare una relazione bidirezionale.

Regola pratica: star schema pulito, RLS sulla dimensione (o sulla tabella di mapping collegata alle dimensioni) e relazioni single-direction quando possibile.

Trappole tipiche d’esame

  • Scenario: centinaia di venditori, un report per regione, minima manutenzione → RLS dinamica con USERPRINCIPALNAME() + tabella di mapping e un solo ruolo (la statica richiederebbe troppi ruoli).
  • Scenario: definiti i ruoli in Desktop, gli utenti vedono ancora tutto → mancano le assegnazioni dei membri nel Service → Security; i ruoli in Desktop non assegnano utenti.
  • Scenario: un utente con permesso Member/Contributor sul workspace non risulta filtrato → corretto: la RLS vale solo per i Viewer; abbassare il ruolo a Viewer.
  • Scenario: il filtro dinamico non raggiunge la fact table attraverso una tabella ponte → abilitare “Apply security filter in both directions” sulla relazione, oppure ridisegnare verso uno star schema.
  • Scenario: USERNAME() restituisce DOMAIN\utente in Desktop ma nel Service serve l’email → usare USERPRINCIPALNAME() per allinearsi all’identità Entra ID.