From ef9f81ba831aa3da678c72f1155c47a51da265ef Mon Sep 17 00:00:00 2001 From: didericis Date: Tue, 21 Jul 2026 22:22:04 -0400 Subject: [PATCH] docs(readme): make the registry route example correct and complete The example previously left DLP enabled on the blob CDNs, which is exactly backwards: those hosts carry the multi-hundred-MB layers whose buffering triggers #455, while the registry hosts they hang off carry little. It also listed one of quay's three CDNs and omitted the CDN requirement from the prose, so a reader following it would authenticate fine and then 403 partway through a pull. Adds the by-design DNS behaviour and the BusyBox wget caveat, both of which cost real time during the #392 verification: nslookup failing inside a nested container looks like breakage but is expected, and BusyBox wget reports "error getting response" for requests the proxy served successfully. Verified by feeding the snippet through parse_frontmatter + ManifestBottle.from_dict: all nine routes parse with the intended preserve_auth and DLP settings. Co-Authored-By: Claude Opus 4.8 --- README.md | 55 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 2ab0df2..2c742b8 100644 --- a/README.md +++ b/README.md @@ -97,38 +97,65 @@ agent user outside it. Nested containers are a build/test convenience, not a security boundary. The bottle remains the boundary. Pulling images goes through the bottle's egress proxy like every other -request, so each registry needs a route. Docker Hub and GHCR additionally need -`preserve_auth: true` (their token dance uses a client-fetched per-scope bearer -token that the proxy would otherwise strip), and large layer pulls should skip -body scanning: +request, so each registry needs a route — **and so does the CDN it redirects +layer blobs to**, which is a different host. Without the CDN route the pull +authenticates, fetches the manifest, then 403s partway through. + +Docker Hub and GHCR additionally need `preserve_auth: true`: their token dance +uses a client-fetched per-scope bearer token that the proxy would otherwise +strip. Turn DLP off on every registry and CDN route — the bodies are +compressed layer blobs that no detector can read, and buffering them is what +triggers the shared-proxy OOM in #455. ```yaml nested_containers: true egress: routes: + # Docker Hub: registry, token endpoint, blob CDN. - host: registry-1.docker.io preserve_auth: true dlp: { outbound_detectors: false, inbound_detectors: false } - host: auth.docker.io preserve_auth: true + dlp: { outbound_detectors: false, inbound_detectors: false } + - host: production.cloudfront.docker.com + dlp: { outbound_detectors: false, inbound_detectors: false } + # GHCR: registry + blob CDN. - host: ghcr.io preserve_auth: true dlp: { outbound_detectors: false, inbound_detectors: false } + - host: pkg-containers.githubusercontent.com + dlp: { outbound_detectors: false, inbound_detectors: false } + # quay.io: registry + blob CDNs. No preserve_auth needed for public pulls. - host: quay.io dlp: { outbound_detectors: false, inbound_detectors: false } - # Registries redirect layer blobs to a separate CDN host, which needs its - # own route or the pull 403s partway through. - - host: production.cloudfront.docker.com - - host: pkg-containers.githubusercontent.com - host: cdn01.quay.io + dlp: { outbound_detectors: false, inbound_detectors: false } + - host: cdn02.quay.io + dlp: { outbound_detectors: false, inbound_detectors: false } + - host: cdn03.quay.io + dlp: { outbound_detectors: false, inbound_detectors: false } ``` -Inside a nested container the same allowlist applies — an allowlisted host -returns 200 and anything else gets a 403 from the proxy. The gateway's CA and -proxy settings are wired in automatically, so `docker run … curl https://…` -works with no extra flags. One caveat: Alpine's BusyBox `wget` drops the -connection after TLS interception and reports "error getting response"; `curl` -against the same host works, so reach for `curl` when testing egress. +`mcr.microsoft.com` and `registry.k8s.io` follow the same shape and also +redirect blobs elsewhere (`*.data.mcr.microsoft.com` and +`us-*-docker.pkg.dev` respectively); route whichever host the 403 names. + +Inside a nested container the same allowlist applies: an allowlisted host +returns 200 and anything else gets a 403 straight from the proxy. The +gateway's CA bundle and proxy settings are wired in automatically, so +`docker run … curl https://…` works with no extra flags — no `--add-host`, +`-e`, or `-v`. + +Two things worth knowing when testing that: + +- Public DNS inside a nested container fails **by design**. Everything + egresses through the proxy, so `nslookup` failing is expected and is not + evidence of a problem. +- Alpine's BusyBox `wget` drops the connection after the proxy's TLS + interception and reports `error getting response`, even though the proxy + logs the decrypted request and returns a response. Use `curl` to test + egress; BusyBox `wget` will lie to you. ### Firecracker on Linux