docs(readme): make the registry route example correct and complete
tracker-policy-pr / check-pr (pull_request) Failing after 32s
test / unit (pull_request) Successful in 1m50s
test / integration-firecracker (pull_request) Successful in 3m19s
test / integration-docker (pull_request) Failing after 31s
test / coverage (pull_request) Has been skipped
test / publish-infra (pull_request) Has been skipped
tracker-policy-pr / check-pr (pull_request) Failing after 32s
test / unit (pull_request) Successful in 1m50s
test / integration-firecracker (pull_request) Successful in 3m19s
test / integration-docker (pull_request) Failing after 31s
test / coverage (pull_request) Has been skipped
test / publish-infra (pull_request) Has been skipped
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 <noreply@anthropic.com>
This commit is contained in:
@@ -97,38 +97,65 @@ agent user outside it. Nested containers are a build/test convenience, not a
|
|||||||
security boundary. The bottle remains the boundary.
|
security boundary. The bottle remains the boundary.
|
||||||
|
|
||||||
Pulling images goes through the bottle's egress proxy like every other
|
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
|
request, so each registry needs a route — **and so does the CDN it redirects
|
||||||
`preserve_auth: true` (their token dance uses a client-fetched per-scope bearer
|
layer blobs to**, which is a different host. Without the CDN route the pull
|
||||||
token that the proxy would otherwise strip), and large layer pulls should skip
|
authenticates, fetches the manifest, then 403s partway through.
|
||||||
body scanning:
|
|
||||||
|
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
|
```yaml
|
||||||
nested_containers: true
|
nested_containers: true
|
||||||
egress:
|
egress:
|
||||||
routes:
|
routes:
|
||||||
|
# Docker Hub: registry, token endpoint, blob CDN.
|
||||||
- host: registry-1.docker.io
|
- host: registry-1.docker.io
|
||||||
preserve_auth: true
|
preserve_auth: true
|
||||||
dlp: { outbound_detectors: false, inbound_detectors: false }
|
dlp: { outbound_detectors: false, inbound_detectors: false }
|
||||||
- host: auth.docker.io
|
- host: auth.docker.io
|
||||||
preserve_auth: true
|
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
|
- host: ghcr.io
|
||||||
preserve_auth: true
|
preserve_auth: true
|
||||||
dlp: { outbound_detectors: false, inbound_detectors: false }
|
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
|
- host: quay.io
|
||||||
dlp: { outbound_detectors: false, inbound_detectors: false }
|
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
|
- 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
|
`mcr.microsoft.com` and `registry.k8s.io` follow the same shape and also
|
||||||
returns 200 and anything else gets a 403 from the proxy. The gateway's CA and
|
redirect blobs elsewhere (`*.data.mcr.microsoft.com` and
|
||||||
proxy settings are wired in automatically, so `docker run … curl https://…`
|
`us-*-docker.pkg.dev` respectively); route whichever host the 403 names.
|
||||||
works with no extra flags. One caveat: Alpine's BusyBox `wget` drops the
|
|
||||||
connection after TLS interception and reports "error getting response"; `curl`
|
Inside a nested container the same allowlist applies: an allowlisted host
|
||||||
against the same host works, so reach for `curl` when testing egress.
|
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
|
### Firecracker on Linux
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user