Repository navigation
feat(inference): AWS Bedrock direct/SigV4 support + non-bridge profile #1940
Copy link
Copy link
Closed as not planned
Closed as not planned
Copy link
Description
Context
Follow-up to PR #1704 (merged), which landed AWS Bedrock as a bridge-fronted inference provider. The bridge-fronted shape ships today with:
providers/aws-bedrock.yaml:endpoints: [],binaries: []— non-egress-granting; operators declare their own bridge egress.crates/openshell-core/src/inference.rs:AWS_BEDROCK_PROFILE.default_base_url = ""so route resolution rejects providers withoutBEDROCK_BASE_URLrather than silently forwarding to real AWS.auth: AuthHeader::Noneon the router — operator's bridge holds upstream auth in its own pod.AWS_BEDROCK_PROTOCOLSadvertises only bufferedaws_bedrock_invoke(/model/{id}/invoke).AWS_*credentials in the YAML profile are declarative-only (required: false); router does not consume them.
This issue tracks the natural follow-up: direct AWS Bedrock, where the router signs requests itself.
Scope
- SigV4 router-side signing. Add
AuthHeader::SigV4 { ... }variant incrates/openshell-core/src/inference.rs, consume the four AWS credential map entries (AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN,AWS_REGION) at outbound request time, and sign every Bedrock request incrates/openshell-router/src/backend.rs. Likely via theaws-sigv4crate. - Streaming protocol + protocol-aware error framing. Re-add
aws_bedrock_invoke_stream(/model/{id}/invoke-with-response-stream) toAWS_BEDROCK_PROTOCOLSand the L7 inference pattern table, but only after the shared streaming relay can emit AWS event-stream-shaped error frames (application/vnd.amazon.eventstream) on truncation/timeout/upstream-error. The current SSE-style error injection corrupts Bedrock event-stream parsers, which is why this was deferred from PR feat(sandbox,providers): add aws-bedrock as a recognized inference provider #1704. - Repopulate the profile. Once SigV4 + streaming exist, flip
providers/aws-bedrock.yamlto advertise the real AWS endpoint, restorebinariesfor the Claude CLI, and set the AWS credentials back torequired: truewithdiscovery.credentialspopulated. The bridge-fronted shape continues to work viaBEDROCK_BASE_URLoverride. {region}placeholder substitution in the YAML profile loader so operators in other regions don't need a fullBEDROCK_BASE_URLoverride.
Compatibility
The single-profile principle (per @johntmyers on PR #1704: "profiles should be usable as is") means the post-follow-up profile should serve both bridge-fronted and direct-AWS shapes without splitting. Operators continue to use:
- Bridge-fronted:
--config BEDROCK_BASE_URL=...(no AWS credentials required). - Direct AWS: omit
BEDROCK_BASE_URL, provide AWS credentials.
Related
- PR feat(sandbox,providers): add aws-bedrock as a recognized inference provider #1704 — initial Bedrock plumbing (this is the follow-up).
- The streaming/error-framing piece may end up as its own sub-issue if the SigV4 work lands first.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
st-gr commentedon Jul 30, 2026
#1801 and #1802 were closed as duplicates into this issue. Consolidating is the right call — SigV4 signing is item 1 here and
{region}substitution is item 4, so this issue is the superset. Two implementation details from #1801 aren't captured above though, and I'd rather they not have to be rediscovered. Recording them here.1.
ResolvedRoutehas nowhere to carry AWS credentials.Item 1 says the router should "consume the four AWS credential map entries," but the route struct the router actually forwards with holds exactly one secret. On
main,crates/openshell-router/src/config.rs:45:So SigV4 needs a carrying mechanism before signing can be wired up. Two options:
secret_credentials: HashMap<String, String>toResolvedRoute, orThe map is more general and keeps future SigV4-authed AWS providers from needing another struct change; explicit fields are more type-safe and make a missing credential a compile error rather than a runtime
None. Either works — worth deciding before the signing code, since it determines whetherAuthHeader::SigV4needs to carryservicealone or more.Note
RouteConfig(config.rs:20) also has anapi_key: Option<String>— that's the serde config type, distinct from the resolved route, and would likely need the same treatment for file-configured routes.2. Test plan for the signer.
Authorizationvalue, which pins the whole chain (canonical request → string-to-sign → signing key → header) rather than just asserting the header is non-empty.x-amz-security-tokenis present iff a session token is present. Emitting it unconditionally with an empty value is the easy mistake here, and AWS rejects that.One convenient hook: the
AuthHeader::Nonedoc comment (crates/openshell-core/src/inference.rs:21-29) already documents thataws-bedrockusesNonebecause "SigV4signing is deferred to a follow-up PR." That comment should be updated when this lands, otherwise it will contradict the new variant. The injection switch to extend iscrates/openshell-router/src/backend.rs:250-258— currently three arms (Bearer/Custom/None), and signing has to happen before it since SigV4 covers the whole request, not just a header slot.johntmyers commentedon Sep 17, 2026