Skip to content

fix(store): resolve and refresh S3 credentials through the AWS default chain - #48

Open
brightsparc wants to merge 4 commits into
tobi:mainfrom
introspection-org:julian/walgit-s3-irsa
Open

fix(store): resolve and refresh S3 credentials through the AWS default chain#48
brightsparc wants to merge 4 commits into
tobi:mainfrom
introspection-org:julian/walgit-s3-irsa

Conversation

@brightsparc

Copy link
Copy Markdown

S3 initialization currently requires a stored access-key pair, so deployments using web identity / IRSA, container roles or instance roles cannot authenticate. This change uses the AWS SDK’s default credential chain when both configured key variables are unset, retaining the provider so temporary credentials can refresh.

Behavior

  • A complete, non-empty pair from store.s3.access_key_env / secret_key_env overrides the default chain and preserves AWS_SESSION_TOKEN.
  • With both variables unset, the SDK resolves credentials through its normal chain (profiles, web identity, container credentials, instance metadata).
  • Partial, empty or non-Unicode explicit keys fail at construction instead of silently switching identities. Errors name the variables, never their values.
  • walgit.example.toml documents this selection.

S3Store::new becomes async, matching GcsStore::new: building the SDK default chain is asynchronous. Both existing in-tree callers now await it; direct library callers must also add .await. No new dependency, store-format change or bucket request is introduced. HEAD and GET still each require one bucket request; STS exchanges happen only when resolving/refreshing identity.

Regression coverage

New hermetic tests run the real AWS credential chain in child processes with clean environments and local synthetic STS/S3 endpoints. They verify projected-token rotation, short-lived credential refresh, SDK-signed HEAD and presigned GET requests, cached-credential reuse, custom-key precedence, session-token propagation, and rejection of incomplete/empty keys without making network calls. They neither read developer credentials nor contact AWS.

Validation

Validated on macOS arm64 with the repository’s Rust 1.97.1 toolchain:

Check Result
just web-build Pass
just warnings Pass
cargo clippy --locked -p walgit-store --all-targets -- -D warnings Pass
just test Pass, including all new credential tests
just e2e 43 passed, 1 intentionally ignored
cargo test --locked -p walgit-server --test sim 20 passed
S3 store contract against local RustFS Pass; static credentials, unique test prefix, cleanup

Workspace just clippy still fails on the two pre-existing macOS cast_lossless warnings in crates/walgit-wal/src/registry.rs:494–495, unchanged from base e5295e6. Consequently this is not a claim that just ci is entirely green on macOS; all other constituent tiers and storage Clippy passed.

A real AWS account / IRSA-enabled cluster has not been tested. The mocked STS exchange exercises the production provider path and refresh behavior, but IAM trust policy, workload projection and bucket permissions still need deployment-level verification.

claude and others added 2 commits September 10, 2026 07:06
S3Store::new required AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and failed
outright without them, then pinned a static provider, so the default chain was
never consulted. A pod holding a projected service-account token could not
authenticate at all and the backend demanded a long-lived key instead. GCS
already resolves through ADC, so this closes the gap between the two.

The env vars now override rather than gate: with both set the behaviour is
unchanged, including AWS_SESSION_TOKEN; without them the default chain runs
and picks up a web-identity token, an ECS task role or IMDS.

DefaultCredentialsChain::build is async, so S3Store::new becomes async.
GcsStore::new already is and open_store already awaits it. Both in-tree call
sites are updated; note this is a breaking change for any caller outside the
workspace.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KaoVaspfci2kQbzQJLTPd7
Require a complete, non-empty explicit key pair or neither key. A partial
custom pair must not silently fall back to a different AWS identity.

Exercise the real SDK credential chain in isolated child processes against
synthetic STS and S3 endpoints. Verify projected-token rotation, refreshing
session credentials for SDK and presigned requests, cache reuse, explicit
custom-key precedence, and failure without network calls for invalid keys.
Document credential selection in the example config.

Bucket protocol depth is unchanged: one request per HEAD/GET, no extra
bucket probes. STS exchanges occur on credential resolution/refresh only.
A host with no AWS identity used to fail on the first request, after
the profile and IMDS lookups timed out, where the explicit-key path had
failed at construction with a clear message. Probe the chain once in
`new` so misconfiguration surfaces the same way. Also formats the S3
contract constructor.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6UZ2AaFQ6m7xgdZKRyHEV
brightsparc added a commit to introspection-org/walgit that referenced this pull request Sep 12, 2026
Upstream main (tobi#42-tobi#45, tobi#49) plus the Azure and IRSA branches as
updated for PRs tobi#50 and tobi#48, plus the store-plugin and notify-transport
lines the production image was already built from (a6ce265). The two
conflicts were additive: the Event Grid handshake test and its doc note
now sit beside the loopback notify-transport test and its bullet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6UZ2AaFQ6m7xgdZKRyHEV
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants