Name the namespace as a repository's parent for IAM
What does this MR do and why?
An Artifact Registry admin on a namespace could not change who has access to the repositories inside it. Roles on the namespace worked. Roles on a repository inside it were refused unless the person also held an admin role on that exact repository. There is one namespace per organization, so this hit the normal case.
Rails sent the target resource on its own, as object: Object.new(id: resource_id). IAM accepts an admin role held above the target only when the request names that resource, and Rails never named it. The same role already allows deleting the repository, and that check does name the namespace.
The fix names a parent resource where that is safe.
- A repository now names the organization's Artifact Registry namespace as its parent. The namespace and the organization name no parent, because a role held there is held on the object itself. Naming a parent only adds a way to pass, so nothing that worked before changes.
- The parent is named only for repositories the namespace owns. IAM stores the object id as an opaque UUID with no organization binding, so it believes whatever Rails names. Unchecked, an admin on one namespace could revoke roles on another organization's repository by passing its UUID. Grant already verified every repository through Artifact Registry, so only revoke was exposed. Revoke now asks which of the submitted ids belong to its namespace.
- When Artifact Registry cannot answer, grant refuses and revoke names no parent and carries on. The caller then needs a role on the repository itself, which is the behaviour before the parent existed, so offboarding keeps working while Artifact Registry is down.
BaseService#verified_ancestor_for is the only method that produces a parent, and both services call it. Authn::IamService::UpdateRelationshipsClient takes an optional parent_id per assignment and per delete key.
I checked this against a local IAM database, with a user holding the admin role on the namespace and nothing on the repository.
| request | result |
|---|---|
| the repository on its own, as Rails sent it | PermissionDenied |
| the same request naming the namespace | allowed |
| user given the admin role on the repository itself | allowed |
IAM reads only the first entry of the parent list, so [namespace, org] is allowed and [org, namespace] is PermissionDenied. Order matters and length does not.
Backend only. No migration and no feature flag. The changelog trailer is on the first commit.
References
- Closes #627231 (closed)
- Related #610042 (revoke has to keep working when Artifact Registry is unreachable)
Screenshots or screen recordings
No UI change.
How to set up and validate locally
Run the specs for the changed services and client.
bundle exec rspec ee/spec/services/authz/artifact_registry/base_service_spec.rb ee/spec/services/authz/artifact_registry/grant_role_assignments_service_spec.rb ee/spec/services/authz/artifact_registry/revoke_role_assignments_service_spec.rb spec/lib/authn/iam_service/update_relationships_client_spec.rbMR acceptance checklist
Evaluated against the MR acceptance checklist.