fix(egress-proxy): build combined trust bundle (system + pipelock CA)
`--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 <noreply@anthropic.com>
This commit is contained in:
+17
-11
@@ -44,14 +44,20 @@ USER mitmproxy
|
|||||||
EXPOSE 9099
|
EXPOSE 9099
|
||||||
|
|
||||||
# Entrypoint:
|
# Entrypoint:
|
||||||
# --mode regular@9099 standard HTTP/HTTPS forward proxy on :9099.
|
# - Build a combined upstream-trust bundle when
|
||||||
# --set ssl_verify_upstream_trusted_ca=... only when
|
# EGRESS_PROXY_UPSTREAM_CA is set (the backend's start step
|
||||||
# EGRESS_PROXY_UPSTREAM_CA env is set (the backend's start step
|
# sets it to the in-container pipelock-CA path).
|
||||||
# sets it to the in-container pipelock-CA path when pipelock is
|
# `--set ssl_verify_upstream_trusted_ca` REPLACES mitmproxy's
|
||||||
# present, so the upstream leg trusts pipelock's MITM). The
|
# default trust store with the file we point it at; if we just
|
||||||
# ${VAR:+expansion} form omits the flag when the var is unset
|
# pointed it at pipelock's CA, mitmproxy would refuse any host
|
||||||
# or empty — useful for standalone runs of the image (e.g. unit
|
# pipelock passes through (api.anthropic.com etc.) because
|
||||||
# tests) where no upstream CA is mounted.
|
# pipelock's CA doesn't sign the real upstream certs. So
|
||||||
# -s /app/egress_proxy_addon.py loads our addon, which reads the
|
# concatenate the system bundle + pipelock CA into one PEM and
|
||||||
# route table from /etc/egress-proxy/routes.yaml.
|
# point mitmproxy at that — covers both pipelock-MITM'd and
|
||||||
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"]
|
# 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"]
|
||||||
|
|||||||
Reference in New Issue
Block a user