La sicurezza a livello di riga, o RLS (Row-Level Security), in Tableau limita le righe di dati che un determinato utente può visualizzare in una cartella di lavoro. Si tratta di una caratteristica diversa dalle autorizzazioni di Tableau, che controllano l'accesso ai contenuti e alle funzionalità. Ad esempio, le autorizzazioni controllano se un utente può inserire commenti o modificare una cartella di lavoro, mentre la sicurezza a livello di riga consente a due utenti che visualizzano la stessa dashboard di visualizzare solo i dati che ogni utente è autorizzato a vedere.

Esistono molti modi per implementare la sicurezza a livello di riga in Tableau. Ad esempio, puoi impostare la sicurezza a livello di riga a livello di origine dati o cartella di lavoro oppure puoi impostare la sicurezza a livello di riga a livello di connessione utilizzando una connessione virtuale con un criterio dati (richiede Data Management). Consulta Panoramica delle opzioni di sicurezza a livello di riga in Tableau per informazioni dettagliate sulle alternative.

Nota: questo argomento è incentrato sulle procedure consigliate per la sicurezza a livello di riga per origini dati e cartelle di lavoro. Per esempi più approfonditi dei concetti illustrati in questo argomento, fai riferimento al whitepaper Best Practices for Row Level Security with Entitlement Tables(Il collegamento viene aperto in una nuova finestra) o consulta How to Set Up Your Database for Row Level Security in Tableau(Il collegamento viene aperto in una nuova finestra) sul blog Tableau and Behold.

Flusso di lavoro per la sicurezza a livello di riga

Per le connessioni live e le estrazioni multi-tabella, il flusso di lavoro di base della sicurezza a livello di riga è:

  1. L'utente viene identificato eseguendo l'accesso a Tableau Server o Tableau Cloud
    • A tale scopo, è necessario un nome utente distinto per ogni utente e un sistema di accesso Single Sign-On (SSO)
    • È possibile utilizzare Active Directory, LDAP o l'API REST di Tableau per sincronizzare i nomi utente e stabilire le autorizzazioni
  2. L'insieme dei diritti di accesso ai dati per l'utente viene recuperato da tutti i possibili diritti di accesso ai dati
    • A tale scopo, è necessaria una struttura di dati in grado di collegare i diritti al nome utente di Tableau
  3. I dati sono filtrati in base ai diritti dell'utente
    • Questo spesso richiede l'utilizzo di funzioni utente in un campo calcolato
  4. I dati pubblicati e filtrati vengono utilizzati per creare il contenuto
    • L'utilizzo di un'origine dati pubblicata (anziché incorporata) con un filtro dell'origine dati assicura che la sicurezza a livello di riga non possa essere modificata scaricando o eseguendo la modifica Web della cartella di lavoro

Il modo in cui sono configurati i join, i campi calcolati e i filtri dipende dalla struttura dei dati e dalla modalità di gestione degli utenti.

Tabelle dei diritti

Qualsiasi combinazione univoca di attributi utilizzabile per filtrare i dati è un diritto. In genere, sono presenti tabelle distinte per specificare i diritti stessi ed eseguirne il mapping agli utenti o ai ruoli utente. Dal punto di vista delle prestazioni, è consigliabile eseguire la denormalizzazione perché i join sono operazioni costose.

La vista dei diritti, che comprende i diritti mappati agli utenti o ai ruoli, viene unita ai dati. Viene quindi applicato un filtro dell'origine dati basato sull'utente, che opera come una clausola WHERE che recupera solo i diritti (e quindi le righe di dati appropriate) per l'utente in questione. L'ottimizzazione delle query dovrebbe garantire che il filtraggio venga eseguito prima del join, al momento dell'elaborazione della query, per ridurre al minimo la duplicazione dei dati. Per maggiori informazioni, consulta Prestazioni e ordine di elaborazione delle operazioni.

Modelli di tabella dei diritti

In generale, esistono due modelli per rappresentare i diritti:

Mapping completo fino al massimo livello di granularità

  • I diritti sono definiti in modo completo per ogni colonna.
  • È presente una riga nella tabella di mapping per ogni possibile diritto dell'utente.
  • Questo modello richiede un minor numero di clausole di join.

Diritti di tipo sparse

  • I diritti sono definiti per ogni livello della gerarchia, con NULL utilizzato per rappresentare uno stato "tutto".
  • È presente un'unica riga nella tabella di mapping per un particolare livello della gerarchia dei diritti, il che riduce notevolmente il numero di righe di diritti per gli utenti ai livelli elevati in una gerarchia.
  • Questo modello richiede join e filtri più complessi.

Utenti e ruoli

Le combinazioni di diritti sono comunemente rappresentate come ruoli, che vengono quindi collegati agli utenti in una tabella di mapping molti-a-molti. Questo consente di modificare o rimuovere facilmente un utente dal ruolo, pur mantenendo un record del ruolo e dei relativi diritti.

In alternativa, è possibile creare una tabella di mapping molti-a-molti che assegna direttamente gli utenti ai diritti, invece di eseguire il join di una tabella dei ruoli. Richiede di gestire i valori in modo più diretto nella tabella, ma elimina la necessità di un join.

Nota: i valori utente associati a un ruolo o un diritto devono corrispondere al nome utente o al nome completo sul sito di Tableau per poter utilizzare le funzioni utente in Tableau Desktop.

Join

Indipendentemente dal modello utilizzato per rappresentare i diritti, è consigliabile riunire tutti i diritti e le tabelle di mapping in un'unica vista denormalizzata dei diritti. Mentre in un primo momento questo causerà una versione "espansa" (con numerosi duplicati) dei diritti, il filtro dell'origine dati in base all'utente ne ridurrà nuovamente le dimensioni. Questa vista è utile anche se prevedi di utilizzare un'estrazione.

Il metodo della massima granularità può presentare un vantaggio in termini di prestazioni quando tutti gli elementi sono gerarchici: basta eseguire un singolo join al livello più profondo della gerarchia. Questo metodo funziona solo se tutti gli attributi al livello più basso sono distinti. Se esiste la possibilità di una duplicazione (ad esempio, una sottoregione Centro in più di una regione), devi eseguire il join di tutte le colonne per ottenere l'effetto di un valore chiave distinto.

I dettagli effettivi e le relative caratteristiche in termini di prestazioni dipendono dal sistema dati e richiedono dei test. Ad esempio, l'utilizzo di una singola chiave potrebbe potenzialmente migliorare le prestazioni perché il join viene eseguito solo su una colonna, ma una corretta indicizzazione di tutte le colonne può dare prestazioni equivalenti quando si prendono in considerazione altri fattori.

Implementare la sicurezza a livello di riga

Massima granularità

Una volta creata la vista denormalizzata dei diritti mappati, viene impostato un inner join tra la vista e i dati nella finestra di dialogo per la connessione dati di Tableau. I dati possono rimanere in un tradizionale schema a stella. In alternativa, le tabelle delle dimensioni e dei fatti possono essere materializzate insieme in due viste. Le estrazioni multi-tabella creeranno tabelle di estrazione in base ai join, quindi la creazione delle due viste semplificherà l'estrazione risultante. Il codice SQL seguirà il seguente schema di base:

SELECT * 
FROM data d INNER JOIN entitlements e ON
d.attribute_a = e.attribute_a AND 
d.attribute_b = e.attribute_b AND ... 
WHERE e.username = USERNAME()

Diritti di tipo sparse

Se per i diritti preferisci applicare il modello di tipo sparse, l'SQL personalizzato per il join dei dati ai diritti è leggermente più complesso a causa dei valori NULL. Concettualmente, si presenta come segue: 

SELECT *
FROM data d 
INNER JOIN entitlements e ON
(e.region_id = d.region_id OR ISNULL(e.region_id) AND
(e.sub_region_id = d.sub_region_id OR ISNULL(e.sub_region_id) AND
(e.country_id = d.country_id OR ISNULL(e.country_id)

Senza utilizzare SQL personalizzato, questa operazione può essere eseguita con un cross join e filtri aggiuntivi in Tableau Desktop. Crea un calcolo di join su entrambi i lati della finestra di dialogo di join che consiste semplicemente nell'intero 1 e impostali come uguali. In questo modo verrà eseguito il join di ogni riga della tabella dei dati con ogni riga della tabella dei diritti.

È quindi necessario un calcolo (o singoli calcoli) per tenere conto dei livelli della gerarchia. Ad esempio, potresti avere diversi calcoli che seguono questo formato: [region_id] = [region_id (Entitlements View)] OR ISNULL([region_id (Entitlements View)]

Oppure potresti avere un calcolo combinato per tutti i livelli in uno solo:

([region_id] = [region_id (Entitlements View)] OR ISNULL([region_id (Entitlements View)])
AND
([sub_region_id] = [sub_region_id (Entitlements View)] OR ISNULL([sub_region_id (Entitlements View)])
AND
([country_id] = [country_id (Entitlements View)] OR ISNULL([country_id (Entitlements View)])

La funzione ISNULL associa qualsiasi colonna dei diritti a tutti gli elementi dell'altra colonna. Come sempre nel caso della sicurezza a livello di riga, questi calcoli dovrebbero essere aggiunti come filtri dell'origine dati.

Filtro dell'origine dati

Per entrambi gli approcci, una volta eseguito correttamente il join dei diritti ai dati, è necessario impostare un filtro per limitare i dati per un utente specifico. Deve essere creato un campo calcolato con una funzione utente. Ad esempio, un semplice confronto booleano per stabilire se l'utente elencato nel campo Nome utente corrisponde al nome utente della persona che ha effettuato l'accesso al sito di Tableau: [Username] = USERNAME()

Questo calcolo deve essere utilizzato come filtro dell'origine dati (con TRUE selezionato).

Se l'origine dati è incorporata e un utente dispone delle autorizzazioni per la modifica Web o il download della cartella di lavoro, la sicurezza a livello di riga è inesistente, in quanto i filtri che la impongono possono essere facilmente rimossi. L'origine dati Tableau deve essere pubblicata separatamente, invece di essere lasciata incorporata nella cartella di lavoro.

Accesso completo con la massima granularità

C'è anche uno scenario comune in cui sono esistono due livelli di accesso all'interno dell'organizzazione: persone che possono vedere tutto ("accesso completo") e persone con un sottoinsieme ragionevolmente definibile di diritti. Si tratta di uno scenario frequente per le applicazioni incorporate: l'organizzazione che ospita i dati può vedere tutto, ma ogni cliente può vedere solo i propri dati. In questo caso, è necessario un modo per restituire tutti i dati per gli utenti "accesso completo", mantenendo i join con la massima granularità per tutti gli altri utenti.

Per questa tecnica, si utilizzeranno i gruppi di Tableau per creare un override utilizzando un calcolo nella condizione di join.

  1. Crea un gruppo per gli utenti che devono vedere tutti i dati (di seguito denominato "All Access") 
  2. Dalla vista dei fatti crea un join sinistro con due condizioni di join
    • La prima condizione di join deve essere sulla colonna che rappresenta il massimo livello di granularità
    • La seconda condizione di join deve essere costituita da due calcoli:
      • Sul lato sinistro (vista dei fatti), per il calcolo, inserisci True
      • Sul lato destro (vista dei diritti), il calcolo deve essere: IF ISMEMBEROF('All Access') THEN False ELSE True END
  3. In un foglio, crea un calcolo strutturato come segue: [Username] = USERNAME() OR ISMEMBEROF(['All Access'] ([Entitlements View)])
  4. Crea un filtro dell'origine dati sul calcolo del nome utente

Se un utente è membro del gruppo All Access, il join diventa un join sinistro su True = False. Questo significa che non ci sono corrispondenze nella vista dei diritti, quindi viene restituita l'intera vista dei fatti con NULL per le colonne dalla vista dei diritti (duplicazione zero). Nel caso l'utente non faccia parte del gruppo All Access, la condizione di join True = True non cambia nulla e il join funzionerà come previsto.

Il calcolo dell'utente usato come filtro dell'origine dati è True per tutte le righe quando l'override del gruppo è in funzione oppure applica il filtro solo fino alla massima granularità dell'utente nella gerarchia.

Prestazioni e ordine di elaborazione delle operazioni

Quando si visualizza una visualizzazione in Tableau Desktop, Tableau Server o Tableau Cloud), Tableau invia una query ottimizzata al sistema RDBMS, che quindi elabora la query e invia i risultati a Tableau per il rendering della visualizzazione con i dati risultanti. L'ordine delle operazioni per l'esecuzione di join, calcoli e filtri dipende dall'ottimizzatore di query e da come questa viene eseguita.

Connessioni live

Quando si utilizza una connessione live con un'origine dati in Tableau, l'esecuzione della query dipende dall'ottimizzatore di query che converte il codice SQL in entrata in un piano efficiente per il recupero dei dati.

Esistono due modi per elaborare la richiesta:

  1. Filtrare le righe dei diritti in base all'utente, quindi eseguire il join alla tabella dei fatti
  2. Eseguire il join alla tabella dei fatti e quindi filtrare le righe dell'utente

In una situazione ideale, l'ottimizzatore di query garantisce che il database elabori la query filtrando e quindi eseguendo il join. Se un utente dispone di diritti per tutti gli elementi, il numero massimo di righe elaborate corrisponderà al numero di righe nella tabella dei dati.

Se il database elabora la query eseguendo il join e quindi filtrando, può verificarsi una duplicazione dei dati. Il numero massimo di righe elaborate sarà il numero di utenti che hanno diritto a vedere una particolare riga per ogni riga nella tabella dei dati.

Se si verifica questo secondo scenario, risulterà evidente: il completamento delle query richiede molto tempo, vengono visualizzati errori o vi sono segni di problemi di prestazioni nel database. Il volume totale dei dati aumenterà in modo esponenziale, cosa che potrebbe determinare uno carico eccessivo sul backend.

Estrazioni

Quando l'origine dati in Tableau è una connessione live, Tableau invia al sistema RDBMS tutte le query necessarie per il rendering di una particolare vista o dashboard. Quando l'origine dati è un'estrazione, il processo di query dei dati dall'origine dati sottostante avviene solo al momento della creazione e dell'aggiornamento dell'estrazione. Le risposte a tutte le singole query per le visualizzazioni vengono inviate tramite il motore di estrazione dal file di estrazione.

Lo stesso ordine delle operazioni viene applicato quando si creano estrazioni di tabelle singole. Tuttavia, l'espansione avverrà sia nell'origine dati sottostante che all'interno della stessa estrazione risultante.

Considerazioni relative alle estrazioni

A partire da Tableau 2018.3, il motore dati può creare un'estrazione multi-tabella e la sicurezza a livello di riga può essere implementata come descritto in precedenza. L'utilizzo di più estrazioni di tabelle riduce il tempo necessario per generare un'estrazione con relazioni molti-a-molti, evitando la materializzazione del join.

L'estrazione deve essere creata con un oggetto dati e un oggetto diritti. Questa è l'archiviazione più semplice nell'estrazione e garantisce le migliori prestazioni.

  • L'oggetto dati è la tabella, la vista o la query SQL personalizzata che rappresenta la combinazione denormalizzata delle tabelle dei fatti e delle dimensioni necessarie
  • L'oggetto diritti è una tabella denormalizzata, una vista o una query SQL personalizzata di qualsiasi diritto necessario per filtrare i dati al massimo livello di granularità richiesto:
    • Una colonna per il nome utente, che corrisponde esattamente ai nomi utente di Tableau Server o Tableau Cloud
    • Una riga per ciascuno dei diritti più granulari per l'oggetto dati

Questo formato è presentato nel metodo della massima granularità descritto in precedenza. Le estrazioni multi-tabella utilizzano lo stesso metodo, ma occorre tenere presente che viene eseguito il join di solo due oggetti di dati e che qualsiasi filtro specifico del campo è già applicato all'interno dell'oggetto.

Poiché per le estrazioni di più tabelle i filtri di estrazione sono disabilitati, puoi filtrare le viste o le tabelle a cui ti connetti nell'origine dati oppure definire i filtri negli oggetti SQL personalizzati nella finestra di dialogo per la connessione dati di Tableau.

Nota: come nel caso delle connessioni live, se l'origine dati è incorporata e un utente dispone delle autorizzazioni per la modifica Web o il download della cartella di lavoro, la sicurezza a livello di riga è inesistente, in quanto i filtri che la impongono possono essere facilmente rimossi. L'estrazione deve essere pubblicata separatamente, invece di essere lasciata incorporata nella cartella di lavoro.

Estrazioni di tabelle singole

Il seguente metodo è consigliato solo quando si utilizza una versione di Tableau precedente alla 2018.3: sono preferibili le estrazioni di più tabelle, se disponibili.

Le estrazioni di tabelle singole materializzano i join che crei durante la costruzione dell'origine dati di Tableau e archiviano tutti i dati come una singola tabella tramite un'unica query, i cui risultati vengono trasformati in una singola tabella nel file di estrazione. Questa denormalizzazione comporta il rischio di causare una massiccia duplicazione dei dati, in quanto ogni riga che è stata assegnata a più di un diritto o utente verrebbe duplicata come risultato della relazione molti-a-molti.

Per evitare questa duplicazione:

  1. Crea un campo Security Users Field che contiene i nomi utente per tale diritto
    • Ad esempio, un valore potrebbe essere "bhowell|mosterheld|rdugger"
  2. Utilizza la funzione CONTAINS() in Tableau per identificare correttamente i singoli utenti
    • Ad esempio, CONTAINS([Security Users Field], USERNAME())

Questo metodo ovviamente presenta alcuni svantaggi. Richiede di passare dai diritti nelle righe a una singola colonna separata correttamente tramite SQL e tale colonna può contenere solo un certo numero di caratteri. Le corrispondenze parziali possono essere un problema ed è necessario utilizzare separatori che non siano mai validi negli ID stessi. Anche se offre buone prestazioni all'interno del motore dati Tableau, come calcolo delle stringhe questo metodo sarà molto lento per la maggior parte dei database. Ciò limita la possibilità di tornare a una connessione live.

In alternativa, è possibile creare diverse estrazioni per "ruolo" o livello di diritti, in modo che solo i dati appropriati per tale persona o livello siano contenuti nell'estrazione. Questo tuttavia richiederà dei processi per autorizzare e utilizzare adeguatamente la pubblicazione dei modelli in Tableau Server, generalmente tramite le API.

Utilizzare la sicurezza a livello di riga integrata in un database

Molti database dispongono di meccanismi integrati per la sicurezza a livello di riga. Se la tua organizzazione ha già configurato la sicurezza a livello di riga in un database, potresti essere in grado di sfruttare la funzionalità esistente. Non è necessariamente meglio o più semplice implementare un modello integrato per la sicurezza a livello di riga rispetto al fatto di crearlo appositamente per Tableau. Queste tecniche sono generalmente utilizzate quando un'organizzazione ha già investito in tali tecnologie e desidera trarre vantaggio dall'investimento. Il vantaggio principale della sicurezza a livello di riga è che consente agli amministratori di implementare e controllare i criteri di sicurezza dei dati in una singola posizione: i relativi database. Per maggiori informazioni, consulta Sicurezza a livello di riga nel database.

Grazie per il tuo feedback.