Data privacy templates help you write DENY rules, which are difficult in Snowflake.
Data privacy templates enable you define a custom list of tables, views, and/or columns across many databases and schemas. These tables will become accessible to a single role only. All other roles are denied access to those tables.
Getting started
This section covers how to create a data privacy rule to protect a list of tables, views, or columns. Further down, we'll dive into how it all works.
1. On the Functional roles page, click on the Data privacy setting.
2. Create a new policy and select tables, views, and/or columns.
3. Open the uncommitted changes and create an access request.
Approve and apply the access request and you're all set!
From here, you can continue to manage the list of tables/views in the Spyglass Cloud UI. Alternatively, you can simply apply the DATA_PRIVACY_PII tag to any Snowflake table or view and all of the necessary masking policies will be applied.
What the rules look like
To understand what is created by these data privacy rules, let's check out another example:
Create a data privacy rule (e.g. FINANCE_VIEWER)
Decide which tables are included in the rule (e.g. ACME.PROD.SENSITIVE_REVENUE)
Grant the FINANCE_VIEWER privacy rule to a functional role (e.g. FINANCE_TEAM)
The end result:
Only members of the FINANCE_TEAM role can SELECT on ACME.PROD.SENSITIVE_REVENUE
Even if another role has SELECT privileges on this table (via future grants or otherwise), they will be deniedaccess to the table (they will see empty results when querying).
For example:
Implementation details
You can think of data privacy rules as masking policytemplates, with some added quality of life improvements.
Data privacy templates use tag-based masking policies at the table level to ensure that the entire table must be accessed by a specific role, which implicitly denies access to all other roles.
This is accomplished by creating a few objects:
A role that will become the low-level access role for the defined tables.
A tag to contain the masking policies. This tag will be applied to tables.
Masking policies that mask every data type, based on whether the new role is present.
And then by creating references that link these objects together:
Apply the masking policies to the tag.
Apply the tag to the defined tables.
Grant the necessary usage/select to the access role.
In the example of creating the FINANCE_VIEWER data privacy rule, the following commands become staged and ready to be applied:
CREATEROLEIFNOTEXISTS SPYGLASS_FINANCE_VIEWER_VIEWER;CREATE TAG IFNOTEXISTS SPYGLASS.GOVERNANCE.DATA_PRIVACY_FINANCE_VIEWER ALLOWED_VALUES 'active';CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_STRING_MASK AS (val string) RETURNS string -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE '***MASKED***' END;
CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_NUMBER_MASK AS (val number) RETURNS number -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE -1 END;
CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_DATE_MASK AS (val date) RETURNS date -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE '0000-01-01' END;
CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_TIME_MASK AS (val time) RETURNS time -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE '00:00:00' END;
CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_TIMESTAMP_MASK AS (val timestamp) RETURNS timestamp -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE '0000-01-01 00:00:00 +00:00' END;
CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_VARIANT_MASK AS (val variant) RETURNS variant -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE '***MASKED***'::VARIANT END;
CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_ARRAY_MASK AS (val array) RETURNS array -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE ['***MASKED***'] END;
CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_OBJECT_MASK AS (val object) RETURNS object -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE {'***MASKED***': '***MASKED***'} END;
CREATE OR REPLACE MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_GEOMETRY_MASK AS (val geometry) RETURNS geometry -> CASE WHEN IS_ROLE_IN_SESSION('SPYGLASS_FINANCE_VIEWER_VIEWER') THEN val ELSE TO_GEOMETRY('POINT(0 0)') END;
GRANT USAGE ONDATABASE FINANCE TOROLE SPYGLASS_FINANCE_VIEWER_VIEWER;GRANT USAGE ONDATABASE SALES TOROLE SPYGLASS_FINANCE_VIEWER_VIEWER;GRANT USAGE ONSCHEMA FINANCE.REPORTS TOROLE SPYGLASS_FINANCE_VIEWER_VIEWER;GRANT USAGE ONSCHEMA SALES.REPORTS TOROLE SPYGLASS_FINANCE_VIEWER_VIEWER;GRANTSELECTONTABLE FINANCE.REPORTS.DATATOROLE SPYGLASS_FINANCE_VIEWER_VIEWER;GRANTSELECTONTABLE SALES.REPORTS.DATATOROLE SPYGLASS_FINANCE_VIEWER_VIEWER;ALTER TAG SPYGLASS.GOVERNANCE.DATA_PRIVACY_FINANCE_VIEWER SET MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_STRING_MASK, MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_NUMBER_MASK, MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_DATE_MASK, MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_TIME_MASK, MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_TIMESTAMP_MASK, MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_VARIANT_MASK, MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_ARRAY_MASK, MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_OBJECT_MASK, MASKING POLICY SPYGLASS.GOVERNANCE.FINANCE_VIEWER_GEOMETRY_MASK;
ALTERTABLE FINANCE.REPORTS.DATASET TAG SPYGLASS.GOVERNANCE.DATA_PRIVACY_FINANCE_VIEWER ='active';ALTERTABLE SALES.REPORTS.DATASET TAG SPYGLASS.GOVERNANCE.DATA_PRIVACY_FINANCE_VIEWER ='active';
After the data privacy rule is defined in Spyglass, you can simply apply the DATA_PRIVACY_FINANCE_VIEWER to any Snowflake table or view and all of the necessary masking policies will be applied.