Last updated
Last updated
In the use case, we covered at length. Subscription policies control table level access.
In this use case, we are focused one level deeper: columns and rows within a table that can be protected in a more granular manner with .
With Immuta, you are able to , or even mask cells within a given column per row using (also termed conditional masking).
This is important for this use case to granularly mask or grant unmasked access to specific columns to specific users. This granularity of policy allows more access to data because you no longer have to roll up coarse access decisions to the table level and can instead make them at the individual column, row, or cell level.
The concept of masking columns has been mentioned a few times already, but as you already know per the guide, your masking policies will actually target tags instead of physical columns. This abstraction is powerful, because it allows you to build a single policy that may apply to many different columns across many different tables (or ).
If you build policy using tags, isn't there a good chance that multiple masking policies could land on the same column? Yes.
This can be avoided . Immuta supports tag hierarchy, so if the depth of a tag targeted by a policy is deeper than the conflicting policy, the deepest (the more specific one) wins. As an example, mask by making null columns tagged PII
is less specific (depth of 1) than the policy mask using hasing columns tagged Discovered.name
(depth of 2), so the hashing masking policy would apply to columns tagged Discovered.name
and PII
rather than the null one.
Immuta meets principle of least privilege by following an . What this means is that if you mask a column, that mask will apply to everyone except [some list of exceptions]
. This uni-directional approach avoids policy conflicts, makes change management easier, authoring policy less complex, and (most importantly) avoids data leaks.
There are many different approaches you can take to masking a column. Some masks render the column completely useless to the querying user, such as nulling it, while other masking techniques can provide some level of utility from the column while at the same time maintaining a level of privacy and security. These advanced masking techniques are sometimes termed . Immuta provides a that allow for privacy-vs-utility trade-off decisions when authoring masking policies.
If you were to build masking policies natively in your data platform, they require that you build a masking policy per data type it could mask. This makes sense, because a varchar
column type can't display numerics, or vice versa, for example. Furthermore, when building masking policies that target tags instead of physical columns, it is possible that policy may target many differing data types, or even target new unforeseen data types in the future when new columns appear.
You may hear this policy called row filter or row access policy. The idea is to redact rows at query time based on the user running the query.
Without this capability, you would need a transform process that segments your data across different tables and then manage access to those tables. This introduces extra compute costs and at some point, when dealing with large tables and many differing permutations of access, it may be impossible to maintain as those tables grow.
@groupsContains('SQL Column or Expression')
allows you to compare the value of a column to see if the user possesses any groups with a matching name (case sensitive).
@attributeValuesContains('Attribute Name', 'SQL Column or Expression')
allows you to compare the value of a column to see if the user possesses any attribute values under a specific key with a matching name (case sensitive).
@purposesContains('SQL Column or Expression')
allows you to compare the value of a column to see if the user is acting under a matching purpose (case sensitive).
@columnTagged('Tag Name')
allows you to target tags instead of physical columns when using one of the above functions.
Here's a simple example that targets a physical column COUNTRY
comparing it to the querying user's country attribute key's values:
@attributeValuesContains('country', 'COUNTRY')
This could also be written to instead use the @columnTagged
function instead of the physical column name:
@attributeValuesContains('country', @columnTagged('Discovered.Country'))
Allowing this policy to be reused across many different tables that may have the COUNTRY
column name spelled differently.
...for everyone except users acting under purpose [some legitimate purpose(s)]
Data sources with the policies they want to be excluded from and
Purposes
This can be made temporary by deleting the project once access is no longer needed or revoking approval for the project after the need for access is gone.
After you've created global data policies as described above, how do you actually give access to the tables?
This adds a large deal of effort to policy authoring. With Immuta, rather than explicitly requiring you to cover all possible data types when building a masking policy, Immuta has . This allows Immuta to apply the masking policy by changing, as minimally as possible, the masking type to something that is possible against that data type, while still maintaining the required privacy level provided by the original masking type.
Immuta allows you to using a global scope by leveraging tags just like with masking policies.
Unlike masking policies, the use of tags for redacting rows not only impacts which tables are targeted with the policy, but also the logic of the policy. When , you must choose the column to "compare against" when making a decision on if the row should be visible to the user or not at query time. The tag can drive this decision. This allows you to author a single row-level policy that targets many different tables (or ).
Sometimes customization is required for scenarios that require more complex logic. When in the policy builder, these are called policies. Within your custom WHERE, Immuta also provides several different functions you can leverage for powerful and scalable policies:
You may want to override and grant access to unmasked data to an individual for a very specific reason. Our recommendation is to use to create exceptions to global data policies.
There is some up front work that needs to occur to make this possible. A user with would need to create for access to different data types unmasked. As part of creating the purposes, they may want to alter the the user must agree to when acting under that purpose.
Then, the masking or row-level policies would need to be updated to to the policy, for example:
Once that is done, users can and add to the project both of the following:
However, that project does nothing until approved by a user with . Once that approval is complete, the user wanting the exception must they will only use the data for that purpose and then, using the Immuta UI, . Once switched to that purpose, the exception(s) will occur for the user.
This is a good question, and it really depends if you already have a table-access process you are already happy with or not. If you do, keep using it. If you don't, we recommend you create a that opens all tables up to anyone, as the point of this use case is not to focus on coarse grained table-level access but instead fine-grained access using global data policies.
When creating new tables, you should follow the best practices to ensure there's while you wait for policy uptime through Immuta schema monitoring.