fix(oci): rate-limit failed token verifications, not successful pulls (BUNYIP-40) #52
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/bunyip-40-oci-token-rate-limit"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes BUNYIP-40. The OCI token endpoint (
/auth/token) shared the/v1/auth/logincap (5/min/email) and counted every request. Docker requests a fresh bearer token per repository per operation, so a singledocker compose pullof 3 images is 4-6 token requests in seconds, and a legitimate member hit429 TOOMANYREQUESTSon their first pull (found in BUNYIP-35 e2e A6).Fix (short term, per the issue): rate-limit failures, not successes
Credential stuffing is many FAILED verifications; Docker's chattiness is many SUCCESSFUL ones with the same correct password. Only failures need the tight cap.
RateLimitConfig::OCI_TOKEN_FAILURES(5/min/email): incremented only on credential-verification failures (unknown email, no password, wrong password) via a newfail_credential()helper. The handler does a read-onlycheckbefore verifying and blocks at/over the cap, so a request that may succeed never consumes the failure budget. Same threat model as the old login cap.RateLimitConfig::OCI_TOKEN_THROUGHPUT(60/min/email): incremented on every request, purely to bound Argon2 CPU (~100ms/verify) so a flood of valid-credential requests cannot exhaust the server. Far above any real multi-image pull.Fix (long term): not in this PR
offline_token=true(Docker registry refresh tokens) in dunite-oci, sodocker loginstores a refresh token and pulls exchange it without re-sending credentials. That removes password verification from the per-pull path entirely. Remains open as the durable solution.Verification
rust-builder-glibc 1.94.1 container: clippy
--workspace --all-targets -D warningsclean, fmt clean, 208 lib tests pass.Live dev stack (
/auth/tokenwith basic auth):🤖 Generated with Claude Code