Repository navigation
Description
Describe the bug
Every chart that renders dashboard-resourcemap.yaml grants get/list/watch on its own <release>-credentials Secret and binds that Role through cozy-lib.rbac.subjectsForTenantAndAccessLevel (list "use" .Release.Namespace).
That helper (packages/library/cozy-lib/templates/_rbac.tpl) expands a namespace such as tenant-abc-def into the chain tenant-abc, tenant-abc-def, tenant-root, and emits for each link both the groups <tenant>-use|admin|super-admin and a ServiceAccount subject named <tenant> in namespace <tenant>.
So, for every managed application:
- the tenant's own ServiceAccount — a workload identity — can read the application's credentials Secret directly, bypassing the
tenantsecretsprojection that exists to mediate that access; - so can the ServiceAccount of every parent tenant, up to
tenant-root.
Expected behaviour
A workload identity does not read managed-service credentials. The dashboard reads them as the logged-in user, so nothing in the product needs the ServiceAccount to hold that grant.
Actual behaviour
kubectl auth can-i get secret <release>-credentials --as=system:serviceaccount:tenant-root:tenant-root -n tenant-abc-def succeeds for a child tenant's application.
How it got here
The Role itself dates from 00f7c3647 (2024-08-07) but had no RoleBinding. The binding was added in 3b8a9f9d2 (2025-06-16, "Configure all apps to use new function to generate subjects"), already carrying ServiceAccount subjects.
Worth stating plainly, because the commit was not a straightforward widening: it simultaneously narrowed the tenant Roles in packages/apps/tenant/templates/tenant.yaml from apiGroups: [""], resources: ["*"] — every Secret in the namespace — to an enumerated list without Secrets. For groups that was a tightening. For ServiceAccounts, which held no access to Secrets at all, it was a widening.
The parent-tenant subject chain is itself the platform's normal idiom: RoleBinding cozy:tenant in the same file binds the same chain. The difference is that ClusterRole cozy:tenant grants no core/v1 Secrets, so until this binding existed the chain never reached a credential.
Scope
subjectsForTenantAndAccessLevel is consumed by 28 charts under packages/apps/* and packages/extra/*, plus packages/apps/tenant/templates/tenant.yaml and packages/apps/vpc/templates/vpc.yaml. Most of those bindings grant reads on Services, Ingresses and WorkloadMonitors, where a ServiceAccount subject is harmless.
Two possible fixes, and I would like direction before sending a patch
- Drop the ServiceAccount subjects from
subjectsForTenantAndAccessLevel. One edit, but it changes the subject list of all 28 bindings, most of which are not about credentials. - Split the
secretsrule out into its own Role bound to groups only, and leave the rest of each resource map untouched. Precise to the defect, but it touches every chart that renders a credentials Secret.
Who depends on the ServiceAccount grant
Nothing I can find. No pod in this repository runs as the bare <tenant> ServiceAccount — the tenant cleanup Job uses its own <tenant>-cleanup. A tenant could nevertheless have issued a token for that ServiceAccount and wired it into their own automation, which is not visible from the source, so whichever fix lands should carry a release note.
Environment
mainat4007db7a0- Affects any installation; not provider-specific.
Related
- rbac: name-scoped list/watch grants in every dashboard resource map never authorise a collection request #4044 and bug(apps): dashboard resource Roles grant list and watch under resourceNames, which never matches #3613 concern the same files but a different defect —
resourceNamescombined withlist/watch. rbac: name-scoped list/watch grants in every dashboard resource map never authorise a collection request #4044 states that nothing is over-granted, which is true of the verbs it examines and orthogonal to the subjects examined here.
Checklist
- I have checked the documentation
- I have searched for similar issues
- I have included all required information
- I have provided clear steps to reproduce
- I have included relevant logs — not applicable, this is a manifest-level grant rather than a runtime failure
Activity
lexfrei commentedon Sep 22, 2026
The info chart doesn't follow this pattern, and its binding for the OIDC-off case is dead. That branch in
packages/extra/info/templates/dashboard-resourcemap.yamlskips the helper and hard-codes a ServiceAccount subject with thetenant-prefix twice. For the release intenant-rootit renderstenant-tenant-rootin namespacetenant-tenant-root, while the tenant ServiceAccount istenant-rootintenant-root. So the binding matches nothing, and the Role behind it (get on thetenant-rootSecret) reaches no one. Whichever fix lands here, that branch needs its own call: fix the name or drop the binding.