Skip to content

Support least-privilege RBAC for apiops publish — avoid requiring Resource Group Reader in preflight #303

Description

Problem or use case

apiops publish fails preflight validation unless the executing identity has
Reader (or broader) at the Resource Group scope, even though publishing
itself only ever touches the target APIM service/workspace.

validatePreFlight() (src/clients/apim-client.ts) performs two sequential
existence checks before publishing:

  1. GET {armEndpoint}/subscriptions/{sub}/resourceGroups/{rg} — requires
    Microsoft.Resources/subscriptions/resourceGroups/read, granted only by
    Reader (or higher) at resource group or subscription scope.
  2. GET {baseUrl} (the APIM service resource itself) — satisfied by
    Reader/Service Reader at APIM service scope.

Step 1 fails with a 403 for any identity scoped only to the APIM service,
before step 2 (the actually-relevant check) even runs:

AuthorizationFailed: The client does not have authorization to perform action
'Microsoft.Resources/subscriptions/resourceGroups/read' over scope
'/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}'

Use case: organizations running a shared-APIM, multi-team model (one
resource group, several teams' service principals) currently must choose
between granting every team broad RG-scoped read access to every other
resource in the RG (other APIM instances, storage, App Insights, etc.), or
funneling all publishes through a single centrally-scoped identity — both
work against per-team least privilege. This also breaks parity with extract,
where workspace-scoped Reader + Service Reader (no RG scope) is already
sufficient.

Proposed solution

Scope the preflight check down to only what publish actually needs: read
access to the target APIM service. Step 2 above already GETs the APIM
service resource directly and will itself return 404 if the resource group
or instance doesn't exist, so the RG-level check in step 1 is purely
diagnostic (a slightly clearer "resource group not found" message) and isn't
load-bearing for correctness. Two options, in order of preference:

  1. Drop the RG-level check entirely and rely on the APIM-service GET
    (step 2) for existence validation. Slightly less specific error message
    on a missing RG vs. missing APIM instance, but removes the RG Reader
    requirement entirely.
  2. Make the RG check non-fatal: if it returns 403 specifically, log a
    warning and continue to step 2, only hard-failing on a genuine 404.
    Preserves the diagnostic for identities that do have RG-level access,
    without hard-blocking least-privilege ones.

Affected command

apiops publish

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions