-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Gordon's internal registry has multiple authentication layers that interact in non-obvious ways. The core confusion when Gordon is deployed on a remote server: the gordon-internal credential is loopback-only by design and cannot be used from outside the host — but this is not obvious from the CLI output or error messages. Several other issues (dead code, non-refreshed service token) compound the complexity.
Confirmed Issues
1. gordon-internal is loopback-only and the error is silent
File: internal/adapters/in/http/middleware/auth.go:128-138
if isLocalhostRequest(r) && isInternalRegistryAuth(r, internalAuth) {
next.ServeHTTP(w, r) // skip all JWT validation
return
}This credential pair works only when the request originates from 127.0.0.1. A client on a remote machine using gordon-internal + the random password gets a generic 401 with no explanation. The error message does not tell the user these credentials are loopback-only.
gordon auth internal explicitly mentions localhost in its output and documentation (internal/adapters/in/cli/auth.go:392, docs/cli/auth.md:222), so the command itself is not misleading. The problem is the 401 response body gives no useful hint to a confused operator.
2. Remote registry access works, but the path is not obvious
Confirmed working path for remote access (documented in docs/config/auth.md:91):
POST /auth/passwordwith the configured username + password → receives a 24h JWT- Use that JWT as the password for
docker login registry.example.com
This works via the token-as-password pattern (internal/adapters/in/http/middleware/auth.go:269). The issue is discoverability: there is no CLI command that wraps this flow (e.g., gordon auth docker-login), and a confused operator will reach for gordon auth internal first.
3. Service token is never refreshed (confirmed)
File: internal/app/run.go:1159
// Note: Service tokens are not auto-refreshed. If the token expires during
// container runtime, the container will need to be recreated to get a new token.
The gordon-service JWT token (used for non-loopback image pulls by the container service) has a 30-day TTL (serviceTokenDefaultTTL = 30 * 24 * time.Hour). After 30 days, internal image pulls will silently fail unless Gordon is restarted.
4. RegistryAuth old middleware is dead code in production (confirmed)
File: internal/adapters/in/http/middleware/auth.go:22
An old basic-auth-only middleware RegistryAuth exists in the same file as the current RegistryAuthV2. The old one is not wired in production (run.go:1479 uses RegistryAuthV2 only) but appears in tests. It should be removed or clearly marked as test-only to avoid confusion when reading the code.
5. GetRegistryAuthConfig() reads a deprecated field (confirmed, test-only)
File: internal/usecase/config/service.go:537-541
Reads auth.password (a deprecated plain-text config field) rather than the active bcrypt hash. Currently only called in tests — not a production bug, but a misleading API that should be removed.
6. isLocalhostRequest is duplicated (confirmed)
Identical helper defined in both:
internal/adapters/in/http/middleware/auth.go:299internal/adapters/in/http/auth/handler.go:354
Authentication Reference
For clarity, the credential types and where each one works:
| Credential | Where it works | Used by |
|---|---|---|
gordon-internal + random hex |
Loopback (127.0.0.1) only |
Docker daemon pulling from localhost |
gordon-service JWT (pull scope) |
Non-loopback, service-to-service | Container service pulling images |
| Configured username + bcrypt password | Anywhere, via POST /auth/password |
Human/CLI login, issues 24h JWT |
| Long-lived user tokens (JWT) | Anywhere | CI/CD, docker login, remote CLI |
| Ephemeral access tokens (≤5 min JWT) | Anywhere | Docker Registry v2 token protocol |
Proposed Improvements
- Add a
gordon registry login(or similar) command that wraps thePOST /auth/password→docker loginflow for operators. - Improve the 401 response body to indicate when loopback-only credentials are detected from a non-loopback source.
- Implement service token auto-refresh (see also feat: extend token expiration on each client-server interaction (+24h with 1h debounce) #84).
- Remove or clearly mark
RegistryAuthas test-only. - Consolidate
isLocalhostRequestto a single shared location.
Affected Files
internal/adapters/in/http/middleware/auth.go— dual middleware, duplicated helper, loopback bypassinternal/adapters/in/http/auth/handler.go— duplicated helper, internal bypass in token endpointinternal/app/run.go:725-737,1151-1173,1479— credential generation and wiringinternal/usecase/config/service.go:537— deprecatedGetRegistryAuthConfig()internal/usecase/container/service.go:1356—pullImage()credential branching logic