Skip to content

Commit

Permalink
[docs] Prevent DLS/FLS if replication is assigned
Browse files Browse the repository at this point in the history
  • Loading branch information
jakelandis committed May 20, 2024
1 parent 05a2046 commit 1f42211
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ At least one of them must be specified.
`names`:::: (required, list) A list of indices or name patterns to which the
permissions in this entry apply.
`field_security`:::: (optional, object) The document fields that the owners of the role have
read access to. For more information, check <<field-and-document-access-control>>.
read access to. This may not be set when the `replication` is also defined. For more information,
see <<ccx-apikeys-dls-fls, Field and document level security with Cross-cluster API keys>>.
`query`:::: (optional) A search query that defines the documents the owners of the role have
read access to. A document within the specified indices must match this query to be accessible by the owners of the role. For more information, check
<<field-and-document-access-control>>.
read access to. A document within the specified indices must match this query to be accessible by the
owners of the role. This may not be set when the `replication` is also defined. For more information,
see <<ccx-apikeys-dls-fls, Field and document level security with Cross-cluster API keys>>.
`allow_restricted_indices`:::: (optional, boolean) This needs to be set to `true` (default
is `false`) if the patterns in the `names` field should cover <<system-indices,system indices>>.
`replication`::: (optional, list) A list of indices permission entries for cross-cluster replication.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
=== Setting up field and document level security

You can control access to data within a data stream or index by adding field and document level
security permissions to a role.
<<field-level-security,Field level security permissions>> restrict access to
particular fields within a document.
<<document-level-security,Document level security permissions>> restrict access
security permissions to a role.
<<field-level-security,Field level security permissions>> restrict access to
particular fields within a document.
<<document-level-security,Document level security permissions>> restrict access
to particular documents.

NOTE: Document and field level security is currently meant to operate with
Expand Down Expand Up @@ -59,3 +59,24 @@ documents by index instead.

include::role-templates.asciidoc[]
include::set-security-user.asciidoc[]


[[ccx-apikeys-dls-fls]]
==== Field and document level security with Cross-cluster API keys

Cross-cluster API keys can be used to authenticate requests to a remote cluster.
`access` controls Cross Cluster Search, and `replication` controls Cross Cluster Replication.

For reasons similar those described in <<multiple-roles-dls-fls,Multiple roles with document and field level security>>,
it is not allowed to create a single Cross-cluster API key with both `access` and `replication` where
`access` has document or field level security defined.

If you need both `access` and `replication` with the need to
define document or field level security, create two separate Cross-cluster API keys. One with `access` that defines
document or field level security, and another with `replication`. You will need to also setup two different
remote connections (to the same cluster), with each named connection using the appropriate Cross-cluster API key.





Original file line number Diff line number Diff line change
Expand Up @@ -162,18 +162,18 @@ public static void checkForInvalidLegacyRoleDescriptors(String apiKeyId, List<Ro
final String[] clusterPrivileges = roleDescriptor.getClusterPrivileges();
// only need to check if both "search" and "replication" are defined
// no need to check for DLS if set of cluster privileges are not the set used pre 8.14
final String[] pre8_14ClusterPrivileges = { "cross_cluster_search", "cross_cluster_replication" };
final boolean hasBoth = Arrays.equals(clusterPrivileges, pre8_14ClusterPrivileges);
final String[] legacyClusterPrivileges = { "cross_cluster_search", "cross_cluster_replication" };
final boolean hasBoth = Arrays.equals(clusterPrivileges, legacyClusterPrivileges);
if (false == hasBoth) {
return;
}

final RoleDescriptor.IndicesPrivileges[] indicesPrivileges = roleDescriptor.getIndicesPrivileges();
for (RoleDescriptor.IndicesPrivileges indexPrivilege : indicesPrivileges) {
final String[] privileges = indexPrivilege.getPrivileges();
final String[] pre8_14IndicesPrivileges = { "read", "read_cross_cluster", "view_index_metadata" };
final String[] legacyIndicesPrivileges = { "read", "read_cross_cluster", "view_index_metadata" };
// find the "search" privilege, no need to check for DLS if set of index privileges are not the set used pre 8.14
if (Arrays.equals(privileges, pre8_14IndicesPrivileges)) {
if (Arrays.equals(privileges, legacyIndicesPrivileges)) {
if (indexPrivilege.isUsingDocumentOrFieldLevelSecurity()) {
throw new IllegalArgumentException(
"Cross cluster API key ["
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,37 +246,39 @@ public void testBuildForSearchAndReplicationWithDLSandFLS() throws IOException {
}

public void testCheckForInvalidLegacyRoleDescriptors() {
final String[] pre8_14ClusterPrivileges_searchAndReplication = { "cross_cluster_search", "cross_cluster_replication" };
final String[] pre8_14ClusterPrivileges_searchOnly = { "cross_cluster_search" };
final String[] pre8_14IndexPrivileges = { "read", "read_cross_cluster", "view_index_metadata" };
// legacy here is in reference to RCS API privileges pre GA, we know which privileges are used in those versions and is used for
// minor optimizations. the "legacy" privileges might also be the same as in newer versions, and that is OK too.
final String[] legacyClusterPrivileges_searchAndReplication = { "cross_cluster_search", "cross_cluster_replication" };
final String[] legacyClusterPrivileges_searchOnly = { "cross_cluster_search" };
final String[] legacyIndexPrivileges = { "read", "read_cross_cluster", "view_index_metadata" };
final String[] otherPrivileges = randomArray(1, 5, String[]::new, () -> randomAlphaOfLength(5));
String apiKeyId = randomAlphaOfLength(5);
RoleDescriptor.IndicesPrivileges pre8_14SearchIndexPrivileges_noDLS = RoleDescriptor.IndicesPrivileges.builder()
RoleDescriptor.IndicesPrivileges legacySearchIndexPrivileges_noDLS = RoleDescriptor.IndicesPrivileges.builder()
.indices(randomAlphaOfLength(5))
.privileges(pre8_14IndexPrivileges)
.privileges(legacyIndexPrivileges)
.build();
RoleDescriptor.IndicesPrivileges pre8_14SearchIndexPrivileges_withDLS = RoleDescriptor.IndicesPrivileges.builder()
RoleDescriptor.IndicesPrivileges legacySearchIndexPrivileges_withDLS = RoleDescriptor.IndicesPrivileges.builder()
.indices(randomAlphaOfLength(5))
.privileges(pre8_14IndexPrivileges)
.privileges(legacyIndexPrivileges)
.query("{\"term\":{\"tag\":42}}")
.build();
RoleDescriptor.IndicesPrivileges otherIndexPrivilege = RoleDescriptor.IndicesPrivileges.builder()
.indices(randomAlphaOfLength(5))
.privileges(otherPrivileges) // replication has fixed index privileges, but for this test we don't care about the actual values
.build();

// role descriptor emulates pre 8.14 with search and replication with DLS: this is the primary case we are trying to catch
RoleDescriptor pre8_14ApiKeyRoleDescriptor_withSearchAndReplication_withDLS = new RoleDescriptor(
// role descriptor emulates pre GA with search and replication with DLS: this is the primary case we are trying to catch
RoleDescriptor legacyApiKeyRoleDescriptor_withSearchAndReplication_withDLS = new RoleDescriptor(
ROLE_DESCRIPTOR_NAME,
pre8_14ClusterPrivileges_searchAndReplication,
new RoleDescriptor.IndicesPrivileges[] { pre8_14SearchIndexPrivileges_withDLS, otherIndexPrivilege },
legacyClusterPrivileges_searchAndReplication,
new RoleDescriptor.IndicesPrivileges[] { legacySearchIndexPrivileges_withDLS, otherIndexPrivilege },
null
);
IllegalArgumentException exception = expectThrows(
IllegalArgumentException.class,
() -> CrossClusterApiKeyRoleDescriptorBuilder.checkForInvalidLegacyRoleDescriptors(
apiKeyId,
List.of(pre8_14ApiKeyRoleDescriptor_withSearchAndReplication_withDLS)
List.of(legacyApiKeyRoleDescriptor_withSearchAndReplication_withDLS)
)
);
assertThat(
Expand All @@ -287,32 +289,32 @@ public void testCheckForInvalidLegacyRoleDescriptors() {
+ "] is invalid: search does not support document or field level security if replication is assigned"
)
);
// role descriptor emulates search only with DLS, this could be a valid role descriptor for pre/post 8.14
// role descriptor emulates search only with DLS, this could be a valid role descriptor for pre/post GA
RoleDescriptor apiKeyRoleDescriptor_withSearch_withDLS = new RoleDescriptor(
ROLE_DESCRIPTOR_NAME,
pre8_14ClusterPrivileges_searchOnly,
new RoleDescriptor.IndicesPrivileges[] { pre8_14SearchIndexPrivileges_withDLS },
legacyClusterPrivileges_searchOnly,
new RoleDescriptor.IndicesPrivileges[] { legacySearchIndexPrivileges_withDLS },
null
);
noErrorCheckRoleDescriptor(apiKeyRoleDescriptor_withSearch_withDLS);

// role descriptor emulates search and replication without DLS, this could be a valid role descriptor for pre/post 8.14
// role descriptor emulates search and replication without DLS, this could be a valid role descriptor for pre/post GA
RoleDescriptor apiKeyRoleDescriptor_withSearchAndReplication_noDLS = new RoleDescriptor(
ROLE_DESCRIPTOR_NAME,
pre8_14ClusterPrivileges_searchAndReplication,
new RoleDescriptor.IndicesPrivileges[] { pre8_14SearchIndexPrivileges_noDLS, otherIndexPrivilege },
legacyClusterPrivileges_searchAndReplication,
new RoleDescriptor.IndicesPrivileges[] { legacySearchIndexPrivileges_noDLS, otherIndexPrivilege },
null
);
noErrorCheckRoleDescriptor(apiKeyRoleDescriptor_withSearchAndReplication_noDLS);

// role descriptor that will never have search and replication with DLS but may have other privileges
RoleDescriptor notpre8_14_apiKeyRoleDescriptor_withSearchAndReplication_DLS = new RoleDescriptor(
RoleDescriptor notLegacyApiKeyRoleDescriptor_withSearchAndReplication_DLS = new RoleDescriptor(
ROLE_DESCRIPTOR_NAME,
otherPrivileges,
new RoleDescriptor.IndicesPrivileges[] { otherIndexPrivilege, otherIndexPrivilege },
null
);
noErrorCheckRoleDescriptor(notpre8_14_apiKeyRoleDescriptor_withSearchAndReplication_DLS);
noErrorCheckRoleDescriptor(notLegacyApiKeyRoleDescriptor_withSearchAndReplication_DLS);
}

private void noErrorCheckRoleDescriptor(RoleDescriptor roleDescriptor) {
Expand Down

0 comments on commit 1f42211

Please sign in to comment.