diff --git a/docs/src/main/sphinx/security/opa-access-control.md b/docs/src/main/sphinx/security/opa-access-control.md index d3bb185e2b31..3c247d84330f 100644 --- a/docs/src/main/sphinx/security/opa-access-control.md +++ b/docs/src/main/sphinx/security/opa-access-control.md @@ -20,7 +20,7 @@ with the following minimal configuration: ```properties access-control.name=opa -opa.policy.uri=https://your-opa-endpoint/v1/data/allow +opa.policy.uri=https://opa.example.com/v1/data/trino/allow ``` To combine OPA access control with file-based or other access control systems, @@ -45,17 +45,21 @@ The following table lists the configuration properties for the OPA access contro - Description * - `opa.policy.uri` - The **required** URI for the OPA endpoint, for example, - `https://opa.example.com/v1/data/allow`. + `https://opa.example.com/v1/data/trino/allow`. * - `opa.policy.row-filters-uri` - The **optional** URI for fetching row filters - if not set no row filtering - is applied. For example, `https://opa.example.com/v1/data/rowFilters`. + is applied. For example, `https://opa.example.com/v1/data/trino/rowFilters`. * - `opa.policy.column-masking-uri` - The **optional** URI for fetching column masks - if not set no masking - is applied. For example, `https://opa.example.com/v1/data/columnMask`. + is applied. For example, `https://opa.example.com/v1/data/trino/columnMask`. +* - `opa.policy.batch-column-masking-uri` + - The **optional** URI for fetching columns masks in batches; must **not** + be used with `opa.policy.column-masking-uri`. For example, + `http://opa.example.com/v1/data/trino/batchColumnMasks`. * - `opa.policy.batched-uri` - The **optional** URI for activating batch mode for certain authorization queries where batching is applicable, for example - `https://opa.example.com/v1/data/batch`. Batch mode is described + `https://opa.example.com/v1/data/trino/batch`. Batch mode is described [](opa-batch-mode). * - `opa.log-requests` - Configure if request details, including URI, headers and the entire body, are @@ -304,6 +308,130 @@ column. The same "identity" field may be returned to evaluate column masks under a different identity. +### Batch column masking + +If column masking is enabled, by default, the plugin will fetch each column +mask individually from OPA. When working with very wide tables this +can result in a performance degradation. + +Configuring `opa.policy.batch-column-masking-uri` allows Trino to fetch the masks +for multiple columns in a single request. The list of requested columns is included +in the request under `action.filterResources`. + +If `opa.policy.batch-column-masking-uri` is set it overrides the value of +`opa.policy.column-masking-uri` so that the plugin uses batch column +masking. + +An OPA policy supporting batch column masking must return a list of objects, +each containing the following data: +- `viewExpression`: + - `expression`: the expression to apply to the column, as a string + - `identity` (optional): the identity to evaluate the expression as, as a + string +- `index`: a reference the index of the column in the request to which this mask + applies + +For example, a policy configuring batch column masking may be defined by the +following rego script: + +```text +package trino +import future.keywords.in +import future.keywords.if +import future.keywords.contains + +default allow := true + +batchColumnMasks contains { + "index": i, + "viewExpression": { + "expression": "NULL" + } +} if { + some i + column_resource := input.action.filterResources[i] + column_resource.catalogName == "sample_catalog" + column_resource.schemaName == "sample_schema" + column_resource.tableName == "restricted_table" + column_resource.columnName == "user_phone" +} + + +batchColumnMasks contains { + "index": i, + "viewExpression": { + "expression": "'****' || substring(user_name, -3)", + "identity": "admin" + } +} if { + some i + column_resource := input.action.filterResources[i] + column_resource.catalogName == "sample_catalog" + column_resource.schemaName == "sample_schema" + column_resource.tableName == "restricted_table" + column_resource.columnName == "user_name" +} +``` + +A batch column masking request is similar to the following example: + +```json +{ + "context": { + "identity": { + "user": "foo", + "groups": ["some-group"] + }, + "softwareStack": { + "trinoVersion": "434" + } + }, + "action": { + "operation": "GetColumnMask", + "filterResources": [ + { + "column": { + "catalogName": "sample_catalog", + "schemaName": "sample_schema", + "tableName": "restricted_table", + "columnName": "user_phone", + "columnType": "VARCHAR" + } + }, + { + "column": { + "catalogName": "sample_catalog", + "schemaName": "sample_schema", + "tableName": "restricted_table", + "columnName": "user_name", + "columnType": "VARCHAR" + } + } + ] + } +} +``` + +The related OPA response is displayed in the following snippet: + +```json +[ + { + "index": 0, + "viewExpression": { + "expression": "NULL" + } + }, + { + "index": 1, + "viewExpression": { + "expression": "'****' || substring(user_name, -3)", + "identity": "admin" + } + } +] +``` + (opa-batch-mode)= ## Batch mode