proxy network: injected CA is wiped when a build step upgrades the ca-certificates package
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- arch-linux, build-system, debian, docker, dockerfile, fedora, go, linux, ubuntu
- Domain
- build-system, cloud, devops, infrastructure, security
Research direction
The bug is in the executor's proxy CA injection logic, likely in the InjectProxyCA function. Start by examining the linuxSystemCertFiles list and the bundle injection code. The fix involves writing the CA to trust anchor directories (e.g., /usr/local/share/ca-certificates) and cleaning up by fingerprint. Look at the linked branch for the proposed implementation. Testing requires setting up a BuildKit proxy network and reproducing with a Dockerfile that upgrades ca-certificates. Verify by running curl after the upgrade in the same RUN step.
Written by the indexing model from the issue text.
Description
Well-formed report checklist:
- I have found a bug that the documentation does not mention anything about my problem
- I have found a bug that there are no open or closed issues that are related to my problem (searched
proxy network CA,PIP_CERT,ca-certificates proxy) - I have provided version/information about my environment and done my best to provide a reproducer
Bug description
With proxy networking enabled (the feature from #6740), a build step that
upgrades the ca-certificates package silently removes the injected CA, and
every later HTTPS request in the same RUN fails.
InjectProxyCA appends the CA inline (marker-wrapped) to the first existing
bundle from linuxSystemCertFiles — always an extracted bundle:
- Debian/Ubuntu/Alpine:
/etc/ssl/certs/ca-certificates.crt(generated by
update-ca-certificates) - RHEL-family/openEuler:
/etc/pki/tls/certs/ca-bundle.crt(symlink into
/etc/pki/ca-trust/extracted/, generated byupdate-ca-trust extract)
Upgrading the ca-certificates package re-runs the update tool, which
rebuilds the extracted bundle from the source directories. The BuildKit CA
is in none of them, so the regenerated bundle drops it:
| Distro | Regeneration tool | Auto trigger | Anchor dir |
|---|---|---|---|
| Debian/Ubuntu | update-ca-certificates |
deb postinst | /usr/local/share/ca-certificates |
| RHEL/openEuler | update-ca-trust extract (p11-kit) |
rpm install | /etc/pki/ca-trust/source/anchors |
| Alpine | update-ca-certificates |
apk trigger | /usr/local/share/ca-certificates |
| Arch | update-ca-trust (p11-kit) |
pacman hook | /etc/ca-certificates/trust-source/anchors |
| SUSE | p11-kit | package upgrade | /etc/pki/trust/anchors |
References: update-ca-certificates(8)
("generates ca-certificates.crt, a concatenated single-file list"),
update-ca-trust(8) ("this
command is being run during rpm package installation"; "add it as a new file
to directory /etc/pki/ca-trust/source/anchors"),
Alpine APKBUILD
(triggers=ca-certificates.trigger=...),
SUSE spec.
Note that the trigger is automatic: any package operation that upgrades
ca-certificates as a dependency (e.g. RUN apt-get install curl) wipes the
CA without any explicit update-ca-* call. Only commands inside the same exec
are affected; each RUN re-injects.
Observed in production CI on openEuler 24.03 (yum update -y && curl https://repo.openeuler.org/... → curl: (60) SSL certificate problem: unable to get local issuer certificate).
Reproduction
Reproducer runs in containers (BuildKit v0.33.0 has the proxy network feature,
so no external proxy setup is needed):
docker buildx create --name bk-proxy --driver docker-container --bootstrap
export BUILDX_BUILDER=bk-proxy
# Dockerfile — deb postinst triggers update-ca-certificates, wiping the CA,
# then curl in the same RUN fails
FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl \
&& curl -fsSL https://deb.debian.org/ -o /dev/null
#35 4.366 curl: (60) SSL certificate problem: unable to get local issuer certificate
#35 4.366 More details here: https://curl.se/docs/sslcerts.html
Expected: the CA injected at exec start stays trusted for the whole exec, so
the curl succeeds. Equivalently reproducible with update-ca-certificates --fresh (Debian) or update-ca-trust extract (RHEL-family) as the
regeneration command, and with yum/apk/pacman package upgrades on their
respective distros.
Version information
buildkitd github.com/moby/buildkit v0.33.0 (upstream release)
buildctl github.com/moby/buildkit v0.33.0
rootful OCI worker, Linux
Proposed fix
In addition to the inline bundle injection, write the CA into the trust
anchor directories that exist in the rootfs:
/usr/local/share/ca-certificates (Debian, Ubuntu, Alpine)
/etc/pki/ca-trust/source/anchors (RHEL, Fedora, openEuler)
/etc/pki/trust/anchors (SUSE, openSUSE)
/etc/ca-certificates/trust-source/anchors (Arch)
Regeneration scans these directories and picks the CA back up, so trust is
preserved for the rest of the exec. Cleanup then removes the anchor files and
strips the CA from the bundles by certificate fingerprint (marker block
first, fingerprint fallback for the regenerated case), which preserves
legitimate changes the exec made — e.g. an actual ca-certificates upgrade
must not be rolled back by restoring a pre-exec copy of the bundle.
Classic bundle paths that are symbolic links (RHEL-family, Arch, SUSE) need
no special handling: fs.RootPath already resolves them to their targets
within the rootfs, so the links themselves are never touched.
Implemented on top of v0.33.0 with unit tests and docs: branch
v0.33.0-ca-inject,
commit f63b1cac1 (executor: write proxy CA into trust anchor directories).
Happy to split it into upstreamable patches.
cc @tonistiigi (author of #6740)
- Dominant language
- Go
- Stars
- 10.4k
- Forks
- 1.6k
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 72
Getting set up
- Ships a Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from moby/buildkit
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 2 days
-
docs: rootless.md should recommend a per-binary AppArmor profile over `apparmor_restrict_unprivileged_userns=0Possibly taken @shashankvarma499 claimed this 59 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 2 days
-
area/dockerfile
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 2 days
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
Maintainers usually reply within 2 days
-
status/triage
Difficulty 4/5 3-5 days Newbie friendliness 43/100
Maintainers usually reply within 2 days
Similar issues
-
model:sonnet runtime:claude security size:S
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
FootprintAI/Containarium#3671 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 5 days
-
good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
keyxmakerx/Chronicle#2190 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
llm-d/llm-d-inference-sim#897 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
inference-sim/inference-sim#2110 ·
Maintainers usually reply within 1 day