Drop groups claim from Secrets Manager user JWTs

What does this MR do and why?

GitLab Secrets Manager lets owners grant secrets permissions to principals: User, MemberRole, Group, and Role. The Group principal is being removed. This MR is step 1: it stops Group grants from being honoured at login. Work item: #623457 (closed)

The Group principal is being removed because a group grant resolves from the group's current membership at every login. This means anyone added to the group later gets secrets access without anyone noticing. Groups can also only be added by URL path, which is easy to get wrong. Group sharing is being deprecated more broadly across GitLab, and Teams in Organizations will replace granting access to a set of users.

Where this fits

Step Change MR
1 Stop sending the groups JWT claim and drop the grps line from the CEL for new namespaces. Group grants stop working. !254051 (merged) 👈 You are here
2 Frontend hides the Group tab and stops sending GROUP. !253896 (merged)
3 Remove Group from the backend and the GraphQL schema. !254392 (merged)
4 Delete leftover group policies in OpenBao. Existing namespaces keep the old CEL text, which is harmless with the claim gone. Later milestone

Merge order is 1, then 2, then 3.

What changes

  • SecretsManagement::ProjectUserJwt and SecretsManagement::GroupUserJwt no longer send the groups claim. ProjectApiJwt and GroupApiJwt inherit from these classes, so the API JWTs drop the claim too.
  • The four CEL programs (project and group, user and API auth roles) drop the grps variable and the line that mapped it to users/direct/group_<id> policies. Newly provisioned namespaces will no longer carry this mapping.
  • Removed "group" from a comment in EffectiveCapabilitiesService that listed the unioned policy types.
  • Docs: added a history entry in doc/ci/secrets/secrets_manager/_index.md noting that group permissions are deprecated in 19.4 and no longer grant access. The "users, groups, or roles" wording in the Add steps is left for the frontend MR, since that is where the Group tab is removed.
  • Updated and added specs (see testing section below).

Why this approach

The CEL program is written into the OpenBao JWT role once, at provision time. Changing the CEL in Ruby only affects namespaces provisioned after this change. Existing namespaces would each need a separate re-provision to pick it up.

However, the CEL reads group IDs from the JWT groups claim, and Rails mints that claim fresh at every login. So if Rails stops sending the claim, the stored CEL maps over an empty list and attaches no group policies. This takes effect on the next login, for every existing namespace, on every instance, without any OpenBao writes needed.

There is no feature flag. Once this MR merges, group grants stop working right away. Rolling back means reverting and redeploying. This approach was agreed in the linked work item because the number of affected grants is small, and affected customers are being told about the change in advance.

Merge timing

Do not merge until product gives the go-ahead in the work item. Group grants stop working as soon as this merges, and the affected customers need to be told first. The frontend MR merges after this one.

Behavior and compatibility

  • Existing Group policies stay in OpenBao, but they no longer grant anything after this change. They are still listed in the permissions UI and API until a later step removes the Group type entirely.
  • New Group grants can still be created through the API and UI until the follow-up steps land, but they will not grant anything.
  • Self-managed instances get this on upgrade. There is no opt-out and nothing to run.
  • The grps mapping stays in the stored CEL of existing namespaces. It is harmless because the claim is no longer present. It will be removed in a later cleanup.

Follow-ups

  • Step 2: frontend hides the Group tab and stops sending GROUP. !253896 (merged) (merges after this one).
  • Step 3: remove Group from the backend principal types, GraphQL enum, validators, and list parser. !254392 (merged) (merges after the frontend MR).
  • Step 4: delete the leftover group policies in OpenBao and drop the grps line from stored CEL.

Testing

All 2258 examples in the secrets management spec tree pass locally against the GDK OpenBao. Coverage by layer:

  • JWT unit specs: confirm none of the four JWT classes has a groups key.
  • CEL specs in the project provision service spec: a JWT carrying a groups claim still logs in but gets no group_ policy, checked on both the user mount and the API mount.
  • Service spec: deleting a project secret with only a Group grant raises permission denied, even for a member of that group.
  • GraphQL request specs: userPermissions returns all false with only a Group grant, for both project and group secrets managers.
  • Request specs against the API mount with real JWTs: value read is denied for a member of the project's own group, a member of a group the project is shared with, a member of a group shared into the project's group, and a member of the group on the group mount.
  • Positive paths (User and Role grants) still pass in the same spec files.

References

Screenshots or screen recordings

No UI changes in this MR. The UI change is in the frontend follow-up MR listed above.

How to set up and validate locally

  1. Make sure OpenBao is running in GDK (gdk status openbao) and the secrets manager is enabled for a project you own.
  2. Create a group, add a second user to it as Developer, and make the project belong to that group (or share the project with the group).
  3. As the owner, add a secrets permission for the group as a Group principal with read_metadata and read_value. For example, use the projectSecretsPermissionUpdate GraphQL mutation with principal: { id: <group id>, type: GROUP }.
  4. Create a project secret.
  5. On master: sign in as the second user and open the project secrets page, or query projectSecretsManager { userPermissions { readMetadata } }. The secret is readable and readMetadata is true.
  6. On this branch: repeat step 5. Access is denied and readMetadata is false. Add a User grant for the second user and access works again.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Erick Bajao

Merge request reports

Loading
Loading