Skip to content

feat(sandbox): proxy-side AWS SigV4 credential signing for CONNECT tunnels #1631

@jhjaggars

Description

@jhjaggars

OpenShell's credential proxy model replaces real secrets with opaque placeholder tokens in sandbox environment variables, then resolves them in HTTP headers (Bearer, Basic auth) before forwarding upstream. This works for APIs that send credentials directly in headers.
AWS SigV4 is fundamentally incompatible: the SDK uses the secret access key to compute an HMAC signature over the canonical request (method, path, headers, body hash). Placeholder values produce invalid signatures that can't be fixed by simple header replacement. This prevents sandboxed agents from accessing any AWS service (Bedrock, S3, STS, etc.) through the credential proxy.
Add proxy-side SigV4 re-signing in the sandbox supervisor's CONNECT tunnel path. When credential_signing: sigv4 is set on a REST endpoint in the policy YAML, the proxy:

  1. Terminates TLS (as normal for protocol: rest)
  2. Strips the client's invalid Authorization, X-Amz-Date, X-Amz-Security-Token, and X-Amz-Content-Sha256 headers before the fail-closed placeholder scan
  3. Resolves AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and optionally AWS_SESSION_TOKEN from the SecretResolver
  4. Computes a fresh SigV4 signature using the official aws-sigv4 crate with real credentials
  5. Injects the new signed headers and forwards the properly signed request upstream
    The signing service name (e.g. bedrock for bedrock-runtime endpoints) is specified explicitly in the policy via a signing_service field, since the aws-sigv4 crate is just signing math — hostname-to-signing-name resolution lives in per-service SDK crates and there is no lightweight alternative.
network_policies:
  bedrock:
    name: aws-bedrock
    endpoints:
      - host: bedrock-runtime.us-east-2.amazonaws.com
        port: 443
        protocol: rest
        credential_signing: sigv4
        signing_service: bedrock
        access: read-write
        enforcement: enforce
  • Minimal signed headers: Only host, content-type, and content-length are included in the SigV4 signature. Signing all request headers causes 403 InvalidSignatureException because the proxy/transport modifies headers like Connection and Accept-Encoding between signing and delivery.
  • Payload checksum: PayloadChecksumKind::XAmzSha256 is enabled so the x-amz-content-sha256 header is included, which AWS Bedrock requires.
  • Body buffering: The full request body is buffered before signing to compute the body hash. This is acceptable since Bedrock invoke-model requests have bounded body sizes.
  • Session token support: AWS_SESSION_TOKEN is resolved from the provider when present, enabling STS temporary credentials. Prepares for feat(providers): add aws_sts_assume_role refresh strategy (v2 only) #1576 (aws_sts_assume_role refresh strategy).
  • Region inference: Extracted from the hostname pattern <service>.<region>.amazonaws.com.
    | Component | Key Files | Change |
    |-----------|-----------|--------|
    | Proto model | proto/sandbox.proto | Add credential_signing (field 18) and signing_service (field 19) to NetworkEndpoint |
    | Policy serde | crates/openshell-policy/src/lib.rs | Add both fields to NetworkEndpointDef and proto conversion |
    | SigV4 module | crates/openshell-sandbox/src/sigv4.rs | New — signing via aws-sigv4 crate, header stripping, region extraction |
    | L7 config | crates/openshell-sandbox/src/l7/mod.rs | Add CredentialSigning enum and signing_service field to L7EndpointConfig |
    | CONNECT relay | crates/openshell-sandbox/src/l7/rest.rs | Hook SigV4 into relay_http_request_with_options_guarded — strip before scan, sign after rewrite |
    | OPA data | crates/openshell-sandbox/src/opa.rs | Plumb credential_signing and signing_service through OPA endpoint data |
    | Relay options | crates/openshell-sandbox/src/l7/relay.rs | Pass credential_signing and signing_service to RelayRequestOptions |
    | Dependencies | crates/openshell-sandbox/Cargo.toml | Add aws-sigv4, aws-credential-types, aws-smithy-runtime-api |
    | Providers | crates/openshell-providers/src/profiles.rs | Add signing_service to endpoint_to_proto |
  1. Gateway-side signing (like Vertex AI in feat(providers): add Google Vertex AI inference provider #1568): Vertex uses standard OAuth2 Bearer tokens, so the existing credential proxy handles them. SigV4 signatures depend on the final request content (method + path + headers + body hash), so signing must happen at the proxy where the final request is assembled — not at the gateway.
  2. Exposing real AWS credentials to the sandbox: Defeats the purpose of the credential proxy security model.
  3. IMDS emulation: Complex, and IMDS is hardcoded-blocked in sandboxes for security.
    Working implementation on branch sigv4-credential-signing at jhjaggars/OpenShell. Tested end-to-end: Claude Code → OpenShell sandbox → Bedrock (us-east-2) with proxy-side SigV4 re-signing. Sandbox never sees real AWS credentials.
    Includes an integration test that exercises the full strip → re-sign → send flow against real Bedrock (#[ignore]'d, requires credentials).
    Related: feat(providers): add aws_sts_assume_role refresh strategy (v2 only) #1576 (STS refresh strategy) — the sandbox-side session token support is already implemented, ready for when gateway-side STS rotation lands.
    Complements feat(providers): add Google Vertex AI inference provider #1568 (Google Vertex AI) — that PR handles server+router level concerns for a Bearer-token API. This feature handles proxy-level concerns for an HMAC-signature API. No architectural conflicts; both can coexist.

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions