Dynamic Masking
Satori provides you with the ability to perform real-time masking of sensitive data. Configuring dynamic masking involves several key components:
Data Classification – Satori automatically classifies data in the data inventory. You can also configure custom classifiers or manually classify data. To enable dynamic masking, ensure the relevant fields are correctly classified in the data inventory.
For more information on data classification, refer to the Data Inventory chapter.
Security Policies – Security policies contain dynamic masking rules, specifying which masking profile to apply based on user roles and conditions. For example, apply the Customer Success masking profile when the user is a member of the Customer Success group and the customer's country is United States.
For more information on security policies, refer to the Security Policies chapter.
Masking Profiles – Masking profiles determine how data is transformed when a masking policy is enforced. For instance, when querying email addresses, a masking profile can obscure the username portion while keeping the domain visible.
For more information on masking profiles, continue reading below.
Masking Profiles
Satori uses masking profiles to simplify the configuration of dynamic masking. Masking profiles define the set of transformations to apply to each data type. Multiple rules can reuse the same profile.
Data Transformations
Satori supports two types of data transformations:
- Generic Data Transformations - These transformations can be applied to any data type. For example, by replacing data fields with predefined strings, hashing the data or removing it completely from the result set.
- Specific Data Transformations - Tailor-made transformations for common data types that provide a better user experience for users when masking data. For example, anonymizing an email address by replacing the address prefix with * or retaining only the year for a date of birth field.
To see the full list of transformations, refer to the link here Transformations List.
Masking Profile Templates
Satori provides three pre-configured profile templates for common masking use-cases.
- Permissive Masking Profile - This masking profile is suited for roles that require some access to PII.
- Restrictive Masking Profile - This masking profile is suited for any role that does not require access to PII.
- Analytics Masking Profile - This masking profile is suited for analytics teams that need to retain statistical data characteristics while protecting PII.
Masking Profile Attributes
Masking profiles are comprised of the following attributes:
- Name - a unique name of the profile.
- Description - a short description of the profile.
- Masking Conditions - a list of masking conditions.
Masking conditions define which transformation to apply for every classifier. Only one condition can be set for each classifier, such as EMAIL, PII or a custom classifier.
Creating a Dynamic Masking Rule
Masking profiles are used by security policies when defining dynamic masking rules. To create a dynamic masking rule, create a masking policy or edit an existing one. There are two modes for configuring dynamic masking rules, simple and advanced.
Simple Dynamic Masking Rule
When using the simple masking rule mode, only one dynamic masking rule can be defined in the security policy, which will apply the same masking profile for all users. To use the simple dynamic masking mode, perform the following steps:
- Open your security policy.
- Select the Dynamic Masking tab.
- Select the masking profile to enforce.
- Click Save.
Advanced Dynamic Masking Rule
In the advanced dynamic masking rule mode, multiple masking rules can be defined. For each rule, a different masking profile can be applied, and masking rules can match user queries based on various attributes. To use the advanced dynamic masking rule mode, perform the following steps:
- Open your security policy.
- Select the Dynamic Masking tab.
- Click on the Advanced button to configure the first rule.
- Select to which users the rule should be match.
- Select the masking profile to apply.
- Click on the plus or minus buttons to add or remove rules.
- Click Save.
Note: You can toggle on or off individual masking rules.
Select Users to Match to a Masking Rule
You can use several options to select which users match a masking rule.
The user is / is not
The dynamic masking rule should match a specific identity or all other users except a specific identity. There are multiple options for this identity:
- User - a user that is defined in the User Management page. For example:
john.smith@acme.com
. - Datastore Username - a user that is defined locally in the data store. For example:
JSMITH
on a Snowflake account.
The user is a member / is not a member of
The dynamic masking rule matches if the user is or is not a member of a group. Several types of groups are supported:
- Group - refers to a Satori directory group. This option is only available for data stores that use the proxy-based integration.
- IdP Group - refers to a group that is managed by the organization’s identity provider and that is synchronized to Satori using the SCIM integration or SAML attributes. This option is only available for data stores that use the proxy-based integration.
- Databricks Group - refers to a group in a Databricks account
Custom Expression
Use this option to match users using a custom expression in a CEL (Common Expression Language) format. This enables you to create Attribute-Based Access Control (ABAC) masking rules, reducing the number of rules you need to manage.
You can either synchronize user attributes from your identity provider using the SCIM integration or manage them directly on Satori in the User Management view.
Satori provides the following built-in functions to create CEL expressions:
userMemberOfGroup - checks if a user is a member of the specified group. For example: userMemberOfGroup('groupA')
.
userHasAttr - checks if a user has an attribute with the specified name. For example: userHasAttr('attribute_name')
.
userAttr - returns the value of the user attribute with the specified name, or null if no such attribute exists. For example: userAttr('country') == 'value_of_attribute_name'
.
You can also create nested logic rules using parenthesis, boolean OR (||
) and boolean AND (&&
). For example: userAttr('country') == 'US' && userAttr('team') = 'Customer Success'
.
Conditional Masking
Conditional masking (sometimes referred to as cell-level security) enables you to apply masking profiles to specific rows of the result set.
To define a conditional masking rule add the SQL expression to determine whether or not to filter a specific cell in the Where section of the rule.
NOTE: Conditional masking is only available in the Databricks and Snowflake Native integrations.
Conditional Masking Examples
To apply a masking profile to rows where the region field is Europe, use the following SQL expression: region = 'Europe'
.
To apply a masking profile to rows where the created_at field is before a certain date, use the following SQL expression: created_at < '2025-01-01'
.
To apply a masking profile to rows where the team field does not equal a user’s team, assuming another table in the database contains that information, use the following SQL expression: team != (SELECT team FROM teams WHERE user = CURRENT_USER())
.
NOTE: Satori validates that the SQL expression is syntactically correct, however, the SQL expression must match the data store type the policy is used for.
Masking Semi-Structured Data
For semi-structured data granularity (e.g. a specific location inside a JSON), masking is applied to specific fields without affecting other JSON locations. To mask information inside of a JSON field in your data source, you must first ensure that the semi-structured fields are created and classified in the Data Inventory.
For example, assume you have a JSON field named attrs
with the following content:
{
"customer": "John Doe",
"items": {
"SSN": "123-45-6789",
"exp": "10/01/2025",
"moresubnesting": {
"SSN": "123-45-6789",
"address": "123 Main Street"
}
}
}
If you want to mask the two SSN
fields, you need to create two new entries in the data inventory under the attrs
column, For example:
Satori uses JSONPath to reference field in semi-structured data types:
- The root object is denoted as
$
. - Fields can be referenced using the dot notation. For example:
$.property_name
. - Fields that contain special characters or spaces should be referenced using the bracket notation. For example:
$['property name']
. - To reference object fields that are located in arrays, use the bracket notation with a wildcard. For example:
$.array_name[*].property_name
.
Once these new entries are created, you can classify them with Satori or custom taxonomy classifiers, just like any other field. From that point forward, Security Policies and Masking Profiles will be applied automatically as defined.
For example, nested masking might work as follows:
{
"customer": "John Doe",
"items": {
"SSN": "******-6789",
"exp":"10/01/2025",
"moresubnesting": {
"SSN": "******-6789",
"address":"****treet"
}
}
}
Transformations
Generic Data Transformations
Name | Example | Definition |
---|---|---|
Hash | data => 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c |
Use this transformation to obfuscate the data completely while retaining its statistical properties for counting, aggregating, etc. note: hash transformations on numeric values result in changed/different numeric values. |
Replace characters with | 12345678 => aaaaaaaa |
Use this transformation to preserve the length of the original data |
Replace entire string | 12345678 => REDACTED |
Use this transformation to make it clear the data has been masked |
Mask everything except last | 12345678 => ******78 |
Use this transformation to retain a hint of the original data |
Specific Data Transformations
In addition to the generic transformation, for selected data types specific transformation are available.
Name | Example | Definition |
---|---|---|
Hash while preserving format | user@company.net => 1234@567890a.bcd |
Generates a hashed version of the original email address. Use this transformation to preserve the original format of the data |
Mask while preserving format | user@company.net => ****@*******.*** |
Use this transformation to obfuscate the data completely while preserving its original format |
Mask username | user@company.net => ****@company.net |
Use this transformation to retain information about the domain name of the email address |
Mask domain | user@company.net => user@*******.*** |
Use this transformation to retain information about the username of the email address |
Credit Card
Name | Example | Definition |
---|---|---|
Hash while preserving format | 1234-5678-9012-3456 => abcd-ef12-3456-7890 |
Generates a hashed version of the original credit card. Use this transformation to preserve the original format of the data |
Mask while preserving format | 1234-5678-9012-3456 => ****-****-****-**** |
Use this transformation to obfuscate the data completely while preserving its original format |
Show only last 4 digits | 1234-5678-9012-3456 => ****-****-****-3456 |
Shows only last 4 digits |
Date of Birth
Name | Example | Definition |
---|---|---|
Show only the year | abcd 2/6/1975 abcd => *********1975***** |
Use this transformation to retain information about the year only |
Public IP Address
Name | Example | Definition |
---|---|---|
Anonymize IP address | 11.20.30.1 => 11.20.0.0 |
Use this transformation to retain /16 of an IPv4 address and /64 of an IPv6 address |
Hash while preserving format | 11.20.30.1 => ab.cd.ef.1 |
Generates a hashed version of the original IP address. Use this transformation to preserve the original format of the data |
Mask while preserving format | 11.20.30.1 => **.**.**.* |
Use this transformation to obfuscate the data completely while preserving its original format |
Considerations and Known Limitations
The following section provides you with the relevant considerations and known limitations of the dynamic masking functionality.
Supported Data Stores
Dynamic masking is not supported in AWS S3, Elasticsearch, Microsoft Fabric, MongoDB and OpenSearch.
Matching Multiple Dynamic Masking Rules
-
When more than one dynamic masking rule matches a user’s query, all masking profiles are logically merged into a single profile, this is the profile that is enforced. For example, if one profile masks emails and another masks person names and the user queries both emails and person names, both will be masked.
-
When more than one data transformation matches a user’s query, the more specific transformation will be selected. For example, if a profile transforms both PII and Email and the user queries both emails and person names, then the PII transformation is used for a persons names and the email transformation will be used for emails.
-
When multiple masking profiles match a user’s query, more than one data transformation of the same specificity can match a user’s query. In this case, Satori orders the profiles alphanumerically by their names in ascending order and selects the first one.
Dynamic Masking for Semi-structured Data
Dynamic masking for semi-structured data is only available for data stores that use the proxy-based integration.
Conditional Masking
-
Conditional masking is only available in the Databricks and Snowflake Native integrations.
-
When specifying an SQL expression for conditional masking, Satori expects the columns that are used for calculating the condition to have the same data types in all relevant tables. For example, when using the condition country is not NULL, Satori expects that the country column in all the tables that are included in the dataset to have the same data type (in the case of this example, it can be either a numeric or a textual data type).
-
The SQL expression used for conditional masking cannot reference the column being masked, only other columns in the table. For example, when masking the
country
column, you cannot use the following SQL expression:country != 'US'
. -
Some changes to the SQL expression for conditoinal masking may result in a short period of time where masking is not applied.
-
Satori considers all non-qualified columns in the SQL expression for conditional masking as columns that are used for calculating the masking condition. For example, consider the following SQL expression used to mask PII in an employees table only for rows representing employees who earn more than their department's avergae. The
salary
anddepartment_id
columns are unqualified (i.e. no schema or database specified) therefore, they are expected to exist in the employees table.
salary > (
SELECT departments.average_salary
FROM departments
WHERE department_id != departments.id
)