Skip to content

Kickstart: pre-flight check for user deploy RBAC (cluster + ACR)#2165

Open
bosesuneha wants to merge 1 commit into
Azure:kickstartfrom
bosesuneha:feat/kickstart-rbac-checks
Open

Kickstart: pre-flight check for user deploy RBAC (cluster + ACR)#2165
bosesuneha wants to merge 1 commit into
Azure:kickstartfrom
bosesuneha:feat/kickstart-rbac-checks

Conversation

@bosesuneha
Copy link
Copy Markdown
Member

@bosesuneha bosesuneha commented May 20, 2026

Summary

Adds a centralized pre-flight check that verifies the signed-in user holds the Azure role assignments required for a successful Kickstart deploy on the Normal Namespace path, and surfaces the result as a markdown table in the CONFIGURE phase.

Cluster scope (only when Azure RBAC for Kubernetes is enabled — always on for AKS Automatic):

  • AKS RBAC Writer / RBAC Admin / RBAC Cluster Admin → required for kubectl apply

ACR scope:

  • AcrPush → required for docker push during BUILD
  • Container Registry Tasks Contributor → required for az acr build

The check uses roleAssignments.listForScope with atScope(), so RG / subscription / management-group-inherited assignments count.

Behavior

  • CONFIGURE phase — displays a single pre-flight table with five always-rendered checks (Cluster SKU, Kubeconfig access, ACR pull (cluster→registry), ACR push (you→registry), ACR Tasks (you→registry)) plus the AKS RBAC row when azureRbacEnabled is true.
  • DEPLOY phase — blocks only when the user definitively lacks an AKS RBAC Writer-tier role on an Azure-RBAC-enabled cluster. All other misses (ACR roles, kubeconfig) are display-only; they fail naturally with a clearer 403 in BUILD if missing.
  • 403 on enumeration*Inconclusive flag is set → warning rendered, no block.

Out of scope (deferred to follow-up PR)

Self-assign / fix-it commands for missing roles. The check results carry all the data needed; this PR is checks-only.

Files

  • New src/commands/utils/aksRbacHelpers.ts — role IDs, isAzureRbacEnabled, isAuthorizationError, checkUserDeployRbac
  • src/commands/aksContainerAssist/oidcSetup.ts — dedup constants, delegate to shared helper
  • src/commands/aksKickstart/configure.ts — fetch cluster once, parallel checks, userDeployRbac on KickstartConfiguration
  • src/chatParticipants/kickstart/state.tsConfigData extended with RBAC fields
  • src/chatParticipants/kickstart/phases/configure.ts — markdown-table renderer
  • src/chatParticipants/kickstart/phases/deploy.ts — pre-deploy RBAC gate

Testing

  • tsc --noEmit clean
  • eslint clean on all touched files
  • Full test suite: 187 passing, 3 failing — the 3 failures (BUILD/DEPLOY/VERIFY validatePrereqs) pre-exist on upstream/kickstart and are unrelated to this change (verified by stash + re-run)
  • Tested manually on an AKS Standard cluster (Azure RBAC disabled): all 5 base checks render, AKS RBAC row is correctly suppressed

Adds a centralized helper that checks whether the signed-in user holds the
Azure role assignments required for a successful Kickstart deploy on the
Normal Namespace path:

  Cluster scope (Azure RBAC for Kubernetes, when enabled):
    - AKS RBAC Writer / RBAC Admin / RBAC Cluster Admin (kubectl apply)
  ACR scope:
    - AcrPush                              (docker push)
    - Container Registry Tasks Contributor (az acr build)

The check uses listForScope with the atScope() filter so RG / subscription /
MG-inherited assignments count. A 403 on enumeration sets a *Inconclusive
flag so the UI warns rather than blocks.

CONFIGURE phase renders results as a single markdown table; DEPLOY phase
blocks only when the user definitively lacks an AKS RBAC Writer-tier role
on an Azure-RBAC-enabled cluster.

Refactors aksContainerAssist/oidcSetup.ts to consume the same role-ID
constants and isAzureRbacEnabled helper from the new shared module.

Self-assign / fix-it commands deferred to a follow-up PR.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a centralized Kickstart pre-flight RBAC check for the signed-in user (cluster deploy roles + ACR push/tasks roles) and surfaces the results in the CONFIGURE phase as a markdown table, with a deploy-phase gate when Azure RBAC for Kubernetes is enabled and the user definitively lacks a deploy-capable AKS RBAC role.

Changes:

  • Introduces aksRbacHelpers.ts with role IDs and helper functions to detect Azure RBAC enablement and enumerate user role assignments at cluster/ACR scopes.
  • Extends Kickstart configuration/state to carry RBAC pre-flight results and renders them in CONFIGURE as a single markdown table.
  • Adds a DEPLOY-phase blocker for Azure-RBAC-enabled clusters when the user is confirmed missing an AKS RBAC Writer/Admin/Cluster Admin role.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/commands/utils/aksRbacHelpers.ts New shared helper for AKS/ACR RBAC pre-flight (role IDs, Azure RBAC detection, role assignment enumeration).
src/commands/aksKickstart/configure.ts Fetch cluster once and run new RBAC pre-flight in parallel; plumbs result into KickstartConfiguration.
src/commands/aksContainerAssist/oidcSetup.ts Deduplicates built-in role IDs and reuses shared aksRbacHelpers utilities.
src/chatParticipants/kickstart/state.ts Extends ConfigData with RBAC pre-flight fields for rendering and gating.
src/chatParticipants/kickstart/phases/configure.ts Renders consolidated pre-flight checks as a markdown table (including RBAC rows when applicable).
src/chatParticipants/kickstart/phases/deploy.ts Blocks deployment when Azure RBAC for Kubernetes is enabled and the user conclusively lacks a deploy role.
src/tests/suite/kickstart.integration.test.ts Updates integration test fixtures to include new ConfigData RBAC fields.
src/chatParticipants/kickstart/state.test.ts Updates state tests for new RBAC fields in ConfigData.
src/chatParticipants/kickstart/phaseRunner.test.ts Updates phase runner tests for new RBAC fields in ConfigData.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

scope: string,
userObjectId: string,
): Promise<Errorable<ScopeRolesResult>> {
const listResult = await listAll(client.roleAssignments.listForScope(scope, { filter: "atScope()" }));
Comment on lines +72 to +90
): Promise<Errorable<ScopeRolesResult>> {
const listResult = await listAll(client.roleAssignments.listForScope(scope, { filter: "atScope()" }));

if (failed(listResult)) {
if (isAuthorizationError(listResult.error)) {
return {
succeeded: true,
result: { roleIds: new Set(), inconclusive: true, reason: listResult.error },
};
}
return listResult;
}

const roleIds = new Set<string>();
for (const ra of listResult.result) {
if (ra.principalId?.toLowerCase() !== userObjectId.toLowerCase()) continue;
const roleDefName = ra.roleDefinitionId?.split("/").pop();
if (roleDefName) roleIds.add(roleDefName.toLowerCase());
}
Comment on lines +8 to +14
/** Result of a single pre-flight check: granted ✅, missing ❌, or inconclusive ⚠️ (403). */
type CheckStatus = "granted" | "missing" | "inconclusive";

const STATUS_ICON: Record<CheckStatus, string> = { granted: "✅", missing: "❌", inconclusive: "⚠️" };

function statusOf(granted: boolean, inconclusive: boolean): CheckStatus {
if (inconclusive) return "inconclusive";
Comment on lines +191 to +202
const checks: PreflightCheck[] = [
check("Cluster SKU", config.clusterSku === "Automatic" ? "inconclusive" : "granted", {
granted: "AKS Standard",
missing: "AKS Standard",
inconclusive:
"AKS Automatic — Azure manages node pools, scaling, and upgrades. Some Kickstart features may behave differently.",
}),
check("Kubeconfig access (you → cluster)", config.canGetKubeconfig ? "granted" : "missing", {
granted: "Available",
missing: "Denied. Ensure you have the **Azure Kubernetes Service Cluster User Role** on the cluster.",
inconclusive: "Could not verify.",
}),
@davidgamero
Copy link
Copy Markdown
Collaborator

Fixes for Copilot review comments

I've addressed all 4 review comments locally. Here's the commit: 0a4b4bc on branch feat/kickstart-rbac-checks in my fork.

Changes:

1. aksRbacHelpers.ts — Fix atScope() filter + server-side filtering

  • Removed atScope() filter from listForScope to include inherited role assignments (RG/subscription/MG)
  • Replaced in-memory principalId filtering with server-side assignedTo('${userObjectId}') filter — much cheaper on large subscriptions

2. configure.ts — Add warning status for AKS Automatic SKU

  • Added warning as a distinct CheckStatus (💡 icon) separate from inconclusive (⚠️ icon)
  • AKS Automatic SKU now uses warning — it's informational, not an auth uncertainty
  • inconclusive is reserved for 403/auth failures as intended
  • Made check() details Partial<Record<CheckStatus, string>> so callers only need to specify relevant statuses

3. configure.ts — Render pre-flight table before kubeconfig failure

  • Moved kubeconfig early return to AFTER renderPreflightTable(stream, checks) so users see all check results before being told kubeconfig access is denied

@bosesuneha Can you pull this into the PR? Branch: davidgamero:feat/kickstart-rbac-checks

davidgamero added a commit that referenced this pull request May 26, 2026
* Add deploy RBAC pre-flight checks to Kickstart configure phase

Adds a centralized helper that checks whether the signed-in user holds the
Azure role assignments required for a successful Kickstart deploy on the
Normal Namespace path:

  Cluster scope (Azure RBAC for Kubernetes, when enabled):
    - AKS RBAC Writer / RBAC Admin / RBAC Cluster Admin (kubectl apply)
  ACR scope:
    - AcrPush                              (docker push)
    - Container Registry Tasks Contributor (az acr build)

The check uses listForScope with the atScope() filter so RG / subscription /
MG-inherited assignments count. A 403 on enumeration sets a *Inconclusive
flag so the UI warns rather than blocks.

CONFIGURE phase renders results as a single markdown table; DEPLOY phase
blocks only when the user definitively lacks an AKS RBAC Writer-tier role
on an Azure-RBAC-enabled cluster.

Refactors aksContainerAssist/oidcSetup.ts to consume the same role-ID
constants and isAzureRbacEnabled helper from the new shared module.

Self-assign / fix-it commands deferred to a follow-up PR.

* fix: address Copilot review comments on PR #2165

- aksRbacHelpers: remove atScope() filter to include inherited roles;
  use assignedTo server-side filter instead of in-memory principalId check
- configure: add 'warning' CheckStatus for AKS Automatic SKU info
  (distinct from 'inconclusive' which means 403/auth failure)
- configure: render pre-flight table before kubeconfig failure so user
  sees all check results even when kubeconfig access is denied

---------

Co-authored-by: Suneha Bose <suneha.bose@gmail.com>
Co-authored-by: David Gamero <davidgamero@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants