This came up while discussing the Headlamp plugin proposal in #6706.
Right now model.APIKey.Role is a two-tier enum — READ_ONLY / READ_WRITE — set once per key at the project level. Enforcement happens per-RPC through requireAPIKey() in pkg/app/server/grpcapi/api.go, where each handler declares its own required role (e.g. ListApplications requires READ_ONLY, SyncApplication requires READ_WRITE). But there's no scoping within a role — a READ_WRITE key satisfies every READ_WRITE check unconditionally, across every RPC.
This becomes a real limitation for external integrations that only need one specific action. For example, if a Headlamp plugin (or any similar tool) just wants to call SyncApplication, the only option today is handing it a full READ_WRITE key — which also unlocks AddApplication, DeleteApplication, and everything else in that tier. There's no way to issue a key that can do less than "all of READ_WRITE."
Filing this mainly to track the idea rather than propose a full design. A couple of directions that seem reasonable on the surface:
- An allowlist of specific RPCs/methods attached to a key, checked alongside the existing role.
- Narrower sub-roles for common cases (e.g. a "sync-only" role) instead of a single blanket
READ_WRITE.
Happy to help implement this if there's interest — just wanted to get the problem written down first in case others have opinions on the right shape for it.
This came up while discussing the Headlamp plugin proposal in #6706.
Right now
model.APIKey.Roleis a two-tier enum —READ_ONLY/READ_WRITE— set once per key at the project level. Enforcement happens per-RPC throughrequireAPIKey()inpkg/app/server/grpcapi/api.go, where each handler declares its own required role (e.g.ListApplicationsrequiresREAD_ONLY,SyncApplicationrequiresREAD_WRITE). But there's no scoping within a role — aREAD_WRITEkey satisfies everyREAD_WRITEcheck unconditionally, across every RPC.This becomes a real limitation for external integrations that only need one specific action. For example, if a Headlamp plugin (or any similar tool) just wants to call
SyncApplication, the only option today is handing it a fullREAD_WRITEkey — which also unlocksAddApplication,DeleteApplication, and everything else in that tier. There's no way to issue a key that can do less than "all of READ_WRITE."Filing this mainly to track the idea rather than propose a full design. A couple of directions that seem reasonable on the surface:
READ_WRITE.Happy to help implement this if there's interest — just wanted to get the problem written down first in case others have opinions on the right shape for it.