Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.14] [docs] Prevent DLS/FLS if replication is assigned (#108839) #108918

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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` field 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` field 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,27 @@ 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

<<security-api-create-cross-cluster-api-key, Cross-Cluster API keys>> can be used to authenticate
requests to a remote cluster. The `search` parameter defines permissions for cross-cluster search.
The `replication` parameter defines permissions for cross-cluster replication.

`replication` does not support any field or document level security. `search` supports field and document level security.

For reasons similar to those described in <<multiple-roles-dls-fls,Multiple roles with document and field level security>>,
you can't create a single cross-cluster API key with both the `search` and `replication` parameters if the
`search` parameter has document or field level security defined.

If you need to use both of these parameters, and you need to define document or field level security for the `search` parameter,
create two separate cross-cluster API keys, one using the `search` parameter,
and one using the `replication` parameter. You will also need to set up 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 @@ -154,18 +154,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 @@ -243,37 +243,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 @@ -284,32 +286,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