feat(credentials): vend AWS credentials via AssumeRoleWithWebIdentity to avoid role chaining#7757
Conversation
📝 WalkthroughWalkthroughAWS credential vending now supports pod web-identity configuration. It resolves token files from properties or environment variables, routes scoped assumptions through ChangesAWS web-identity credential vending
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CredentialVendor
participant PodTokenFile
participant STS
CredentialVendor->>PodTokenFile: Read projected OIDC token
CredentialVendor->>STS: AssumeRoleWithWebIdentity
STS-->>CredentialVendor: Return scoped credentials
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rust/lance-namespace-impls/src/credentials.rs`:
- Around line 514-533: Update the pod web-identity selection around
ASSUME_VIA_POD_WEB_IDENTITY so that when the opt-in is true but
AWS_WEB_IDENTITY_TOKEN_FILE is unset, emit an operator-visible warning before
continuing with the existing chained AssumeRole fallback. Keep explicit
POD_WEB_IDENTITY_TOKEN_FILE behavior unchanged and do not warn when the opt-in
is disabled or when a later error will already provide the relevant signal.
In `@rust/lance-namespace-impls/src/credentials/aws.rs`:
- Around line 813-836: The test test_pod_web_identity_path_reads_token_file must
assert the concrete NamespaceError/lance_core::Error variant as well as the
existing message text; destructure or match the returned error before validating
its message, while preserving the missing-token-file scenario. Run cargo fmt to
normalize formatting in the affected file.
- Line 443: Remove the stale doc comment above assume_scoped. Keep the shared
routine’s documentation aligned with its generic role across API-key and
static-config credential vending, without describing it as specifically
performing API-key-validated AssumeRole.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e27d14be-4337-4dec-aef0-c0d94f02300c
📒 Files selected for processing (2)
rust/lance-namespace-impls/src/credentials.rsrust/lance-namespace-impls/src/credentials/aws.rs
… to avoid role chaining The api_key/static credential-vendor flows assume the target role with `AssumeRole` signed by the process's ambient credentials. When the process runs with temporary credentials (e.g. an IRSA / EKS pod role), that is *role chaining*, which STS hard-caps to 1 hour regardless of the role's MaxSessionDuration -- and the returned `Expiration` can exceed the token's real validity, so downstream credential caches keep serving a token S3 already considers expired. Add an optional pod web-identity path: when `pod_web_identity_token_file` is configured (property `credential_vendor.aws_assume_via_pod_web_identity=true`, resolving `AWS_WEB_IDENTITY_TOKEN_FILE`, or an explicit `credential_vendor.aws_pod_web_identity_token_file`), the scoped assume uses `AssumeRoleWithWebIdentity` with the pod's projected service-account OIDC token. This is a direct (non-chained) assumption that honors MaxSessionDuration (up to 12h) and reports an accurate expiration. The per-table scoped session policy, permission handling, and the default chained `AssumeRole` behavior are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
523d66e to
b073b77
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rust/lance-namespace-impls/src/credentials/aws.rs`:
- Around line 467-500: Extract the shared STS request construction from
vend_with_web_identity and the pod-token branch into a private helper such as
call_assume_role_with_web_identity, accepting the token, session name, policy,
and duration. Have both call sites use the helper while preserving their token
acquisition and surrounding behavior, and centralize the common error mapping
and credentials extraction there.
- Around line 470-477: Update the token_file read error mapping in
AwsCredentialVendor::new to use lance_core::Error::io(...) instead of
NamespaceError::Internal, preserving the existing contextual message and
propagation behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 5357d3d4-f385-4d50-b95d-e316a2048527
📒 Files selected for processing (2)
rust/lance-namespace-impls/src/credentials.rsrust/lance-namespace-impls/src/credentials/aws.rs
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…error chain Two observability improvements for the AWS credential vendor: - Apply full_error_chain() to the scoped AssumeRoleWithWebIdentity and AssumeRole failure sites so a vend failure reports the actual STS code and message (walked from the SDK error's source() chain) instead of a bare "service error". - Log once at vendor init which assume path was resolved: direct AssumeRoleWithWebIdentity via the pod token file, or the chained AssumeRole fallback. Warns when aws_assume_via_pod_web_identity=true but no token file is resolvable, which otherwise silently falls back to chaining. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
rust/lance-namespace-impls/src/credentials.rs (1)
229-233: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winDocument the complete public web-identity configuration surface with examples.
The new public configuration APIs explain their semantics but lack the required usage examples and cross-links.
rust/lance-namespace-impls/src/credentials.rs#L229-L233: document both property-key constants with accepted values, precedence, and a configuration example.rust/lance-namespace-impls/src/credentials/aws.rs#L76-L85: add an example for the token-file field and link to the builder.rust/lance-namespace-impls/src/credentials/aws.rs#L128-L135: add an example usingAwsCredentialVendorConfig::new(...).with_pod_web_identity_token_file(...).As per coding guidelines, “All public APIs must have documentation with examples, and documentation should link to relevant structs and methods.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rust/lance-namespace-impls/src/credentials.rs` around lines 229 - 233, Expand documentation at rust/lance-namespace-impls/src/credentials.rs:229-233 for both public web-identity property-key constants, including accepted values, precedence rules, and a configuration example. In rust/lance-namespace-impls/src/credentials/aws.rs:76-85, document the token-file field with an example and a link to its builder method; in rust/lance-namespace-impls/src/credentials/aws.rs:128-135, add an example using AwsCredentialVendorConfig::new(...) with with_pod_web_identity_token_file(...). Ensure all examples and cross-links accurately reference the relevant constants, struct, and methods.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@rust/lance-namespace-impls/src/credentials.rs`:
- Around line 229-233: Expand documentation at
rust/lance-namespace-impls/src/credentials.rs:229-233 for both public
web-identity property-key constants, including accepted values, precedence
rules, and a configuration example. In
rust/lance-namespace-impls/src/credentials/aws.rs:76-85, document the token-file
field with an example and a link to its builder method; in
rust/lance-namespace-impls/src/credentials/aws.rs:128-135, add an example using
AwsCredentialVendorConfig::new(...) with with_pod_web_identity_token_file(...).
Ensure all examples and cross-links accurately reference the relevant constants,
struct, and methods.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 91c65094-66e0-4c5b-af1f-bb5b9009fec8
📒 Files selected for processing (2)
rust/lance-namespace-impls/src/credentials.rsrust/lance-namespace-impls/src/credentials/aws.rs
Problem
The credential vendor's
api_keyand static flows assume the target role withAssumeRole, signed by the process's ambient credentials. When the vendor runs with temporary credentials — e.g. an IRSA / EKS pod role — that is role chaining, which STS hard-caps to 1 hour regardless of the role'sMaxSessionDuration.In that setup the returned
Expirationcan also exceed the token's real validity, so downstream credential caches (StorageOptionsAccessor,CachingCredentialVendor) keep serving a token S3 already rejects withExpiredTokenand never refresh — their expiry checks trust the inflatedexpires_at_millis.Change
Add an optional pod web-identity path. When
pod_web_identity_token_fileis configured — via propertycredential_vendor.aws_assume_via_pod_web_identity=true(resolving the EKS-injectedAWS_WEB_IDENTITY_TOKEN_FILE), or an explicitcredential_vendor.aws_pod_web_identity_token_file— the scoped assume usesAssumeRoleWithWebIdentitywith the pod's projected service-account OIDC token.AssumeRoleWithWebIdentityis a direct (non-chained) assumption, so STS honors the role'sMaxSessionDuration(up to 12h) and reports an accurate expiration.AssumeRolebehavior are unchanged.This change also improves error handling to propagate the object store error message in namespace error messages.
Tests
test_config_builderextended for the new field.test_pod_web_identity_path_reads_token_file— verifies the web-identity branch is selected and reads the token file.🤖 Co-authored with Claude Opus 4.8
Summary by CodeRabbit