Prepstellar

DP-700 · Access Control and Data Masking

31 cards

Warehouse SQL Granular Security

Swipe, scroll or use ← →
  1. When SQL permissions are the right tool

    A workspace role or an item permission opens a whole warehouse. Often that is too much: an analyst should query two views, a partner should not see the credit card column, and each sales representative should see only their own orders. When the default permissions from workspace role assignment or item permissions do not give you the level of control you need, use standard SQL constructs in a Fabric warehouse or SQL analytics endpoint for finer-grained access control.

    There are three levels, and each has its own T-SQL construct.

    Level What it restricts T-SQL construct
    Object-level security Tables, views, procedures, functions GRANT, REVOKE, and DENY, and SQL roles
    Column-level security Columns of a table GRANT SELECT with a column list
    Row-level security Rows of a table CREATE SECURITY POLICY with a predicate function

    These constructs work in a Warehouse and in the SQL analytics endpoint of a lakehouse. They have one limit that decides many scenarios: these permissions only apply to queries made through SQL.

    Dynamic data masking is the fourth SQL protection, and it has its own lesson.

    1 / 31
  2. Quick check

    A team defines column-level security with T-SQL on the SQL analytics endpoint of a lakehouse. A data scientist then reads the same table from a Spark notebook. What applies to the notebook?

    1. AThe same column restriction, because T-SQL security is stored with the table in OneLake

      SQL security is not stored with the table. It lives in the SQL engine, and these permissions only apply to queries made through SQL.

    2. BNothing from the SQL definition, because SQL permissions apply only to SQL queries

      Right. Security configured through SQL commands applies only to queries made through SQL, so the notebook is not limited by it.

    3. CAn error, because a table with SQL security cannot be read from Spark

      Spark is not blocked by a SQL definition. The SQL permissions simply do not apply outside queries made through SQL.

    2 / 31

  3. Connect first, then query

    SQL permissions decide what a user can query. They do not let the user in. For a user to connect to a Fabric warehouse or SQL analytics endpoint, you must assign them to a workspace role or grant them the item Read permission. Without Read permission at a minimum, the connection fails.

    The item Read permission alone opens the door and nothing else. When a warehouse is shared with no additional permissions, the recipient receives Read, which only allows the recipient to connect to the SQL analytics endpoint. The recipient cannot query any table or view or execute any function or stored procedure unless they are provided access to objects within the warehouse using the T-SQL GRANT statement.

    3 / 31
  4. Connect first, then query

    The sharing options are the subject of the lesson on item permissions and sharing. One of them is the pattern for granular access. If you want to provide granular access to specific objects within the warehouse, share the warehouse with no additional permissions, then provide granular access to specific objects using the T-SQL GRANT statement.

    The order can also be reversed, so that the user never connects with wrong permissions. To set up a user's granular permissions before they connect to the warehouse, define the permissions in SQL first. Then give them access by assigning a workspace role or granting item permissions.

    One statement from other SQL platforms is missing. You cannot explicitly run CREATE USER in a Fabric warehouse or SQL analytics endpoint. When you run GRANT or DENY, Fabric creates the database user automatically. The user cannot connect until they also have sufficient workspace-level rights.

    4 / 31
  5. Quick check

    An engineer runs a `GRANT` on a warehouse table for a colleague who has no workspace role and no item permission. The colleague then tries to connect with the SQL connection string. What happens?

    1. AThe connection fails, because the colleague has no Read permission on the item

      Right. A SQL permission does not let the user in. Without Read permission at a minimum, the connection fails.

    2. BThe connection works, and the colleague can query only the granted table

      That is the result after the item is shared too. A `GRANT` alone is not enough to connect: the user needs a workspace role or the item Read permission.

    3. CThe `GRANT` fails, because the database user must be created first

      The `GRANT` succeeds, and Fabric creates the database user automatically. What is missing is the right to connect.

    5 / 31

  6. Object-level security: GRANT, REVOKE, DENY, and roles

    Object-level security answers which objects a user can use. You manage object-level security with the GRANT, REVOKE, and DENY T-SQL statements. They are the Data Control Language commands of T-SQL.

    The general concept is to GRANT some permission ON some object TO some user or role:

    GRANT SELECT ON OBJECT::Person.Address TO [RosaQdM@contoso.com];
    GRANT SELECT ON Person.Address TO [RosaQdM@contoso.com];
    

    Both lines grant SELECT on the table Person.Address to one Microsoft Entra user. The OBJECT phrase is optional if the schema name is specified, so the second line is the usual form. For stored procedures and functions, use GRANT EXECUTE to assign permissions.

    Statement What it does
    GRANT Grants permissions on a securable to a principal.
    DENY Denies a permission to a principal, and prevents that principal from inheriting the permission through its group or role memberships.
    REVOKE Removes a previously granted or denied permission.

    The three statements have the same shape. DENY ends with TO and the principal, and REVOKE accepts FROM or TO. A permission can also target a whole schema, with the class SCHEMA and the scope qualifier ::, as in GRANT SELECT ON SCHEMA::Sales TO Vendors.

    6 / 31
  7. Object-level security: GRANT, REVOKE, DENY, and roles

    DENY and REVOKE both take access away, but they are not the same.

    DENY wins. DENY takes precedence over all permissions, except that it does not apply to object owners. A user who is in a role with SELECT on a table, and who is denied SELECT on that table, cannot read it.

    REVOKE only removes. It removes a permission that was granted or denied to that principal. To stop one member of a role, deny the permission to that member. A REVOKE for that member has nothing to remove, because the grant belongs to the role.

    The scope of a DENY matters when you grant again.

    Earlier DENY Later GRANT Result
    On a table The same permission on the same table Granting a permission removes the DENY of that permission on the specified securable.
    On a schema The same permission on one table of the schema If the same permission is denied at a higher scope that contains the securable, the DENY takes precedence.

    One exception is kept for backward compatibility: a table-level DENY does not take precedence over a column-level GRANT.

    7 / 31
  8. Quick check

    A user received `SELECT` on a table through a `GRANT` to the user. The permission must be taken away, but the user must still be able to get it later through a role. Which statement fits?

    1. A`DENY`, because it removes the grant and nothing else

      `DENY` does more than remove. It prevents the user from inheriting the permission through role memberships, so a later role would not help.

    2. B`REVOKE`, because it only removes the granted permission

      Right. `REVOKE` removes a previously granted or denied permission and leaves nothing behind that could block a role.

    3. C`GRANT` again, because a second grant cancels the first one

      A second `GRANT` of the same permission takes nothing away. Granting removes an earlier `DENY`, never an earlier grant.

    8 / 31

  9. Keep your progress in the app

    That’s 3 of 12 quick checks. In the app they stay answered, and every lesson remembers where you left off.

    Opens in your browser. Nothing to install.

    Start studying

    On your phone, with the same account

    Get it on Google Play Download on the App Store
    Keep reading here
  10. SQL roles, and checking the result

    You do not have to grant user by user. You can assign users to SQL roles, both custom database roles and built-in database roles. For simplicity of management, assigning permissions to roles is preferred to using individuals.

    CREATE ROLE SalesReaders;
    GRANT SELECT ON sales.Orders TO SalesReaders;
    ALTER ROLE SalesReaders ADD MEMBER [charlie@contoso.com];
    ALTER ROLE SalesReaders DROP MEMBER [charlie@contoso.com];
    

    CREATE ROLE creates a new database role in the current database. After you create a role, configure its permissions by using GRANT, DENY, and REVOKE. To add members to a database role, use ALTER ROLE with ADD MEMBER. DROP MEMBER removes a member from the role.

    A member can be a database user or a user-defined database role. ALTER ROLE has one more form, WITH NAME, which changes the name of a user-defined database role.

    9 / 31
  11. SQL roles, and checking the result

    After granting, verify. A connected user can view the permissions available to them by using the sys.fn_my_permissions function, at three scopes:

    SELECT * FROM sys.fn_my_permissions(NULL, 'Database');
    SELECT * FROM sys.fn_my_permissions('<schema-name>', 'Schema');
    SELECT * FROM sys.fn_my_permissions('<schema-name>.<object-name>', 'Object');
    

    The first query lists the permissions of the current user on the database, the second on one schema, and the third on one object.

    A user with elevated permissions can list the permissions granted explicitly to users by joining the system views sys.database_principals and sys.database_permissions. Read the result with care: this query does not return permissions that users receive through a Fabric workspace role or item. A user who is missing from the result can still read everything as a workspace Contributor.

    10 / 31
  12. Quick check

    An admin joins `sys.database_principals` and `sys.database_permissions` to audit a warehouse. A workspace Contributor who reads every table is not in the result. Why?

    1. ABecause the query lists only the users who are connected at that moment

      The query does not depend on who is connected. It lists permissions granted explicitly in SQL, and the Contributor's access comes from the workspace role.

    2. BBecause a Contributor has no access to data until a `GRANT` is run

      A Contributor reads the warehouse through the workspace role, with no `GRANT`. That is the reason the system views show nothing for this user.

    3. CBecause the query omits permissions that come from a workspace role

      Right. This query does not return permissions that users receive through a Fabric workspace role or item.

    11 / 31

  13. Column-level security: GRANT SELECT with a column list

    Column-level security protects a sensitive column inside a table that the user may otherwise read. You implement column-level security with the GRANT T-SQL statement, by adding a list of columns after the table name.

    Take a Customers table with the columns CustomerID, FirstName, CreditCard, LastName, Phone, and Email. This statement lets Charlie read every column except CreditCard:

    GRANT SELECT ON Customers(CustomerID, FirstName, LastName, Phone, Email) TO [Charlie@contoso.com];
    

    The statement grants SELECT only on the five columns between the parentheses. CreditCard is not in the list, so Charlie has no permission on it.

    The effect is an error, not a silent filter. Queries executed as Charlie fail if they include the CreditCard column:

    SELECT * FROM Customers;
    -- Msg 230: The SELECT permission was denied on the column 'CreditCard' of the object 'Customers'
    
    12 / 31
  14. Column-level security: GRANT SELECT with a column list

    Four facts complete the picture of column-level security in a warehouse.

    • Column-level security is simpler than designing additional views to filter out columns.
    • Assigning the column permissions to roles is preferred to using individuals.
    • Only Microsoft Entra authentication is supported.
    • Column-level security is applied to a shared warehouse or lakehouse accessed through a SQL analytics endpoint, because the underlying data source has not changed.

    The restriction lives in the database tier, not in an application. The database applies the access restrictions every time data access is attempted, from any application or reporting platform including Power BI.

    13 / 31
  15. Quick check

    A SQL role named Support must read only CustomerID and Email in `Customers`. Which statement is column-level security for this?

    1. A`GRANT SELECT ON Customers TO Support;`

      This grants `SELECT` on the whole table, so the role would read every column, CreditCard included.

    2. B`CREATE SECURITY POLICY Support ADD FILTER PREDICATE Customers(CustomerID, Email);`

      A security policy filters rows with a predicate function. It does not choose columns, and it does not take a column list in this way.

    3. C`GRANT SELECT ON Customers(CustomerID, Email) TO Support;`

      Right. Column-level security is a `GRANT SELECT` with the list of allowed columns after the table name.

    14 / 31

  16. Row-level security: the predicate function

    Row-level security lets workers see only the rows of their department, or lets each customer of a multitenant solution see only the rows of their company. You implement RLS by using the CREATE SECURITY POLICY Transact-SQL statement, and predicates created as inline table-valued functions.

    So there are two objects. The function holds the logic, and the policy connects the function to a table. Start with the function:

    CREATE FUNCTION Security.tvf_securitypredicate(@SalesRep AS nvarchar(50))
        RETURNS TABLE
    WITH SCHEMABINDING
    AS
        RETURN SELECT 1 AS tvf_securitypredicate_result
    WHERE @SalesRep = USER_NAME() OR USER_NAME() = 'manager@contoso.com';
    

    Read it in three parts. The function receives one value, the SalesRep of a row. It is an inline table-valued function, created WITH SCHEMABINDING. And its WHERE condition is the security predicate. Security predicates are conditions that determine which rows a user can access. Here a user can access the rows where the SalesRep column, mapped to the @SalesRep parameter, matches the result of USER_NAME(). The second part of the condition is an exception for one user name, the manager.

    The function USER_NAME() is what makes one definition serve every user. Each sales representative sees their own rows, and the manager sees all of them.

    15 / 31
  17. Quick check

    In the predicate function, the condition is `@SalesRep = USER_NAME() OR USER_NAME() = 'manager@contoso.com'`. What does `Sales1@contoso.com` see in the table after the policy is on?

    1. AThe rows whose SalesRep value is Sales1@contoso.com

      Right. For this user the first part is true only on rows whose SalesRep value is the user's own name, so only those rows are visible.

    2. BThe rows of every sales representative except the manager

      The condition compares the SalesRep of each row with the current user. Rows of other representatives make both parts false and are filtered.

    3. CNo rows, because the second part of the condition is false

      The two parts are joined with OR, so one true part is enough. The first part is true on the user's own rows.

    16 / 31

  18. Row-level security: the security policy

    The function does nothing until a policy uses it. The security policy invokes and enforces the function on a table:

    CREATE SECURITY POLICY SalesFilter
    ADD FILTER PREDICATE Security.tvf_securitypredicate(SalesRep)
    ON sales.Orders
    WITH (STATE = ON);
    

    The statement names the policy, adds the function as a filter predicate, passes the SalesRep column of the table as the argument, names the table sales.Orders, and turns the policy on. A table that has a security predicate defined but disabled is not filtered.

    Filter predicates silently filter the rows available to read operations. The application is unaware of rows that are filtered from the result set, and if all rows are filtered, a null set is returned. No error tells the user that rows are missing.

    17 / 31
  19. Row-level security: the security policy

    The filter covers more than SELECT.

    Operation Effect of a filter predicate
    SELECT Filtered rows are not returned.
    UPDATE The user cannot update rows that are filtered.
    DELETE The user cannot delete rows that are filtered.
    INSERT Allowed, even if the new rows will be filtered during any other operation.

    Two limits of scope are easy to forget. Each table must have its own row-level security defined separately. And users who query tables without a row-level security policy view unfiltered data.

    In a SQL analytics endpoint the tables already exist, and the work is the same. In the SQL analytics endpoint, you cannot CREATE TABLE, but you can CREATE SCHEMA, CREATE FUNCTION, and CREATE SECURITY POLICY.

    18 / 31
  20. Quick check

    A policy with a filter predicate is on for `sales.Orders`. A sales representative runs a `DELETE` with no `WHERE` clause on the table. What is deleted?

    1. AEvery row of the table, because filter predicates affect only `SELECT`

      Filter predicates affect `SELECT`, `UPDATE`, and `DELETE`. The rows of other representatives are filtered, so the statement cannot delete them.

    2. BNothing, because a filter predicate makes the table read-only

      The table is not read-only. The user can still change and delete visible rows, and can even insert rows.

    3. CThe rows the representative can see, because filtered rows cannot be deleted

      Right. Filter predicates are applied while reading data from the base table, and users cannot delete rows that are filtered.

    19 / 31

  21. Who the policy applies to, and who can create it

    A SQL security policy has no privileged readers. Security policies apply to all users, including dbo users in the database. If members of roles like Administrator, Member, or Contributor need to see all rows to troubleshoot or validate data, the security policy must be written to allow that.

    This is why the example function has a second condition for the manager. Take the function without it. For an Admin whose name is in no SalesRep value, the condition is false on every row, so all rows are filtered, and if all rows are filtered, a null set is returned.

    Creating the policy needs specific permissions.

    Action Permission required
    Create, alter, or drop a security policy ALTER ANY SECURITY POLICY
    Create or drop a security policy Also ALTER permission on the schema
    Add a predicate SELECT and REFERENCES on the function, and REFERENCES on the target table and on every column used as an argument

    Users who only query the table need nothing more than their table permission. If a security policy is created with SCHEMABINDING = ON, which is the default, the permission checks on the predicate function are bypassed when users query the target table.

    20 / 31
  22. Who the policy applies to, and who can create it

    Row-level security hides rows from a direct query, but a careful user can still learn values from errors. A query such as SELECT 1/(SALARY-100000) FROM PAYROLL WHERE NAME='John Doe' returns a divide-by-zero exception only when the salary is exactly 100,000, so the error reveals the value. Limit permissions and monitor suspicious activity, such as constantly changing policies and predicate functions.

    21 / 31
  23. Quick check

    A developer has `ALTER ANY SECURITY POLICY` and runs `CREATE SECURITY POLICY` in the `Security` schema. The statement fails for lack of permission. Which permission is the likely gap?

    1. A`ALTER` permission on the schema

      Right. Creating or dropping a security policy also requires `ALTER` permission on the schema.

    2. B`UNMASK` permission on the target table

      `UNMASK` belongs to dynamic data masking. A security policy needs `REFERENCES` on the target table, not `UNMASK`.

    3. C`EXECUTE` permission on the predicate function

      Adding a predicate needs `SELECT` and `REFERENCES` on the function. `EXECUTE` is not in the list.

    22 / 31

  24. Change a predicate that is in use

    A predicate function that is bound to a policy is protected. Attempts to modify a function that is used as a predicate on a table within a schema-bound security policy result in an error. To modify a row-level security function, you must first drop the security policy.

    The change is a sequence of three steps:

    DROP SECURITY POLICY SalesFilter;
    ALTER FUNCTION Security.tvf_securitypredicate(@SalesRep AS nvarchar(50)) ...
    CREATE SECURITY POLICY SalesFilter ADD FILTER PREDICATE Security.tvf_securitypredicate(SalesRep) ON sales.Orders WITH (STATE = ON);
    

    Drop the policy, alter the function with the new condition, and create the policy again. Between the first and the last step the table has no policy, and users who query tables without a row-level security policy view unfiltered data.

    The binding protects the table too. Attempts to alter the schema of a table bound by a schema-bound security policy result in an error. However, columns not referenced by the predicate can be altered.

    23 / 31
  25. Quick check

    A schema-bound security policy on `sales.Orders` passes the SalesRep column to its predicate function. Which change to the table succeeds while the policy exists?

    1. AAltering the SalesRep column, because the binding protects only the function

      The binding protects the table too. An attempt to alter the schema of a table bound by a schema-bound security policy results in an error when the column is used by the predicate.

    2. BAltering any column, because a filter predicate works on rows and not on columns

      A filter predicate does work on rows, but it reads the SalesRep column to do it. That column is protected while the policy exists.

    3. CAltering a column that the predicate does not reference

      Right. Altering the schema of the bound table results in an error, but columns not referenced by the predicate can be altered.

    24 / 31

  26. The effect on Power BI Direct Lake

    SQL security has a cost for reports, and it appears as a change of storage mode. Row-level security and column-level security only apply to queries on a Warehouse or SQL analytics endpoint in Fabric.

    The result is a fallback. Power BI queries on a warehouse in Direct Lake mode fall back to Direct Query mode to abide by row-level security. The same happens to abide by column-level security.

    For a report on a lakehouse the rule is general. If any security is defined in the SQL analytics endpoint that the report is built on, the queries automatically fall back to DirectQuery mode. If you do not want this fallback, you can create a new lakehouse using shortcuts to the tables in the original lakehouse and not define RLS or OLS in SQL on the new lakehouse.

    25 / 31
  27. Quick check

    A report on a lakehouse must keep Direct Lake mode, but SQL security on the SQL analytics endpoint makes its queries fall back. Which option avoids the fallback?

    1. AGrant the readers of the report ReadData on the lakehouse

      More permissions do not change the mode. The fallback happens because security is defined in the SQL analytics endpoint that the report is built on.

    2. BBuild the report on a new lakehouse with shortcuts and no SQL security

      Right. A new lakehouse with shortcuts to the tables, and with no RLS or OLS defined in SQL, has nothing that forces the fallback.

    3. CAdd the readers of the report to a SQL role on the endpoint

      A SQL role is one more piece of SQL security on the same endpoint. The queries keep falling back to DirectQuery mode.

    26 / 31

  28. SQL security or OneLake security

    Both models can restrict rows, columns, and objects. They differ in where the restriction is enforced.

    Question SQL security OneLake security
    Which access paths does it cover? Only queries made through SQL Spark, SQL, and OneLake APIs
    Where is it defined? In the warehouse or SQL analytics endpoint, with T-SQL In OneLake security roles on the item

    OneLake security applies its restrictions consistently across all compute engines. So when the same users read a lakehouse table from Spark and from SQL, a SQL policy protects only one of the two paths.

    A warehouse has a related leak. Security policies defined using SQL constructs in a warehouse are enforced only within the SQL execution context of the warehouse. When you access data from a warehouse through shortcuts in OneLake, these SQL security semantics are not translated into OneLake security policies. Users accessing the data through a shortcut might see the full warehouse data.

    27 / 31
  29. SQL security or OneLake security

    In the SQL analytics endpoint of a lakehouse, the access mode decides which of the two models governs tables.

    Delegated identity mode User identity mode
    Default for a new endpoint Yes No
    Access to tables Full control using SQL GRANT and REVOKE OneLake security roles. SQL GRANT and REVOKE on tables is not allowed.
    Row-level security CREATE SECURITY POLICY Part of OneLake security roles
    Column-level security GRANT SELECT with column list Part of OneLake security roles
    Views, procedures, functions SQL GRANT SQL GRANT

    In delegated identity mode, OneLake security roles do not carry over to table-level access, so everything in this lesson is how you secure the endpoint. In user identity mode, you cannot define RLS, CLS, or OLS directly using T-SQL.

    Switching the mode changes what happens to the SQL security that already exists. The lesson on OneLake security enforcement covers the modes and the switch in detail.

    28 / 31
  30. Quick check

    A warehouse table has a SQL security policy that shows each analyst the rows of one region. Another team reads the same table through a OneLake shortcut in their lakehouse. What might that team see?

    1. AOnly the rows of their region, because the policy follows the data

      The policy does not follow the data. It is enforced only within the SQL execution context of the warehouse.

    2. BNothing, because a table with a SQL security policy cannot be a shortcut target

      The shortcut works. The problem is the opposite: it gives a path to the data that the SQL policy does not control.

    3. CThe full table, because SQL security is not translated into OneLake security

      Right. Through shortcuts, SQL security semantics are not translated into OneLake security policies, so users might see the full warehouse data.

    29 / 31

  31. Key takeaways

    • CREATE USER cannot be run. Fabric creates the database user automatically when you run GRANT or DENY.
    • DENY takes precedence, also over a permission that comes from a role, and a DENY on a schema beats a GRANT on one of its tables. REVOKE only removes a grant or a deny.
    • SQL roles carry the permissions. CREATE ROLE creates the role, and ALTER ROLE with ADD MEMBER adds a member to it.
    • Column-level security is GRANT SELECT with a column list, and a query that includes a column outside the list fails with a permission error.
    • Row-level security is a schema-bound inline table-valued function plus CREATE SECURITY POLICY ... ADD FILTER PREDICATE ... WITH (STATE = ON).
    • Security policies apply to all users, so a predicate must include the people who need every row.
    • To change a predicate function, drop the security policy first, then alter the function and create the policy again.
    • Direct Lake falls back to Direct Query mode when SQL row-level or column-level security protects the data.
    • SQL security covers only SQL queries. For Spark and SQL together, use OneLake security roles with the endpoint in user identity mode.
    30 / 31
  32. Quick check

    Which statement about SQL granular security in a Fabric warehouse is correct?

    1. AA filter predicate hides rows from `SELECT` only, so `DELETE` still reaches them

      Filter predicates affect `SELECT`, `UPDATE`, and `DELETE`. Only `INSERT` stays allowed for rows that would be filtered.

    2. BA `GRANT` runs for a user who has no database user, and Fabric creates it

      Right. You cannot run `CREATE USER`, and Fabric creates the database user automatically when you run `GRANT` or `DENY`.

    3. CMembers of the workspace Admin role are never filtered by a security policy

      Security policies apply to all users, including dbo users. An Admin sees all rows only if the predicate is written to allow that.

    31 / 31

  33. 12 quick checks · then the test

    In the app, finishing the quick checks opens this lesson’s 10-question test, and the ones you miss come back exactly when you’re about to forget them.

    Take this lesson’s test →

    Opens in your browser. Nothing to install.

    Start studying

    On your phone, with the same account

    Get it on Google Play Download on the App Store

The whole course, on your computer and your phone

Lessons you can read, audio you can listen to on the way to work, and practice that remembers what you got wrong.

Opens in your browser. Nothing to install.

Start studying

On your phone, with the same account

Get it on Google Play Download on the App Store

“This app is the ‘One Lake’ for preparing the certification exams. Really worth it.”

Abdelhak Y. Google Play review