Skip to content

solver: add proxy network mode - #6740

Merged
tonistiigi merged 13 commits into
moby:masterfrom
tonistiigi:exec-net-proxy
Jun 8, 2026
Merged

tonistiigi merged 13 commits into
moby:masterfrom
tonistiigi:exec-net-proxy

Conversation

@tonistiigi

Copy link
Copy Markdown
Member

Add a build request option that rewrites default exec networking to an
internal proxy network while preserving explicit none networking.

Route HTTP and HTTPS traffic through a BuildKit-owned proxy namespace, enforce
source policy checks for proxied requests, and inject a temporary CA into Linux
rootfs trust bundles for HTTPS interception.

Share namespace pooling between CNI and proxy providers, and cover proxy mode
with unit and integration tests.

Record successful GET responses through the exec proxy as provenance
materials and report incomplete material coverage as a typed solve error.
Thread proxy policy and capture state through typed executor/network options.

Route proxy network policy checks through the existing source policy evaluator so
session metadata, deny messages, and URL converts use the same path as LLB
sources. Keep proxy-specific request rewriting in the proxy provider.

@tonistiigi

tonistiigi commented May 13, 2026 •

Copy link
Copy Markdown
Member Author

@tonistiigi tonistiigi added this to the v0.31.0 milestone May 27, 2026
@tonistiigi
tonistiigi marked this pull request as ready for review June 1, 2026 18:47
Comment thread docs/buildkitd.toml.md
insecure-entitlements = [ "network.host", "security.insecure", "device" ]
# proxyNetwork enables proxy network enforcement for all builds, disabled by default.
# It can also be enabled with buildkitd --proxy-network.
proxyNetwork = true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a comprehensive docs/proxy.md?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tonistiigi

Copy link
Copy Markdown
Member Author

@AkihiroSuda @crazy-max Rebased. I've tested this quite a bit and it seems to work quite well. I also opened a new update in #6816 . I can combine them, but didn't want to make this PR even larger.

Comment on lines +707 to +732
func newCA() ([]byte, *x509.Certificate, *rsa.PrivateKey, error) {
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, nil, errors.WithStack(err)
}
now := time.Now()
tmpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "BuildKit exec proxy"},
NotBefore: now.Add(-time.Hour),
NotAfter: now.Add(24 * time.Hour),
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
BasicConstraintsValid: true,
IsCA: true,
}
der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key)
if err != nil {
return nil, nil, nil, errors.WithStack(err)
}
cert, err := x509.ParseCertificate(der)
if err != nil {
return nil, nil, nil, errors.WithStack(err)
}
pemBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
return pemBytes, cert, key, nil
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iiuc the CA and leaf certs expire after 24h but are never rotated so HTTPS interception would break on any daemon up >24h?

if err != nil {
return nil, errors.WithStack(err)
}
p.certs[host] = &cert

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

related to previous comment, caching leaf certs permanently and also stamps them with a 24h NotAfter. Even ignoring the CA, the first request to a host pins a leaf that becomes unusable 24h later and is never regenerated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking again at p.certs, it grows for every distinct host for the daemon's lifetime with no eviction. So a build that hits many hosts leaks memory potentially?

return true
}

func New(opt Opt) (network.Provider, error) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cniprovider calls cleanOldNamespaces(cp) in its constructor but not proxyprovider.New. So let's say after daemon crash mid-new NS, the bind-mounted netns files under root/net/proxy can leak across restarts? Maybe worth miroring CNI cleanup?

Comment on lines +504 to +507
if e.op.Network == pb.NetMode_PROXY {
e.proxyCap = network.NewProxyCapture()
meta.ProxyCapture = e.proxyCap
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iiuc it creates ProxyCapture when the exec actually runs and for provenance is only records proxy materials if that runtime capture exists. What would happen for a cached proxy exec? I guess it will not re-run the proxy so current source-policy DENY/CONVERT rules are not re-evaluated and complete-materials=true can pass with missing HTTP materials potenaitally?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I missed the new deny test uses llb.IgnoreCache in policy_test to avoid this case.

tonistiigi added 12 commits June 4, 2026 11:23
Add a build request option that rewrites default exec networking to an
internal proxy network while preserving explicit none networking.

Route HTTP and HTTPS traffic through a BuildKit-owned proxy namespace, enforce
source policy checks for proxied requests, and inject a temporary CA into Linux
rootfs trust bundles for HTTPS interception.

Share namespace pooling between CNI and proxy providers, and cover proxy mode
with unit and integration tests.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Record successful GET responses through the exec proxy as provenance
materials and report incomplete material coverage as a typed solve error.
Thread proxy policy and capture state through typed executor/network options.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Route proxy network policy checks through the existing source policy evaluator so
session metadata, deny messages, and URL converts use the same path as LLB
sources. Keep proxy-specific request rewriting in the proxy provider.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Record each proxied exec request and print a redacted method and URL list in
the exec progress logs after the process completes.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Apply proxy network as an explicit LLB mutation before digest recompute,
while keeping runtime load options such as platform normalization applied
when creating vertices.

This preserves distinct cache keys for proxy-network builds without
breaking gateway warning and source-map lookups that use the original LLB
digests from the frontend.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Add a proxyNetwork TOML setting and --proxy-network daemon flag to enable
exec proxy enforcement for every build. Wire the default through controller
and solver setup while preserving per-build enablement.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Add integration coverage for exec proxy source policy conversion. The test
requests /foo, rewrites it to /bar, and verifies exported content and
provenance materials use the converted source.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Refresh generated proxy leaf certificates before they expire and cap cached
hosts to avoid daemon-lifetime growth. Clean stale proxy network namespaces
on provider startup to mirror CNI cleanup after daemon crashes.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
@tonistiigi
tonistiigi merged commit c662666 into moby:master Jun 8, 2026
226 of 227 checks passed
@cpuguy83

cpuguy83 commented Jun 8, 2026

Copy link
Copy Markdown
Member

Really nice, I was just digging into this.
Is there a planned followup for dealing with CA roots for stuff like java, node.js, etc?

@cpuguy83

cpuguy83 commented Jun 8, 2026

Copy link
Copy Markdown
Member

It also seems like this makes the passthrough HTTP_PROXY not work when in proxy mode?

@tonistiigi

Copy link
Copy Markdown
Member Author

Is there a planned followup for dealing with CA roots for stuff like java, node.js, etc?

Do they look up CAs from non-standard places? Interested in any examples that don't currently work.

It also seems like this makes the passthrough HTTP_PROXY not work when in proxy mode?

Indeed that case would need some special handling. Essentially, we would need a double proxy in here. The HTTP_PROXY would still point to our proxy and then our proxy dial could go to user-configured proxy?

@cpuguy83

cpuguy83 commented Jun 9, 2026

Copy link
Copy Markdown
Member

@tonistiigi

Findings (including ones that don't need extra help):

Runtime Default trust source Honors HTTPS_PROXY Error signature Fix
curl / wget OpenSSL system bundle yes — none needed
Go (net/http) system bundle (crypto/x509) yes — none needed
Python stdlib (ssl/urllib) system bundle (OpenSSL) yes — none needed
pip ≥ 24.2 system bundle (truststore) yes — none needed
Python + certifi (requests) certifi PEM bundle yes CERTIFICATE_VERIFY_FAILED REQUESTS_CA_BUNDLE / SSL_CERT_FILE
Java / JVM $JAVA_HOME/lib/security/cacerts yes (explicit proxy) PKIX path building failed … unable to find valid certification path PKCS12 keystore + JAVA_TOOL_OPTIONS=-Djavax.net.ssl.trustStore=…
Node / npm embedded Mozilla roots (OpenSSL) yes UNABLE_TO_VERIFY_LEAF_SIGNATURE NODE_EXTRA_CA_CERTS=<ca.pem>
Bun embedded Mozilla roots (BoringSSL) yes (fetch + bun install) SELF_SIGNED_CERT_IN_CHAIN NODE_EXTRA_CA_CERTS=<ca.pem> (read at launch) or NODE_USE_SYSTEM_CA=1
Bazel — http_archive JVM cacerts yes TLS error: PKIX path building failed … startup --host_jvm_args=-Djavax.net.ssl.trustStore=… (Bazel unsets JAVA_TOOL_OPTIONS)
Bazel — gRPC --remote_cache JVM cacerts / Netty-BoringSSL no proxy support — --tls_certificate=<pem>

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.

4 participants