diff --git a/doc/modules/cassandra/examples/CQL/ddm_alter_mask.cql b/doc/modules/cassandra/examples/CQL/ddm_alter_mask.cql deleted file mode 100644 index 6e10308125..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_alter_mask.cql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE patients ALTER name MASKED WITH mask_default(); diff --git a/doc/modules/cassandra/examples/CQL/ddm_create_table.cql b/doc/modules/cassandra/examples/CQL/ddm_create_table.cql deleted file mode 100644 index 65ba56dde7..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_create_table.cql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE patients ( - id timeuuid PRIMARY KEY, - name text MASKED WITH mask_inner(1, null), - birth date MASKED WITH mask_default() -); diff --git a/doc/modules/cassandra/examples/CQL/ddm_create_table_with_udf.cql b/doc/modules/cassandra/examples/CQL/ddm_create_table_with_udf.cql deleted file mode 100644 index 85d6555f3a..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_create_table_with_udf.cql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE FUNCTION redact(input text) - CALLED ON NULL INPUT - RETURNS text - LANGUAGE java - AS 'return "redacted";'; - -CREATE TABLE patients ( - id timeuuid PRIMARY KEY, - name text MASKED WITH redact(), - birth date -); diff --git a/doc/modules/cassandra/examples/CQL/ddm_create_users.cql b/doc/modules/cassandra/examples/CQL/ddm_create_users.cql deleted file mode 100644 index 7e66a1a830..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_create_users.cql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE USER privileged WITH PASSWORD 'xyz'; -GRANT SELECT ON TABLE patients TO privileged; -GRANT UNMASK ON TABLE patients TO privileged; - -CREATE USER unprivileged WITH PASSWORD 'xyz'; -GRANT SELECT ON TABLE patients TO unprivileged; diff --git a/doc/modules/cassandra/examples/CQL/ddm_drop_mask.cql b/doc/modules/cassandra/examples/CQL/ddm_drop_mask.cql deleted file mode 100644 index 06e032ce5f..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_drop_mask.cql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE patients ALTER name DROP MASKED; diff --git a/doc/modules/cassandra/examples/CQL/ddm_insert_data.cql b/doc/modules/cassandra/examples/CQL/ddm_insert_data.cql deleted file mode 100644 index 59e916fafb..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_insert_data.cql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO patients(id, name, birth) VALUES (now(), 'alice', '1984-01-02'); -INSERT INTO patients(id, name, birth) VALUES (now(), 'bob', '1982-02-03'); diff --git a/doc/modules/cassandra/examples/CQL/ddm_revoke_unmask.cql b/doc/modules/cassandra/examples/CQL/ddm_revoke_unmask.cql deleted file mode 100644 index 93e2b90c7b..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_revoke_unmask.cql +++ /dev/null @@ -1 +0,0 @@ -REVOKE UNMASK ON TABLE patients FROM privileged; diff --git a/doc/modules/cassandra/examples/CQL/ddm_select_with_masked_columns.cql b/doc/modules/cassandra/examples/CQL/ddm_select_with_masked_columns.cql deleted file mode 100644 index 8acd066066..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_select_with_masked_columns.cql +++ /dev/null @@ -1,6 +0,0 @@ -SELECT name, birth FROM patients; - -// name | birth -// -------+------------ -// a**** | 1970-01-01 -// b** | 1970-01-01 diff --git a/doc/modules/cassandra/examples/CQL/ddm_select_with_select_masked.cql b/doc/modules/cassandra/examples/CQL/ddm_select_with_select_masked.cql deleted file mode 100644 index 0093855ad7..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_select_with_select_masked.cql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE USER trusted_user WITH PASSWORD 'xyz'; -GRANT SELECT, SELECT_MASKED ON TABLE patients TO trusted_user; -LOGIN trusted_user -SELECT name, birth FROM patients WHERE name = 'Alice' ALLOW FILTERING; - -// name | birth -// -------+------------ -// a**** | 1970-01-01 diff --git a/doc/modules/cassandra/examples/CQL/ddm_select_with_unmask_permission.cql b/doc/modules/cassandra/examples/CQL/ddm_select_with_unmask_permission.cql deleted file mode 100644 index 35072c7c9a..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_select_with_unmask_permission.cql +++ /dev/null @@ -1,7 +0,0 @@ -LOGIN privileged -SELECT name, birth FROM patients; - -// name | birth -// -------+------------ -// alice | 1984-01-02 -// bob | 1982-02-03 diff --git a/doc/modules/cassandra/examples/CQL/ddm_select_without_select_masked.cql b/doc/modules/cassandra/examples/CQL/ddm_select_without_select_masked.cql deleted file mode 100644 index af15cf8abb..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_select_without_select_masked.cql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE USER untrusted_user WITH PASSWORD 'xyz'; -GRANT SELECT ON TABLE patients TO untrusted_user; -LOGIN untrusted_user -SELECT name, birth FROM patients WHERE name = 'Alice' ALLOW FILTERING; - -// Unauthorized: Error from server: code=2100 [Unauthorized] message="User untrusted_user has no UNMASK nor SELECT_UNMASK permission on table k.patients" diff --git a/doc/modules/cassandra/examples/CQL/ddm_select_without_unmask_permission.cql b/doc/modules/cassandra/examples/CQL/ddm_select_without_unmask_permission.cql deleted file mode 100644 index 4b80b83329..0000000000 --- a/doc/modules/cassandra/examples/CQL/ddm_select_without_unmask_permission.cql +++ /dev/null @@ -1,7 +0,0 @@ -LOGIN unprivileged -SELECT name, birth FROM patients; - -// name | birth -// -------+------------ -// a**** | 1970-01-01 -// b** | 1970-01-01 diff --git a/doc/modules/cassandra/examples/CQL/dynamic-data-masking.cql b/doc/modules/cassandra/examples/CQL/dynamic-data-masking.cql new file mode 100644 index 0000000000..a060a25f12 --- /dev/null +++ b/doc/modules/cassandra/examples/CQL/dynamic-data-masking.cql @@ -0,0 +1,99 @@ +// tag::table-create-ddm[] +CREATE TABLE patients ( + id timeuuid PRIMARY KEY, + name text MASKED WITH mask_inner(1, null), + birth date MASKED WITH mask_default() + ); +// end::table-create-ddm[] + +// tag::table-create-ddm-udt[] +CREATE FUNCTION redact(input text) + CALLED ON NULL INPUT + RETURNS text + LANGUAGE java + AS 'return "redacted";'; + +CREATE TABLE patients ( + id timeuuid PRIMARY KEY, + name text MASKED WITH redact(), + birth date +); +// end::table-create-ddm-udt[] + +// tag::table-alter-ddm[] +ALTER TABLE patients ALTER name + MASKED WITH mask_default(); +// end::table-alter-ddm[] + +// tag::table-alter-ddm-drop-mask[] +ALTER TABLE patients ALTER name + DROP MASKED; +// end::table-alter-ddm-drop-mask[] + +// tag::users-grant-ddm[] +CREATE USER privileged WITH PASSWORD 'xyz'; +GRANT SELECT ON TABLE patients TO privileged; +GRANT UNMASK ON TABLE patients TO privileged; + +CREATE USER unprivileged WITH PASSWORD 'xyz'; +GRANT SELECT ON TABLE patients TO unprivileged; +// end::users-grant-ddm[] + +// tag::users-revoke-ddm[] +REVOKE UNMASK ON TABLE patients + FROM privileged; +// end::users-revoke-ddm[] + +// tag::data-insert-ddm[] +INSERT INTO patients(id, name, birth) VALUES (now(), 'alice', '1984-01-02'); +INSERT INTO patients(id, name, birth) VALUES (now(), 'bob', '1982-02-03'); +// end::data-insert-ddm[] + +// tag::select-with-masked-column[] +SELECT name, birth FROM patients; + +// name | birth +// -------+------------ +// a**** | 1970-01-01 +// b** | 1970-01-01 +// end::select-with-masked-column[] + +// tag::select-without-unmask-permission[] +LOGIN unprivileged +SELECT name, birth FROM patients; + +// name | birth +// -------+------------ +// a**** | 1970-01-01 +// b** | 1970-01-01 +// end::select-without-unmask-permission[] + +// tag::select-with-unmask-permission[] +LOGIN privileged +SELECT name, birth FROM patients; + +// name | birth +// -------+------------ +// alice | 1984-01-02 +// bob | 1982-02-03 +// end::select-with-unmask-permission[] + +// tag::select-without-select-masked[] +CREATE USER untrusted_user WITH PASSWORD 'xyz'; +GRANT SELECT ON TABLE patients TO untrusted_user; +LOGIN untrusted_user +SELECT name, birth FROM patients WHERE name = 'Alice' ALLOW FILTERING; + +// Unauthorized: Error from server: code=2100 [Unauthorized] message="User untrusted_user has no UNMASK nor SELECT_UNMASK permission on table k.patients" +// end::select-without-select-masked[] + +// tag::select-with-select-masked[] +CREATE USER trusted_user WITH PASSWORD 'xyz'; +GRANT SELECT, SELECT_MASKED ON TABLE patients TO trusted_user; +LOGIN trusted_user +SELECT name, birth FROM patients WHERE name = 'Alice' ALLOW FILTERING; + +// name | birth +// -------+------------ +// a**** | 1970-01-01 +// end::select-with-select-masked[] \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/select_with_mask_functions.cql b/doc/modules/cassandra/examples/CQL/select-with-mask-functions.cql similarity index 100% rename from doc/modules/cassandra/examples/CQL/select_with_mask_functions.cql rename to doc/modules/cassandra/examples/CQL/select-with-mask-functions.cql diff --git a/doc/modules/cassandra/nav.adoc b/doc/modules/cassandra/nav.adoc index 7d79e4fcc7..bf2f3c696e 100644 --- a/doc/modules/cassandra/nav.adoc +++ b/doc/modules/cassandra/nav.adoc @@ -40,6 +40,7 @@ *** xref:cassandra:developing/cql/types.adoc[Data types] *** xref:cassandra:developing/cql/ddl.adoc[Data definition (DDL)] *** xref:cassandra:developing/cql/dml.adoc[Data manipulation (DML)] +*** xref:cassandra:developing/cql/dynamic-data-masking.adoc[] *** xref:cassandra:developing/cql/operators.adoc[Operators] *** xref:cassandra:developing/cql/indexing/indexing-concepts.adoc[] // SAI diff --git a/doc/modules/cassandra/pages/developing/cql/dynamic-data-masking.adoc b/doc/modules/cassandra/pages/developing/cql/dynamic-data-masking.adoc new file mode 100644 index 0000000000..1bbcaecb9e --- /dev/null +++ b/doc/modules/cassandra/pages/developing/cql/dynamic-data-masking.adoc @@ -0,0 +1,179 @@ += Dynamic Data Masking (DDM) +:description: Dynamic Data Masking (DDM) is a method for making sensitive data unavailable to non-privileged users. + +Dynamic data masking (DDM) obscures sensitive information while still allowing access to the masked columns. +DDM doesn't alter the stored data. +Instead, it just presents the data in its obscured form during `SELECT` queries. +This aims to provide some degree of protection against accidental data exposure. However, anyone with direct access to the SSTable files will be able to read the clear data. + +== Masking functions + +DDM is based on a set of CQL native functions that obscure sensitive information. +The available functions are: + +include::partial$masking_functions.adoc[] + +Those functions can be used on `SELECT` queries to get an obscured view of the data. +For example: + +[source,cql] +---- +include::example$CQL/select-with-mask-functions.cql[] +---- + +== Attaching masking functions to table columns + +A masking function can be permanently attached to any column of a table. +If a masking column is defined, `SELECT` queries will always return the column values in their masked form. +The masking will be transparent to the users running `SELECT` queries. +The only way to know that a column is masked is to consult the table definition. + +This is an optional feature that is disabled by default. +To use the feature, enable the `dynamic_data_masking_enabled` property in `cassandra.yaml`. + +The masks of the columns of a table can be defined in the `CREATE TABLE` to create the table schema. This example uses the `mask_inner` function with two arguments: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=table-create-ddm] +---- + +When using a `SELECT` query on this data, three arguments are required for the `mask_inner` function, but the first argument is always omitted when attaching the function to the table schema. +The value of that first argument is always interpreted as the value of the masked column, in this case a `text` column. + +For the same reason, using the masking function `mask_default` doesn't have any argument when creating the table schema, but it requires one argument when used on `SELECT` queries. + +Data can be normally inserted into the masked table without alteration. +For example: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=data-insert-ddm] +---- + +The `SELECT` query will return the masked data. +The masking function will be automatically applied to the column values. + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=select-with-masked-column] +---- + +An `ALTER TABLE` query can be used to make changes to a masking function on a table column. + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=table-alter-ddm] +---- + +In a similar way, a masking function can be detached from a column with an `ALTER TABLE` query: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=table-alter-ddm-drop-mask] +---- + +== Permissions + +Ordinary users are created without the `UNMASK` permission and will see masked values. +Giving a user the `UNMASK` permission allows them to retrieve the unmasked values of masked columns. +Superusers are automatically created with the `UNMASK` permission, +and will see the unmasked values in a `SELECT` query results. + +For example, suppose that we have a table with masked columns: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=table-create-ddm] +---- + +And we insert some data into the table: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=data-insert-ddm] +---- + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=select-without-unmask-permission] +---- + +Then we create two users with `SELECT` permission for the table, but we only grant the `UNMASK` permission to one of the users: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=users-grant-ddm] +---- + +The user with the `UNMASK` permission can see the clear, unmasked data: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=select-with-unmask-permission] +---- + +The user without the `UNMASK` permission can only see the masked data: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=select-without-unmask-permission] +---- + +The `UNMASK` permission works like any other permission, and can be revoked at will: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=users-revoke-ddm] +---- + +Please note that, when authentication is disabled, the anonymous default user has all the permissions, including the `UNMASK` permission, and can see the unmasked data. +In other words, attaching data masking functions to columns only makes sense if authentication is enabled. + +Only users with the `UNMASK` permission are allowed to use masked columns in the `WHERE` clause of a `SELECT` query. +Users without the `UNMASK` permission cannot use this feature. +This feature prevents malicious users seeing clear data by running exhaustive, brute force queries. +The user without the `UNMASK` permission will see the following: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=select-without-select-masked] +---- + +There are some use cases where a trusted database user needs to produce masked data that untrusted external users will query. +For instance, a trusted app can connect to the database and with a query extract masked data that will be displayed to its end users. +In that case, the trusted user (the app) can be given the `SELECT_MASKED` permission. +This permission lets the user query masked columns in the `WHERE` clause of a `SELECT` query, +while still only seeing the masked data in the query results: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=select-with-select-masked] +---- + +== Custom functions + +xref:developing/cql/functions.adoc#user-defined-functions[User-defined functions (UDFs)] can be attached to a table column. +The UDFs used for masking should belong to the same keyspace as the masked table. +The column value to mask will be passed as the first argument of the attached UDF. +Thus, the UDFs attached to a column should have at least one argument, +and that argument should have the same type as the masked column. +Also, the attached UDF should return values of the same type as the masked column: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=table-create-ddm-udt] +---- + +This creates a dependency between the table schema and the functions. +Any attempt to drop the function will be rejected while this dependency exists. +Consequently, you must drop the mask column in the table before dropping the function: + +[source,cql] +---- +include::example$CQL/dynamic-data-masking.cql[tag=table-alter-ddm-drop-mask] +---- + +Dropping the column, or its containing table, or its containing keyspace will also remove the dependency. + +xref:developing/cql/functions.adoc#aggregate-functions[Aggregate functions] cannot be used as masking functions. diff --git a/doc/modules/cassandra/pages/developing/cql/dynamic_data_masking.adoc b/doc/modules/cassandra/pages/developing/cql/dynamic_data_masking.adoc deleted file mode 100644 index 16599c9053..0000000000 --- a/doc/modules/cassandra/pages/developing/cql/dynamic_data_masking.adoc +++ /dev/null @@ -1,179 +0,0 @@ -= Dynamic Data Masking - -Dynamic data masking (DDM) allows to obscure sensitive information while still allowing access to the masked columns. -DDM doesn't change the stored data. Instead, it just presents the data in its obscured form during `SELECT` queries. -This aims to provide some degree of protection against accidental data exposure. However, it's important to know that -anyone with direct access to the sstable files will be able to read the clear data. - -== Masking functions - -DDM is based on a set of CQL native functions that obscure sensitive information. The available functions are: - -include::partial$masking_functions.adoc[] - -Those functions can be discretionarily used on `SELECT` queries to get an obscured view of the data. For example: - -[source,cql] ----- -include::example$CQL/select_with_mask_functions.cql[] ----- - -== Attaching masking functions to table columns - -The masking functions can be permanently attached to any column of a table. -If a masking columns is defined, `SELECT` queries will always return the column values in their masked form. -The masking will be transparent to the users running `SELECT` queries, -so their only way to know that a column is masked will be to consult the table definition. - -This is an optional feature that should be enabled with the `dynamic_data_masking_enabled` property in `cassandra.yaml`, -since it's disabled by default. - -The masks of the columns of a table can be defined on `CREATE TABLE` queries: - -[source,cql] ----- -include::example$CQL/ddm_create_table.cql[] ----- - -Note that in the example above we are referencing the `mask_inner` function with two arguments. -However, that CQL function actually has three arguments when explicitely used on `SELECT` queries. -The first argument is always ommitted when attaching the function to a schema column. -The value of that first argument is always interpreted as the value of the masked column, in this case a `text` column. -For the same reason the call to `mask_default` attached to the column doesn't have any argument, -even when that function requires one argument when explicitely used on `SELECT` queries. - -Data can be inserted into the masked table as usual. For example: - -[source,cql] ----- -include::example$CQL/ddm_insert_data.cql[] ----- - -The attached column masks will make `SELECT` queries automatically return masked data, -without the need of including the masking function on the query: - -[source,cql] ----- -include::example$CQL/ddm_select_with_masked_columns.cql[] ----- - -The masking function attached to a column can be changed with an `ALTER TABLE` query: - -[source,cql] ----- -include::example$CQL/ddm_alter_mask.cql[] ----- - -In a similar way, a masking function can be dettached from a column with an `ALTER TABLE` query: - -[source,cql] ----- -include::example$CQL/ddm_drop_mask.cql[] ----- - -== Permissions - -The `UNMASK` permission allows users to retrieve the unmasked values of masked columns. -Ordinary users are created without the `UNMASK` permission and will see masked values. -Superusers are created with the `UNMASK` permission, -and will be able to see the unmasked values in a SELECT query results. - -As an example, suppose that we have a table with masked columns: - -[source,cql] ----- -include::example$CQL/ddm_create_table.cql[] ----- - -And we insert some data into the table: - -[source,cql] ----- -include::example$CQL/ddm_insert_data.cql[] ----- - -[source,cql] ----- -include::example$CQL/ddm_select_without_unmask_permission.cql[] ----- - -Then we create two users with `SELECT` permission for the table, but we only grant the `UNMASK` permission to one of -the users: - -[source,cql] ----- -include::example$CQL/ddm_create_users.cql[] ----- - -We can now see that the user with the `UNMASK` permission can see the clear data, unmasked: - -[source,cql] ----- -include::example$CQL/ddm_select_with_unmask_permission.cql[] ----- - -However, the user without the `UNMASK` permission can only see the masked data: - -[source,cql] ----- -include::example$CQL/ddm_select_without_unmask_permission.cql[] ----- - -The `UNMASK` permission works as any other permission. Thus, it can be revoked in any moment: - -[source,cql] ----- -include::example$CQL/ddm_revoke_unmask.cql[] ----- - -Please note that the anonymous user that is used when authentication is disabled has all the permissions. -Since it includes the `UNMASK` permission, that anonymous user will always see the clear data. -In other words, attaching data masking functions to columns only makes sense if authentication is enabled. - -Users without the `UNMASK` permission are not allowed to use masked columns in the `WHERE` clause of a `SELECT` query. -This prevents malicious users from figuring out the clear data by running exhaustive queries. For example: - -[source,cql] ----- -include::example$CQL/ddm_select_without_select_masked.cql[] ----- - -However, there are some use cases where trusted database users just need a useful way to produce masked data -that will be served to untrusted external users. -For example, a trusted app can connect to the database and extract masked data that will be served to its end users. -In that case the trusted user (the app) can be given the `SELECT_MASKED` permission. -That permission allows to use masked columns in the `WHERE` clause of a `SELECT` query, -while still seeing the masked data in the query results. For instance: - -[source,cql] ----- -include::example$CQL/ddm_select_with_select_masked.cql[] ----- - -== Custom functions - -xref:developing/cql/functions.adoc#user-defined-scalar-functions[User-defined functions (UDFs)] can be attached to a table column. -The UDFs used for masking should belong to the same keyspace as the masked table. -The column value to mask will be passed as the first argument of the attached UDF. -Thus, the UDFs attached to a column should have at least one argument, -and that argument should have the same type as the masked column. -Also, the attached UDF should return values of the same type as the maked column. For instance: - -[source,cql] ----- -include::example$CQL/ddm_create_table_with_udf.cql[] ----- - -This creates a dependency between the table schema and the functions. -Any attempt to drop the function will be rejected while this dependency exists. -Thus, to drop the function you should first drop the mask. -This can be done with: - -[source,cql] ----- -include::example$CQL/ddm_drop_mask.cql[] ----- - -Dropping the column, or its containing table, or its containing keyspace would also remove the dependency. - -xref:developing/cql/functions.adoc#aggregate-functions[Aggregate functions] cannot be used as masking functions. diff --git a/doc/modules/cassandra/pages/developing/cql/index.adoc b/doc/modules/cassandra/pages/developing/cql/index.adoc index 411977788f..3b31a4d381 100644 --- a/doc/modules/cassandra/pages/developing/cql/index.adoc +++ b/doc/modules/cassandra/pages/developing/cql/index.adoc @@ -13,13 +13,13 @@ For that reason, when used in this document, these terms (tables, rows and colum * xref:developing/cql/types.adoc[Data types] * xref:developing/cql/ddl.adoc[Data definition language] * xref:developing/cql/dml.adoc[Data manipulation language] +* xref:developing/cql/dynamic-data-masking.adoc[Dynamic data masking] * xref:developing/cql/operators.adoc[Operators] * xref:developing/cql/indexing/indexing-concepts.adoc[Indexing] * xref:developing/cql/mvs.adoc[Materialized views] * xref:developing/cql/functions.adoc[Functions] * xref:developing/cql/json.adoc[JSON] * xref:developing/cql/security.adoc[CQL security] -* xref:developing/cql/dynamic_data_masking.adoc[Dynamic data masking] * xref:developing/cql/triggers.adoc[Triggers] * xref:developing/cql/appendices.adoc[Appendices] * xref:developing/cql/changes.adoc[Changes] \ No newline at end of file diff --git a/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-query.adoc b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-query.adoc index 1868d1fec9..a6593b66d7 100644 --- a/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-query.adoc +++ b/doc/modules/cassandra/pages/developing/cql/indexing/sai/sai-query.adoc @@ -4,7 +4,7 @@ The xref:cassandra:getting-started/sai-quickstart.adoc[SAI quickstart] focuses only on defining multiple indexes based on non-primary key columns (a very useful feature). Let's explore other options using some examples of how you can run queries on tables that have differently defined SAI indexes. -include::developing:partial$sai/sai-only-select.adoc[] +include::cassandra:partial$sai/sai-only-select.adoc[] // IS THERE AN EXAMPLE OF // WITH OPTIONS = {'case_sensitive': false, 'normalize': true }; diff --git a/doc/modules/cassandra/pages/new/index.adoc b/doc/modules/cassandra/pages/new/index.adoc index 0980244fc6..5d36e59b73 100644 --- a/doc/modules/cassandra/pages/new/index.adoc +++ b/doc/modules/cassandra/pages/new/index.adoc @@ -12,10 +12,10 @@ This section covers the new features in Apache Cassandra 5.0. * More guardrails: https://github.com/apache/cassandra/blob/trunk/NEWS.txt[NEWS.txt] * TTL and writetime on collections and UDTs: xref:cassandra:developing/cql/dml.html#writetime-and-ttl-function[Docs], https://issues.apache.org/jira/browse/CASSANDRA-8877[JIRA ticket] * New vector data type: xref:cassandra:reference/vector-data-type.adoc[Docs], https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-30%3A+Approximate+Nearest+Neighbor%28ANN%29+Vector+Search+via+Storage-Attached+Indexes[CEP-30], https://issues.apache.org/jira/browse/CASSANDRA-18504[JIRA ticket] -* New vector similarity functions: xref:cassandra:vector-search/overview.adoc[Docs], https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-30%3A+Approximate+Nearest+Neighbor%28ANN%29+Vector+Search+via+Storage-Attached+Indexes[CEP-30],https://issues.apache.org/jira/browse/CASSANDRA-18640[JIRA ticket] -* Unified Compaction Strategy: xref:cassandra:managing/operating/compaction/ucs.adoc[Docs], https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-26%3A+Unified+Compaction+Strategy[CEP-26], (https://issues.apache.org/jira/browse/CASSANDRA-18397)[CASSANDRA-18397] +* New vector similarity functions: xref:cassandra:vector-search/overview.adoc[Docs], https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-30%3A+Approximate+Nearest+Neighbor%28ANN%29+Vector+Search+via+Storage-Attached+Indexes[CEP-30], https://issues.apache.org/jira/browse/CASSANDRA-18640[JIRA ticket] +* Unified Compaction Strategy: xref:cassandra:managing/operating/compaction/ucs.adoc[Docs], https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-26%3A+Unified+Compaction+Strategy[CEP-26], https://issues.apache.org/jira/browse/CASSANDRA-18397[JIRA ticket] * New Mathematical CQL functions: abs, exp, log, log10 and round: xref:cassandra:developing/cql/functions.adoc[Docs], https://issues.apache.org/jira/browse/CASSANDRA-17221[JIRA ticket] -* Dynamic Data Masking: xref:cassandra:developing/cql/dynamic_data_masking.adoc[Docs], https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-20%3A+Dynamic+Data+Masking[CEP-20], https://issues.apache.org/jira/browse/CASSANDRA-17940[CASSANDRA-17940] +* Dynamic Data Masking: xref:cassandra:developing/cql/dynamic-data-masking.adoc[Docs], https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-20%3A+Dynamic+Data+Masking[CEP-20], https://issues.apache.org/jira/browse/CASSANDRA-17940[JIRA ticket] * New CIDR authorizer: https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-33%3A+CIDR+filtering+authorizer[CEP-33], https://issues.apache.org/jira/browse/CASSANDRA-18592[JIRA ticket] * Extend maximum expiration date (TTL): https://github.com/apache/cassandra/blob/trunk/NEWS.txt[NEWS.txt], https://issues.apache.org/jira/browse/CASSANDRA-14227[JIRA ticket] * New CQL native scalar functions for collections: https://issues.apache.org/jira/browse/CASSANDRA-18060[JIRA ticket] diff --git a/doc/modules/cassandra/partials/masking_functions.adoc b/doc/modules/cassandra/partials/masking_functions.adoc index a91f168067..528da7d825 100644 --- a/doc/modules/cassandra/partials/masking_functions.adoc +++ b/doc/modules/cassandra/partials/masking_functions.adoc @@ -2,7 +2,9 @@ |=== |Function | Description -| `mask_null(value)` | Replaces the first argument with a `null` column. The returned value is always a non-existent column, and not a not-null column representing a `null` value. +| `mask_null(value)` +| Replaces the first argument with a `null` column. +The returned value is always a non-existent column, and not a not-null column representing a `null` value. Examples: @@ -10,12 +12,13 @@ Examples: `mask_null(123)` -> `null` -| `mask_default(value)` | Replaces its argument by an arbitrary, fixed default value of the same type. +| `mask_default(value)` +| Replaces its argument by an arbitrary, fixed default value of the same type. This will be `\***\***` for text values, zero for numeric values, `false` for booleans, etc. -Variable-length multivalued types such as lists, sets and maps are masked as empty collections. +Variable-length multi-valued types such as lists, sets and maps are masked as empty collections. -Fixed-length multivalued types such as tuples, UDTs and vectors are masked by replacing each of their values by the default masking value of the value type. +Fixed-length multi-valued types such as tuples, user-defined types (UDTs) and vectors are masked by replacing each of their values by the default masking value of the value type. Examples: @@ -27,7 +30,9 @@ Examples: `mask_default((vector) [1, 2, 3])` -> `[0, 0, 0]` -| `mask_replace(value, replacement])` | Replaces the first argument by the replacement value on the second argument. The replacement value needs to have the same type as the replaced value. +| `mask_replace(value, replacement])` +| Replaces the first argument by the replacement value on the second argument. +The replacement value needs to have the same type as the replaced value. Examples: @@ -35,7 +40,10 @@ Examples: `mask_replace(123, -1)` -> `-1` -| `mask_inner(value, begin, end, [padding])` | Returns a copy of the first `text`, `varchar` or `ascii` argument, replacing each character except the first and last ones by a padding character. The 2nd and 3rd arguments are the size of the exposed prefix and suffix. The optional 4th argument is the padding character, `\*` by default. +| `mask_inner(value, begin, end, [padding])` +| Returns a copy of the first `text`, `varchar` or `ascii` argument, replacing each character except the first and last ones by a padding character. +The second and third arguments are the size of the exposed prefix and suffix. +The optional fourth argument is the padding character, `\*` by default. Examples: @@ -47,7 +55,10 @@ Examples: `mask_inner('Alice', 2, 1, '\#')` -> `'Al##e'` -| `mask_outer(value, begin, end, [padding])` | Returns a copy of the first `text`, `varchar` or `ascii` argument, replacing the first and last character by a padding character. The 2nd and 3rd arguments are the size of the exposed prefix and suffix. The optional 4th argument is the padding character, `\*` by default. +| `mask_outer(value, begin, end, [padding])` +| Returns a copy of the first `text`, `varchar` or `ascii` argument, replacing the first and last character by a padding character. +The second and third arguments are the size of the exposed prefix and suffix. +The optional fourth argument is the padding character, `\*` by default. Examples: @@ -59,7 +70,10 @@ Examples: `mask_outer('Alice', 2, 1, '\#')` -> `'##ic#'` -| `mask_hash(value, [algorithm])` | Returns a `blob` containing the hash of the first argument. The optional 2nd argument is the hashing algorithm to be used, according the available Java security provider. The default hashing algorithm is `SHA-256`. +| `mask_hash(value, [algorithm])` +| Returns a `blob` containing the hash of the first argument. +The optional second argument is the hashing algorithm to be used, according the available Java security provider. +The default hashing algorithm is `SHA-256`. Examples: