Table masks (mask_table)
Each mask_table task specifies the masking rules to apply to a
database table, as well as any required joins and any conditionals needed to define which rows
should be masked. Masking rules and masks are applied sequentially in the order
they are listed. When multiple masks are combined in sequence, the output value
from each mask is passed as the input to the next mask in the sequence.
More detail about mask functions and rules is provided under Masking Overview section.
Note: While
mask_tableis suitable for the majority of generic masking requirements, many masking functions are not capable of masking unique keys or primary keys. To mask these columns, use theimitate_uniquemask function, or the special-purposemask_unique_keytask.
Parameters
Each task with type mask_table is defined by the following parameters:
table(required): The name of the table in the database. The table name can be prefixed with a schema name to reference a table in another schema. If the table or schema name are case-sensitive, you must enclose the name in double and single quotation marks in order to specify the casing of the name. For example,table: '"CaseSensitiveSchema"."CaseSensitiveTable"'- For rulesets run against Amazon DynamoDB connections, the table name can be prefixed with the AWS region that
contains the table e.g.
<region>/<table-name>(without angle brackets). Note that the region prefix is required if you have not created a.aws/credentialsfile or environment variable with the default region or are running DataMasque on EC2.
- For rulesets run against Amazon DynamoDB connections, the table name can be prefixed with the AWS region that
contains the table e.g.
alias(optional): An alternate name for the table being masked, used to reference its columns in conditional masking and joins. Once an alias is set, the table's original name can no longer be used.key(required): One or more columns that identify each table row. Composite keys may be specified for thekeyparameter. For more details on using composite keys, see Composite keys- For Oracle databases it should always be
ROWID(key: ROWID). For more details, refer to Query optimisation. - For Microsoft SQL Server and PostgreSQL databases it is recommended to use the primary key, or any other unique key that is not modified during masking, for better performance.
- The key columns must not contain any NULL value.
- Each database has a limited range of data types for key columns.
Refer to the Database Connections page
for information on which data types are accepted as key columns for
mask_tabletasks. - If the key column names are case-sensitive, you may enclose each key value in double
and single quotation marks in order to specify the casing of the key. For example,
key: '"Customer_ID"' - If the columns specified for the key parameter cannot be used to uniquely identify rows, then the masked values will be the same for rows that have the same key value. Refer to the key and hash columns example in the Notes section for how to avoid producing duplicate masked values.
- Columns specified in the key cannot be masked in the task's
rules. Amazon DynamoDB is an exception to this rule, allowing key columns to be masked with e.g. thefrom_uniquemask type. IMPORTANT: Masking the key column in DynamoDB can result in loss of rows if the final key column values are not all unique.
- For Oracle databases it should always be
on_missing_column(optional): The action to take if acolumnin the ruleset is not found on the table. This option is only available for Amazon DynamoDB. If specified, must be one oferrororskip. Defaults toerror, which means a masking run will fail if a column in the ruleset does not exist. If set toskipthen missing columns do not cause an error and other columns are masked as normal.use_calculated_bounds(optional): When set totrue(default) then the batch bounding keys are calculated using values in the database. If set tofalse, then DataMasque generates these keys without querying the database, which may improve performance. However, this option is only supported for integer, non-composite keys. For more details, see Calculated or generated bounds.hash_columns(optional): A list of columns which will be used as input to the Deterministic masking algorithm for all masking rules in this task, unless overridden at the column level. When specified at the task level, this provides a default deterministic behavior for all columns being masked in the table. Ifhash_columnsis provided, all mask types that rely on randomisation become deterministic based on thehash_columnscolumn values. Values in the provided columns can benull.Task-level
hash_columnscan be overridden for individual columns by:- Specifying different
hash_columnsat the column level (in the rule'shash_columnsparameter). This completely replaces the task-level hash_columns for that column. - Setting
hash_columns: nullat the column level to disable deterministic masking for that specific column.
For database masking, the hash column can be prefixed with a table name to reference a column in another table, and that table name can be prefixed with a schema name to reference a table in another schema.
Hash columns can also be specified by a list of dictionaries with the following keys:
column_name: The name of the column which will be used as input as above. Required unlesssourceis specified.source(optional): Set toselfto use the value being masked as its own hash source, ensuring identical input values produce identical masked outputs.case_transform(optional):upper/lower- Allows for case transforms on the values of the input, ensuring consistent hashed values irrespective of case.trim(optional): If the value extracted from the column,json_path, orxpathcontains leading or trailing white space, it can be trimmed by setting this option totrue. Defaults tofalse.json_path(optional): If the column contains JSON data, the path to the value in the JSON data you wish to perform the hash on can be specified here, otherwise the hash will be performed on the entire column.xpath(optional): If the column contains XML data, the Xpath to the value stored in the XML data you wish to perform the hash on can be specified here, otherwise the hash will be performed on the entire column.coerce_whole_numbers_to_int(optional): When set totrue, this option will coerce whole number float values in the specified column to integers before being used for hashing.regex(optional): A regular expression pattern to extract and concatenate values from the hash column before hashing. When specified, all matches (or capturing groups, if present) are concatenated together to form the value used for hashing. If the pattern does not match, the original value is preserved. This is applied before other transforms (trim,case_transform).match_index(optional): A zero-based index specifying which occurrence of theregexpattern to use for hashing. For example,0uses only the first match,1uses only the second match, and so on. If omitted, all matches are concatenated (default behaviour). Requiresregexto be specified.
A
hash_columnsentry can also be atable_referencelookup instead of a column: a mapping that seeds masking from a shared identity map, so the same entity masks consistently across systems. See Seeding masking from a table reference.- Specifying different
About regex
The regex transform is useful when hash column values have inconsistent formatting that should not affect deterministic masking.
For example, SSN values may be stored as 123-45-6789 or 123456789 —
using regex: '\d+' extracts all digit sequences and concatenates them, producing 123456789 in both cases and ensuring consistent hash output.
If the pattern contains capturing groups, all captured groups across all matches are concatenated. If no capturing groups are defined, all matched substrings are concatenated.
Example
hash_columns:
- column_name: ssn
regex: '\d+'
| Input | Regex | Hash Input |
|---|---|---|
123-45-6789 |
\d+ |
123456789 |
123456789 |
\d+ |
123456789 |
(123) 456-789 |
\d+ |
123456789 |
no-digits |
\d+ |
no-digits |
About coerce_whole_numbers_to_int
When coerce_whole_numbers_to_int is enabled, whole number float values will be
coerced to integers (e.g. 1.0 to 1, 4.0 to 4, and so on). This ensures consistent
hashing between integer columns and columns where whole numbers are stored as floats/decimals.
Numbers that aren't whole are not affected by this option. For example, 1.5
will still be treated as 1.5 even when this option is enabled. Strings are also not affected.
Example Behavior
| Input | Input Type | Output with coerce_whole_numbers_to_int set to false |
Output with coerce_whole_numbers_to_int set to true |
|---|---|---|---|
| 2.4 | float/decimal | 2.4 | 2.4 |
| "3.0" | string | "3.0" | "3.0" |
| "3.1" | string | "3.1" | "3.1" |
| 2.0 | float/decimal | 2.0 | 2 |
| 5 | integer | 5 | 5 |
For more information on the json_path, please refer to the JSON documentation.
For more information on the xpath, please refer to the XML documentation.
For more information on deterministic masking, please refer to the Deterministic masking.
rules (required): A list of masking rules (or dictionary mapping arbitrary keys to rules) to apply to the
table. Rules are applied sequentially according to the order they
are listed. Regular (non-conditional) masking
rules are defined by the following attributes:
- column (required): The name of the column to mask. For rulesets run against Amazon DynamoDB connections, a wildcard *
can be used to apply masks to columns not matched by other column's rules.
- masks (required): A list of masks (or dictionary mapping arbitrary keys to masks) to apply to the column.
Masks are applied sequentially according to the order they are
listed, so the output value from each mask is passed to the next
mask in the list. Each type of mask has a different set of
required attributes, as described for each type in Mask
functions.
- hash_columns (optional): A list of columns to use for
Deterministic masking for this specific rule,
overriding any task-level hash_columns.
Set to null to disable deterministic masking for this column.
See the task-level hash_columns parameter above for full details on syntax and options.
- auto_truncate_value (optional): When set to true, a masked value wider than this
column is truncated to fit for this specific rule, overriding the ruleset-level
auto_truncate_value. If not set, the ruleset-level value is used
(which itself defaults to false).
- disable_warning_on_auto_truncate_value (optional): When set to true, suppresses the
truncation warning for this specific rule, overriding the ruleset-level setting.
If not set, the ruleset-level value is used.
workers(optional): The number of parallel processes to use for masking this table (defaults to 1). Each process will operate on a separate batch of rows from the table (batch size is a configurable run option). Increasingworkersmay decrease masking run times, dependent on database performance and the complexity (e.g. number of columns to mask) of the masking task. It is recommended to increase the number of workers if DataMasque connections to your target database spend more time processing queries than waiting for DataMasque (i.e. the "waiting for clients" time approximates DataMasque CPU time), which suggests DataMasque could efficiently use multiple workers to mask other batches while waiting for database responses. Additionally, it is recommended that the number of parallel processes multiplied by the number of workers assigned to each process does not exceed twice the number of CPUs available on your deployed instance.index_key_columns(optional): Whenindex_key_columnsistrue(the default setting), DataMasque will create an additional index on all key columns if there is no existing index contains all key columns. You may wish to disable the creation of a new index if you have an existing index on some of the key columns that will provide adequate performance.- Redshift databases do not support indexes, so this option has no effect for them.
allow_masking_foreign_keys(optional): To preserve referential integrity, an error will be raised if any of therulesmasks a column that is a foreign key, as the parent of a foreign key should usually be masked withmask_unique_keyand cascaded to its foreign key(s) when possible. This error is disabled when this option is set totrue. Defaults tofalse.disable_warning_on_use_of_conditionals(optional): By default, a warning is shown if conditional optionsskip,if/elseorwhereare used, as this may mean not all rows are being masked (see Conditional Masking). To disable this warning, setdisable_warning_on_use_of_conditionalstotrueon the specificmask_tabletask. Defaults tofalse.auto_manage_triggers(optional): When set totrue, DataMasque will automatically detect and disable database triggers on the target table, orON UPDATEexpressions on the table's columns, before masking. After masking, triggers and expressions are enabled. This overrides any ruleset-levelauto_manage_triggerssetting. For detailed information, see Automatic trigger management. Defaults totruefor supported databases.auto_manage_indexes(optional): When set totrue, DataMasque will automatically detect and disable or drop non-unique indexes on the target table for columns being masked. After masking, indexes are re-added. This can help with performance and index-related issues during the masking process. For detailed information on database support and usage, see Automatic index management. Defaults totruefor supported databases.action_on_batch_size_exceeded(optional): Specifies what DataMasque will do if the number of rows returned from the database exceeds the specified batch size, which can lead to excessive memory usage and performance degradation. This could happen if the key columns are non-unique or when querying corrupt tables. If specified, must be eitherwarningorerror. Defaults toerror. Thewarningoption will cause DataMasque to log a warning in the run log and continue masking. Theerroroption will cause DataMasque to fail the masking run and log the error.log_row_key_on_failure(optional): When set totrue, if an error occurs while masking a row, the primary key values of the failing row will be included in the error message. The error message will include the key column names and their values in the format: "Row key values: column1=value1, column2=value2 - skipping remainder of table: table_name". This is useful when debugging issues with masks that validate data format (e.g.,credit_cardwithon_invalid: error,set_checksumwithon_invalid_format: error). Defaults tofalse.Note: This parameter is only available for
mask_tabletasks, not for other task types likemask_unique_key.
Composite keys
A composite key can be specified in following formats:
- A list of columns; for example,
key: ['invoice_id', 'product_id']would be used to indicate a composite key consisting of a combination of two columns,invoice_idandproduct_id. - For Microsoft SQL Server and PostgreSQL, when specifying a composite key, the order of the keys listed must respect the original order as defined in the database.
- A multiline composite key. An example of a multiline composite key is shown below.
key:
- 'invoice_id'
- 'product_id'
Calculated or generated bounds
DataMasque's mask_table processes a table's data in batches.
It fetches a specified number of rows, masks them, and writes them back to the database.
The number of rows is determined by the batch size.
By default, DataMasque calculates bounding keys for each batch using the values in the
key column(s) specified in the mask_table task.
For example, if a table's id column has values ranging from 100,000 to 200,000 and the batch size is 50,000,
the batches would be as follows:
| Batch Number | Start id |
End id |
No. Rows In Batch |
|---|---|---|---|
| 1 | 100,000 | 149,999 | 50,000 |
| 2 | 150,000 | 199,999 | 50,000 |
| 3 | 200,000 | 200,000 | 1 |
This approach is called calculated bounds
and is the default method if use_calculated_bounds is not specified or set to true.
Calculated bounds work with non-integer columns and composite keys.
As long as the key is unique,
all batches (except the last one if the total number of rows is not divisible by the batch size),
will have the same number of rows as the batch size.
Generating bounding keys requires querying the database,
which can be time-consuming for large tables (e.g. 100,000,000 rows or more).
In such cases,
setting use_calculated_bounds to false allows DataMasque to generate bounding keys without querying the table.
This means batch sizes may vary if key values are non-contiguous or do not start at 0,
but no batch will exceed the specified batch size.
With use_calculated_bounds: false,
DataMasque generates bounds by incrementally adding the batch size until the largest value in the key column is reached.
Here's how the batches would look for the same example:
| Batch Number | Start id |
End id |
No. Rows In Batch |
|---|---|---|---|
| 1 | 0 | 49,999 | 0 |
| 2 | 50,000 | 99,999 | 0 |
| 3 | 100,000 | 149,999 | 50,000 |
| 4 | 150,000 | 199,999 | 50,000 |
| 5 | 200,000 | 200,000 | 1 |
In this scenario, batch 1 is empty. DataMasque skips empty batches, but querying still occurs, which can be inefficient if there are many non-contiguous IDs.
The performance impact of enabling or disabling use_calculated_bounds depends on your dataset.
Experimenting with use_calculated_bounds: false is recommended to see if it improves masking speed.
use_calculated_bounds may only be disabled if all the following conditions are true:
- A single
keycolumn is specified. - The column is of an integer* type.
- The column must contain no negative values.
0is allowed. - The column must be a primary key or have a unique index/constraint.
- The maximum value in the column must be less than or equal to 2^32 (4,294,967,296).
- The column must not be nullable (e.g. should be created with
NOT NULLconstraint).
* Supported column types for all databases: INTEGER, BIGINT and SMALLINT.
Additionally, Oracle also supports NUMBER columns with a scale of 0.
When to disable calculated bounds
The following table compares the effects of enabling or disabling use_calculated_bounds:
use_calculated_bounds: true |
use_calculated_bounds: false |
|
|---|---|---|
| Supports non-integer keys | Yes | No |
| Supports composite keys | Yes | No |
| Time spent up front querying bounds keys | May have long delays for bigger tables | No time spent up front |
| May waste time querying empty batches | No | Yes |
| Batch sizes consistent | Yes, except for last batch | Not consistent for non-contiguous keys |
| Requires an index* | No | Yes |
*If use_calculated_bounds is true and no index is present,
an index will be temporarily added for the task.
Setting use_calculated_bounds to false is intended to boost performance on large tables.
However, adding an index to such large tables may be time-consuming, thus making the overall task take longer.
Therefore, if no index exists, the task will fail instead of adding an index.
An index should be added prior to executing the mask_table task,
either manually or with the use of a run_sql task.
Supported Database Engines
Disabling calculated bounds is supported on:
- IBM Db2 for i
- IBM Db2 LUW
- MariaDB
- Microsoft SQL Server
- MySQL
- Oracle
- PostgreSQL
Example mask_table ruleset
version: '1.0'
tasks:
- type: mask_table
table: users
key: user_id
rules:
- column: last_name
masks:
- type: from_fixed
value: "redacted last name"
Notes
- Index operations will be performed online (
ONLINE=ON) on SQL Server editions that support this feature.- Certain data types cannot be used as
keycolumns for specific database connections. See Unsupported Key Columns by Database for details.- While
rulesandmasksshould typically be provided as lists, they can also be specified as dictionaries that map arbitrary keys to rules/masks. For example:... rules: last_name_rule: column: last_name masks: fixed_mask: type: from_fixed value: "redacted last name"
- Specifying
rulesormasksas a dictionary can allow you to override the rule/mask for a specific key when inheriting from a definition.- When masking a table, if a non-unique key is specified for the
mask_tabletask alongsidehash_columns, if the value of thehash_columnsis different for more than one row with same key value, the final masked values will arbitrarily depend on the order that update statements are executed. This can be avoided by including the targetedhash_columnsas part of a composite key for themask_tabletask.