Domain 2 of 4 · Chapter 1 of 2

Secure Unity Catalog Objects

The grant model: who, what, and where

A data analyst has been granted SELECT on the orders table, runs SELECT * FROM sales.finance.orders, and still gets a permission error. The fix reveals the whole model: reading a table in Unity Catalog needs three grants working together, not one.

Unity Catalog authorizes access by granting privileges on securable objects to principals. A securable is any object in the three-level namespace — a catalog, a schema, or a table, view, volume, or function inside a schema. A principal is a user, an account group, or a service principal (an identity for jobs and tools rather than a person, covered under machine identity below). The statement reads GRANT <privilege> ON <securable> TO <principal>, and REVOKE takes it away; the everyday privileges are SELECT (read a table or view), MODIFY (write), and CREATE TABLE (Manage privileges in Unity Catalog[1]). Prefer granting to a group over naming individuals: the principal is not limited to a single user, and group membership is far easier to keep correct as people join and leave.

The three grants the analyst actually needs are SELECT on the table, USE CATALOG on its parent catalog, and USE SCHEMA on its parent schema. USE CATALOG and USE SCHEMA are usage privileges: they grant traversal of the namespace so you can reach an object, but they expose no data by themselves. All three are required, and holding only SELECT is not enough — which is exactly why the query above failed (Unity Catalog permissions model[2]). This is deliberate: because only catalog and schema owners, or a user with MANAGE, can grant the USE privileges, a table owner cannot hand out access to their table beyond the boundary an administrator has drawn.

Privileges inherit downward. A privilege granted on a container object — a catalog or a schema — automatically applies to all of its current and future children. Grant SELECT on a catalog and the grantee can read every table in every schema it contains, present and future, still subject to the USE privileges (Unity Catalog permissions model[2]). One catalog-level grant can thus replace hundreds of table-level ones, which is why you set broad read access high in the hierarchy and reserve table-level grants for exceptions. Metastore-level grants are the exception that does not inherit: they control operations such as CREATE CATALOG, not access to data.

The figure below stacks the three levels and shows the grant each one needs before a query can read the table.

Cataloggrant USE CATALOGSchemagrant USE SCHEMATable or viewgrant SELECTInheritancea grant on a parentflows to all childrenAll three requiredUSE grants traversal;SELECT reads the data
Reading a table needs USE CATALOG, USE SCHEMA, and SELECT; a grant on a parent object is inherited by its children. Source: Azure Databricks Unity Catalog docs.

Ownership, MANAGE, and account-level identity

Being able to read an object and being able to control who else reads it are different powers, and Unity Catalog keeps them strictly apart. The rule in one line: only an object's owner, or a user with MANAGE, can grant on it; a plain SELECT holder cannot.

Every securable has exactly one owner, and the owner can be a user, a group, or a service principal (Unity Catalog permissions model[2]). The owner implicitly holds all privileges on the object, without any privilege being explicitly listed, and is the principal who can GRANT and REVOKE, ALTER, transfer ownership, and DROP it. Ownership moves with a single statement.

Reassign a table's owner to a group

ALTER TABLE mycatalog.myschema.orders OWNER TO `data-eng`;

Transferring to a group is the recommended pattern for shared objects: any group member can then administer the object, while data access still follows the group's own grants (Manage privileges in Unity Catalog[1]).

When a non-owner must administer an object without becoming the owner, grant the MANAGE privilege. MANAGE lets a principal grant and revoke privileges, drop the object, and even transfer its ownership, and on a container it cascades to child objects — it is close to ownership, not a lesser grant-only role. Two things still keep it short of ownership: a MANAGE holder is not automatically given the object's data privileges such as SELECT — they must grant those to themselves, which is the whole point of keeping the roles distinct — and, unlike an owner, they must hold USE CATALOG and USE SCHEMA on the parents to exercise MANAGE at all (Unity Catalog permissions model[2]). The line to remember is between a plain SELECT holder — who can read but neither grant nor drop — and a MANAGE holder or owner, who can administer the object.

One more distinction the exam probes: who the principals even are. Users, groups, and service principals in Unity Catalog are account-level identities, provisioned from Microsoft Entra ID — historically through SCIM provisioning, and now, by default for newer accounts, through automatic identity management with Entra ID as the source of record (Manage users, service principals, and groups[3]). Groups are managed once at the account level, never per workspace, and an account group must be assigned to a workspace through identity federation before it can be granted anything there. A grant therefore always targets an account-level principal federated into the workspace, not a group that lives only inside one workspace.

Column and row security beyond object grants

You have a sales_raw table with an email column and a total column. Analysts should see every row but never the raw email, auditors should see the email, and each regional manager should see only their own region's rows. A SELECT grant cannot express any of that, because a grant is all-or-nothing: it covers the entire table and every column. Trying to grant SELECT on only the non-sensitive columns is not a Unity Catalog capability; it would break SELECT * with a permission error rather than hide values. Fine-grained control is added as a layer on top of the base grant, and Unity Catalog offers four.

A dynamic view wraps a base table in a view whose SQL redacts or filters per caller. For column-level redaction, a CASE expression calls is_account_group_member(), returning the real value to members of an authorized group and a placeholder to everyone else.

Column redaction in a dynamic view

CREATE VIEW sales_redacted AS
SELECT
  user_id,
  CASE WHEN is_account_group_member('auditors') THEN email
       ELSE 'REDACTED' END AS email,
  region,
  total
FROM sales_raw;

is_account_group_member() returns TRUE when the current user belongs to a named account-level group; Databricks recommends it over is_member(), which only checks workspace-local groups and should be avoided against Unity Catalog data (Create a dynamic view[4]). For row-level security, a WHERE predicate built from the caller's identity keeps only the rows that principal may see — is_account_group_member('managers') to lift a limit, or current_user() (equivalently session_user()) to match rows to the person running the query. When entitlements change often, move them into data: join the base table to a mapping table that records which principal or group may see which key values, so you adjust access by editing rows rather than rewriting the view (Row filters and column masks[5]). For any of this to hold, grant SELECT on the view and do not grant the base table, forcing every principal through the view.

The other two layers attach to the table itself instead of wrapping it in a view. A column mask is a SQL user-defined function (UDF) bound to a column with ALTER TABLE ... ALTER COLUMN ... SET MASK; it takes the column value and returns the original or a masked version (Row filters and column masks[5]). A row filter is a boolean SQL UDF bound to the table with ALTER TABLE ... SET ROW FILTER; rows for which it returns FALSE are dropped from results. Masks and filters travel with the table, so they hold no matter which query or downstream view reaches it — the advantage over a dynamic view, which only protects data accessed through that one view.

When the same rule must hold across many tables, reach for attribute-based access control (ABAC). An ABAC policy attaches at the catalog or schema level and applies a row filter or column mask automatically to any table or column carrying a governed tag, so newly tagged tables are covered with no per-table configuration (Attribute-based access control in Unity Catalog[6]). Databricks now recommends ABAC over per-table masks and filters when you need consistent, centrally-authored rules at scale.

The figure shows how one query is routed to different results by the caller's group membership.

Base tablesales_rawgrant withheldEnforcement layerview, mask, or filterCASE picks value or REDACTEDWHERE keeps the caller rowsgated by group membershipGroup memberreal values, all rowsNot a memberREDACTED, rows filteredquerymembernon-member
Group membership routes a query through the enforcement layer to either real values and all rows, or redacted, filtered results. Source: Azure Databricks docs.

Secrets: keep credentials out of code

A pipeline that connects to an external database needs a password, and the wrong move is to type it into the notebook. Databricks secrets store that value outside your code and hand it back only at runtime, redacted from output.

A secret scope is a named collection of secrets, and a secret is a key-value pair inside a scope. There are two scope types, and the distinction matters on Azure. An Azure Key Vault-backed scope maps a Databricks scope onto an Azure Key Vault, so the secrets actually live in Key Vault; it is a read-only interface from Databricks, meaning you create, update, and rotate the values in Azure Key Vault, never from Databricks (Secret management[7]). A Databricks-backed scope stores its secrets in an encrypted store that Databricks manages, and you write to it with the Databricks CLI or SDK. So if a question says the secret must be created and rotated in Azure, the answer is a Key Vault-backed scope, and remember you cannot write to it from Databricks.

Code reads a secret with the secrets utility rather than hardcoding it.

Read a secret in a notebook

password = dbutils.secrets.get(scope='sales-prod', key='db-password')

dbutils.secrets.get(scope, key) returns the value, and Databricks redacts it: any attempt to print the value, in a notebook cell or through a Spark configuration property, is replaced with the literal [REDACTED] so the secret cannot leak into output or logs (Secret management[7]). Redaction covers literal values only — it cannot stop a deliberate transformation of the secret — so treat it as a safety net, not the access control.

The access control is the scope ACL. Each secret scope carries per-principal permissions at three levels: READ, WRITE, and MANAGE. READ permits reading the secret values and listing the keys in the scope; WRITE adds creating and deleting secrets; MANAGE adds managing the scope's own permissions (Secret management[7]). A principal needs at least READ on the scope before dbutils.secrets.get returns anything. Because ACLs are set at the scope level, align a scope to a role or application and grant READ to the group that runs that workload.

Machine identity and Azure storage access

Two different non-human identities appear when a pipeline runs, and confusing them is a classic exam trap: the identity the job runs as is not the identity that reaches the storage account.

The job runs as a service principal — an identity created for tools, jobs, and CI/CD rather than a person. A service principal is granted Unity Catalog privileges exactly like a user, so an automated pipeline can authenticate and read data without depending on any individual's account (Service principals[8]). Configuring a Lakeflow Job to run as a service principal decouples it from its author: the job keeps working when that person leaves or loses access, and it can touch only the data the service principal itself has been granted. Service principals authenticate non-interactively with OAuth machine-to-machine (M2M) tokens — the principal presents its client ID (its application ID) and an OAuth secret and receives a short-lived access token, valid for one hour, that tools use on its behalf (OAuth machine-to-machine authorization[9]). Databricks recommends OAuth M2M over long-lived personal access tokens for automation.

Reaching the storage account is a separate mechanism. Unity Catalog governs cloud storage through two securables built on an Azure managed identity. First, an Access Connector for Azure Databricks is a first-party Azure resource carrying a system-assigned or user-assigned managed identity; you grant that identity a storage role such as Storage Blob Data Contributor on the ADLS Gen2 account, letting Databricks reach the storage with no keys stored anywhere (Connect to an ADLS Gen2 external location[10]). Second, you register that managed identity in Unity Catalog as a storage credential, and an external location then references the storage credential to govern reads and writes to a specific container path (an abfss:// URL). Managed identities are recommended over embedding storage account keys or SAS tokens precisely because Azure manages the credential and it never appears in notebook code or cluster configuration.

Now the trap, stated plainly: the managed identity authenticates the workspace to the underlying storage resource, while a service principal is a principal whose Unity Catalog privileges govern who may read the data. They are not interchangeable. A production pipeline usually uses both — it runs as a service principal that has SELECT on a table, and that table's files sit under an external location whose storage credential wraps an Access Connector managed identity. The figure traces that storage chain from the managed identity to the container path.

Access Connectormanaged identity+ Blob Data roleStorage credentialwraps the identityExternal locationgoverns a pathADLS Gen2abfss containerregistered asreferenced byreads / writes
An Access Connector managed identity, registered as a storage credential, is referenced by an external location to reach ADLS Gen2. Source: Azure Databricks docs.

Exam-pattern recognition

Most questions on securing Unity Catalog objects turn on one distinction. Read the stem for the signal, then pick the answer that honors the stated constraint.

  • A SELECT grant exists but the query still fails with a permission error: the principal is missing USE CATALOG or USE SCHEMA on the parents. All three grants are required to read a table.
  • Give one group read access to every table in a catalog, including future ones: grant at the catalog level and let inheritance carry it down, rather than enumerating tables.
  • A privileged user must not be able to drop or re-grant a table: give them SELECT (or MODIFY), not ownership or MANAGE. A SELECT/MODIFY holder can read or write but cannot DROP or re-grant the table; MANAGE and ownership both can, which is exactly why you withhold them here.
  • Hide a column from most users but not from auditors: a column mask (reused across tables) or a dynamic view with CASE and is_account_group_member(); never a partial-column grant, which does not exist.
  • Show each regional manager only their own rows: a row filter, or a dynamic view with a WHERE predicate on the caller's identity; a mapping table when entitlements change often.
  • Apply the same masking rule automatically across many tables: an ABAC policy driven by a governed tag, not a separate per-table mask on each one.
  • The secret must be rotated in Azure, not Databricks: an Azure Key Vault-backed secret scope, which is read-only from Databricks.
  • Keep a scheduled job working after its author leaves: run the Lakeflow Job as a service principal that authenticates with OAuth M2M.
  • Let Databricks read ADLS Gen2 with no keys in code: an Access Connector managed identity, registered as a storage credential and referenced by an external location.
  • Managed identity versus service principal: the managed identity authenticates the storage resource; the service principal's Unity Catalog privileges govern data access.

Access-control granularity: the object grant and the four fine-grained layers

MechanismWhat it scopesHow it is enforcedChoose when
Object GRANT (SELECT / MODIFY)The whole table or view, every columnUSE CATALOG + USE SCHEMA + the privilege on the securableWhole-object access is the right granularity
Dynamic viewColumns and/or rows, per callerCASE / WHERE calling is_account_group_member() or current_user()One-off redaction; grant the view, withhold the base table
Column maskOne column's values, via a reusable UDFA SQL UDF bound with ALTER TABLE ... SET MASKThe same masking logic must apply across many tables
Row filterWhich rows the query returnsA boolean SQL UDF bound with ALTER TABLE ... SET ROW FILTERRow-level filtering that travels with the table itself
ABAC policyColumns or rows matched by a governed tagA policy attached at catalog or schema level, applied by tagConsistent rules across many tables, applied automatically

Decision tree

Whole table enough?Object GRANTSELECT + USE privilegesRows or columns?Same rule, many tables?Reuse across tables?ABAC row-filter policygoverned tag, auto-appliedRow filterSET ROW FILTER / view WHEREColumn maskSET MASK / ABAC policyDynamic viewCASE, per groupyesnorowscolumnsyesnoyesno

Sharp facts the exam loves — give these one last read before exam day.

Cheat sheet

Sharp facts the exam loves — scan these before test day.

GRANT assigns a privilege on a securable to a user, group, or service principal

Access to a Unity Catalog securable is granted with GRANT ON TO , where the principal can be a user, an account group, or a service principal, and REVOKE removes it; common privileges include SELECT, MODIFY, and CREATE.

Trap A principal is not limited to individual users; groups and service principals are equally valid grant targets and groups are preferred for manageability.

8 questions test this
Reading a table also requires USE CATALOG and USE SCHEMA on its parents

To query a table a principal needs SELECT on the table plus USE CATALOG on its catalog and USE SCHEMA on its schema; the USE privileges grant traversal of the three-level namespace but do not by themselves expose any data.

Trap SELECT on the table alone is insufficient; without USE CATALOG and USE SCHEMA on the parents the query fails with a permission error.

15 questions test this
A privilege granted on a catalog or schema is inherited by its child objects

Unity Catalog privileges are inherited down the object hierarchy, so a privilege granted on a catalog applies to all of its current and future schemas and tables, and a grant on a schema applies to its tables, views, and volumes.

7 questions test this
Object owners and MANAGE control who can grant on a securable

In Unity Catalog the owner of a securable (a user, group, or service principal) implicitly holds all privileges on it and is the principal who can GRANT/REVOKE, ALTER, and DROP it; granting the MANAGE privilege lets a non-owner administer the object, including granting and revoking privileges and even dropping or transferring it, without being the owner, and ownership can be reassigned with ALTER OWNER TO.

Trap Holding SELECT is not enough to administer an object - only the owner or a MANAGE holder can grant, drop, or transfer it, and MANAGE differs from ownership only in that it is not automatically given the object's data privileges (it must self-grant SELECT).

UC principals are account-level identities federated from Microsoft Entra ID

Users, groups, and service principals in Unity Catalog are account-level identities, typically provisioned from Microsoft Entra ID via SCIM; account groups must be assigned to a workspace through identity federation before they can be granted privileges there.

Trap Groups are managed at the account level, not per-workspace - grants target account-level principals federated to the workspace, not a workspace-local group.

Object-level grants cover every column; column limits need a view, mask, or ABAC

A SELECT grant applies to the entire table securable and cannot be scoped to individual columns, so column-level access control is achieved by layering a view that exposes only permitted columns, a column mask, or an ABAC policy on top of the base grant.

Trap Granting SELECT on only the non-sensitive columns is not a Unity Catalog capability; it would break SELECT * with a permission error rather than hide values.

16 questions test this
A dynamic view redacts columns per group with is_account_group_member in CASE

A dynamic view wraps a base table and uses CASE expressions calling is_account_group_member() so that members of an authorized group receive the real column value while all other callers receive NULL or a redacted literal.

16 questions test this
Grant the secure view and withhold the base table so users query only the view

For view-based access control you grant SELECT on the dynamic or restricted view and do not grant access to the underlying base table, forcing every principal through the view where the column and row rules are enforced.

A dynamic view enforces row-level security with a caller-identity WHERE predicate

Row-level security through a dynamic view adds a WHERE predicate built from current_user() or is_account_group_member(), returning only the rows whose values match the querying principal, such as their own region or business unit.

23 questions test this
Data-driven row-level security joins to an entitlement mapping table

A scalable row-level-security pattern joins the base table to a mapping table that records which principal or group may see which key values, so entitlement changes are made by editing data rather than by rewriting the view definition.

An Azure Key Vault-backed secret scope exposes Key Vault secrets read-only

An Azure Key Vault-backed secret scope maps a Databricks secret scope onto an Azure Key Vault so notebooks can read its secrets; it is a read-only interface, meaning the secret values are created, updated, and rotated in Azure rather than in Databricks.

Trap A Key Vault-backed scope cannot be written from Databricks; secrets must be added and rotated in the Azure Key Vault itself.

13 questions test this
dbutils.secrets.get reads a secret and Databricks redacts it from output

Code retrieves a secret with dbutils.secrets.get(scope, key) instead of hardcoding credentials, and Databricks automatically replaces any printed secret value with [REDACTED] so it cannot leak into notebook cell output or logs.

13 questions test this
Secret access is governed by READ, WRITE, and MANAGE scope ACLs

Secret scope access control assigns per-scope ACLs at the READ, WRITE, and MANAGE levels, and a principal needs at least READ on the scope, which permits reading secret values and listing keys, before dbutils.secrets.get will succeed.

A service principal is a non-human identity for automated data workloads

A service principal is an identity created for tools, jobs, and CI/CD rather than a person, and it is granted Unity Catalog privileges like any principal so automated pipelines can authenticate and access data without depending on an individual user's account.

22 questions test this
Running a job as a service principal decouples it from a user account

Configuring a Lakeflow Job or pipeline to run as a service principal keeps it working when the original author leaves or loses access, and confines the job's data access to exactly the Unity Catalog privileges granted to that service principal.

16 questions test this
Service principals authenticate with OAuth machine-to-machine tokens

A service principal authenticates non-interactively using OAuth machine-to-machine (M2M) tokens minted from its client ID and secret, which are the recommended automation credential in place of long-lived personal access tokens.

An Access Connector managed identity authenticates the workspace to Azure storage

Resource access to ADLS Gen2 uses an Access Connector for Azure Databricks, a first-party Azure resource whose system- or user-assigned managed identity is granted a storage role such as Storage Blob Data Contributor, letting Databricks reach the storage account with no stored keys.

Trap A managed identity authenticates the underlying storage resource; a service principal instead represents a principal whose Unity Catalog privileges govern data access, not the storage connection.

20 questions test this
A storage credential wraps the managed identity for an external location to use

In Unity Catalog the Access Connector's managed identity is registered as a storage credential, and an external location then references that credential to govern reads and writes to a specific ADLS Gen2 container path.

15 questions test this
Managed identities are preferred over storage account keys or SAS tokens

Authenticating storage access through an Access Connector managed identity is recommended over embedding storage account keys or SAS tokens, because the credential is managed by Azure and is never exposed in notebook code or cluster configuration.

Also tested in

References

  1. Manage privileges in Unity Catalog
  2. Unity Catalog permissions model concepts
  3. Manage users, service principals, and groups
  4. Create a dynamic view
  5. Row filters and column masks
  6. Attribute-based access control in Unity Catalog
  7. Secret management
  8. Service principals
  9. Authorize service principal access to Azure Databricks with OAuth
  10. Connect to an Azure Data Lake Storage Gen2 (ADLS Gen2) external location