-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Introduce remote cluster security interceptor and authenticator #134245
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
Merged
slobodanadamovic
merged 29 commits into
elastic:main
from
slobodanadamovic:rcs-interceptor-refactoring
Sep 9, 2025
Merged
Changes from 26 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
063f212
add `RemoteClusterTransportInterceptor` interface
slobodanadamovic 6e6f79f
add RemoteClusterAuthenticationService interface
slobodanadamovic 9d5d6b3
change SecurityNetty4Transport to depend on RemoteClusterAuthenticati…
slobodanadamovic d3f2df9
add empty CrossClusterAccessTransportInterceptor that implements Remo…
slobodanadamovic 90a6c54
construct RemoteClusterTransportInterceptor in security interceptor
slobodanadamovic 9b25155
move interceptForCrossClusterAccessRequests and RCS_INTERNAL_ACTIONS_…
slobodanadamovic 5018173
move profile intialization logic into CrossClusterAccessTransportInte…
slobodanadamovic cbebc26
inline profile filters intitialization and remove initializeProfileFi…
slobodanadamovic 1325d3b
change order of parameters in shouldRemoveParentAuthorizationFromThre…
slobodanadamovic f07cd23
replace Optional<String> with boolean
slobodanadamovic 9a21578
implement isRemoteClusterConnection and invoke it instead resolving a…
slobodanadamovic 201fcad
delegate last call to remoteClusterCredentialsResolver and remove it
slobodanadamovic 179b339
remove other unused fields from SecurityServerTransportInterceptor
slobodanadamovic b493336
move RemoteClusterCredentials record
slobodanadamovic 71e94a4
move remote access headers check into RemoteClusterTransportInterceptor
slobodanadamovic 9b5aa27
add new SecurityServerTransportInterceptor constructor
slobodanadamovic 4d54614
construct RemoteClusterTransportInterceptor in security plugin and ca…
slobodanadamovic 99d7319
move to using new constructor part 1
slobodanadamovic 4981394
move to using new constructor part 2
slobodanadamovic af00bcd
move to using new constructor part 3
slobodanadamovic 35f2a44
spotless and remove repeat annotation
slobodanadamovic de29062
Merge branch 'main' of github.com:elastic/elasticsearch into rcs-inte…
slobodanadamovic b7b8aa7
introduce destructiveOperations field in test class
slobodanadamovic 3dd666f
rename tryAuthenticate to authenticateHeaders
slobodanadamovic 7450a83
renaming and javadoc
slobodanadamovic 84ed0b5
inline `interceptForCrossClusterAccessRequests` method
slobodanadamovic 75aa5ca
address review feedback
slobodanadamovic 25d558c
Merge branch 'main' into rcs-interceptor-refactoring
slobodanadamovic 2d96a32
Merge branch 'main' into rcs-interceptor-refactoring
slobodanadamovic File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
.../main/java/org/elasticsearch/xpack/security/authc/RemoteClusterAuthenticationService.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.security.authc; | ||
|
||
import org.elasticsearch.action.ActionListener; | ||
import org.elasticsearch.transport.TransportRequest; | ||
import org.elasticsearch.xpack.core.security.authc.Authentication; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* Service interface for authenticating remote cluster requests. | ||
* | ||
* <p> | ||
* This service handles authentication for cross-cluster requests. | ||
* It provides methods to authenticate both full transport requests | ||
* and credential headers only. | ||
*/ | ||
public interface RemoteClusterAuthenticationService { | ||
|
||
/** | ||
* Called to authenticates a remote cluster transport request. | ||
* | ||
* @param action the transport action being performed | ||
* @param request the transport request containing authentication headers | ||
* @param listener callback to receive the authenticated {@link Authentication} | ||
* object on success, or an exception on failure | ||
*/ | ||
void authenticate(String action, TransportRequest request, ActionListener<Authentication> listener); | ||
|
||
/** | ||
* This method is called to do a preliminary check if headers contain valid | ||
* remote cluster credentials, without the overhead of full authentication | ||
* processing. | ||
* | ||
* @param headers map of request headers containing authentication credentials | ||
* @param listener callback to receive {@code null} on successful authentication, | ||
* or an exception on authentication failure | ||
*/ | ||
void authenticateHeaders(Map<String, String> headers, ActionListener<Void> listener); | ||
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little bit confused about the contract of this method.
CrossClusterAccessAuthenticationService.tryAuthenticate
appears to require and authenticate the API Key, but not set theAuthentication
.I'm not quite sure what to make of that.
Perhaps the issue is what "if headers contain valid remote cluster credentials" actually means. I would read that and assume it was just checking whether the headers exist, but I think it might mean it does more than that. So, I guess my question is what doesn't it do? Is it just that it doesn't create an
Authentication
object?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is confusing. It's vague because the "validation" may mean different for cross-project than for RCS 2.0.
The order of method calls is:
authenticateHeaders
authenticate
The
authenticateHeaders
method validates and verifies the cross cluster credentials based on the received headers. It's called early during request processing, and only for requests on the remote cluster port. We only read headers (body is not consumed yet) at the stage when this method is called. This means that required cross cluster headers must be present and credentials must be valid. Fro RCS 2.0, there is no authentication nor role building happening at this stage, hence thewithout the overhead of full authentication processing
comment.But thinking further, this may not hold true in all use cases. This method could chose to build authentication object and stash it in the thread context, but it's not required at this phase. It gets required when we call
ServerTransportFilter
to process inbound message.Also, I leaned on the fact that all communication is going over RCS port and
REMOTE_CLUSTER_PROFILE
. This is explicit inSecurityNetty4Transport
, but implicit whenauthenticateHeaders
is called. I can try to make that contract clearer. And also make it explicit and changeRemoteClusterTransportInterceptor#getProfileTransportFilters
to provide a single filter for theREMOTE_CLUSTER_PROFILE
only. Currently, it's pretty generic as I wanted to keep flexibility to inject different transport filters for other profiles. We may not need to be able to do it, but I couldn't foresee it at this stage. Let me know what you think.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is where the semantic mismatch occurs. For me, verifying the api key (which, unless I'm horribly confused, is done in
authenticateHeaders
) is authentication. That's the primary credential that determines whether this is an authenticated request.We don't determine the identity of the end-user, their roles (intersection with the API key) or construct an
Authentication
object, but in my mental model, those are side-effects of the actual "authentication" which is checking the validity of the API key.I don't want to bike shed this, or argue about precise terminology, but it seems we draw the box around "authentication" differently, and your mindset is "unless we've done all the things we typically do during authentication, then we haven't done authentication" and mine is "if we've verified credentials, that's authentication".
So calling it
authenticateHeaders
but saying it doesn't do "full authentication" is confusing to me, I don't know what that means.Calling it
authenticateConnection
would be more meaningful to me, at least in the context of RCS2.0, but maybe that's not a terminology that fits with CPS (I'm not sure what you think we'll do in that method for CPS).Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think semantics are important and this should have read as For RCS 2.0, there is no authentication object nor role building happening at this stage.
I tried to make distinction between
authenticateHeaders
andauthenticate
methods, but failed to name correctly the other typical things we do after we execute authentication. Which could be summed up as "building authentication informations and stashing them in the thread context".Both methods are called for each request. I don't have full picture on why this was implemented the way it is, but I'm assuming it has to do with how thread context is handled at these different points in time.
We may need to do more refactoring here, because we execute authentication two times for the same RCS request. This may have not been a big of an issue for RCS 2.0, but I think it will be for CPS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can defer this conversation until we know what the CPS version looks like. That's going to require coming up with a clearer concept of why we have 2 methods and what we're supposed to do in each one, and trying to name the methods now is probably going to be a waste of effort.