CertSafari
    Snowflake SnowPro Advanced: Data Engineer (DEA-C02)· Lessons

    Domain 4 · Lesson 15/22

    Column-Level Security: Masking Policies, External Tokenization and Projection Policies

    Establish and maintain data protection.

    13 min read
    7% of exam
    7 sources
    Published 5 Oct 2026
    Docs as of 4 Oct 2026

    What you will be able to do

    • Tell Dynamic Data Masking apart from External Tokenization, and explain where each one changes the data
    • Set up masking-policy privileges with RBAC so that policy administrators are separate from object owners
    • Use DDL to create, apply, update, unset and monitor masking policies, and fix the common errors
    • Decide when a projection policy fits better than a masking policy, and what a projection policy cannot protect

    Key concept

    Masking policy (query-time protection) — A masking policy is a schema-level object attached to a column. At query time it decides whether the caller sees the real value, a partly masked value or a fully masked value. The stored data never changes, so the protection comes entirely from evaluating the policy at runtime.

    1.Two features, one policy object

    In Snowflake, column-level security means attaching a masking policy to a column in a table or view. Two features use this mechanism. Dynamic Data Masking stores plain text and masks it when a query runs. External Tokenization works the other way round: a third-party provider tokenizes the data before it is loaded, and Snowflake detokenizes it at query time for callers who are authorized.

    Both features use the same policy structure, with one difference. A tokenization policy must call an external function in its body. That function makes a REST call to the tokenization provider, which applies its own tokenization policy and returns either the token or the clear value. Because of this, roles must be mapped in both Snowflake and the provider.

    The same policy shape for masking and for detokenization. Only the function in the authorized branch differs.sql
    -- Dynamic Data Masking
    
    CREATE MASKING POLICY employee_ssn_mask AS (val string) RETURNS string ->
      CASE
        WHEN CURRENT_ROLE() IN ('PAYROLL') THEN val
        ELSE '******'
      END;
    
    -- External Tokenization
    
      CREATE MASKING POLICY employee_ssn_detokenize AS (val string) RETURNS string ->
      CASE
        WHEN CURRENT_ROLE() IN ('PAYROLL') THEN ssn_unprotect(VAL)
        ELSE val -- sees tokenized data
      END;

    The way the rewrite works is important. Snowflake does not mask only the output. It replaces the column with the policy expression wherever the column appears in the query. For an unauthorized role, joins, filters, groupings and sorts all run on the masked value. A join on a masked column can therefore return no matches for one role and the correct matches for another.

    Secure views could also hide columns, so why use policies? Secure views need many views and dashboards to manage, and they do not separate the people who protect the data from the people who own it. Masking policies avoid both problems.

    Checkpoint 1 of 8· Match them up

    Match each mechanism to its defining behaviour

    Tap a term, then the definition that fits it.

    Sources12

    2.Masking policies with RBAC: separating policy admins from owners

    Masking policies work alongside role-based access control. The usual pattern is a custom role, such as MASKING_ADMIN, held by a security or privacy officer. The officer decides which columns are protected. The table owner does not. By default, object owners cannot unset masking policies and cannot see the masked data. A policy can also stop ACCOUNTADMIN and SECURITYADMIN from viewing data they do not need.

    Three privileges control this:

    Privileges for column-level security masking policies
    PrivilegeGranted onWhat it controls
    CREATE MASKING POLICYSchemaWho can create masking policies
    APPLY MASKING POLICYAccountWho can set or unset policies on columns. ACCOUNTADMIN has it by default
    APPLYMasking policyOptional. Lets the policy owner hand the set and unset operations for one policy to object owners
    SECURITYADMIN grants the policy-admin privileges to the custom rolesql
    use role securityadmin; GRANT CREATE MASKING POLICY on SCHEMA <db_name.schema_name> to ROLE masking_admin; GRANT APPLY MASKING POLICY on ACCOUNT to ROLE masking_admin;

    The per-policy APPLY privilege is what makes a decentralized or hybrid model possible. Policy administrators write the policies, then let trusted object owners attach them, acting as data stewards. With hundreds of teams, the central team does not have to apply every policy itself.

    Inside the policy body, RBAC appears as conditions:

    - CURRENT_ROLE() checks the active role. - IS_ROLE_IN_SESSION takes the role hierarchy into account. - INVOKER_ROLE is used for views. - INVOKER_SHARE is used for shares.

    A policy can also look up a custom entitlement table. If it uses a subquery, wrap it in EXISTS. A memoizable function can cache that lookup.

    Checkpoint 2 of 8· Put it in order

    Put the high-level steps for setting up Dynamic Data Masking in order

    1. 1.Run queries. Snowflake rewrites them and applies the policy expression
    2. 2.The officer creates masking policies and applies them to sensitive columns
    3. 3.Grant the custom role to the appropriate users
    4. 4.Grant masking policy management privileges to a custom role for a security or privacy officer

    Checkpoint 3 of 8· Check yourself

    A policy administrator wants the TABLE_OWNER role to attach and detach ssn_mask on its own tables, without giving that role account-wide power over every policy. What should they grant?

    Checkpoint 4 of 8· Exam question

    A payment_card_number column arrives already tokenized by a third-party vault before it is loaded into Snowflake, and the support team occasionally needs the real card number revealed for verified customer calls. Which design correctly combines column-level security mechanisms for this requirement?

    Sources231

    3.Managing masking policies with DDL, and the best practices

    These commands manage masking policies:

    - CREATE MASKING POLICY - ALTER MASKING POLICY - DROP MASKING POLICY - SHOW MASKING POLICIES - DESCRIBE MASKING POLICY

    To attach a policy, use ALTER TABLE or ALTER VIEW with MODIFY COLUMN ... SET MASKING POLICY. You can also attach it when you create the table or view. To change a policy's logic, read the current definition with GET_DDL or DESCRIBE, then run ALTER MASKING POLICY. You do not need to unset the policy first, so the column stays protected while you edit it.

    Checkpoint 5 of 8· Fill the gap

    Which keyword attaches the policy to the column?

    ALTER TABLE IF EXISTS user_info MODIFY COLUMN email  ?  MASKING POLICY email_mask;

    Most masking-policy questions on the exam come down to a few lifecycle rules. A column can have only one masking policy at a time. A policy's input and output data types must match, so to mask a timestamp you return a made-up timestamp rather than a string. If a policy is still attached anywhere, you cannot drop it. Unset it first.

    Common masking-policy errors and their fixes
    SituationFix
    DROP MASKING POLICY fails because the policy is associated with entitiesUNSET it with ALTER TABLE/VIEW ... MODIFY COLUMN, then run DROP again
    A column is already attached to another masking policyChoose one policy. A column cannot have more than one
    Argument and return type mismatchRecreate the policy so the input and output types match
    ALTER ... IF EXISTS reports success but nothing changedRemove IF EXISTS and run the statement again
    A policy on a virtual column or a materialized view columnApply the policy to the column in the source table

    Best practices that the documentation calls out:

    - Write a policy once and apply it to every matching column. - Be careful with hash-based masks such as SHA2, because hashes can collide. - In conditional policies that read other columns, keep the number of column arguments small, because every argument is evaluated at runtime.

    For auditing, the Account Usage MASKING_POLICIES view lists every policy, and POLICY_REFERENCES shows where each one is set. To find which policy affected a particular query, look in the Query Profile. QUERY_HISTORY does not record policy names.

    Checkpoint 6 of 8· Check yourself

    An engineer runs ALTER MASKING POLICY IF EXISTS email_mask SET BODY -> .... Snowflake replies 'Statement executed successfully', but queries still show the old masking behaviour. What is the documented fix?

    Checkpoint 7 of 8· Exam question

    A governance team wants a `national_id` column to never appear in any query result for analyst roles, including inside WHERE clauses or SELECT * output, rather than showing a masked placeholder value. Which control fits this requirement?

    Sources132

    4.Projection policies: use a column without showing it

    A masking policy changes the value that users see. A projection policy decides whether a column can appear in the final output at all. A column with a projection policy is called projection constrained. If the caller's active role does not meet the policy condition, the column comes back as NULL in the outer query. It also cannot be inserted into another table or passed to an external function or stored procedure. A column can have only one projection policy.

    The point of a projection policy is that the column can still be used. It works in inner queries, in WHERE filters and as a join key, so analysts can work with the real values without seeing them. This is more flexible than working with a masked or tokenized value, and it is designed for sharing data with partners.

    Checkpoint 8 of 8· Check yourself

    t_protected.email has a projection policy, and t_unprotected.email has none. A partner joins the two tables on email and selects t_unprotected.email. What happens?

    That flexibility comes with limits:

    - A projection policy does not stop anyone from targeting an individual with a WHERE filter. - It cannot be tag-based, and it cannot go on a virtual column. - Its body cannot reference a column that has a masking policy or a table that has a row access policy. - A determined attacker can still extract values with carefully built queries.

    Use projection policies with partners you already trust. If a column must never leak, remove it from the data or use differential privacy.

    How it fits with other policies. A projection policy does not exclude a masking policy or a row access policy. The same column can carry a projection policy and a masking policy, and the table can carry a row access policy. The restriction is only on the projection policy body, which cannot reference a masked column or a row-access-protected table.

    When a projection policy has to be swapped for another, the FORCE keyword on the column clause of ALTER TABLE replaces the masking or projection policy currently set on the column in a single statement. Projection policies also interact with aggregation policies. They are enforced after aggregation policies, whereas masking policies are enforced before them. If a column is protected by a projection policy, a query against an aggregation-constrained table cannot use that column as an argument of the COUNT function.

    Sources4567

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.The role that owns a table can always see its unmasked data and can remove a masking policy from it.Why is that wrong?

      Masking policies separate duties. By default, object owners can neither unset the policy nor see the protected column data.

      Covered in Masking policies with RBAC: separating policy admins from owners

    2. 2.DROP MASKING POLICY removes the policy from every column it is attached to.Why is that wrong?

      The drop fails while any column still uses the policy. Unset it with ALTER TABLE/VIEW ... MODIFY COLUMN first, then drop it.

      Covered in Managing masking policies with DDL, and the best practices

    3. 3.A projection policy stops users from learning anything about the column's values.Why is that wrong?

      Hidden columns still work in inner queries and WHERE clauses, so filters and joins can reveal information.

      Covered in Projection policies: use a column without showing it

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “External Tokenization enables accounts to tokenize data before loading it into Snowflake and detokenize the data at query runtime.”
      ↩︎ Two features, one policy object
      “masking policies for External Tokenization require using Writing external functions in the masking policy body.”
      ↩︎ Two features, one policy object
      “Note that role mapping must exist in Snowflake and the tokenization provider”
      ↩︎ Two features, one policy object
      “Masking policies solve this management challenge by avoiding an explosion of views and dashboards to manage.”
      ↩︎ Two features, one policy object
      “You can use the context functions INVOKER_ROLE and INVOKER_SHARE for use with views and shares, respectively.”
      ↩︎ Masking policies with RBAC: separating policy admins from owners
      “This command does not require unsetting a masking policy from a column, if the masking policy is set on a column.”
      ↩︎ Managing masking policies with DDL, and the best practices
      “Minimize the number of column arguments in the policy definition.”
      ↩︎ Managing masking policies with DDL, and the best practices
      “sensitive data in Snowflake is not modified in an existing table (i.e. no static masking)”
      ↩︎ Key concept
      “Object owners (i.e. the role that has the OWNERSHIP privilege on the object) do not have the privilege to unset masking policies.”
      ↩︎ Exam trap 1
      “Secure views do not have SoD, which is a profound limitation to their utility.”
      ↩︎ Checkpoint
    2. 2.
      “The column rewrite occurs at every place where the column specified in the masking policy appears in the query”
      ↩︎ Two features, one policy object
      “A security or privacy officer should serve as the masking policy administrator (i.e. custom role: MASKING_ADMIN)”
      ↩︎ Masking policies with RBAC: separating policy admins from owners
      “This privilege controls who can [un]set masking policies on columns and is granted to the ACCOUNTADMIN role by default.”
      ↩︎ Masking policies with RBAC: separating policy admins from owners
      “Always use EXISTS when including a subquery in the masking policy body.”
      ↩︎ Masking policies with RBAC: separating policy admins from owners
      “the input and output data types must match.”
      ↩︎ Managing masking policies with DDL, and the best practices
      “Using a hashing function in a masking policy may result in collisions; therefore, exercise caution with this approach.”
      ↩︎ Managing masking policies with DDL, and the best practices
      “(e.g. projections, join predicate, where clause predicate, order by, and group by)”
      ↩︎ Prediction
      “Grant masking policy management privileges to a custom role for a security or privacy officer.”
      ↩︎ Checkpoint
      “used by a policy owner to decentralize the [un]set operations of a given masking policy on columns to the object owners”
      ↩︎ Checkpoint
    3. 3.
      “can prohibit privileged users with the ACCOUNTADMIN or SECURITYADMIN role from unnecessarily viewing data.”
      ↩︎ Masking policies with RBAC: separating policy admins from owners
      “A column cannot be attached to multiple masking policies.”
      ↩︎ Managing masking policies with DDL, and the best practices
      “Masking policy names are not included in the QUERY_HISTORY view.”
      ↩︎ Managing masking policies with DDL, and the best practices
      “The POLICY_REFERENCES view provides a list of all objects in which a masking policy is set.”
      ↩︎ Managing masking policies with DDL, and the best practices
      “statement to UNSET the policy first, then try the DROP statement again.”
      ↩︎ Exam trap 2
      “Remove IF EXISTS from the ALTER statement and try again.”
      ↩︎ Checkpoint
    4. 4.
      “A projection policy is a first-class, schema-level object that defines whether a column can be projected in the output of a SQL query result.”
      ↩︎ Projection policies: use a column without showing it
      “Projection policies are ignored in a nested query.”
      ↩︎ Projection policies: use a column without showing it
      “A column can only have one projection policy assigned to it at any given time.”
      ↩︎ Projection policies: use a column without showing it
      “A projection policy body cannot reference a column protected by a masking policy or a table protected by a row access policy.”
      ↩︎ Projection policies: use a column without showing it
      “Projection policies are best suited for use with partners and customers with whom you have an existing level of trust.”
      ↩︎ Projection policies: use a column without showing it
      “you should omit the column entirely from your data, or employ differential privacy.”
      ↩︎ Projection policies: use a column without showing it
      “a projection constrained column can also be protected by a masking policy”
      ↩︎ Projection policies: use a column without showing it
      “columns that are hidden by projection policies can still be used in inner queries or in WHERE clauses”
      ↩︎ Exam trap 3
      “nothing prevents the user from projecting values from the column in the unprotected table.”
      ↩︎ Checkpoint
    5. 5.
      “Replaces a masking or projection policy that is currently set on a column with a different policy in a single statement.”
      ↩︎ Projection policies: use a column without showing it
    6. 6.
      “Projection policies are enforced after aggregation policies.”
      ↩︎ Projection policies: use a column without showing it
      “Masking policies are enforced before aggregation policies.”
      ↩︎ Projection policies: use a column without showing it
    7. 7.
      “a query against that table cannot use the column as an argument of the COUNT function.”
      ↩︎ Projection policies: use a column without showing it

    Continue to page 2 of 2

    Row Access Policies, Aggregation Policies, Clean Rooms and Horizon Catalog

    Spotted a mistake, or was something unclear? Tell us.