Secrets Manager: Consolidate authorization abilities
Context
Reviewing !240596 (merged) surfaced how confusing the permission zoo around Secrets Manager has become. There are at least three abilities whose relationship isn't obvious from the names alone:
:read_secrets_manager— maintainer+ (assignable permission, granular scope). Used by the granular directive and the enrollment/entitlement types.:read_project_secrets_manager_status/:read_group_secrets_manager_status— reporter+ (viareporter.yml). Used by the SM type/resolver as the CE session gate.:read_secrets_permission— maintainer+. Used to view the assigned permissions grid.:read_secret/:read_project_secrets— reporter+ on group / reporter+ on project. Used to read individual secret values, but has been reused historically to gate other things too.- Plus the SM disabled/entitlement prevent rules and the OpenBao capability layer sit on top.
Each was added incrementally; the naming and the access boundaries diverged over time. Contributors have to reverse-engineer the intent before every change.
Goal
Audit the SM ability surface end to end and either:
- Merge/rename abilities so each concept has a single canonical name, or
- Document the intended split clearly (for example a
README.mdin the policies directory, or an ADR under.agent-docs/secrets-manager/).
Known concrete inconsistencies
-
Entitlement rule blocks group SM status but not project SM status.
ee/app/policies/ee/group_policy.rb'ssecrets_manager_entitlement_denies_accessrule prevents:read_group_secrets_manager_status, so an entitlement-denied group returns a top-level access error ongroupSecretsManagerqueries. The equivalent project rule inee/app/policies/ee/project_policy.rbdoes not prevent:read_project_secrets_manager_status, so an entitlement-denied project still returnsstatus: 'ACTIVE'fromprojectSecretsManager— misleading, since the SM is actually inaccessible.The status enum returns pure lifecycle state (
PROVISIONING/ACTIVE/DEPROVISIONING) with no entitlement awareness, so the current project behavior gives callers no way to distinguish "usable" from "entitlement-denied". The group side is the more correct behavior; project should match by addingprevent :read_project_secrets_manager_statusto its entitlement-denies rule, along with a request spec mirroring the group'saccess_control_speccontext added in !243141 (merged).Related history: the group side blocks status only by accident — the entitlement rule was designed to gate secret values and admin, and Ahmad's !234896 (merged) had reused
:read_secretfor the group SM type authorize. !240596 (merged) then introduced the dedicated:read_group_secrets_manager_statusand explicitly added it to the entitlement prevent block to keep the behavior tested in !243141 (merged) (D2).
References
- !240596 (merged) (thread that surfaced this: !240596 (comment 3530371487))
- !234896 (merged) (introduced
:read_secretonGroupSecretsManagerTypebecause:read_secrets_managerwas maintainer-only) - !242456 (merged) (introduced the entitlement-denies rules; asymmetric preventions)
- !243141 (merged) (D2 write-entitlement enforcement; added the group entitlement-denies read test)
config/authz/permissions/secrets_manager/read.ymlconfig/authz/roles/{reporter,maintainer,auditor}.ymlee/app/policies/ee/{project,group}_policy.rb
Raised by @hmehra during review of !240596 (merged).