diff --git a/docs/changelog/112226.yaml b/docs/changelog/112226.yaml new file mode 100644 index 0000000000000..ac36c0c0fe4e2 --- /dev/null +++ b/docs/changelog/112226.yaml @@ -0,0 +1,6 @@ +pr: 112226 +summary: "Fix \"unexpected field [remote_cluster]\" for CCS (RCS 1.0) when using API\ + \ key that references `remote_cluster`" +area: Security +type: bug +issues: [] diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java index 6ef2441011e6a..3e3b1178b372c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java @@ -54,6 +54,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import static org.elasticsearch.TransportVersions.ROLE_REMOTE_CLUSTER_PRIVS; import static org.elasticsearch.transport.RemoteClusterPortSettings.TRANSPORT_VERSION_ADVANCED_REMOTE_CLUSTER_SECURITY; import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg; import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg; @@ -1319,6 +1320,24 @@ private static Map maybeRewriteMetadataForApiKeyRoleDescriptors( ) ); } + + if (authentication.getEffectiveSubject().getTransportVersion().onOrAfter(ROLE_REMOTE_CLUSTER_PRIVS) + && streamVersion.before(ROLE_REMOTE_CLUSTER_PRIVS)) { + metadata = new HashMap<>(metadata); + metadata.put( + AuthenticationField.API_KEY_ROLE_DESCRIPTORS_KEY, + maybeRemoveRemoteClusterFromRoleDescriptors( + (BytesReference) metadata.get(AuthenticationField.API_KEY_ROLE_DESCRIPTORS_KEY) + ) + ); + metadata.put( + AuthenticationField.API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY, + maybeRemoveRemoteClusterFromRoleDescriptors( + (BytesReference) metadata.get(AuthenticationField.API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY) + ) + ); + } + if (authentication.getEffectiveSubject().getTransportVersion().onOrAfter(VERSION_API_KEY_ROLES_AS_BYTES) && streamVersion.before(VERSION_API_KEY_ROLES_AS_BYTES)) { metadata = new HashMap<>(metadata); @@ -1397,7 +1416,15 @@ private static BytesReference convertRoleDescriptorsMapToBytes(Map roleDescriptor = (Map) value; - boolean removed = roleDescriptor.remove(RoleDescriptor.Fields.REMOTE_INDICES.getPreferredName()) != null; + boolean removed = roleDescriptor.remove(topLevelField) != null; if (removed) { removedAtLeastOne.set(true); } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authc/AuthenticationTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authc/AuthenticationTests.java index 1e33a7f54394b..3d4d6106a7eaf 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authc/AuthenticationTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authc/AuthenticationTests.java @@ -1089,6 +1089,51 @@ public void testMaybeRewriteMetadataForApiKeyRoleDescriptorsWithRemoteIndices() ); } + public void testMaybeRewriteMetadataForApiKeyRoleDescriptorsWithRemoteCluster() { + final String apiKeyId = randomAlphaOfLengthBetween(1, 10); + final String apiKeyName = randomAlphaOfLengthBetween(1, 10); + final Map metadata = Map.ofEntries( + entry(AuthenticationField.API_KEY_ID_KEY, apiKeyId), + entry(AuthenticationField.API_KEY_NAME_KEY, apiKeyName), + entry(AuthenticationField.API_KEY_ROLE_DESCRIPTORS_KEY, new BytesArray(""" + {"base_role":{"cluster":["all"], + "remote_cluster":[{"privileges":["monitor_enrich"],"clusters":["*"]}] + }}""")), + entry(AuthenticationField.API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY, new BytesArray(""" + {"limited_by_role":{"cluster":["*"], + "remote_cluster":[{"privileges":["monitor_enrich"],"clusters":["*"]}] + }}""")) + ); + + final Authentication original = AuthenticationTestHelper.builder() + .apiKey() + .metadata(metadata) + .transportVersion(TransportVersions.ROLE_REMOTE_CLUSTER_PRIVS) + .build(); + + // pick a version before that of the authentication instance to force a rewrite + final TransportVersion olderVersion = TransportVersionUtils.randomVersionBetween( + random(), + Authentication.VERSION_API_KEY_ROLES_AS_BYTES, + TransportVersionUtils.getPreviousVersion(original.getEffectiveSubject().getTransportVersion()) + ); + + final Map rewrittenMetadata = original.maybeRewriteForOlderVersion(olderVersion) + .getEffectiveSubject() + .getMetadata(); + assertThat(rewrittenMetadata.keySet(), equalTo(original.getAuthenticatingSubject().getMetadata().keySet())); + assertThat( + ((BytesReference) rewrittenMetadata.get(AuthenticationField.API_KEY_ROLE_DESCRIPTORS_KEY)).toBytesRef(), + equalTo(new BytesArray(""" + {"base_role":{"cluster":["all"]}}""").toBytesRef()) + ); + assertThat( + ((BytesReference) rewrittenMetadata.get(AuthenticationField.API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY)).toBytesRef(), + equalTo(new BytesArray(""" + {"limited_by_role":{"cluster":["*"]}}""").toBytesRef()) + ); + } + public void testMaybeRemoveRemoteIndicesFromRoleDescriptors() { final boolean includeClusterPrivileges = randomBoolean(); final BytesReference roleWithoutRemoteIndices = new BytesArray(Strings.format(""" diff --git a/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityBwcRestIT.java b/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityBwcRestIT.java index cbf735c66462c..17acd258ed34b 100644 --- a/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityBwcRestIT.java +++ b/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityBwcRestIT.java @@ -113,6 +113,12 @@ public void testBwcWithLegacyCrossClusterSearch() throws Exception { "privileges": ["read", "read_cross_cluster"], "clusters": ["my_remote_cluster"] } + ], + "remote_cluster": [ + { + "privileges": ["monitor_enrich"], + "clusters": ["*"] + } ] }"""); assertOK(adminClient().performRequest(putRoleRequest)); @@ -157,6 +163,12 @@ public void testBwcWithLegacyCrossClusterSearch() throws Exception { "privileges": ["read", "read_cross_cluster"], "clusters": ["my_remote_*", "non_existing_remote_cluster"] } + ], + "remote_cluster": [ + { + "privileges": ["monitor_enrich"], + "clusters": ["*"] + } ] } }