Lets agents running outside the pod (Claude Code on the workstation) work as Paperclip company agents.
External agents only make outbound REST calls to /api/* with Authorization: Bearer <agent key>; the Authentik gate on paperclip.renner.uno rejects those. Machine door, per the wiki-index pattern:
paperclip-api.renner.uno — LAN-only (no dns.renner.uno/public label), routes /api straight to the paperclip Service. Paperclip's bearer keys are the auth.
/api/auth on that host → 403 (Traefik ipAllowList matching nothing), so password sign-in/sign-up stays behind the gate (upstream serves all password login under /api/auth).
Host added to PAPERCLIP_ALLOWED_HOSTNAMES; CNP admits Traefik on 3100.
Trade-off: anything on the LAN can reach /api; only Paperclip's key auth protects it.
After merge: mint an agent key (paperclipai agent local-cli <name>) and use PAPERCLIP_API_URL=https://paperclip-api.renner.uno.
Lets agents running outside the pod (Claude Code on the workstation) work as Paperclip company agents.
External agents only make outbound REST calls to `/api/*` with `Authorization: Bearer <agent key>`; the Authentik gate on `paperclip.renner.uno` rejects those. Machine door, per the wiki-index pattern:
- `paperclip-api.renner.uno` — **LAN-only** (no `dns.renner.uno/public` label), routes `/api` straight to the `paperclip` Service. Paperclip's bearer keys are the auth.
- `/api/auth` on that host → 403 (Traefik `ipAllowList` matching nothing), so password sign-in/sign-up stays behind the gate (upstream serves all password login under `/api/auth`).
- Host added to `PAPERCLIP_ALLOWED_HOSTNAMES`; CNP admits Traefik on 3100.
Trade-off: anything on the LAN can reach `/api`; only Paperclip's key auth protects it.
After merge: mint an agent key (`paperclipai agent local-cli <name>`) and use `PAPERCLIP_API_URL=https://paperclip-api.renner.uno`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Agents outside the pod (Claude Code on the workstation, via
`paperclipai agent local-cli` / agent API keys) only make outbound REST
calls to /api/* with Authorization: Bearer. The Authentik gate on
paperclip.renner.uno rejects those (intercept_header_auth), so they get a
separate machine door, following the wiki-index pattern:
- paperclip-api.renner.uno (no dns.renner.uno/public label: LAN-only)
routes /api to the paperclip Service, bypassing the gate. Paperclip's
bearer agent/board keys are the authentication.
- /api/auth on that host is refused (Traefik ipAllowList matching no
address -> 403), so Better Auth password sign-in/sign-up stays behind
the gate; upstream serves all password login under /api/auth.
- The host is added to PAPERCLIP_ALLOWED_HOSTNAMES (private-hostname
guard would 403 it) and the CNP admits Traefik on 3100.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖Automated review — model CLI default (complexity: complex), commit 053e0f1a9b478eeb9044db04f7e3b0b51269eaf8.
Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.
Summary
Adds a LAN-only Ingress (paperclip-api.renner.uno) that lets external agents hit Paperclip's /api directly with a bearer key, bypassing the Authentik gate, while a second Ingress + ipAllowList Middleware is meant to keep /api/auth (password sign-in/sign-up) blocked on that host. The manifests are internally consistent with the rest of the repo's conventions (Cilium CNP labels, cert-manager/secret reuse, dns.renner.uno/public opt-out), but the auth-block mechanism departs from this repo's own established pattern in a way worth a second look before merge.
No blocking issues found, but one point below is security-relevant enough that I'd want it confirmed before relying on it in production.
🟡 Suggestions
kubernetes/apps/paperclip/api-door.yaml:9-68 — the /api/auth block relies entirely on implicit Traefik router-priority ordering, with no fallback. The two Ingress objects for the same host (/api → real backend, /api/auth → deny-all middleware) rely on Traefik's Kubernetes-Ingress provider picking the longer/more-specific PathPrefix('/api/auth') rule over PathPrefix('/api') — no traefik.ingress.kubernetes.io/router.priority annotation is set to make that explicit. This is very likely correct (Traefik's default priority is derived from rule length), but it's the sole protection keeping password sign-in/sign-up off this LAN-reachable host — there's no secondary guard the way this repo has consistently built elsewhere:
kubernetes/apps/wiki/ingress.yaml sidesteps the ambiguity entirely by putting the machine door on a different hostname (wiki-index.renner.uno) than the gated one (wiki.renner.uno), so there's never a same-host path-priority question.
kubernetes/apps/paperless/docs-traefik-ingress.yaml:5-8 explicitly reasons about the failure mode ("even if the redirect regex misses, the outpost rejects... so there is no failure mode that leaks access") and designs so a miss is still safe.
Here, if the priority ever resolved the other way (Traefik upgrade, provider quirk, a future PR adding another overlapping path under /api), requests to /api/auth would silently fall through to the real backend with no compensating control. I did not find anything indicating this is currently broken — it should work — but given this repo's own track record of building in a safety net for exactly this kind of ordering assumption, consider either an explicit router.priority annotation on paperclip-api-auth-deny (belt-and-suspenders, cheap) or moving the machine door to its own hostname as the wiki-index pattern does. Worth verifying post-deploy with a direct request to https://paperclip-api.renner.uno/api/auth/... and confirming a 403.
🟢 Nits
kubernetes/apps/paperclip/api-door.yaml:36-39 — the Middleware is named deny-all, which is generic for a namespace that may grow more middlewares later. Every other Middleware in this repo is named after its specific function/app (wiki-api-basic-auth, docs-to-paperless-redirect, loki-basic-auth). Something like paperclip-api-auth-deny (matching the Ingress it's paired with) would be more consistent and self-documenting in kubectl get middleware -A output.
Tests
This is a Kubernetes manifest change with no traditional test suite; correctness here means "does Traefik/Cilium actually enforce what the comments say" post-deploy. The one thing worth manually confirming after merge (noted above) is that GET/POST https://paperclip-api.renner.uno/api/auth/... returns 403 rather than reaching the backend, since that's the crux of the security boundary this PR introduces. The /api bearer-key path and the CiliumNetworkPolicy admission are lower-risk and match existing, already-proven patterns in this file.
Recommendation
Looks reasonable — no blocking issues; the suggestion above (explicit router priority or a separate machine-door hostname, plus a post-deploy check of the /api/auth block) is worth doing given it's a password-auth bypass boundary, but nothing here is a confirmed defect.
🤖 **Automated review** — model `CLI default` (complexity: complex), commit `053e0f1a9b478eeb9044db04f7e3b0b51269eaf8`.
> Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review.
---
## Summary
Adds a LAN-only Ingress (`paperclip-api.renner.uno`) that lets external agents hit Paperclip's `/api` directly with a bearer key, bypassing the Authentik gate, while a second Ingress + `ipAllowList` Middleware is meant to keep `/api/auth` (password sign-in/sign-up) blocked on that host. The manifests are internally consistent with the rest of the repo's conventions (Cilium CNP labels, cert-manager/secret reuse, `dns.renner.uno/public` opt-out), but the auth-block mechanism departs from this repo's own established pattern in a way worth a second look before merge.
No blocking issues found, but one point below is security-relevant enough that I'd want it confirmed before relying on it in production.
## 🟡 Suggestions
- **`kubernetes/apps/paperclip/api-door.yaml:9-68` — the `/api/auth` block relies entirely on implicit Traefik router-priority ordering, with no fallback.** The two Ingress objects for the same host (`/api` → real backend, `/api/auth` → `deny-all` middleware) rely on Traefik's Kubernetes-Ingress provider picking the longer/more-specific `PathPrefix('/api/auth')` rule over `PathPrefix('/api')` — no `traefik.ingress.kubernetes.io/router.priority` annotation is set to make that explicit. This is very likely correct (Traefik's default priority is derived from rule length), but it's the *sole* protection keeping password sign-in/sign-up off this LAN-reachable host — there's no secondary guard the way this repo has consistently built elsewhere:
- `kubernetes/apps/wiki/ingress.yaml` sidesteps the ambiguity entirely by putting the machine door on a **different hostname** (`wiki-index.renner.uno`) than the gated one (`wiki.renner.uno`), so there's never a same-host path-priority question.
- `kubernetes/apps/paperless/docs-traefik-ingress.yaml:5-8` explicitly reasons about the failure mode ("even if the redirect regex misses, the outpost rejects... so there is no failure mode that leaks access") and designs so a miss is still safe.
Here, if the priority ever resolved the other way (Traefik upgrade, provider quirk, a future PR adding another overlapping path under `/api`), requests to `/api/auth` would silently fall through to the real backend with no compensating control. I did not find anything indicating this is currently broken — it should work — but given this repo's own track record of building in a safety net for exactly this kind of ordering assumption, consider either an explicit `router.priority` annotation on `paperclip-api-auth-deny` (belt-and-suspenders, cheap) or moving the machine door to its own hostname as the wiki-index pattern does. Worth verifying post-deploy with a direct request to `https://paperclip-api.renner.uno/api/auth/...` and confirming a 403.
## 🟢 Nits
- `kubernetes/apps/paperclip/api-door.yaml:36-39` — the Middleware is named `deny-all`, which is generic for a namespace that may grow more middlewares later. Every other Middleware in this repo is named after its specific function/app (`wiki-api-basic-auth`, `docs-to-paperless-redirect`, `loki-basic-auth`). Something like `paperclip-api-auth-deny` (matching the Ingress it's paired with) would be more consistent and self-documenting in `kubectl get middleware -A` output.
## Tests
This is a Kubernetes manifest change with no traditional test suite; correctness here means "does Traefik/Cilium actually enforce what the comments say" post-deploy. The one thing worth manually confirming after merge (noted above) is that `GET/POST https://paperclip-api.renner.uno/api/auth/...` returns 403 rather than reaching the backend, since that's the crux of the security boundary this PR introduces. The `/api` bearer-key path and the CiliumNetworkPolicy admission are lower-risk and match existing, already-proven patterns in this file.
## Recommendation
Looks reasonable — no blocking issues; the suggestion above (explicit router priority or a separate machine-door hostname, plus a post-deploy check of the `/api/auth` block) is worth doing given it's a password-auth bypass boundary, but nothing here is a confirmed defect.
<!-- pr-review:sha=053e0f1a9b478eeb9044db04f7e3b0b51269eaf8 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Lets agents running outside the pod (Claude Code on the workstation) work as Paperclip company agents.
External agents only make outbound REST calls to
/api/*withAuthorization: Bearer <agent key>; the Authentik gate onpaperclip.renner.unorejects those. Machine door, per the wiki-index pattern:paperclip-api.renner.uno— LAN-only (nodns.renner.uno/publiclabel), routes/apistraight to thepaperclipService. Paperclip's bearer keys are the auth./api/authon that host → 403 (TraefikipAllowListmatching nothing), so password sign-in/sign-up stays behind the gate (upstream serves all password login under/api/auth).PAPERCLIP_ALLOWED_HOSTNAMES; CNP admits Traefik on 3100.Trade-off: anything on the LAN can reach
/api; only Paperclip's key auth protects it.After merge: mint an agent key (
paperclipai agent local-cli <name>) and usePAPERCLIP_API_URL=https://paperclip-api.renner.uno.🤖 Generated with Claude Code
🤖 Automated review — model
CLI default(complexity: complex), commit053e0f1a9b478eeb9044db04f7e3b0b51269eaf8.Summary
Adds a LAN-only Ingress (
paperclip-api.renner.uno) that lets external agents hit Paperclip's/apidirectly with a bearer key, bypassing the Authentik gate, while a second Ingress +ipAllowListMiddleware is meant to keep/api/auth(password sign-in/sign-up) blocked on that host. The manifests are internally consistent with the rest of the repo's conventions (Cilium CNP labels, cert-manager/secret reuse,dns.renner.uno/publicopt-out), but the auth-block mechanism departs from this repo's own established pattern in a way worth a second look before merge.No blocking issues found, but one point below is security-relevant enough that I'd want it confirmed before relying on it in production.
🟡 Suggestions
kubernetes/apps/paperclip/api-door.yaml:9-68— the/api/authblock relies entirely on implicit Traefik router-priority ordering, with no fallback. The two Ingress objects for the same host (/api→ real backend,/api/auth→deny-allmiddleware) rely on Traefik's Kubernetes-Ingress provider picking the longer/more-specificPathPrefix('/api/auth')rule overPathPrefix('/api')— notraefik.ingress.kubernetes.io/router.priorityannotation is set to make that explicit. This is very likely correct (Traefik's default priority is derived from rule length), but it's the sole protection keeping password sign-in/sign-up off this LAN-reachable host — there's no secondary guard the way this repo has consistently built elsewhere:kubernetes/apps/wiki/ingress.yamlsidesteps the ambiguity entirely by putting the machine door on a different hostname (wiki-index.renner.uno) than the gated one (wiki.renner.uno), so there's never a same-host path-priority question.kubernetes/apps/paperless/docs-traefik-ingress.yaml:5-8explicitly reasons about the failure mode ("even if the redirect regex misses, the outpost rejects... so there is no failure mode that leaks access") and designs so a miss is still safe.Here, if the priority ever resolved the other way (Traefik upgrade, provider quirk, a future PR adding another overlapping path under
/api), requests to/api/authwould silently fall through to the real backend with no compensating control. I did not find anything indicating this is currently broken — it should work — but given this repo's own track record of building in a safety net for exactly this kind of ordering assumption, consider either an explicitrouter.priorityannotation onpaperclip-api-auth-deny(belt-and-suspenders, cheap) or moving the machine door to its own hostname as the wiki-index pattern does. Worth verifying post-deploy with a direct request tohttps://paperclip-api.renner.uno/api/auth/...and confirming a 403.🟢 Nits
kubernetes/apps/paperclip/api-door.yaml:36-39— the Middleware is nameddeny-all, which is generic for a namespace that may grow more middlewares later. Every other Middleware in this repo is named after its specific function/app (wiki-api-basic-auth,docs-to-paperless-redirect,loki-basic-auth). Something likepaperclip-api-auth-deny(matching the Ingress it's paired with) would be more consistent and self-documenting inkubectl get middleware -Aoutput.Tests
This is a Kubernetes manifest change with no traditional test suite; correctness here means "does Traefik/Cilium actually enforce what the comments say" post-deploy. The one thing worth manually confirming after merge (noted above) is that
GET/POST https://paperclip-api.renner.uno/api/auth/...returns 403 rather than reaching the backend, since that's the crux of the security boundary this PR introduces. The/apibearer-key path and the CiliumNetworkPolicy admission are lower-risk and match existing, already-proven patterns in this file.Recommendation
Looks reasonable — no blocking issues; the suggestion above (explicit router priority or a separate machine-door hostname, plus a post-deploy check of the
/api/authblock) is worth doing given it's a password-auth bypass boundary, but nothing here is a confirmed defect.