From 54541fa8357cf2af616effbaeb7d5b8d76f80ea2 Mon Sep 17 00:00:00 2001 From: agent Date: Sat, 7 Nov 2026 09:00:55 +0100 Subject: Public read-only distroless OCI mirror (zot + edge vhost + auditor) --- AGENTS.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 AGENTS.md (limited to 'AGENTS.md') diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..594ffaa --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,45 @@ +# AGENTS — distroless-mirror + +Public read-only OCI mirror of `gcr.io/distroless/{static,base,cc,python3}` on +`img.dieschoenewolke.de`, served by zot on the VPS. `README.md` has the +architecture, the deploy sequence and the zot-vs-registry:2 rationale. + +## Rules + +- **Read-only is a property of the registry, not of the edge.** Keep + `http.accessControl.repositories."**".anonymousPolicy` at `["read"]` and keep + the config free of any `auth` block. Adding htpasswd or an LDAP block would + create an authenticated write path that the internet could reach. +- The port publish stays `127.0.0.1:5000`. The edge vhost is the only entry + point; never publish zot on `0.0.0.0` or a host interface. +- Keep the tag allowlist short (`latest|nonroot|debug|debug-nonroot`). It bounds + both disk and what an anonymous client can make zot fetch from gcr.io. +- `platforms` stays `linux/amd64` + `linux/arm64`. Without the allowlist zot + copies every child of the index (arm, ppc64le, riscv64, s390x) and the mirror + triples in size on a 28 GB root. +- Marker tags (`synced---`) are written only after a + successful pull **by digest** through the public hostname. Do not move tag + creation before the verification, and do not mark from the digest comparison + alone. +- Sync one way only: VPS pulls from gcr.io; nothing pushes into the registry. + +## Traps + +- `edge-nginx/nginx/default.conf` is a single-file bind mount. Write in place + (`cat new > default.conf`), then `docker exec edge-nginx nginx -t` and + `nginx -s reload` (or force-recreate). Replacing the file breaks the mount. +- AppSec must stay off for this host: docker/containerd/skopeo/crane user + agents trip CRS scanner rules. The CrowdSec IP bouncer still applies. +- Do not test from the VPS: its own requests go through AppSec and can be + challenged. Test from codeserver over the public name. +- The wildcard `*.dieschoenewolke.de` SAN covers `img`; a new **name** needs a + DNS record, not a certificate change. A new apex-level domain would need the + certbot SAN list and a 300 s deSEC propagation wait. +- zot's periodic sync updates an existing tag only on the next `pollInterval` + (2 h). A digest mismatch in the auditor is therefore "pending", not "failed"; + only a 404 for a ref that was already marked is a regression. +- `proxy_buffering off` and `proxy_max_temp_file_size 0` are deliberate: layer + blobs are streamed, not spooled onto the 28 GB root filesystem. +- zot GC removes untagged manifests after `gcDelay` (1 h). Never rely on an + untagged digest staying pullable — keep the tag (or a marker tag) that + references it. -- cgit v1.2.3