From 628c0da8689541f6fcda0fa62e5140325e304587 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Aug 2026 00:22:10 +0000 Subject: [PATCH 1/4] Initial plan From a075c17abdc247c9277d4d9cff18b454d34bf50e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Aug 2026 00:32:42 +0000 Subject: [PATCH 2/4] Grant Arc machine identity full AKS RBAC roles matching MSI Flex Node Co-authored-by: bcho <1975118+bcho@users.noreply.github.com> --- hack/e2e/lib/node-join-arc.sh | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/hack/e2e/lib/node-join-arc.sh b/hack/e2e/lib/node-join-arc.sh index 73e2176d..70674cd2 100755 --- a/hack/e2e/lib/node-join-arc.sh +++ b/hack/e2e/lib/node-join-arc.sh @@ -8,7 +8,13 @@ set -euo pipefail [[ -n "${_E2E_NODE_JOIN_ARC_LOADED:-}" ]] && return 0 readonly _E2E_NODE_JOIN_ARC_LOADED=1 readonly arcHybridComputeAPIVersion="2024-07-10" +# Same built-in roles granted to the MSI Flex Node in infra/main.bicep (see +# roleClusterAdmin / roleAKSContributor / roleRbacAdmin). The Arc machine +# principal doesn't exist until after azcmagent connect, so it can't be +# pre-provisioned via bicep and these are assigned at runtime instead. +readonly aksClusterAdminRoleDefinitionID="0ab0b1a8-8aac-4efd-b8c2-3ee1fb270be8" readonly aksContributorRoleDefinitionID="ed7f3fbd-7b88-4dd4-9017-9adb7ce333f8" +readonly aksRBACClusterAdminRoleDefinitionID="b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b" # shellcheck disable=SC1091 source "$(dirname "${BASH_SOURCE[0]}")/common.sh" @@ -220,12 +226,20 @@ node_join_arc() { state_set "arc_principal_id" "${principal_id}" if [[ "$(state_get arc_role_assigned)" != "true" ]]; then - az role assignment create \ - --assignee-object-id "${principal_id}" \ - --assignee-principal-type ServicePrincipal \ - --role "${aksContributorRoleDefinitionID}" \ - --scope "${cluster_id}" \ - --output none + local role_definition_id + # Grant the Arc machine principal the same roles as the MSI Flex Node so + # it can call listBootstrapData and operate its AKS Machine resource. + for role_definition_id in \ + "${aksClusterAdminRoleDefinitionID}" \ + "${aksContributorRoleDefinitionID}" \ + "${aksRBACClusterAdminRoleDefinitionID}"; do + az role assignment create \ + --assignee-object-id "${principal_id}" \ + --assignee-principal-type ServicePrincipal \ + --role "${role_definition_id}" \ + --scope "${cluster_id}" \ + --output none + done state_set "arc_role_assigned" "true" fi From 502cb8b3a3a534bceb421be14e65c959c76fde35 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Aug 2026 06:33:28 +0000 Subject: [PATCH 3/4] Add TODO for dedicated Arc machine RBAC role Co-authored-by: bcho <1975118+bcho@users.noreply.github.com> --- hack/e2e/lib/node-join-arc.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hack/e2e/lib/node-join-arc.sh b/hack/e2e/lib/node-join-arc.sh index 70674cd2..4326a087 100755 --- a/hack/e2e/lib/node-join-arc.sh +++ b/hack/e2e/lib/node-join-arc.sh @@ -12,6 +12,8 @@ readonly arcHybridComputeAPIVersion="2024-07-10" # roleClusterAdmin / roleAKSContributor / roleRbacAdmin). The Arc machine # principal doesn't exist until after azcmagent connect, so it can't be # pre-provisioned via bicep and these are assigned at runtime instead. +# TODO: replace these broad built-in roles with a single dedicated custom role +# scoped to only the permissions the Arc machine actually needs. readonly aksClusterAdminRoleDefinitionID="0ab0b1a8-8aac-4efd-b8c2-3ee1fb270be8" readonly aksContributorRoleDefinitionID="ed7f3fbd-7b88-4dd4-9017-9adb7ce333f8" readonly aksRBACClusterAdminRoleDefinitionID="b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b" From 85a90f78cc80e8b2cfb8b3175402e24121f16548 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:33:10 +0000 Subject: [PATCH 4/4] Address Arc RBAC review feedback Co-authored-by: bcho <1975118+bcho@users.noreply.github.com> --- hack/e2e/lib/node-join-arc.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hack/e2e/lib/node-join-arc.sh b/hack/e2e/lib/node-join-arc.sh index 4326a087..43c01a0c 100755 --- a/hack/e2e/lib/node-join-arc.sh +++ b/hack/e2e/lib/node-join-arc.sh @@ -8,7 +8,7 @@ set -euo pipefail [[ -n "${_E2E_NODE_JOIN_ARC_LOADED:-}" ]] && return 0 readonly _E2E_NODE_JOIN_ARC_LOADED=1 readonly arcHybridComputeAPIVersion="2024-07-10" -# Same built-in roles granted to the MSI Flex Node in infra/main.bicep (see +# Same built-in roles granted to the MSI Flex Node in hack/e2e/infra/main.bicep (see # roleClusterAdmin / roleAKSContributor / roleRbacAdmin). The Arc machine # principal doesn't exist until after azcmagent connect, so it can't be # pre-provisioned via bicep and these are assigned at runtime instead. @@ -228,19 +228,24 @@ node_join_arc() { state_set "arc_principal_id" "${principal_id}" if [[ "$(state_get arc_role_assigned)" != "true" ]]; then - local role_definition_id + local role_assignment_output role_definition_id # Grant the Arc machine principal the same roles as the MSI Flex Node so # it can call listBootstrapData and operate its AKS Machine resource. for role_definition_id in \ "${aksClusterAdminRoleDefinitionID}" \ "${aksContributorRoleDefinitionID}" \ "${aksRBACClusterAdminRoleDefinitionID}"; do - az role assignment create \ + if ! role_assignment_output="$(az role assignment create \ --assignee-object-id "${principal_id}" \ --assignee-principal-type ServicePrincipal \ --role "${role_definition_id}" \ --scope "${cluster_id}" \ - --output none + --output none 2>&1)"; then + if [[ "${role_assignment_output}" != *"RoleAssignmentExists"* ]]; then + printf '%s\n' "${role_assignment_output}" >&2 + return 1 + fi + fi done state_set "arc_role_assigned" "true" fi