Seguridad de nivel de fila
Use la pertenencia a grupos o el contexto de ejecución para controlar el acceso a las filas de una tabla de base de datos.
La Seguridad de nivel de fila (RLS) simplifica el diseño y la codificación de la seguridad. Permite aplicar restricciones en el acceso a las filas de datos en la aplicación. Por ejemplo, limite el acceso de los usuarios a las filas pertinentes para su departamento o restrinja el acceso de los clientes solo a los datos pertinentes para su empresa.
La lógica de la restricción de acceso está ubicada en el nivel de base de datos en lugar de estar alejada de los datos en otra capa de aplicación. El sistema de base de datos aplica las restricciones de acceso cada vez que se intenta acceder a los datos desde cualquier nivel. Esta lógica hace que el sistema de seguridad sea más confiable y sólido al reducir el área expuesta del sistema de seguridad.
RLS le permite proporcionar acceso a otras aplicaciones y usuarios, solo a una parte determinada de una tabla. Por ejemplo, puedes:
- Conceder acceso solo a las filas que cumplen algunos criterios
- Anonimización de datos en algunas de las columnas
- Todo lo anterior
Nota
Cuando se habilita una directiva RLS en una tabla, el acceso se reemplaza por completo por la consulta RLS definida en la tabla. La restricción de acceso se aplica a todos los usuarios, incluidos los administradores de bases de datos y el creador de RLS. La consulta de RLS debe incluir explícitamente definiciones para todos los tipos de usuarios a los que desea conceder acceso.
Para obtener más información, vea Comandos de control para administrar la directiva de seguridad de nivel de fila.
Sugerencia
Estas funciones suelen ser útiles para row_level_security consultas:
Limitaciones
No hay ningún límite en el número de tablas en las que se puede configurar la directiva de seguridad de nivel de fila.
La directiva de RLS no se puede habilitar en una tabla:
- para el que se configura la exportación continua de datos .
- a la que hace referencia una consulta de una directiva de actualización.
- en el que se configura la directiva de acceso a vistas restringidas .
- en la que está habilitada otra directiva de seguridad de nivel de fila.
Ejemplos
Limitar el acceso a la tabla Sales
En una tabla denominada Sales, cada fila contiene detalles sobre una venta. Una de las columnas contiene el nombre del vendedor. En lugar de conceder a los vendedores acceso a todos los registros de Sales, habilite una directiva de seguridad de nivel de fila en esta tabla para devolver solo los registros en los que el vendedor es el usuario actual:
Sales | where SalesPersonAadUser == current_principal()
También puede enmascarar la dirección de correo electrónico:
Sales | where SalesPersonAadUser == current_principal() | extend EmailAddress = "****"
Si desea que cada vendedor vea todas las ventas de un país específico, puede definir una consulta similar a la siguiente:
let UserToCountryMapping = datatable(User:string, Country:string)
[
"john@domain.com", "USA",
"anna@domain.com", "France"
];
Sales
| where Country in ((UserToCountryMapping | where User == current_principal_details()["UserPrincipalName"] | project Country))
Si tiene un grupo que contiene los administradores, es posible que quiera concederles acceso a todas las filas. Consulte la directiva de seguridad de nivel de fila.
let IsManager = current_principal_is_member_of('aadgroup=sales_managers@domain.com');
let AllData = Sales | where IsManager;
let PartialData = Sales | where not(IsManager) and (SalesPersonAadUser == current_principal());
union AllData, PartialData
| extend EmailAddress = "****"
Exposición de datos diferentes a los miembros de diferentes grupos de Azure AD
Si tiene varios grupos de Azure AD y desea que los miembros de cada grupo vean un subconjunto diferente de datos, use esta estructura para una consulta RLS. Supongamos que un usuario solo puede pertenecer a un único grupo de Azure AD.
let IsInGroup1 = current_principal_is_member_of('aadgroup=group1@domain.com');
let IsInGroup2 = current_principal_is_member_of('aadgroup=group2@domain.com');
let IsInGroup3 = current_principal_is_member_of('aadgroup=group3@domain.com');
let DataForGroup1 = Customers | where IsInGroup1 and <filtering specific for group1>;
let DataForGroup2 = Customers | where IsInGroup2 and <filtering specific for group2>;
let DataForGroup3 = Customers | where IsInGroup3 and <filtering specific for group3>;
union DataForGroup1, DataForGroup2, DataForGroup3
Aplicación de la misma función RLS en varias tablas
En primer lugar, defina una función que reciba el nombre de la tabla como parámetro de cadena y haga referencia a la tabla mediante el table() operador .
Por ejemplo:
.create-or-alter function RLSForCustomersTables(TableName: string) {
table(TableName)
| ...
}
Después, configure RLS en varias tablas de esta manera:
.alter table Customers1 policy row_level_security enable "RLSForCustomersTables('Customers1')"
.alter table Customers2 policy row_level_security enable "RLSForCustomersTables('Customers2')"
.alter table Customers3 policy row_level_security enable "RLSForCustomersTables('Customers3')"
Generar un error tras el acceso no autorizado
Si desea que los usuarios de tabla no autorizados reciban un error en lugar de devolver una tabla vacía, use la assert() función . En el ejemplo siguiente se muestra cómo generar este error en una función RLS:
.create-or-alter function RLSForCustomersTables() {
MyTable
| where assert(current_principal_is_member_of('aadgroup=mygroup@mycompany.com') == true, "You don't have access")
}
Puede combinar este enfoque con otros ejemplos. Por ejemplo, puede mostrar resultados diferentes a los usuarios de grupos de AAD diferentes y generar un error para todos los demás.
Permisos de control en bases de datos de seguidor
La directiva RLS que configure en la base de datos de producción también surtirá efecto en las bases de datos del seguidor. No se pueden configurar directivas RLS diferentes en las bases de datos de producción y seguidor. Sin embargo, puede usar la función en la current_cluster_endpoint() consulta de RLS para lograr el mismo efecto, ya que tiene consultas RLS diferentes en las tablas del seguidor.
Por ejemplo:
.create-or-alter function RLSForCustomersTables() {
let IsProductionCluster = current_cluster_endpoint() == "mycluster.eastus.kusto.windows.net";
let DataForProductionCluster = TempTable | where IsProductionCluster;
let DataForFollowerClusters = TempTable | where not(IsProductionCluster) | extend EmailAddress = "****";
union DataForProductionCluster, DataForFollowerClusters
}
Más casos de uso
- Una persona de soporte técnico del centro de llamadas puede identificar a los autores de llamadas por varios dígitos de su número de seguridad social. Este número no debe exponerse completamente a la persona de soporte técnico. Se puede aplicar una directiva de RLS en la tabla para enmascarar todos los cuatro últimos dígitos del número de seguridad social en el conjunto de resultados de cualquier consulta.
- Establezca una directiva de RLS que enmascara la información de identificación personal (PII) y permita a los desarrolladores consultar entornos de producción con fines de solución de problemas sin infringir las regulaciones de cumplimiento.
- Un hospital puede establecer una directiva de RLS que permita a las enfermeras ver las filas de datos solo para sus pacientes.
- Un banco puede establecer una directiva de RLS para restringir el acceso a las filas de datos financieros en función de la división o el rol de negocio de un empleado.
- Una aplicación multiinquilino puede almacenar datos de muchos inquilinos en un único conjunto de tablas (que es eficaz). Usarían una directiva RLS para aplicar una separación lógica de las filas de datos de cada inquilino de las filas de cada otro inquilino, por lo que cada inquilino solo puede ver sus filas de datos.
Impacto en el rendimiento en las consultas
Cuando se habilita una directiva RLS en una tabla, habrá algún impacto en el rendimiento en las consultas que acceden a esa tabla. El acceso a la tabla se reemplazará por la consulta RLS definida en esa tabla. El impacto en el rendimiento de una consulta RLS normalmente constará de dos partes:
- Comprobaciones de pertenencia en Azure Active Directory: las comprobaciones son eficaces. Puede comprobar la pertenencia a decenas o incluso cientos de grupos sin un impacto importante en el rendimiento de las consultas.
- Filtros, combinaciones y otras operaciones que se aplican a los datos: el impacto depende de la complejidad de la consulta.
Por ejemplo:
let IsRestrictedUser = current_principal_is_member_of('aadgroup=some_group@domain.com');
let AllData = MyTable | where not(IsRestrictedUser);
let PartialData = MyTable | where IsRestrictedUser and (...);
union AllData, PartialData
Si el usuario no forma parte de some_group@domain.com, IsRestrictedUser se evaluará como false. La consulta que se evaluará es similar a esta:
let AllData = MyTable; // the condition evaluates to `true`, so the filter is dropped
let PartialData = <empty table>; // the condition evaluates to `false`, so the whole expression is replaced with an empty table
union AllData, PartialData // this will just return AllData, as PartialData is empty
Del mismo modo, si IsRestrictedUser se evalúa como true, solo se evaluará la consulta de PartialData .
Mejora del rendimiento de las consultas cuando se usa RLS
- Si se aplica un filtro en una columna de cardinalidad alta, por ejemplo, DeviceID, considere la posibilidad de usar la directiva de creación de particiones o la directiva de orden de fila.
- Si se aplica un filtro en una columna de cardinalidad media baja, considere la posibilidad de usar la directiva de orden de fila.
Impacto en el rendimiento en la ingesta
No hay ningún impacto en el rendimiento en la ingesta.