Support EKS Pod Identity credentials in the S3 repository - #151614
Conversation
|
💚 CLA has been signed |
|
Pinging @elastic/es-distributed (Team:Distributed) |
This comment was marked as off-topic.
This comment was marked as off-topic.
DaveCTurner
left a comment
There was a problem hiding this comment.
Similar to the IRSA identity setup, we need to ask users to set this up themselves with env vars or system properties. We can't override system properties as you propose because this has JVM-wide repercussions.
|
Thanks, that makes sense. I've dropped the system-property override entirely. The plugin no longer touches So |
DaveCTurner
left a comment
There was a problem hiding this comment.
Thanks, ok, with all that gone it seems we could use repository-s3/aws-web-identity-token-file for EKS pod identity too, avoiding the need for this change entirely. Can you explain why the filename matters? Or am I missing something?
DaveCTurner
left a comment
There was a problem hiding this comment.
On reflection I think I accept the need for a different file name - it's not really the same thing, and it'd be confusing to overload this one location with two different meanings.
I left a couple of comments about the test, but overall it's doing pretty much the right thing.
The code comments aren't particularly useful (are they LLM-generated?) as they don't really describe the "why" of anything, only reiterating the "how". I think you could reasonably delete them, although comments linking to the relevant AWS docs might be useful in their places.
We also need to add to the reference manual the instructions about how to set up the relevant symlink, similar to the IRSA instructions here. Unfortunately that's in a different repository so will need a separate PR, but I'll be able to merge them together.
| private static final String BASE_PATH = PREFIX + "base_path"; | ||
| private static final String CLIENT = "pod_identity_credentials_client"; | ||
|
|
||
| private static final String POD_IDENTITY_TOKEN_FILE_CONTENTS = "test-pod-identity-auth-token-" + UUID.randomUUID(); |
There was a problem hiding this comment.
This UUID.randomUUID() is not a deterministic function of the test seed - I'd rather we stuck to using deterministic randomness. A little tricky here because deterministic randomness isn't available in static context so you'll need to use a Supplier<String> to delay the generation of this token until later when the test is running.
There was a problem hiding this comment.
Done — the token is now produced lazily by a memoized Supplier<String> (LazyInitializable over randomIdentifier()) instead of UUID.randomUUID() in static context, so it's a deterministic function of the test seed and isn't evaluated until the test runs. The same memoized supplier feeds both the config file and the fixture's verification (see the other thread), so they always observe the same token.
| private static final Supplier<String> regionSupplier = new DynamicRegionSupplier(); | ||
| private static final DynamicAwsCredentials dynamicCredentials = new DynamicAwsCredentials(regionSupplier, "s3"); | ||
|
|
||
| private static final Ec2ImdsHttpFixture podIdentityCredentialsFixture = new Ec2ImdsHttpFixture( |
There was a problem hiding this comment.
This appears to be approximately right but I'm not sure it's quite the same shape of response (e.g. does it include the RoleArn field?) and it doesn't verify that the token is correct.
There was a problem hiding this comment.
Split into the two parts you raised:
- Response shape: the credentials JSON the shared
Ec2ImdsHttpHandleremits already includesRoleArn(alongsideAccessKeyId/Expiration/SecretAccessKey/Token), which is whatContainerCredentialsProviderconsumes — so the shape was already correct. - Token verification: added.
Ec2ImdsServiceBuilder.authorizationTokenSupplier(...)makes the credentials endpoint require the exactAuthorizationheader the SDK sends (the token it read from the entitled file) and return 403 otherwise, mirroringAwsStsHttpHandler. It's opt-in (null by default) so the other IMDS/ECS consumers are unaffected. The pod-identity test wires in the same memoized token, so it now genuinely verifies the SDK forwarded the entitled token. Also added a fixture unit test (testAlternativeCredentialsEndpointRequiresAuthorizationToken) covering the missing/wrong/correct-token cases, and confirmed the fullRepositoryS3PodIdentityCredentialsRestITstill passes end-to-end.
There was a problem hiding this comment.
the credentials JSON the shared
Ec2ImdsHttpHandleremits already includesRoleArn
Indeed, but should it? Is this what the pod identity credentials endpoint returns? I couldn't find any docs confirming one way or the other.
There was a problem hiding this comment.
You're right, it shouldn't be there. I checked the eks-pod-identity-agent source (EksCredentialsResponse in pkg/credentials/model.go) and the pod identity endpoint returns AccessKeyId, SecretAccessKey, Token, AccountId and Expiration, so an AccountId and no RoleArn. The RoleArn was just leaking in from reusing the shared IMDS/ECS handler.
I added a podIdentityCredentialsResponse() option to the fixture so this test now returns AccountId and drops RoleArn, with a unit test asserting the shape. Pushed as a new commit.
d05a344 to
81d02b5
Compare
|
Thanks, I hope to get to this again next week. Please don't force-push to PRs under review -- we've lost the commits against which my earlier reviews were done. |
|
Sorry about the force-push, I won't rebase this branch again while it's under review. Pushed the RoleArn fix above as a new commit on top instead. Also opened the companion reference-manual PR you mentioned: elastic/docs-content#7182. It adds an EKS Pod Identity section next to the IRSA one. |
|
Thanks for the review, @DaveCTurner. Pushed
PTAL when you have a moment. The reference-manual docs are in the companion PR elastic/docs-content#7182. |
#7182) Documents how to use EKS Pod Identity credentials with the S3 snapshot repository, as a companion to elastic/elasticsearch#151614. Adds an "Using EKS Pod Identity for authentication" subsection alongside the existing IRSA instructions.
What
repository-s3already supports EKS IRSA (web identity) but not EKS Pod Identity. With the ES 9.x entitlements model, the AWS SDK'sContainerCredentialsProviderreads the Pod Identity auth token fromAWS_CONTAINER_AUTHORIZATION_TOKEN_FILE(/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token), which is outside therepository-s3entitlement-grantable area, so credential resolution fails withFailed to read token file.How
This mirrors the IRSA web-identity setup:
repository-s3grants read access to a fixed entitled location, and the operator points the credential source at it.entitlement-policy.yamlgrantsreadon a fixed config-relative symlinkrepository-s3/eks-pod-identity-token, alongside the existing IRSArepository-s3/aws-web-identity-token-filegrant.AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE(or theaws.containerAuthorizationTokenFilesystem property) at that entitled path and symlinks the Kubernetes-injected token there, exactly as they already do for the IRSA web-identity token.S3Servicedoes not override the env var or any system property, so there are no JVM-wide repercussions.Token rotation needs no extra handling:
ContainerCredentialsProviderre-reads the token on each resolution.Testing
./gradlew :modules:repository-s3:compileJava :modules:repository-s3:compileJavaRestTestJava :modules:repository-s3:checkstyleMain :modules:repository-s3:forbiddenApisMain— BUILD SUCCESSFUL./gradlew :modules:repository-s3:javaRestTest --tests "*RepositoryS3PodIdentityCredentialsRestIT"— BUILD SUCCESSFUL, 16 tests / 0 failures, run locally with Docker / testcontainers. The IT setsAWS_CONTAINER_AUTHORIZATION_TOKEN_FILEto${ES_PATH_CONF}/repository-s3/eks-pod-identity-tokento mirror the operator setup.Closes #106484
This change was implemented with the assistance of Claude Code (Opus 4.8). I have reviewed it and take responsibility for its correctness.