catalog = spark.sql("SELECT current_catalog()").first()[0]
spark.sql(f"USE SCHEMA {catalog}.dbx_course")
spark.sql("CREATE OR REPLACE TABLE customers_sec AS SELECT * FROM customers")
Module 17: Security & Enterprise Governance
Identity, secrets, network security and enterprise governance.
Topics in this module
- Identity and Access Management
- OAuth and Service Principals
- Secrets Management
- Network Security and Private Connectivity
- Workspace Isolation
- Data Encryption
- Fine-Grained Access Control
- Data Masking and Sensitive Data
- Data Retention and GDPR
- Cross-Workspace Data Sharing
- Enterprise Governance Architecture
- Security Auditing
Control who can do what, protect sensitive data, and prove it. Free Edition has no account console, SSO, SCIM or network settings, so about half of this module is concept. The data-level parts (grants, masking, GDPR deletes, auditing) you can run.
- Practice tables:
customers,orders(Module 4). Setup:
- The three layers of security: identity (who), access (what they may do), data and network (how it's protected)
Identity and Access Management
By the end: explain how identities and access fit together.
| Identity | Use |
|---|---|
| User | A person: signs in with SSO |
| Group | A set of users or service principals: grant to groups |
| Service principal | An identity for jobs and automation |
| Control | Where |
|---|---|
| Authentication | SSO and MFA through your identity provider |
| Provisioning | SCIM syncs users and groups from the provider |
| Data permissions | Unity Catalog GRANTs (Module 6) |
| Object permissions | ACLs on jobs, notebooks, warehouses, secrets |
%sql
SELECT current_user() AS me,
is_account_group_member('users') AS in_users_group,
is_member('admins') AS is_workspace_admin
- Manage identities at the account level, from your identity provider. Avoid ad-hoc workspace users
- Least privilege: the smallest grant that lets the work happen
- Owners of production objects should be groups
Free Edition
One user, no SSO or SCIM. You can still practise grants with account users (Module 6).
OAuth and Service Principals
By the end: use OAuth and service principals for automation.
- A service principal has its own identity, so production jobs don't depend on a person who may leave
- Run production jobs as a service principal (
run_asin a job or bundle) - Give it only the privileges the pipeline needs:
USE CATALOG,USE SCHEMA,SELECTorMODIFYon specific schemas - Only service principal users can run a job as it. Managers don't get this automatically
- Prefer OAuth to personal access tokens: short-lived and revocable. In CI use OIDC (workload identity federation) where supported
- Rotate secrets and tokens, and set expiry
| Never | Because |
|---|---|
| Share a person's token in CI | It dies when they leave, and it has all their access |
| Give a service principal admin rights | One leaked secret = full access |
Free Edition
No account console, so you can't create service principals. Read this one as reference.
Secrets Management
By the end: store and use a secret without exposing it.
Concept: a secret scope holds secrets. Code reads them with dbutils.secrets.get. Output shows [REDACTED].
# try this from a notebook: create a scope and a secret with the SDK
from databricks.sdk import WorkspaceClient
w = WorkspaceClient()
w.secrets.create_scope(scope="course_scope")
w.secrets.put_secret(scope="course_scope", key="demo_key", string_value="not-a-real-secret")
value = dbutils.secrets.get(scope="course_scope", key="demo_key")
print(value) # [REDACTED]
print(len(value)) # 17: the value is usable, just hidden in output
| Step | CLI |
|---|---|
| Create scope | databricks secrets create-scope <scope> |
| Add secret | databricks secrets put-secret <scope> <key> |
| Give access | databricks secrets put-acl <scope> <principal> READ |
| List | databricks secrets list-secrets <scope> |
- Only the literal value is redacted: if you transform it (
value[::-1]), it prints in clear - Scope names are case-insensitive. Create scopes per application or role, not per person
- Anyone with
READcan use the value in code. Workspace admins and the scope creator can read it too - Keep secrets out of widgets, parameters, logs, and tables
- For cloud access prefer Unity Catalog credentials over keys in a secret
Free Edition
The SDK call may be refused. If so, read the topic as reference. Remove the practice scope after: w.secrets.delete_scope(scope="course_scope").
Network Security and Private Connectivity
By the end: understand the network controls around Databricks.
| Control | Protects against |
|---|---|
| IP access lists | Sign-ins from unknown networks |
| Private connectivity (PrivateLink) | Traffic over the public internet |
| Customer-managed VPC | Classic compute inside your own network rules |
| Serverless egress control (network policies) | Data exfiltration: jobs sending data to unapproved destinations |
| Firewall rules with stable IPs | Your systems accept only Databricks' addresses |
- Serverless and classic use different mechanisms: classic is in your VPC, serverless is governed by network policies
- Private connectivity to your own databases and APIs from serverless uses private endpoint rules
- Networking features are admin, account-level settings
- Free Edition already restricts outbound traffic to trusted domains (Module 2): a small taste of egress control
Workspace Isolation
By the end: isolate environments and teams with workspaces and catalogs.
| Boundary | Tool |
|---|---|
| Data | Catalogs (the primary isolation boundary), schemas, grants |
| Compute | Workspaces, compute policies |
| Access to a catalog | Workspace-catalog binding: a catalog is visible only in chosen workspaces |
| Storage | Managed storage location per catalog |
| Admin | Separate account groups per environment |
- Typical:
dev,test,prodcatalogs. Prod is bound to the prod workspace, and only service principals can write - One metastore per region. Sharing across regions uses sharing, not a shared metastore
- Don't reuse DBFS buckets as metastore storage
Catalogs are the main wall
Put environments, and sensitive domains such as HR or finance, in their own catalogs. Then permissions and binding stay simple.
Data Encryption
By the end: know how data is encrypted and who holds the keys.
| Where | How |
|---|---|
| At rest: cloud storage | Encrypted by the cloud provider by default |
| At rest: managed services (notebooks, secrets, queries) | Can use customer-managed keys |
| In transit: users and APIs | TLS |
| In transit: between cluster workers (classic) | Optional encryption setting |
| Secrets | Stored encrypted and redacted in output |
- Customer-managed keys let you control and revoke the key: an account-level setting
- Encryption doesn't replace access control: authorised users read plain data
- Column-level protection (masking, hashing) covers what disk encryption can't (topic 8)
- Compliance profiles (for example for regulated industries) are workspace-level choices made at creation
Free Edition
Encryption is handled by the platform. Customer-managed keys and compliance profiles are not configurable.
Fine-Grained Access Control
By the end: restrict rows and columns with views, row filters and attributes.
1. A view that exposes only some columns:
%sql
CREATE OR REPLACE VIEW customers_public AS
SELECT customer_id, country, signup_date FROM customers_sec;
SELECT * FROM customers_public LIMIT 3
2. A row filter (recap of Module 6.5):
%sql
CREATE OR REPLACE FUNCTION nl_only(country STRING) RETURNS BOOLEAN
RETURN is_account_group_member('admins') OR country = 'NL';
ALTER TABLE customers_sec SET ROW FILTER nl_only ON (country)
%sql
ALTER TABLE customers_sec DROP ROW FILTER
| Technique | Restricts | Applies to |
|---|---|---|
| GRANT / REVOKE | Whole objects | Tables, views, schemas, catalogs |
| View | Columns and rows, fixed | Anyone with access to the view |
| Row filter | Rows | Based on who is asking |
| Column mask | Values in a column | Based on who is asking |
| ABAC policies | Rows, columns, privileges | By governed tag, many tables at once |
- ABAC (attribute-based access control) attaches policies to a catalog or schema and applies them to every object carrying a governed tag, such as
pii. One policy covers many tables - Filters and masks live with the table: every tool sees the same result
- Test as a different user or group, not only as yourself
ABAC
Policy syntax isn't covered here. Use the current Unity Catalog ABAC documentation. Parts of it are in Beta.
Data Masking and Sensitive Data
By the end: mask and protect sensitive data.
%sql
CREATE OR REPLACE VIEW customers_masked_view AS
SELECT customer_id,
CASE WHEN is_account_group_member('pii_readers') THEN name
ELSE concat(left(name, 1), '*****') END AS name,
sha2(cast(customer_id AS STRING), 256) AS customer_hash,
country
FROM customers_sec;
SELECT * FROM customers_masked_view LIMIT 3
| Method | Result | Reversible? |
|---|---|---|
| Redact / partial mask | J***** |
No |
Hash (sha2) |
Stable pseudonym, good for joins | Not directly: guessable for small value sets |
| Tokenise | Token replaces the value, lookup table kept apart | Yes, with access to the vault |
| Encrypt column | Ciphertext | Yes, with the key |
| Drop the column | Gone | No |
- Classify first: tag columns that are personal or sensitive (
ALTER TABLE ... ALTER COLUMN ... SET TAGS ('pii' = 'true')) - Prefer column masks (Module 6.4) over many one-off views: the rule lives with the column
- Hash with a secret salt so values can't be looked up from a table of guesses
- Don't copy raw personal data into dev: use masked or synthetic data (Module 14.4)
- Mask in the serving layer, keep raw data in restricted bronze/silver
A hash is not anonymous
sha2 of a phone number or national id can be reversed by trying all values.
Data Retention and GDPR
By the end: delete personal data for real, and set retention.
%sql
-- 1. delete the person's rows
DELETE FROM customers_sec WHERE customer_id IN (1, 2)
%sql
-- 2. physically remove the data files that held them (needed when deletion vectors are on)
REORG TABLE customers_sec APPLY (PURGE)
%sql
-- 3. remove old files that are no longer referenced (default retention: 7 days)
VACUUM customers_sec DRY RUN
| Retention knob | Sets |
|---|---|
VACUUM retention (default 7 days) |
How long time travel can read deleted data |
delta.logRetentionDuration |
How long table history is kept |
delta.deletedFileRetentionDuration |
How long removed files are kept |
| Source system retention | Kafka, landing files, other databases: delete there too |
- Delete in bronze first, then propagate to silver and gold. Rebuild or refresh materialized views
- Streaming tables from Delta sources: add
skipChangeCommitsto the streaming read, or use the change data feed - Keep a control table of requests and what was done: auditable
- Full deletion is safer than pseudonymising: reidentification risk remains otherwise
- Predictive optimization on managed tables runs
VACUUMfor you
Time travel
After VACUUM, older versions can't be restored. That is the point, and the cost, of a real delete.
Cross-Workspace Data Sharing
By the end: share data across workspaces and organisations.
- Delta Sharing / OpenSharing: you create a share (tables, views, filtered data, notebooks, models), a recipient, and grant access
- Recipients read live data without you copying it
- Lineage and access control don't cross metastore boundaries: recipients apply their own
- Use a view or filter to share only the right rows and columns
- Rule of thumb: inside your metastore use grants. To another region, cloud or company use sharing
- You can revoke a recipient's access at any time
Free Edition
Sharing availability isn't confirmed. This is reference only.
Enterprise Governance Architecture
By the end: sketch an enterprise governance architecture.
| Principle | Practice |
|---|---|
| Single source of identity | Provision from the identity provider |
| Group-based access | Never grant to individuals |
| Production by automation | Service principals write, humans read |
| Classify and tag | Governed tags drive policy |
| Central visibility | Audit logs, lineage, system tables |
| Discoverability | BROWSE for everyone, data access by request |
- Name owners for each catalog and schema (a group), and a data steward per domain
- Change governance through code (Terraform, bundles), reviewed like any change
- Review access regularly: remove what isn't used
Security Auditing
By the end: audit access and changes.
%sql
-- who can do what on a table
SHOW GRANTS ON TABLE customers_sec
%sql
-- every change to a table: who, when, which operation
DESCRIBE HISTORY customers_sec
%sql
-- account-wide audit events (system tables: account-level, may not exist on Free Edition)
SELECT event_time, user_identity.email, service_name, action_name
FROM system.access.audit
WHERE event_date >= current_date() - INTERVAL 7 DAYS
ORDER BY event_time DESC LIMIT 20
| Question | Tool |
|---|---|
| Who has access? | SHOW GRANTS, information_schema privilege views |
| What changed on this table? | DESCRIBE HISTORY |
| Who did what across the account? | system.access.audit |
| Where did this data come from or go? | Lineage |
| Who ran which query? | Query history |
- Filter audit queries on
event_date - Alert on sensitive actions: new grants to broad groups, changes to row filters and masks, token creation
- Keep audit data longer than operational data if compliance needs it
- Review should be routine, not only after an incident
Audit what you grant
A quarterly review of who can read the most sensitive tables is cheap and catches most drift.
What you can do now
- Identities, groups, service principals and OAuth
- Secrets, network controls, isolation and encryption
- Fine-grained access, masking and ABAC
- GDPR deletes and retention
- Sharing, governance architecture and auditing