From b9c70f7daa9645b81e3dd9b656321759baefd555 Mon Sep 17 00:00:00 2001 From: didericis Date: Mon, 25 May 2026 15:52:08 -0400 Subject: [PATCH] fix(egress-proxy): build combined trust bundle (system + pipelock CA) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `--set ssl_verify_upstream_trusted_ca` REPLACES mitmproxy's default trust store with the file we point it at. The earlier wiring pointed it at just pipelock's CA, which broke for any host pipelock passes through (api.anthropic.com is in DEFAULT_TLS_PASSTHROUGH): pipelock CONNECT-tunnels the handshake to the real upstream, egress-proxy sees the real public cert (signed by e.g. DigiCert), and refuses to validate because pipelock's CA doesn't sign it. Fix in Dockerfile entrypoint: when EGRESS_PROXY_UPSTREAM_CA is set, concatenate /etc/ssl/certs/ca-certificates.crt + the pipelock CA into /home/mitmproxy/.mitmproxy/combined-trust.pem, and pass that as ssl_verify_upstream_trusted_ca. Covers both legs: - pipelock-MITM'd hosts → leaf cert signed by pipelock CA → validates against the pipelock half of the bundle. - pipelock-passthrough hosts (api.anthropic.com et al.) → real upstream cert → validates against the system half. Standalone runs of the image (no EGRESS_PROXY_UPSTREAM_CA) skip the concat and use mitmproxy's default trust store. Reproduces against today's main: agent gets "Unable to connect to API: SSL certificate verification failed" on api.anthropic.com, egress-proxy logs "Server TLS handshake failed. Certificate verify failed: unable to get local issuer certificate". After this patch the trust bundle includes the real upstream root + pipelock's CA and both validation paths succeed. Co-Authored-By: Claude Opus 4.7 --- Dockerfile.egress-proxy | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/Dockerfile.egress-proxy b/Dockerfile.egress-proxy index 8cce9e3..8f75a18 100644 --- a/Dockerfile.egress-proxy +++ b/Dockerfile.egress-proxy @@ -44,14 +44,20 @@ USER mitmproxy EXPOSE 9099 # Entrypoint: -# --mode regular@9099 standard HTTP/HTTPS forward proxy on :9099. -# --set ssl_verify_upstream_trusted_ca=... only when -# EGRESS_PROXY_UPSTREAM_CA env is set (the backend's start step -# sets it to the in-container pipelock-CA path when pipelock is -# present, so the upstream leg trusts pipelock's MITM). The -# ${VAR:+expansion} form omits the flag when the var is unset -# or empty — useful for standalone runs of the image (e.g. unit -# tests) where no upstream CA is mounted. -# -s /app/egress_proxy_addon.py loads our addon, which reads the -# route table from /etc/egress-proxy/routes.yaml. -ENTRYPOINT ["sh", "-c", "exec mitmdump --mode regular@9099 ${EGRESS_PROXY_UPSTREAM_CA:+--set ssl_verify_upstream_trusted_ca=$EGRESS_PROXY_UPSTREAM_CA} -s /app/egress_proxy_addon.py"] +# - Build a combined upstream-trust bundle when +# EGRESS_PROXY_UPSTREAM_CA is set (the backend's start step +# sets it to the in-container pipelock-CA path). +# `--set ssl_verify_upstream_trusted_ca` REPLACES mitmproxy's +# default trust store with the file we point it at; if we just +# pointed it at pipelock's CA, mitmproxy would refuse any host +# pipelock passes through (api.anthropic.com etc.) because +# pipelock's CA doesn't sign the real upstream certs. So +# concatenate the system bundle + pipelock CA into one PEM and +# point mitmproxy at that — covers both pipelock-MITM'd and +# pipelock-passthrough hosts. +# - --mode regular@9099 → standard HTTP/HTTPS forward proxy. +# - -s /app/egress_proxy_addon.py → loads our addon, reads +# /etc/egress-proxy/routes.yaml. +# Standalone runs (no EGRESS_PROXY_UPSTREAM_CA) skip the bundle +# build and use mitmproxy's default trust store. +ENTRYPOINT ["sh", "-c", "if [ -n \"$EGRESS_PROXY_UPSTREAM_CA\" ] && [ -f \"$EGRESS_PROXY_UPSTREAM_CA\" ]; then COMBINED=/home/mitmproxy/.mitmproxy/combined-trust.pem; cat /etc/ssl/certs/ca-certificates.crt \"$EGRESS_PROXY_UPSTREAM_CA\" > \"$COMBINED\"; exec mitmdump --mode regular@9099 --set ssl_verify_upstream_trusted_ca=\"$COMBINED\" -s /app/egress_proxy_addon.py; else exec mitmdump --mode regular@9099 -s /app/egress_proxy_addon.py; fi"]