ABAC With Governed Tags: Tag at Schema, Not Table

Estimated read: 3 min

The privilege migration matrix and the tag compression you just finished still leave one open question: where do you attach the policy? A traditional Unity Catalog row filter or column mask (from the security layer cake two sections back) is bound directly to one table – fine for a handful of objects, but you’re back to per-object sprawl the moment a schema has 200 tables and a new PII column shows up in table 201 with no mask attached. Attribute-Based Access Control (ABAC) solves this by making the policy reference a tag condition instead of an object name: write the rule once, against pii = true, and every current and future object carrying that tag is covered automatically.

Governed tags are the attribute half of ABAC – key-value pairs (pii=true, domain=finance, tier=restricted) defined once at the account level and applied to catalogs, schemas, tables, or columns. Two things make them “governed” rather than just decorative metadata: the taxonomy of allowed keys and values is centrally controlled (so nobody invents a fifth spelling of pii), and Unity Catalog exposes has_tag() and has_tag_value() functions that ABAC policies evaluate at query time to decide whether a rule applies to the object being read.

The lecture title’s rule of thumb – tag at schema, not table – comes from how inheritance works. Tags applied to a catalog or schema flow down to every table and view inside it automatically; a table only needs its own tag when it genuinely diverges from its schema’s default (a pii=false exception inside an otherwise sensitive schema, for instance). Columns are the one exception: because a table can mix public and sensitive columns, column-level tags always have to be applied directly rather than inherited. Tagging every table individually just to reproduce what the parent schema would have given you for free is the same anti-pattern as the per-table grant sprawl this whole part has been collapsing.

-- Tag once at the schema -- every table underneath inherits it
ALTER SCHEMA finance.accounts_receivable SET TAGS ('domain' = 'finance', 'tier' = 'restricted');

-- Column tags still need to be explicit, since sensitivity varies column by column
ALTER TABLE finance.accounts_receivable.customers
  ALTER COLUMN ssn SET TAGS ('pii' = 'true');

An ABAC row filter or column mask policy then references the tag, not the object:

CREATE POLICY restrict_pii_columns
ON SCHEMA finance.accounts_receivable
COLUMN MASK finance.governance.mask_pii
TO `account groups:analysts`
FOR TABLES
MATCH COLUMNS has_tag_value('pii', 'true') AS pii_col
ON COLUMN pii_col;

Because tags are the trigger for policy enforcement, tagging is itself a security boundary: whoever can add or remove a governed tag can effectively turn a masking or row-filter policy on or off for that object. Restrict tag-management privileges as tightly as you restrict the policies themselves – a wide-open tagging permission quietly defeats an otherwise well-designed ABAC rollout.

This is a genuine step up from the ad hoc “tag-checking IS_ACCOUNT_GROUP_MEMBER function” pattern from the privilege migration lecture: that approach still required someone to remember to attach the masking function to each new table. ABAC policies are declarative and schema-scoped, so a new table landing in a tagged schema inherits governance the moment it’s created, with zero migration follow-up. See the ABAC overview and core concepts documentation for the full policy and tag-inheritance model.


| ← Previous: ABAC, Masking, and Cross-Engine Governance | Next: Dynamic Views and Row-Level Security → | |:—|—:|


Back to top

Independent, self-authored Databricks companion notes.

This site uses Just the Docs, a documentation theme for Jekyll.