feat: add opt-in HTTPS MITM to the network interceptor#63
Open
tgockel wants to merge 1 commit into
Open
Conversation
Add an opt-in MITM mode that composes with the existing audit and filter modes. When enabled, the interceptor mints a per-session ECDSA P-256 CA, writes the public cert and 0600 private key under <session_dir>/tls/, installs the cert into the container trust store (Debian, Red Hat, and standalone PEM plus four language env vars), terminates incoming TLS on the configured HTTPS-bearing ports with per-host leaf certificates, re-encrypts upstream against the host's native trust anchors, and emits one audit record per HTTP request carrying method, URL, and status. ALPN advertises both http/1.1 and h2 in each direction so HTTP/2 clients work transparently; hyper 1.x serves both protocols. MITM is strictly opt-in. Disabled, the audit and filter behavior from 0060 stays bit-for-bit identical -- the new optional audit fields skip serialization, the CA is never generated, and HTTPS still passes through opaquely. HTTPS connections without SNI (IP-literal destinations) also pass through opaquely; the interceptor declines to mint a leaf cert without a name to bind it to, and the audit record stays the 0060 shape. URL-aware policy reuses the existing allow / deny lists with an optional path glob (inline-table form only). Entries with path are skipped by the TCP-open decision and only fire after MITM has parsed the request line. A path entry without [network.mitm].enable = true is a schema error. Body capture is off by default. When enabled, request and response bodies are base64-encoded into outrig.request_body_b64 / outrig.response_body_b64, capped per body (default 64 KiB), and the truncation status lands in outrig.body_truncated. Bodies past the cap still pass on the wire; only the captured copy is truncated. Repo configs may flip [network.mitm].enable to opt out (or in if the global config has not), but ports, capture-bodies, and max-body-bytes stay global-only -- mirroring the existing decision that the policy lists are not part of the repo surface. The session CA's private key is removed during NetworkInterceptor::shutdown; the public certificate remains so audit-log readers can verify recorded handshakes after the session ends. CA validity is 30 days.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add an opt-in MITM mode that composes with the existing audit and filter modes. When enabled, the interceptor mints a per-session ECDSA P-256 CA, writes the public cert and 0600 private key under <session_dir>/tls/, installs the cert into the container trust store (Debian, Red Hat, and standalone PEM plus four language env vars), terminates incoming TLS on the configured HTTPS-bearing ports with per-host leaf certificates, re-encrypts upstream against the host's native trust anchors, and emits one audit record per HTTP request carrying method, URL, and status. ALPN advertises both http/1.1 and h2 in each direction so HTTP/2 clients work transparently; hyper 1.x serves both protocols.
MITM is strictly opt-in. Disabled, the audit and filter behavior from 0060 stays bit-for-bit identical -- the new optional audit fields skip serialization, the CA is never generated, and HTTPS still passes through opaquely. HTTPS connections without SNI (IP-literal destinations) also pass through opaquely; the interceptor declines to mint a leaf cert without a name to bind it to, and the audit record stays the 0060 shape.
URL-aware policy reuses the existing allow / deny lists with an optional path glob (inline-table form only). Entries with path are skipped by the TCP-open decision and only fire after MITM has parsed the request line. A path entry without [network.mitm].enable = true is a schema error.
Body capture is off by default. When enabled, request and response bodies are base64-encoded into outrig.request_body_b64 / outrig.response_body_b64, capped per body (default 64 KiB), and the truncation status lands in outrig.body_truncated. Bodies past the cap still pass on the wire; only the captured copy is truncated.
Repo configs may flip [network.mitm].enable to opt out (or in if the global config has not), but ports, capture-bodies, and max-body-bytes stay global-only -- mirroring the existing decision that the policy lists are not part of the repo surface. The session CA's private key is removed during NetworkInterceptor::shutdown; the public certificate remains so audit-log readers can verify recorded handshakes after the session ends. CA validity is 30 days.