The ABAC Tag Taxonomy and Masking Policy Pack
Estimated read: 3 min
Everything in this section – schema-level tagging, row filters, tag-triggered masking, credential-vended cross-engine access – depends on one thing existing before any of it is built: an agreed, governed tag taxonomy. Skip that step and teams tag ad hoc, which recreates the exact problem the “500 roles to 12 tags” lecture solved for groups, except now for tags: pii=true, PII=Y, sensitive=pii, and contains_pii=1 all mean the same thing to a human and nothing to a policy engine that matches on exact key-value pairs.
A workable starter taxonomy for a legacy migration is small on purpose – three or four keys, each with a short, closed list of values:
| Tag key | Purpose | Example values |
|---|---|---|
domain |
Business area, drives group-based grants | finance, sales, hr, supply_chain |
pii |
Triggers column masking | true, false |
tier |
Drives row filters and access breadth | public, internal, restricted |
retention_years |
Feeds lifecycle/VACUUM policy, not access – carried here for a single source of truth | 1, 7, indefinite |
Pair the taxonomy with a small masking policy pack: a handful of reusable functions covering the disclosure levels a real audit actually asks for, rather than one bespoke function per table.
CREATE FUNCTION governance.mask_redact(val STRING)
RETURN IF(is_account_group_member('pii_reviewers'), val, '***REDACTED***');
CREATE FUNCTION governance.mask_last4(val STRING)
RETURN IF(is_account_group_member('pii_reviewers'), val, concat('***-**-', right(val, 4)));
CREATE FUNCTION governance.mask_null(val STRING)
RETURN IF(is_account_group_member('pii_reviewers'), val, CAST(NULL AS STRING));
Three or four functions, each bound to a tag value via ABAC policies rather than to individual columns, cover the overwhelming majority of masking needs a legacy warehouse migration surfaces – a full-redaction default, a partial-disclosure option for operational analysts, and a hard-null option for fields (like free-text notes) where partial disclosure isn’t meaningful.
Define the taxonomy and the policy pack in version-controlled code (a Databricks Asset Bundle or Terraform, applied through a review process) rather than through ad hoc
ALTER ... SET TAGSstatements in a notebook – a taxonomy that isn’t reviewable is a taxonomy that will drift exactly as fast as the 500-role hierarchy it replaced.
Rolling this out during migration, rather than after, means every table lands in Unity Catalog already tagged and already covered by a masking or row-filter policy – there’s no “phase two: go back and add governance” step competing for attention once the business has moved on to the next initiative. With ABAC, masking, and cross-engine access in place, the check-your-knowledge quiz closes out the governance arc before the next section turns to what all of this costs to run.
| ← Previous: Cross-Engine Access: Delta Sharing, Iceberg, Credential Vending | Next: Check Your Knowledge → | |:—|—:|