excalidraw: grant emo-browser SA port-forward for drawing uploads
All checks were successful
ci/woodpecker/push/default Pipeline was successful
All checks were successful
ci/woodpecker/push/default Pipeline was successful
Viktor asked to fix emo's permission so his Claude can upload to the Excalidraw service. emo's recent sessions show the documented upload recipe (kubectl port-forward svc/draw + X-Authentik-Username header, from his ~/.claude/CLAUDE.md) failing with: pods/portforward forbidden for system:serviceaccount:chrome-service:emo-browser in namespace excalidraw because his default kubeconfig is the read-only emo-browser SA (its port-forward grant covers only chrome-service) and his old admin kubeconfig at /home/emo/code/config expired and was removed. Add a namespace-scoped Role (pods/portforward create) + RoleBinding for that SA in the excalidraw namespace, mirroring the 2026-06-28 chrome-service grant. Trade-off (any-user drawings via the trusted username header) documented in the file and accepted. Also record the grant in docs/architecture/chrome-service.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
88c86e2109
commit
6f03ccd1aa
2 changed files with 55 additions and 0 deletions
|
|
@ -329,6 +329,12 @@ Two independent grants make up "browser access" for a user:
|
|||
the provisioner. To revoke: remove from `CHROME_ALLOWED` and delete the SA (rotate
|
||||
a token by deleting its `<user>-browser-token` Secret).
|
||||
|
||||
Because the SA is the user's DEFAULT kubectl credential, other per-namespace
|
||||
port-forward grants hang off the same identity: `stacks/excalidraw/rbac.tf`
|
||||
grants `emo-browser` `pods/portforward` in `excalidraw` (2026-07-02) so emo's
|
||||
agent can upload drawings via the port-forward + `X-Authentik-Username` recipe
|
||||
in his `~/.claude/CLAUDE.md`. Revoking the SA revokes those too.
|
||||
|
||||
## Limits + risks
|
||||
|
||||
- **Anti-bot vs stealth arms race** — when an upstream beats us (DRM
|
||||
|
|
|
|||
49
stacks/excalidraw/rbac.tf
Normal file
49
stacks/excalidraw/rbac.tf
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# emo's Claude → Excalidraw upload RBAC.
|
||||
#
|
||||
# emo's agent uploads drawings with `kubectl -n excalidraw port-forward svc/draw`
|
||||
# + `PUT /api/drawings/<name>` carrying the X-Authentik-Username header (the
|
||||
# documented recipe in emo's ~/.claude/CLAUDE.md — the app sits behind Authentik
|
||||
# forward-auth, so direct curl gets redirected). His hands-off credential is the
|
||||
# chrome-service/emo-browser ServiceAccount kubeconfig (stacks/chrome-service/rbac.tf);
|
||||
# its cluster-wide grant (oidc-power-user-readonly) is read-only, so pods/portforward
|
||||
# must be granted per namespace. This is the excalidraw-namespace grant
|
||||
# (Viktor's call, 2026-07-02; same pattern as the chrome-service one).
|
||||
#
|
||||
# TRADE-OFF (accepted): port-forward into this namespace bypasses the Authentik
|
||||
# ingress and the drawings API trusts the X-Authentik-Username header, so the SA
|
||||
# can read/write ANY user's drawings, not only emo's. The namespace runs nothing
|
||||
# but the drawings app, and the same class of trade-off was already accepted for
|
||||
# the shared browser (CDP reach into Viktor's sessions).
|
||||
|
||||
resource "kubernetes_role" "portforward" {
|
||||
metadata {
|
||||
name = "excalidraw-portforward"
|
||||
namespace = kubernetes_namespace.excalidraw.metadata[0].name
|
||||
}
|
||||
rule {
|
||||
api_groups = [""]
|
||||
resources = ["pods/portforward"]
|
||||
verbs = ["create"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_role_binding" "emo_browser_portforward" {
|
||||
metadata {
|
||||
name = "emo-browser-portforward"
|
||||
namespace = kubernetes_namespace.excalidraw.metadata[0].name
|
||||
}
|
||||
role_ref {
|
||||
api_group = "rbac.authorization.k8s.io"
|
||||
kind = "Role"
|
||||
name = kubernetes_role.portforward.metadata[0].name
|
||||
}
|
||||
subject {
|
||||
kind = "ServiceAccount"
|
||||
# Defined in stacks/chrome-service/rbac.tf — referenced by name across
|
||||
# stacks, same as that file references the oidc-power-user-readonly
|
||||
# ClusterRole. get/list on pods+services (needed to resolve svc/draw) comes
|
||||
# from the SA's cluster-read binding there.
|
||||
name = "emo-browser"
|
||||
namespace = "chrome-service"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue