Skip to content

feat: implement aws authentication for the MiTM proxy #1195

Open
intentionally-left-nil wants to merge 2 commits into
always-further:mainfrom
intentionally-left-nil:aws-proxy-impl
Open

feat: implement aws authentication for the MiTM proxy #1195
intentionally-left-nil wants to merge 2 commits into
always-further:mainfrom
intentionally-left-nil:aws-proxy-impl

Conversation

@intentionally-left-nil

@intentionally-left-nil intentionally-left-nil commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Linked Issue

Closes #1189

Summary

Now that the config is piped through, we can take a request, determine that aws credentials should be applied, determine the correct parameters (region, service), and then apply the signing to the body

This works by hooking up the aws_routes config to the underlying aws (smithy) providers. Then, when a route comes in, we can strip out the old headers and attach the new ones

Test Plan

profile:

{
    "meta": { "name": "qa-aws-bedrock" },
    "filesystem": {
        "allow": [
            ".",
            "~/.config/opencode",
            "~/.local/share/opencode"
        ]
    },
    "network": {
        "credentials": ["bedrock"],
        "custom_credentials": {
            "bedrock": {
                "upstream": "https://bedrock-runtime.us-east-1.amazonaws.com",
                "aws_auth": {}
            }
        }
    },
    "environment": {
        "deny_vars": ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_PROFILE"],
        "set_vars": {
            "AWS_ACCESS_KEY_ID": "dummy-access-key",
            "AWS_SECRET_ACCESS_KEY": "dummy-secret-key",
            "HOME": "$HOME"
        }
    }
}

Debug logs:
command: RUST_LOG=nono_proxy=debug cargo run -p nono-cli -- run --profile qa-profiles/04-aws-bedrock.json -- opencode run "say hi"

2026-06-18T06:58:44.942699Z  INFO Proxy server listening on 127.0.0.1:42419
2026-06-18T06:58:44.984157Z DEBUG Loading route 'bedrock' -> https://bedrock-runtime.us-east-1.amazonaws.com
2026-06-18T06:58:45.018663Z DEBUG added 119 native system CA(s) to upstream trust store
2026-06-18T06:58:45.018833Z DEBUG aws credential load: prefix='bedrock' upstream='https://bedrock-runtime.us-east-1.amazonaws.com' explicit_region=None explicit_service=None profile=None
2026-06-18T06:58:45.020096Z DEBUG aws credential load: prefix='bedrock' region='us-east-1' service='bedrock'
2026-06-18T06:58:45.020130Z DEBUG aws credential load: prefix='bedrock' building provider for profile=None
2026-06-18T06:58:45.020168Z DEBUG aws::route: building provider for profile=None
2026-06-18T06:58:45.020181Z DEBUG aws::route: building default credential chain provider
2026-06-18T06:58:45.056672Z DEBUG aws credential load: prefix='bedrock' route inserted (profile=None)
2026-06-18T06:58:45.057061Z DEBUG tls_intercept: merging parent SSL_CERT_FILE contents (182895 bytes) into trust bundle
2026-06-18T06:58:45.100360Z DEBUG tls_intercept: appending 119 certs from the system trust store to bundle
2026-06-18T06:58:45.102185Z DEBUG tls_intercept: wrote trust bundle (362705 bytes) to /home/anil/.local/state/nono/sessions/intercept-525634-942046923/intercept-ca.pem
2026-06-18T06:58:45.102298Z  INFO TLS interception active for 1 route(s); trust bundle at /home/anil/.local/state/nono/sessions/intercept-525634-942046923/intercept-ca.pem
  Applying sandbox...

2026-06-18T06:58:49.065441Z DEBUG Accepted connection from 127.0.0.1:46362
2026-06-18T06:58:49.065699Z DEBUG CONNECT request to github.com:443
2026-06-18T06:58:49.094932Z  INFO proxy request allowed mode=connect host="github.com" port=443 method="CONNECT" decision="allow"
2026-06-18T06:58:49.213196Z DEBUG Accepted connection from 127.0.0.1:46366
2026-06-18T06:58:49.213423Z DEBUG CONNECT request to release-assets.githubusercontent.com:443
2026-06-18T06:58:49.222811Z  INFO proxy request allowed mode=connect host="release-assets.githubusercontent.com" port=443 method="CONNECT" decision="allow"
2026-06-18T06:58:49.225728Z DEBUG CONNECT tunnel closed for github.com:443: Ok((982, 8497))

> build · us.anthropic.claude-sonnet-4-6

2026-06-18T06:58:49.829045Z DEBUG Accepted connection from 127.0.0.1:46370
2026-06-18T06:58:49.829268Z DEBUG tls_intercept: accepting CONNECT to bedrock-runtime.us-east-1.amazonaws.com:443 for L7 inspection
2026-06-18T06:58:49.837942Z DEBUG tls_intercept: minted leaf certificate for bedrock-runtime.us-east-1.amazonaws.com
2026-06-18T06:58:49.839333Z  INFO proxy request allowed mode=connect_intercept host="bedrock-runtime.us-east-1.amazonaws.com" port=443 method="CONNECT" decision="allow"
2026-06-18T06:58:49.839480Z DEBUG tls_intercept: inner request POST /model/global.anthropic.claude-haiku-4-5-20251001-v1%3A0/converse-stream
2026-06-18T06:58:49.839526Z DEBUG tls_intercept: selected route 'bedrock' for POST /model/global.anthropic.claude-haiku-4-5-20251001-v1%3A0/converse-stream
2026-06-18T06:58:49.841142Z DEBUG tls_intercept: signing AWS request: method=POST url='https://bedrock-runtime.us-east-1.amazonaws.com/model/global.anthropic.claude-haiku-4-5-20251001-v1%3A0/converse-stream' service='bedrock' region='us-east-1' body_len=2630 header_count=6
2026-06-18T06:58:50.091130Z DEBUG Accepted connection from 127.0.0.1:46386
2026-06-18T06:58:50.091758Z DEBUG CONNECT request to registry.npmjs.org:443
2026-06-18T06:58:50.100267Z DEBUG Accepted connection from 127.0.0.1:46388
2026-06-18T06:58:50.100420Z DEBUG CONNECT request to registry.npmjs.org:443
2026-06-18T06:58:50.117167Z  INFO proxy request allowed mode=connect host="registry.npmjs.org" port=443 method="CONNECT" decision="allow"
2026-06-18T06:58:50.118264Z  INFO proxy request allowed mode=connect host="registry.npmjs.org" port=443 method="CONNECT" decision="allow"
2026-06-18T06:58:50.258905Z DEBUG CONNECT tunnel closed for registry.npmjs.org:443: Ok((2127, 16635))
2026-06-18T06:58:50.259795Z DEBUG CONNECT tunnel closed for registry.npmjs.org:443: Ok((2095, 2980))
2026-06-18T06:58:50.278739Z DEBUG Accepted connection from 127.0.0.1:46402
2026-06-18T06:58:50.278973Z DEBUG tls_intercept: accepting CONNECT to bedrock-runtime.us-east-1.amazonaws.com:443 for L7 inspection
2026-06-18T06:58:50.289027Z  INFO proxy request allowed mode=connect_intercept host="bedrock-runtime.us-east-1.amazonaws.com" port=443 method="CONNECT" decision="allow"
2026-06-18T06:58:50.289113Z DEBUG tls_intercept: inner request POST /model/us.anthropic.claude-sonnet-4-6/converse-stream
2026-06-18T06:58:50.289134Z DEBUG tls_intercept: selected route 'bedrock' for POST /model/us.anthropic.claude-sonnet-4-6/converse-stream
2026-06-18T06:58:50.290042Z DEBUG tls_intercept: signing AWS request: method=POST url='https://bedrock-runtime.us-east-1.amazonaws.com/model/us.anthropic.claude-sonnet-4-6/converse-stream' service='bedrock' region='us-east-1' body_len=41953 header_count=6
2026-06-18T06:58:50.777889Z DEBUG aws::sign: signing POST https://bedrock-runtime.us-east-1.amazonaws.com/model/global.anthropic.claude-haiku-4-5-20251001-v1%3A0/converse-stream for service=bedrock region=us-east-1
2026-06-18T06:58:50.778735Z DEBUG aws::sign: produced 4 signing headers: ["x-amz-date", "authorization", "x-amz-content-sha256", "x-amz-security-token"]
2026-06-18T06:58:50.778878Z DEBUG tls_intercept: SigV4 signing succeeded; injecting 4 headers
2026-06-18T06:58:51.113681Z DEBUG Upstream read error: peer closed connection without sending TLS close_notify: https://docs.rs/rustls/latest/rustls/manual/_03_howto/index.html#unexpected-eof
2026-06-18T06:58:51.113831Z  INFO l7 proxy response mode=connect_intercept target="bedrock-runtime.us-east-1.amazonaws.com" method="POST" path="/model/global.anthropic.claude-haiku-4-5-20251001-v1%3A0/converse-stream" status=403
2026-06-18T06:58:51.136478Z DEBUG aws::sign: signing POST https://bedrock-runtime.us-east-1.amazonaws.com/model/us.anthropic.claude-sonnet-4-6/converse-stream for service=bedrock region=us-east-1
2026-06-18T06:58:51.138008Z DEBUG aws::sign: produced 4 signing headers: ["x-amz-date", "authorization", "x-amz-content-sha256", "x-amz-security-token"]
2026-06-18T06:58:51.138095Z DEBUG tls_intercept: SigV4 signing succeeded; injecting 4 headers
2026-06-18T06:58:52.739927Z DEBUG Upstream read error: peer closed connection without sending TLS close_notify: https://docs.rs/rustls/latest/rustls/manual/_03_howto/index.html#unexpected-eof
2026-06-18T06:58:52.740056Z  INFO l7 proxy response mode=connect_intercept target="bedrock-runtime.us-east-1.amazonaws.com" method="POST" path="/model/us.anthropic.claude-sonnet-4-6/converse-stream" status=200
Hi!
2026-06-18T06:58:53.065350Z DEBUG CONNECT tunnel closed for release-assets.githubusercontent.com:443: Ok((1845, 2270487))

Checklist

  • An issue exists and is linked above
  • All commits are signed-off, using DCO
  • All new code follows the project's coding standards (CLAUDE.md) and is covered by tests
  • Public-facing changes are paired with documentation updates
  • Release note has been added to CHANGELOG.md if needed

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

PR Review Summary

Size

Metric Value
Lines added +1610
Lines removed -59
Total changed 1669
Classification Large (> 300 lines)

Affected crates

  • crates/nono-proxydownstream consumers depend on this crate. API or behaviour changes will affect external callers; treat any breaking change with extra scrutiny.

Blast radius — Contained

This PR touches: source code


Updated automatically on each push to this PR.

@intentionally-left-nil

Copy link
Copy Markdown
Contributor Author

Note that this is built on top of #1192, so the diff will be a bit more manageable once that is merged. There's a somewhat related bug where credential is required for customCredentials to work, but I'll fix that in a separate PR. Just note that to test this, your profile must include at least one credential along with customCredentials

@intentionally-left-nil intentionally-left-nil changed the title feature: implement aws authentication for the MiTM proxy feat: implement aws authentication for the MiTM proxy Jun 18, 2026

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request implements AWS SigV4 signing support for nono-proxy, enabling the proxy to intercept AWS requests, strip dummy credentials, and re-sign them using resolved AWS credentials. Key additions include AWS endpoint parsing, route state management with provider caching, and request signing integration within the TLS interception pipeline. The review feedback highlights a few critical improvement opportunities: using aws_config::from_env() instead of ProfileFileCredentialsProvider directly to leverage automatic caching and advanced profile features (like SSO), and normalizing the Host header to prevent duplicate headers and signature mismatches. Minor cleanups regarding unused imports and duplicate variable definitions were also suggested.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/nono-proxy/src/aws/route.rs
Comment thread crates/nono-proxy/src/tls_intercept/handle.rs
Comment thread crates/nono-proxy/src/tls_intercept/handle.rs
Comment thread crates/nono-proxy/src/aws/route.rs Outdated
Comment thread crates/nono-proxy/src/tls_intercept/handle.rs
@SequeI

SequeI commented Jun 18, 2026

Copy link
Copy Markdown
Member

Once rebased on top of the other 2 pr's (refactor + not needing credential field for custom creds) we can get this tested and review :)

Now that the config is piped through, we can take a request, determine
that aws credentials should be applied, determine the correct parameters
(region, service), and then apply the signing to the body

Streaming-based signing is not implemented

Signed-off-by: Anil Kulkarni <anil@terminal.space>
…points.rs

Also use from_env() to create the profile in all cases, just specifying
the profile name

Signed-off-by: Anil Kulkarni <anil@terminal.space>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AWS: Support sigv4 credential injection for the MITM proxy

2 participants