catalog = spark.sql("SELECT current_catalog()").first()[0]
spark.sql(f"USE SCHEMA {catalog}.dbx_course")
print(catalog)
Module 6: Unity Catalog & Data Governance
Catalogs, schemas, volumes, privileges, lineage and sharing with Unity Catalog.
Topics in this module
- Unity Catalog Architecture
- Metastore, Catalog, Schema, and Table
- Managed vs External Storage
- Storage Credentials and External Locations
- Volumes
- Users, Groups, and Service Principals
- Privileges and Access Control
- Row Filters and Column Masks
- Data Lineage
- Data Discovery and Classification
- Auditing and Monitoring
- Delta Sharing
- Lakehouse Federation
- Governance Across Workspaces
Unity Catalog (UC) governs data and AI assets across workspaces: access control, lineage, auditing, discovery.
- Everything you built so far already lives in UC:
catalog.dbx_course.orders - Hands-on where Free Edition allows it. Account-level topics are explanation only (no account console, one workspace, one metastore)
- Setup cell for the examples:
On Free Edition
You are the only user. Granting and masking still work on your own objects, so you can practise the syntax. You can't invite users or create account-level groups.
Unity Catalog Architecture
By the end: draw the Unity Catalog object model and say which objects sit above and below the catalog.
- Securable object: anything you can grant privileges on
- Metastore-level objects: storage credentials, external locations, connections, shares
- UC works across workspaces: one place for permissions, lineage and audit
- Enabled automatically for workspaces created after November 8, 2023
%sql
SHOW CATALOGS
display(spark.sql("SELECT current_metastore() AS metastore"))
Remember
Govern once in UC. Every workspace, notebook, job and SQL warehouse then follows the same rules.
Metastore, Catalog, Schema, and Table
By the end: create catalogs, schemas and tables and find them with SHOW commands and the information schema.
%sql
SHOW SCHEMAS
%sql
SHOW TABLES IN dbx_course
display(spark.sql(f"""
SELECT table_name, table_type, data_source_format
FROM {catalog}.information_schema.tables
WHERE table_schema = 'dbx_course'
"""))
information_schemaexists in every catalog:tables,columns,schemata,volumes, privileges- Create a schema for experiments:
%sql
CREATE SCHEMA IF NOT EXISTS sandbox COMMENT 'Throwaway experiments'
| Level | Create with | Note |
|---|---|---|
| Catalog | CREATE CATALOG |
May need privileges Free Edition doesn't give you |
| Schema | CREATE SCHEMA |
Needs CREATE SCHEMA on the catalog |
| Table | CREATE TABLE |
Needs USE SCHEMA + CREATE TABLE |
Naming
Catalog per environment or domain (dev, prod), schema per layer or subject (bronze, silver, sales). Always use full three-level names in jobs.
Managed vs External Storage
By the end: explain who owns the files of a managed object and what changes for an external one.
- Managed storage can be set per metastore, catalog or schema. Objects use the closest one
- Managed tables are the default and recommended type
- External tables and volumes: UC governs access, you manage the files and their lifecycle
- Pick external only when other tools must write the same files, or the data must stay where it is
Storage Credentials and External Locations
By the end: explain how storage credentials and external locations let UC reach cloud storage.
- Storage credential: the cloud identity (IAM role, managed identity, service account) UC uses
- External location: a path plus the credential that opens it
- Privileges:
CREATE EXTERNAL TABLE,READ FILES,WRITE FILESon the location - Paths of external locations can't overlap in confusing ways: plan the layout up front
On Free Edition
Custom storage locations aren't supported, so this is explanation only. Use managed tables and volumes.
Volumes
By the end: create managed volumes, set volume privileges and use them from Spark and Python.
%sql
CREATE VOLUME IF NOT EXISTS sandbox.files
path = f"/Volumes/{catalog}/sandbox/files"
with open(f"{path}/note.txt", "w") as f:
f.write("hello volume\n")
print(open(f"{path}/note.txt").read())
display(dbutils.fs.ls(path))
- Path:
/Volumes/<catalog>/<schema>/<volume>/.... Works with Spark,dbutils.fs,osandopen - Privileges:
READ VOLUME,WRITE VOLUME - Managed volume: UC owns the storage. External volume: points at a location you registered
- Use volumes for files (CSV, JSON, images, wheels, checkpoints). Use tables for tabular data
%sql
DESCRIBE VOLUME sandbox.files
Don't use the DBFS root
It's legacy and may be disabled. Volumes are governed, permissioned and the supported place for files.
Users, Groups, and Service Principals
By the end: tell users, groups and service principals apart and say who should own what.
- Grant to groups, not individuals. People join and leave groups
- Run production as a service principal, so jobs don't depend on one person's account
- Identities are managed at the account level and assigned to workspaces
- Built-in groups:
account users(everyone),admins(workspace admins)
On Free Edition
One workspace, one user, no account console, no SSO or SCIM. Explanation only.
Privileges and Access Control
By the end: grant, check and revoke privileges and explain how inheritance works.
%sql
SHOW GRANTS ON SCHEMA dbx_course
%sql
GRANT USE SCHEMA, SELECT ON SCHEMA dbx_course TO `account users`
%sql
REVOKE SELECT ON SCHEMA dbx_course FROM `account users`
| Privilege | Allows |
|---|---|
USE CATALOG, USE SCHEMA |
See and reach the container |
SELECT |
Read a table or view |
MODIFY |
Insert, update, delete, merge |
CREATE TABLE |
Create tables in a schema |
EXECUTE |
Run a function or use a model |
READ VOLUME, WRITE VOLUME |
Read or write files in a volume |
MANAGE |
Manage grants on the object |
- Every object has an owner with all privileges. Transfer:
ALTER TABLE t OWNER TO ... REVOKEsucceeds even if the privilege wasn't granted
On Free Edition
You are the only user, so these changes have no visible effect. The point is the syntax. Revoke what you grant.
Least privilege
Grant USE CATALOG + USE SCHEMA + SELECT to a group for read access. Give MODIFY and CREATE TABLE only to pipelines.
Row Filters and Column Masks
By the end: hide rows and mask columns with row filters and column masks.
Column mask (hide customer names from everyone except a group):
%sql
CREATE OR REPLACE TABLE customers_masked AS SELECT * FROM customers
%sql
CREATE OR REPLACE FUNCTION mask_name(name STRING)
RETURNS STRING
RETURN CASE WHEN is_account_group_member('pii_readers') THEN name ELSE '***' END
%sql
ALTER TABLE customers_masked ALTER COLUMN name SET MASK mask_name
%sql
SELECT customer_id, name, country FROM customers_masked LIMIT 3
- You're not in
pii_readers, sonameshows***
Row filter (only show Dutch customers to everyone not in a group):
%sql
CREATE OR REPLACE FUNCTION nl_only(country STRING)
RETURNS BOOLEAN
RETURN country = 'NL' OR is_account_group_member('all_countries')
%sql
ALTER TABLE customers_masked SET ROW FILTER nl_only ON (country)
Remove both:
%sql
ALTER TABLE customers_masked DROP ROW FILTER
%sql
ALTER TABLE customers_masked ALTER COLUMN name DROP MASK
Limits
Not on views. No time travel, deep or shallow clones, or Delta Lake APIs on a table with a filter or mask. Keep ANSI mode on so bad casts raise errors instead of becoming NULL. For many tables use ABAC policies.
Data Lineage
By the end: find where a table's data comes from and goes to using lineage.
- UC records lineage from queries run on UC-enabled compute: tables, views, columns, notebooks, jobs, pipelines
- See it in Catalog Explorer: open a table, then the Lineage tab
- Try: create a derived table and look at its lineage
spark.sql("""
CREATE OR REPLACE TABLE revenue_by_category AS
SELECT p.category, SUM(o.quantity * p.unit_price) AS revenue
FROM orders o JOIN products p USING (product_id)
GROUP BY p.category
""")
- Lineage can take a few minutes to appear
- Uses: impact analysis before a change, debugging a bad number, compliance questions
- Queryable through system tables and the lineage API where enabled
On Free Edition
I couldn't confirm which lineage and system-table features your workspace exposes. Check the Lineage tab. Skip what's missing.
Data Discovery and Classification
By the end: document and tag data so people can find it, and know what automatic classification does.
%sql
COMMENT ON TABLE orders IS 'One row per order. Orders can include duplicates in the raw layer.'
%sql
ALTER TABLE customers SET TAGS ('domain' = 'sales', 'contains_pii' = 'true')
%sql
ALTER TABLE customers ALTER COLUMN name SET TAGS ('pii' = 'name')
display(spark.sql(f"""
SELECT * FROM {catalog}.information_schema.table_tags
WHERE schema_name = 'dbx_course'
"""))
- Find assets with the search bar and Catalog Explorer filters (owner, tag, type)
- Comments (table and column) feed search and AI-generated descriptions
- Tags drive policies: classify once, apply masks and access rules by tag
- Automatic data classification can detect sensitive data types and tag them. Availability depends on your workspace
Habit
Every table gets a comment, an owner and a domain tag. Every PII column gets a tag.
Auditing and Monitoring
By the end: explain how auditing and system tables show who accessed what.
- System tables live in the
systemcatalog:system.access.audit, lineage tables, billing usage, query history - A metastore admin enables each schema of system tables
- Typical questions: who read the customer table, who changed a grant, which jobs touch this data
- Retention and availability vary by system table: check the docs
SELECT event_time, user_identity.email, action_name
FROM system.access.audit
WHERE event_date >= current_date() - 7
ORDER BY event_time DESC
LIMIT 20
On Free Edition
I couldn't confirm system tables are available. The query above is for a full workspace.
Delta Sharing
By the end: explain how Delta Sharing shares data with other organisations or platforms without copying it.
- Open protocol: recipients may be on Databricks (Databricks-to-Databricks) or not (pandas, Spark, Power BI, ...)
- Provider side:
CREATE SHARE,ALTER SHARE ... ADD TABLE,CREATE RECIPIENT,GRANT SELECT ON SHARE - Recipient side: mount the share as a catalog
- Control access like any UC object. Audit who reads what
On Free Edition
Explanation only: I couldn't confirm sharing is available.
Lakehouse Federation
By the end: explain how Lakehouse Federation queries external databases through UC.
- Sources include PostgreSQL, MySQL, SQL Server, Snowflake, BigQuery and others
- Queries run in place: no ingestion, no copy
- Fine for exploration and small lookups. For heavy or repeated use, ingest into Delta (Module 7)
- Governance (grants, lineage, audit) applies to foreign catalogs too
On Free Edition
Outbound internet is limited to trusted domains, so reaching your own database isn't possible. Explanation only.
Governance Across Workspaces
By the end: explain how one metastore governs many workspaces and how to separate environments.
- One metastore per cloud region is the usual design. All workspaces in the region attach to it
- Same users, groups and grants everywhere. Bind a catalog to the workspaces that may use it
- Common layouts: catalog per environment (
dev,prod), or per domain - Share across regions or clouds with Delta Sharing
Environments
Separate dev and prod by catalog (and bind prod to the prod workspace). Code stays identical: only the catalog name changes (Module 26).
What you can do now
- UC object model, three-level names, managed vs external
- Volumes for files,
information_schemato explore - Grant to groups, run automation as service principals
- Row filters, column masks, comments and tags
- Lineage, audit, sharing, federation and multi-workspace design