feat(sandbox): proxy-side AWS SigV4 credential signing for CONNECT tunnels#1638
feat(sandbox): proxy-side AWS SigV4 credential signing for CONNECT tunnels#1638jhjaggars wants to merge 2 commits into
Conversation
|
All contributors have signed the DCO ✍️ ✅ |
|
I have read the DCO document and I hereby sign the DCO. |
| #[serde(default, skip_serializing_if = "String::is_empty")] | ||
| credential_signing: String, | ||
| #[serde(default, skip_serializing_if = "String::is_empty")] | ||
| signing_service: String, |
There was a problem hiding this comment.
Are there practical extensions to the values for these fields? Is there ever a non-AWS use case? Just trying to understand how AWS-specific these settings are vs the names of the settings that imply they could map to other service provider use cases.
There was a problem hiding this comment.
These feel pretty specific to AWS. It's awkward, but I didn't see an obviously better way to have a special case like this today. credential_signing might be used in other services, but the signing_service almost certainly wouldn't.
There was a problem hiding this comment.
I could imagine a cleaner way of expressing these things aligning with your issue here: #896. It does seem like a middleware pattern would fit nicely as well.
bec3afc to
e2f78da
Compare
|
just for visibility - I started working on AWS STS credential support (#1576), using access to S3 as a test case. This depends on sigv4 support, so I pulled that in to my branch, or at least a version of it from the end of last week. |
1ee1ee5 to
84c5c3d
Compare
| let mut full_request = rewrite_result.rewritten.clone(); | ||
| full_request.extend_from_slice(overflow); | ||
| // Read remaining body based on content-length | ||
| if let BodyLength::ContentLength(body_len) = parse_body_length(header_str)? { |
There was a problem hiding this comment.
One issue that we can address in a follow-up is that this doesn't support chunked transfer (no content length for the whole body). When I was trying to test S3 access using the python boto library, it was doing chunked transfer. I started working on this in my branch, so maybe I'll get it worked out, but it's worth noting the limitation I think.
There was a problem hiding this comment.
I gave this a shot, but it turned out to be a little harder than I thought. I think most aws services support skipping body signatures which is probably what we should do, but I think there are some edge cases that make it a little tricky.
There was a problem hiding this comment.
Yeah, I didn't get it working, either. Skipping sounds good if supported!
84c5c3d to
54e0f39
Compare
…nnels
Add proxy-side AWS SigV4 re-signing so sandbox clients can reach AWS
services (Bedrock) through the CONNECT tunnel using placeholder
credentials. The proxy strips the invalid signature, resolves real
credentials from the SecretResolver, re-signs with the aws-sigv4 crate,
and forwards. Configuration is policy-driven via two new fields
(credential_signing, signing_service).
Policy YAML example:
credential_signing: sigv4
signing_service: bedrock
Implementation:
- sigv4.rs: strip_aws_headers removes old auth headers before the
fail-closed placeholder scan; apply_sigv4_to_request re-signs using
the aws-sigv4 SDK with PayloadChecksumKind::XAmzSha256 enabled.
Returns Result instead of panicking. Non-signed headers (Accept,
User-Agent, etc.) are preserved in the output.
- rest.rs: SigV4 path buffers body (capped at MAX_REWRITE_BODY_BYTES)
for signing, then forwards the re-signed request upstream.
- Proto: credential_signing (field 19), signing_service (field 20)
on NetworkEndpoint.
- Policy/OPA: plumbed through serde, proto conversion, and Rego data.
- Supports AWS session tokens (STS temporary credentials).
- Integration test against real Bedrock (ignored, requires AWS creds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reject policies where credential_signing is set but signing_service is empty during validate_sandbox_policy() instead of failing at connection time. The runtime check in rest.rs is kept as defense-in-depth.
54e0f39 to
7141a81
Compare
Add proxy-side AWS SigV4 credential signing for CONNECT tunnel requests. When
credential_signing: sigv4is set on a REST endpoint in the policy YAML, the sandbox proxy strips the client's invalid SigV4 signature (computed with placeholder credentials), re-signs the request with real AWS credentials from the SecretResolver using the officialaws-sigv4crate, and forwards the properly signed request upstream. This enables AWS services like Bedrock to work through OpenShell's credential proxy without exposing real secrets to the sandbox.Closes #1631
Related: #1576 (STS refresh strategy — sandbox-side session token support is included here), #1568 (Google Vertex AI — complementary, no conflicts)
credential_signing(field 18) andsigning_service(field 19) toNetworkEndpointNetworkEndpointDefserde struct and proto conversionssigv4.rsmodule: SigV4 signing viaaws-sigv4crate, AWS header stripping, region extraction from hostnameCredentialSigningenum andsigning_servicefield, parse from OPA policy datal7/rest.rs): hook SigV4 intorelay_http_request_with_options_guarded— strip AWS headers before fail-closed placeholder scan, buffer body, re-sign after credential rewritecredential_signingandsigning_servicethrough OPA data andRelayRequestOptionsAWS_SESSION_TOKENfor STS temporary credentialsaws-sigv4,aws-credential-types,aws-smithy-runtime-api; removehmac#[ignore]'d, requires AWS credentials)host,content-type, andcontent-lengthare included in the signature. Signing all headers causes403 InvalidSignatureExceptionbecause the proxy modifies headers likeConnectionandAccept-Encodingbetween signing and delivery.signing_servicefield: AWS signing service names don't always match hostname prefixes (e.g.bedrock-runtime→bedrock). Theaws-sigv4crate is just signing math — hostname-to-signing-name resolution lives in per-service SDK crates with no lightweight alternative. Making the policy author specify it is correct and extensible.PayloadChecksumKind::XAmzSha256is enabled to includex-amz-content-sha256, which Bedrock requires.credential_signingandsigning_serviceround-trip through proto → OPA data → L7 configcargo test -p openshell-sandbox --test sigv4_signing -- --ignored)mise run pre-commitpasses