Skip to content

Bedrock: opt-in ambient IAM via the container credentials endpoint - #1168

Open
worsnoptr wants to merge 1 commit into
enricoros:mainfrom
worsnoptr:bedrock-container-credentials
Open

Bedrock: opt-in ambient IAM via the container credentials endpoint#1168
worsnoptr wants to merge 1 commit into
enricoros:mainfrom
worsnoptr:bedrock-container-credentials

Conversation

@worsnoptr

Copy link
Copy Markdown
Contributor

What

Opt-in ambient AWS IAM credentials for Bedrock via the container credentials endpoint (ECS/Fargate task roles): set BEDROCK_USE_CONTAINER_CREDENTIALS=true and big-AGI authenticates with the task's IAM role — no static BEDROCK_ACCESS_KEY_ID / BEDROCK_SECRET_ACCESS_KEY needed.

Why

Enterprises with IAM-role-only security mandates cannot use long-lived static credentials — a hard requirement in many orgs (see e.g. BerriAI/litellm#29665, which documents deployments where "a long-lived Bedrock API key ... is a non-starter under the security posture: no long-lived static secrets, IAM-role-only access"; litellm has a trail of similar asks). For big-AGI on ECS/Fargate this currently forces an IAM user + secret distribution + rotation machinery that the platform already solves natively with task roles.

How — Edge Runtime compatible, zero dependencies

The existing constraint ("SigV4 uses explicit credentials only, no SDK credential chain, for Edge Runtime compatibility") is honored: no AWS SDK is introduced. On ECS the agent injects AWS_CONTAINER_CREDENTIALS_RELATIVE_URI, and a plain fetch of http://169.254.170.2<uri> returns { AccessKeyId, SecretAccessKey, Token, Expiration } as JSON. The existing aws4fetch signer already accepts sessionToken, so short-lived role credentials need no signing changes.

Empirical Edge-sandbox verification (self-hosted next start, which runs runtime = 'edge' routes in the edge-runtime sandbox): globalThis.EdgeRuntime === 'edge-runtime', no Node process.version, yet process.env is readable and fetch reaches the credentials endpoint (measured <100 ms; it's link-local). On Vercel/Cloudflare the env var never exists, so the code path stays dormant.

  • bedrock.containerCredentials.ts (new, ~110 lines): endpoint detection (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI / _FULL_URI, optional static AWS_CONTAINER_AUTHORIZATION_TOKEN), module-level cache, refresh 5 minutes before Expiration, single-flight concurrent refreshes, stale-tolerant on refresh failure while credentials remain valid, one-time log of the assumed role. Out of scope by design (documented in the header): EC2 IMDSv2, EKS IRSA, EKS Pod Identity's rotating token file (needs fs, unavailable on Edge).
  • bedrock.access.ts: ambient credentials slot in at the lowest priority — client bearer > client IAM > server bearer > server IAM env > container credentials (opt-in). Explicit configuration always wins; existing deployments see zero behavior change unless they set the flag. _bedrockResolveAuth becomes async; bedrockResolveRegion is split out to stay sync and credential-free (same region semantics as before).
  • backend.router.ts: hasLlmBedrock also lights up when the flag is set and the endpoint is present, so client auto-configuration works for keyless deployments.
  • env.server.ts + docs/environment-variables.md: the new variable.

Tested

  • Live on ECS Fargate (us-east-1), task role only (no credential env vars in the task definition): model listing (140 models) plus chats across all Bedrock API paths — Converse (Nova Pro), Invoke-Anthropic (Claude Sonnet 5, Fable 5), and Mantle. Container logs show the one-time [Bedrock] using container credentials (role: arn:aws:iam::…:role/…) line.
  • Credential lifecycle: a single credentials fetch served an entire session of concurrent listing + chat requests (cache + single-flight verified).
  • Priority: with explicit env credentials present alongside the flag, the ambient endpoint is never contacted.
  • Failure path: with the flag set but no endpoint (or fetch failure) and no other credentials, the standard "Missing AWS credentials" error is returned and a console.warn explains the ambient failure; a still-valid cached credential keeps serving through transient refresh failures.
  • tsc --noEmit clean, next build passes.

Notes

  • Pairs well with (but does not depend on) the Bedrock Responses-API PR from the same deployment work; both are independently mergeable from main.
  • Infra simplification for deployers: an ECS task role statement replaces the IAM user, secret distribution, and rotation machinery entirely; container env shrinks to BEDROCK_REGION + BEDROCK_USE_CONTAINER_CREDENTIALS=true.

Enterprises with IAM-role-only security mandates cannot deploy big-AGI
against Bedrock today: the server only accepts long-lived static
credentials (BEDROCK_ACCESS_KEY_ID/SECRET_ACCESS_KEY or a bearer key).
On ECS/Fargate the task role already provides rotating short-lived
credentials via the container credentials endpoint - no SDK needed:
the ECS agent injects AWS_CONTAINER_CREDENTIALS_RELATIVE_URI and a
plain fetch of http://169.254.170.2<uri> returns { AccessKeyId,
SecretAccessKey, Token, Expiration } as JSON.

This adds an opt-in (BEDROCK_USE_CONTAINER_CREDENTIALS=true) ambient
credentials provider at the LOWEST priority of the existing chain:
client bearer > client IAM > server bearer > server IAM env >
container credentials. Explicit configuration always wins, and
nothing changes for existing deployments unless they set the flag.

Edge Runtime compatible by design, honoring the 'no SDK credential
chain' constraint: the new module is pure fetch + env vars (verified
empirically inside the edge-runtime sandbox of a self-hosted `next
start`: process.env is readable and fetch reaches the endpoint).
The existing aws4fetch signer already accepts sessionToken, so the
short-lived role credentials need no signing changes.

Details:
- bedrock.containerCredentials.ts (new): endpoint detection
  (RELATIVE_URI/FULL_URI + optional AWS_CONTAINER_AUTHORIZATION_TOKEN),
  module-level cache, refresh 5 minutes before Expiration,
  single-flight concurrent refreshes, stale-tolerant on refresh
  failure while credentials remain valid. Logs the assumed role once.
  Out of scope: EC2 IMDSv2, EKS IRSA, and the Pod Identity token FILE
  (needs fs, unavailable on Edge) - see the module header.
- bedrock.access.ts: _bedrockResolveAuth becomes async for the
  (potential) credentials fetch; bedrockResolveRegion is split out to
  stay sync and credential-free (client credentials use the client
  region, server-side credentials use the server region, as before).
- backend.router.ts: hasLlmBedrock also lights up when the flag is
  set and the endpoint is present, so client auto-configuration
  triggers for keyless deployments.
- env.server.ts + docs/environment-variables.md: the new variable.

Verified live on ECS Fargate (us-east-1): task role only (no secret
env vars), model listing + Converse + Invoke-Anthropic + Mantle chat
paths all pass; one credentials fetch served the whole session; with
explicit env credentials present the ambient path is never consulted.
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

@worsnoptr is attempting to deploy a commit to the Token Fabrics Pro Team on Vercel.

A member of the Team first needs to authorize it.

@enricoros

Copy link
Copy Markdown
Owner

Leaving open, not merging.

The craft is high - pure-fetch, Edge-compatible, the credential lifecycle handling is right. The math is what fails: this serves ECS/Fargate task-role deployments, a thin slice of self-hosters, and costs permanent surface (auth-chain priority, capability wiring, docs) on files the hosted branch reworks on every rebase. Narrow benefit, standing cost. Deployments that need it can carry the patch - it applies cleanly.

If the audience is bigger than I think, make the case and I'll reconsider.

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