Skip to content

fix: resolve S3 credentials via AWS default chain when static keys are unset (#9429)#9430

Merged
minitriga merged 2 commits into
stablefrom
fix-s3-irsa-credentials-ifc-2683
Jun 3, 2026
Merged

fix: resolve S3 credentials via AWS default chain when static keys are unset (#9429)#9430
minitriga merged 2 commits into
stablefrom
fix-s3-irsa-credentials-ifc-2683

Conversation

@minitriga

@minitriga minitriga commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #9429. S3 object storage failed with AuthorizationHeaderMalformed: a non-empty Access Key (AKID) must be provided on deployments that rely on AWS role-based credentials (IRSA, EC2 instance profiles, ECS task roles) instead of static keys.

S3StorageSettings defaults access_key_id / secret_access_key to empty strings, and the storage layer forwarded those empty strings straight to boto3.resource(...). boto3 treats an empty string as an explicit credential and skips the default credential provider chain, so role-based credential resolution never happened.

Change

InfrahubS3ObjectStorage.__init__ now treats blank, whitespace-only, or incomplete static credentials as "not configured" and passes None, letting boto3 fall back to the default AWS credential provider chain. Complete static credentials are forwarded unchanged, so existing static-key and S3-compatible (e.g. MinIO) deployments are unaffected.

The fix lives entirely in Infrahub's subclass — the upstream fastapi_storages library is not modified.

Behavior

Access key Secret key Result
set set forwarded verbatim (unchanged)
blank blank None → default credential chain
set blank (or reverse) incomplete → None → default credential chain
whitespace-only whitespace-only treated as blank → default credential chain

Tests

New backend/tests/unit/test_storage.py stubs boto3.resource and asserts the credential kwargs across all four states (5 tests, all passing). No external services required.

Verification not covered by CI

The end-to-end IRSA path (removing the sitecustomize.py workaround on a live EKS deployment) can only be confirmed on a role-based deployment — see dev/specs/ifc-2683-fix-s3-irsa-credentials/quickstart.md §4.

Notes

  • Two # type: ignore[assignment] are introduced (one per credential attribute): fastapi_storages.S3Storage types them as str, but boto3 requires None to trigger credential-chain fallback. Justified inline.
  • Changelog: changelog/9429.fixed.md.
  • Spec/plan/tasks artifacts under dev/specs/ifc-2683-fix-s3-irsa-credentials/.

🤖 Generated with Claude Code


Summary by cubic

Fix S3 storage auth for AWS role-based credentials by letting boto3 use the default credential chain when both static keys are unset. Partial static credentials now raise a clear error. Addresses Linear IFC-2683.

  • Bug Fixes
    • In InfrahubS3ObjectStorage.__init__, treat blank/whitespace-only keys as not configured and set them to None so boto3.resource(...) resolves IRSA/instance-profile/task-role credentials.
    • Reject partial credentials with a ValueError explaining both or neither must be set.
    • Forward complete static credentials unchanged (S3-compatible deployments unaffected).

Written for commit 732e394. Summary will update on new commits.

Review in cubic

@minitriga minitriga requested a review from a team as a code owner June 2, 2026 15:02
@github-actions github-actions Bot added group/backend Issue related to the backend (API Server, Git Agent) type/spec A specification for an upcoming change to the project labels Jun 2, 2026
@codspeed-hq

codspeed-hq Bot commented Jun 2, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 12 untouched benchmarks


Comparing fix-s3-irsa-credentials-ifc-2683 (732e394) with stable (79721de)1

Open in CodSpeed

Footnotes

  1. No successful run was found on stable (49cb868) during the generation of this report, so 79721de was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 12 files

Confidence score: 3/5

  • There is a concrete regression risk in .specify/feature.json: feature_directory points to specs/... instead of the checked-in dev/specs/..., which can break downstream spec-tool resolution for this feature.
  • The issue in dev/specs/ifc-2683-fix-s3-irsa-credentials/plan.md is low severity (documentation accuracy), but the incorrect Pydantic version can still mislead implementation and validation choices if left uncorrected.
  • Given one medium-severity, high-confidence tooling-path break plus a minor documentation mismatch, this looks mergeable after a small fix but carries some user-impacting risk as-is.
  • Pay close attention to .specify/feature.json, dev/specs/ifc-2683-fix-s3-irsa-credentials/plan.md - fix the spec directory path and align the documented Pydantic version.

Shadow auto-approve: would not auto-approve because issues were found.

Re-trigger cubic

Comment thread .specify/feature.json Outdated
Comment thread dev/specs/ifc-2683-fix-s3-irsa-credentials/plan.md Outdated

@ajtmccarty ajtmccarty left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say that the ~500 lines of spec/plan/etc for this pretty small code change is excessive and can be left out. But I don't know if we've really agreed on a limit or border for including these specs or not

Comment thread backend/infrahub/storage.py Outdated
Comment thread .specify/feature.json Outdated
Comment thread CLAUDE.md Outdated
…e unset (#9429)

S3StorageSettings defaults the access key and secret to empty strings, and the
storage layer forwarded them straight to boto3. boto3 treats an empty string as
an explicit credential and skips the default credential provider chain, so S3
storage failed with AuthorizationHeaderMalformed on deployments relying on IRSA,
EC2 instance profiles, or ECS task roles.

InfrahubS3ObjectStorage now treats blank, whitespace-only, or incomplete static
credentials as "not configured" and passes None, letting boto3 fall back to the
default AWS credential provider chain. Complete static credentials are forwarded
unchanged, so existing static-key and S3-compatible deployments are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@minitriga minitriga force-pushed the fix-s3-irsa-credentials-ifc-2683 branch from f02542d to b9d289b Compare June 3, 2026 09:48
@github-actions github-actions Bot removed the type/spec A specification for an upcoming change to the project label Jun 3, 2026
@minitriga

Copy link
Copy Markdown
Contributor Author

Pushed an update addressing the review:

  • Removed all spec/plan/tasks artifacts (dev/specs/..., .specify/feature.json) and reverted the accidental CLAUDE.md change. The PR diff is now just the three code files: backend/infrahub/storage.py, backend/tests/unit/test_storage.py, changelog/9429.fixed.md. Agreed they were excessive for a change this size.
  • storage.py: simplified the credential check, and partial config (only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY) now raises a ValueError instead of silently falling back — per @ajtmccarty's suggestion.
  • Updated the changelog and the unit tests accordingly (partial config now asserts the raise). ruff, mypy, and the 5 unit tests pass.

Force-pushed to rewrite the single commit so the spec files are absent from history, not just deleted in a follow-up.

@minitriga minitriga merged commit 9b08603 into stable Jun 3, 2026
63 checks passed
@minitriga minitriga deleted the fix-s3-irsa-credentials-ifc-2683 branch June 3, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

group/backend Issue related to the backend (API Server, Git Agent)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: S3 storage breaks with IRSA / instance-profile credentials (empty access key passed to boto3)

2 participants