Optional VM egress MITM proxy with mock-secret header rewriting#134
Optional VM egress MITM proxy with mock-secret header rewriting#134sjmiller609 wants to merge 20 commits intomainfrom
Conversation
Add a new host-side egress proxy module that supports HTTP/HTTPS interception and per-instance header secret substitution from mock values to real host environment secrets. Wire proxy lifecycle into instance create/start/restore/stop/standby/delete flows, inject guest proxy settings via config disk, and install proxy CA material in guest init. Add Linux egress enforcement rules to require proxy path for outbound 80/443 traffic, document behavior in lib/egressproxy/README.md, and add an integration test validating HTTPS header rewrite end to end.
✱ Stainless preview buildsThis PR will update the Edit this comment to update it. It will appear in the SDK's changelogs. ✅ hypeman-typescript studio · code · diff
✅ hypeman-openapi studio · code · diff
✅ hypeman-go studio · code · diff
This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push. |
…n test Switch the new egress proxy integration test away from curlimages/curl:8.12.1 so it works with CI strict prewarm registry mirror. Use docker.io/library/nginx:alpine (already mirrored in CI) while keeping HTTPS header rewrite validation via curl.
There was a problem hiding this comment.
Automated risk triage result: High risk.
Why this is high risk (from code diff evidence):
- Introduces a new host-side HTTP/HTTPS MITM subsystem (
lib/egressproxy/*) including dynamic cert signing, CONNECT interception, and header rewriting logic. - Adds Linux egress enforcement via host
iptablesFORWARD rules (lib/egressproxy/enforce_linux.go), which affects networking behavior and operational safety. - Wires proxy/enforcement into core VM lifecycle flows (
create,start,restore,stop,standby,delete) acrosslib/instances/*. - Expands external API surface (
openapi.yaml,lib/oapi/oapi.go, API request mapping) and guest init trust/bootstrap behavior (lib/system/init/*,lib/vmconfig/config.go).
Decision:
- Code review is required.
- No auto-approval (high-risk PRs are not approved by automation).
Reviewer assignment:
- PR already has 2 reviewers requested, so no additional reviewers were added.
…roxy-secret-rewrite # Conflicts: # lib/instances/create.go # lib/instances/fork.go # lib/instances/types.go # lib/oapi/oapi.go # openapi.yaml
…roxy-secret-rewrite # Conflicts: # lib/instances/create.go # lib/instances/manager.go # lib/oapi/oapi.go
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| Gateway: alloc.Gateway, | ||
| Netmask: alloc.Netmask, | ||
| TAPDevice: alloc.TAPDevice, | ||
| } |
There was a problem hiding this comment.
Restore path constructs NetworkConfig missing DNS field
High Severity
The NetworkConfig manually constructed from the Allocation in the restore path omits the DNS field. When createConfigDisk uses this incomplete config via buildGuestConfig, the resulting GuestDNS will be empty, breaking DNS resolution in the restored guest. The create and start paths get DNS from the network manager's returned NetworkConfig, but this restore path constructs one by hand and leaves DNS zeroed.
| if stored.EgressProxy != nil && stored.EgressProxy.Enabled { | ||
| proxyRegistered = true | ||
| } | ||
| } |
There was a problem hiding this comment.
Restore unconditionally regenerates config disk for all networked instances
Medium Severity
The new restore block at step 4b regenerates the config disk for every networked instance, not just proxy-enabled ones. For non-proxy instances, this is unnecessary and introduces a new requirement that the image metadata still be loadable via GetImage during restore. A restore that previously succeeded can now fail at the "get image for restore config disk" step. The image load and createConfigDisk call belong inside a guard checking stored.EgressProxy != nil && stored.EgressProxy.Enabled.
| example: | ||
| PORT: "3000" | ||
| NODE_ENV: production | ||
| egress_proxy: |
There was a problem hiding this comment.
i like the direction here, but i’m a little worried the public api is getting shaped around the current implementation (egress_proxy + mocked env var rewriting) rather than the longer-term policy model we may want.
after looking at a few similar products, the ones that seem to age best expose this as a network/credential policy problem, not a proxy feature:
- vercel sandbox firewall has first-class network policy (
allow-all/deny-all/ custom allow+deny rules) and then layers credential brokering / header transforms on top - deno sandbox separates
allowNetfromsecrets, where secrets are host-scoped and substituted on outbound requests without ever entering the vm - e2b already has
allowOut/denyOut, and even their open credential brokering proposal models secret injection as an egress transform layered onto network policy - daytona is simpler, but even there the api is framed as network restriction (
networkAllowList/networkBlockAll), not proxy config
the reason i’m flagging it is that this shape feels pretty mechanism-specific:
egress_proxybakes in “host-side mitm proxy” as the conceptual modelmock_env_varsassumes env vars are the long-term secret source abstractionmock_env_var_domainscouples destination policy to that env-var abstractionenforcement_modeis really egress/firewall policy, but it lives inside the same object as secret substitution
if we ever want to grow this into broader outbound controls (allow/deny rules, port restrictions, runtime policy updates, non-env-backed credentials, different injection strategies, explicit private-network blocking, etc), i think this api may box us in a bit.
maybe the public shape wants to be closer to something like this, even if the backend implementation for v1 is still proxy-based:
network:
egress:
default: allow | deny
allow:
- hosts: ["api.openai.com", "*.anthropic.com"]
- cidrs: ["10.0.0.0/8"]
deny:
- cidrs: ["169.254.169.254/32"]
enforcement:
mode: all | http_https_only
credentials:
OPENAI_API_KEY:
source:
env: OPENAI_API_KEY
inject:
- hosts: ["api.openai.com"]
as:
header: Authorization
format: "Bearer ${value}"or some variation of that. the main thing i’m after is separating:
- what outbound destinations are reachable
- what credentials can be brokered where
- how we currently implement that under the hood
that feels a little more future-proof to me than making egress_proxy itself the core api concept.




Summary
This PR adds an optional, default-off egress MITM proxy mode for Hypeman VMs so workloads can run with mock secrets in-VM while real secrets stay on the host.
When enabled per instance, Hypeman now:
HTTP_PROXY/HTTPS_PROXY, lower-case variants).Why
This enables safer execution of untrusted or lower-trust workloads in VMs without placing real secrets inside guest env/config, while still allowing authenticated outbound API traffic.
API / Config changes
CreateInstanceRequestnow supports top-levelegress_proxy:enabled: boolmock_to_real_env_var: map[string]string(mock literal -> host env var name)EgressProxyConfig.Implementation details
lib/egressproxy/Tests
Added integration test:
TestEgressProxyRewritesHTTPSHeadersAuthorizationheader.Validation run
Executed on
deft-kernel-devas root:sudo -n /usr/local/go/bin/go test ./cmd/api/api -run TestDoesNotExist -count=1sudo -n /usr/local/go/bin/go test ./lib/instances -run TestEgressProxyRewritesHTTPSHeaders -count=1 -vsudo -n /usr/local/go/bin/go test ./... -run TestDoesNotExist -count=1All passed for this change set.
Notes
Note
High Risk
Introduces a security-sensitive MITM proxy and host firewall enforcement (iptables) that affects VM networking and secret handling across create/start/restore/cleanup paths; misconfiguration or lifecycle bugs could leak secrets or break connectivity.
Overview
Adds an optional, default-off per-instance
egress_proxymode that starts a host-side HTTP/HTTPS MITM proxy, injects proxy env vars + a trusted CA into the guest, and rewrites outbound HTTPS header values frommock-<ENV_VAR>back to real host-provided secrets (optionally gated by destination-domain allowlists).Wires this into the instance lifecycle (create/start/restore register policy + enforcement; stop/standby/delete unregister) and persists config via new
instances.EgressProxyConfigplusvmconfig/guest-init CA installation; on Linux, adds iptables-based direct egress blocking with selectable enforcement mode (allvshttp_https_only).Updates OpenAPI (
openapi.yaml+ generatedlib/oapi) and API handler mapping forCreateInstanceRequest.egress_proxy, adds extensive unit/integration tests (including a VM test verifying HTTPS header rewriting), and improves CI/e2e reliability by supporting a test registry mirror (HYPEMAN_TEST_REGISTRY) and retrying async image pulls;cmd/test-prewarmalso prewarms additional images.Written by Cursor Bugbot for commit 8c3775f. This will update automatically on new commits. Configure here.