Seleccionar página
22 de agosto de 2024

Implementar RLS Dinámico con Grupos de Seguridad en Power BI

Uno de los pilares fundamental a la hora de elaborar nuestros informes es la protección de los datos y la información generada. En Power BI, podemos garantizar esta seguridad restringiendo el acceso únicamente a ciertos usuarios, implementando la seguridad a nivel de fila (RLS) mediante el uso de roles.

 

¡Comenzamos!

La seguridad a nivel de fila (RLS) en Power BI nos permite restringir el acceso de los datos a los usuarios mediante el uso de roles. Esta seguridad puede ser estática, creando roles predefinidos en función de las necesidades del negocio, o dinámica, donde mediante la creación de un único rol y una tabla auxiliar de seguridad se establece y gestiona el acceso a los datos.

Además, en Power BI hay que tener en cuenta los siguientes factores:

– Los roles se crean desde la aplicación de escritorio (Power BI Desktop), y luego se administran desde el servicio.

– Solo se aplica para los usuarios del área de trabajo con permisos de visor, no aplicándose a los administradores, miembros o colaboradores.

– Los roles son aditivos, por lo que si un usuario pertenece a varios va acumulando el acceso a esas filas.

RLS Estático

Se corresponde con la seguridad que se establece al nivel de rol de forma uniforme, independientemente del usuario que está consumiendo el informe. Los roles se crean mediante filtros DAX utilizando literales aplicados directamente sobre el campo de la tabla de interés. En el caso de los modelos en estrella, se recomienda crear estos filtros sobre las dimensiones.

En la siguiente imagen podemos ver un ejemplo de un modelo con cuatro roles, donde filtrando por el campo desCountry de la dimensión Country se establece que solo se pueden ver los datos relacionados con ese país.

modelo-rls-estatico

Analítica y Reporting a Medida. Implanta ya Power BI en tu Empresa

Descubre Microsoft Power BI, la herramienta de analítica y reporting empresarial líder que te ayudará a tomar tus decisiones de negocio basadas en datos con éxito.

RLS Dinámico

Entendemos por RLS Dinámico a las reglas que restringen el acceso a los datos en función del usuario que está consumiendo el informe. Además, en lugar de crear múltiples roles, se crea un único rol que filtraría la tabla de seguridad mediante funciones DAX, como USERNAME() o USERPRINCIPALNAME().

Una forma de implementarla sería utilizando una tabla auxiliar, comúnmente conocida como tabla de seguridad, donde se deberían incluir como mínimo un campo con el email del usuario y otro relacionado con el campo que se está filtrando.

Aquí tendríamos un ejemplo de una tabla de seguridad, y de cómo se crearía el rol con la función USERPRINCIPALNAME().

tabla-seguridad-rls-dinamico
tabla-seguridad-userprincipalname

Grupos de Microsoft Entra ID

Microsoft Entra ID, anteriormente denominado Azure Active Directory, es una solución integral de gestión de identidades y acceso en la nube, que destacada en el mercado por su capacidad para administrar directorios, facilitar el acceso a aplicaciones y proteger las identidades.

Principalmente, distinguidos dos grupos de Microsoft Entra ID, los grupos de seguridad, que nos permiten gestionar fácilmente el acceso a los recursos dentro de una organización, y los grupos de Microsoft 365, encargados de facilitar la colaboración entre los miembros de un grupo compartiendo el acceso a un buzón, calendario, archivos, SharePoint, etc.

Para la seguridad RLS los grupos de Microsoft 365 no son compatibles, por lo que entre los grupos de seguridad, y también entre los grupos de distribución y los grupos habilitados para correo electrónico, se recomienda el uso de los grupos de seguridad para el RLS dinámico, por su gestión centralizada, seguridad, eficiencia, integración con Azure, y su capacidad de auditoría y monitorización.

Comparativa RLS Estático VS Dinámico

En todo proyecto de Power BI surge la duda de cuál de los tipos utilizar, decantándonos por el uno u el otro según las necesidades de nuestro negocio.

En la siguiente tabla podemos ver un resumen de las principales diferencias entre ambos tipos de seguridad:

comparativa-rls-dinamico-vs-estatico

La estática destaca principalmente en su simplicidad a la hora de aplicarse con grupos frente a la dinámica, como veremos más adelante, y en no necesitar gestionar tablas de seguridad auxiliares. No obstante, a medida que aumenta la complejidad del negocio la estática puede comenzar a dejar de ser recomendable por contra de la dinámica, que por su parte nos ofrece una fácil gestión y mantenimiento de los roles al ser presentar un único rol que se gestiona mediante la función USERPRINCIPALNAME() y una tabla auxiliar. El inconveniente de estas tablas y el uso de grupos lo desarrollaremos en el siguiente apartado mediante un caso de uso.

Problemática

Supongamos que somos el equipo de BI de una organización que quiere empezar a publicar sus informes de Power BI en el servicio, utilizando la seguridad RLS Dinámica con Grupos de Seguridad para restringir el acceso solo a los miembros de las unidades de negocio correspondientes. El departamento de sistemas gestiona toda la parte los grupos y la tabla de seguridad, y el equipo de BI se encarga de gestionar los modelos y los permisos del servicio.

Cuando los usuarios de negocio se conectan a los informes se dan cuenta de que no pueden acceder al contenido de estos. Tras analizar la incidencia, los miembros de BI se dan cuenta que la función USERPRINCIPALNAME() no es capaz de interpretar si ese email pertenece o no a los grupos de la tabla de seguridad, ya que solo se limita a extraerlo como literal para compararlo con el campo de la tabla de seguridad.

Solución

La solución propuesta consiste en desarrollar un flujo con dos dataflows conectados en el servicio de Power BI, de forma que con el primero de ellos extraeríamos los emails de los miembros de los grupos, y con el segundo leyendo de la tabla de seguridad compuesta por los nombres de los grupos y su restricción generaríamos una tabla final con cada usuario individual con sus permisos correspondientes.

flujo-dos-dataflows-conectados-servicio-power-bi

Para el primer dataflow (Entra Groups) utilizaremos el origen de datos de tipo Active Directory. Para configurarlo necesitamos establecer el nombre el dominio, una conexión, una puerta de enlace local (On-premises Gateway) e introducir el nombre del usuario junto con su contraseña, ya que la autentificación es mediante Windows.

primer-dataflow-entra-grops-connect-data-source

El código M utilizado para recuperar los emails de los grupos se adaptó a partir del publicado en el siguiente post:

https://www.fourmoo.com/2018/02/20/dynamic-row-level-security-is-easy-with-active-directory-security-groups/

 

Código M para generar la tabla inicial del dataflow Entra Groups:

let

Source = ActiveDirectory.Domains(#»Domain Name»),

my.domain.com = Source{[Domain = #»Domain Name»]}[Object Categories],

user1 = my.domain.com{[Category = «user»]}[Objects],

#»Removed Other Columns» = Table.Buffer(Table.SelectColumns(user1,{«displayName», «user»})),

#»Expanded user» = Table.ExpandRecordColumn(#»Removed Other Columns», «user», {«userPrincipalName»}, {«user.userPrincipalName»}),

#»Filtered Rows» = Table.SelectRows(#»Expanded user», each not Text.Contains([displayName], «@»)),

#»Renamed Columns» = Table.RenameColumns(#»Filtered Rows», {{«user.userPrincipalName», «User Principal name»}, {«displayName», «Display Name»}})

in

#»Renamed Columns»

 

 

Código M para generar la tabla final del dataflow Entra Groups:

 

let

Source = ActiveDirectory.Domains(#»Domain Name»),

my.domain.com = Source{[Domain = #»Domain Name»]}[Object Categories],

person1 = my.domain.com{[Category = «person»]}[Objects],

#»Expanded top» = Table.Buffer(Table.ExpandRecordColumn(person1, «top», {«cn», «memberOf»}, {«top.cn», «top.memberOf»})),

#»Expanded top.memberOf» = Table.ExpandListColumn(#»Expanded top», «top.memberOf»),

#»Expanded top.memberOf1″ = Table.ExpandRecordColumn(#»Expanded top.memberOf», «top.memberOf», {«mail», «displayName», «name»}, {«top.memberOf.mail», «top.memberOf.displayName», «top.memberOf.name»}),

#»Filtered Rows» = Table.SelectRows(#»Expanded top.memberOf1″, each [displayName] <> null),

#»Removed Columns» = Table.RemoveColumns(#»Filtered Rows», {«person», «distinguishedName»}),

#»Renamed Columns» = Table.RenameColumns(#»Removed Columns», {{«displayName», «Display Name»}, {«top.cn», «CN»}, {«top.memberOf.mail», «Group Display Name»}, {«top.memberOf.displayName», «Group Email Address»}, {«top.memberOf.name», «Group Name»}}),

#»Merged Queries» = Table.NestedJoin(#»Renamed Columns», {«Display Name»}, #»AD – User Details», {«Display Name»}, «NewColumn», JoinKind.LeftOuter),

#»Expanded NewColumn» = Table.ExpandTableColumn(#»Merged Queries», «NewColumn», {«User Principal name», «First Name Letter», «Surname Letter»}, {«User Principal name», «First Name Letter», «Surname Letter»}),

#»Transform columns» = Table.TransformColumnTypes(#»Expanded NewColumn», {{«Group Display Name», type text}, {«Group Email Address», type text}, {«Group Name», type text}}),

#»Replace errors» = Table.ReplaceErrorValues(#»Transform columns», {{«Group Display Name», null}, {«Group Email Address», null}, {«Group Name», null}}),

#»Removed columns 1″ = Table.RemoveColumns(#»Replace errors», {«Surname Letter», «First Name Letter», «CN», «Display Name», «Group Email Address», «Group Name»}),

#»Filtered rows 1″ = Table.SelectRows(#»Removed columns 1″, each ([Group Display Name] <> null))

in

#»Filtered rows 1″

En estas líneas de códigos, el nombre del dominio está definido en el parámetro “Domain Name”.

El resultado del primer dataflow sería una tabla con la extración de los emails por grupos:

 

tabla-exxtraccion-emails-grupos

El segundo dataflow (Security) utilizará como origen de datos una tabla de seguridad compuesta por el nombre del grupo/email de este y el campo relacionado con la restricción a nivel de fila.

Ejemplo de tabla origen segundo dataflow:

tabla-origen

Después, se leerá la tabla final del primer dataflow, para mediante, por ejemplo, un inner join generar la tabla final con el desglose de los usuarios individuales junto con sus permisos.

Ejemplo de tabla final:

tabla-final

Por último, solo nos quedaría conectar la tabla de seguridad generada en los modelos semánticos que queramos aplicar la seguridad, añadir los grupos al rol y establecer el horario de actualización de los dataflows en función del licenciamiento que dispongamos.

Conclusión

La seguridad RLS dinámica nos aporta grandes ventajas frente a la estática, sobre todo en cuando a flexibilidad y mantenimiento a medida que aumentan la complejidad de las unidades de negocio de las empresas.

A pesar de que la gestión de la tabla auxiliar puede ser uno de sus principales inconvenientes, con este método podemos gestionar el RLS con tablas de seguridad al nivel de usuario individual, pero gestionadas desde los grupos de Microsoft Entra ID.

Conviértete en un experto en BI con nuestros cursos de Microsoft Power BI

Descubre nuestro catálogo de cursos de Power BI y conviértete en un experto en BI. Sea cual sea tu nivel encontrarás un curso que se adapte a ti.

pablo-garcia-caballero

Pablo García Caballero

Data & AI Specialist