你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。

准备弹性节点主机和标识(预览版)

Important

AKS 预览功能可在自助服务和自愿选择的基础上启用。 预览版按“现状”和“视供应情况”提供,它们不包括在服务级别协议和有限保证范围内。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

将 Linux 主机附加为弹性节点之前,请准备主机,配置在规划期间选择的标识,并授予该标识对Azure Kubernetes 服务 (AKS)群集的访问权限。

在本文中,你将了解:

  • 查看主机要求,然后预配或选择 Linux 主机及其Azure标识。
  • 准备并检查主机,并记录附件工作流使用的值。
  • 在 AKS 群集范围内分配标识访问权限,并验证该标识。

在 Linux 兼容的 Bash 环境中运行具有所需工具和网络访问权限的本文中的管理命令。 本文将该环境称为你的 Bash 环境。 加入集群的独立机器是 flex 节点主机;仅当某个步骤明确指示您这样做时,才在该主机上运行命令。

在您开始之前

  • 完成 配置网络并在 AKS 中创建弹性节点池。
  • 查看 弹性节点的标识和访问概念 ,并选择一个标识选项。
  • 使用Azure帐户,该帐户可以检查主机资源并在 AKS 群集范围内创建角色分配。 Role Based 访问控制 Administrator 和 User Access Administrator 是可创建该分配的角色示例。
  • 在 Bash 环境中安装Azure CLI和 OpenSSH 客户端。
  • 准备主机可接受的 SSH 密钥对。

加载部署环境

启动新的 Bash 会话,从规划文章中标识环境文件,然后加载它。 将 <deployment-name> 替换为您的部署标签。

export FLEXNODE_DEPLOYMENT="<deployment-name>"
export FLEXNODE_ENV_FILE="${HOME}/.config/aks-flexnode/${FLEXNODE_DEPLOYMENT}.env"
test -s "${FLEXNODE_ENV_FILE}"
source "${FLEXNODE_ENV_FILE}"

环境文件提供了本文要读取的共享部署值,包括 WORK_DIR(即你在 Bash 环境中用于存储本文下载内容和生成文件的目录)。 默认情况下,WORK_DIR 为 ~/.local/share/aksflexnode/<deployment-name>。 本文会推导出所需的其他变量。 如果尚未创建环境文件,请先 完成计划弹性节点部署 。

如果找不到文件或无法加载,请在继续之前停止并返回到规划文章。

设置当前订阅并确认所选集群:

az account set --subscription "${SUBSCRIPTION_ID}"

az aks show \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --query "{Name:name,ResourceId:id,ProvisioningState:provisioningState}" \
    --output table

当资源 ID 匹配 AKS_RESOURCE_ID 且预配状态为 Succeeded时继续。

1.查看主机要求

使用满足以下要求的专用主机:

  • 运行 Ubuntu 24.04 LTS、Azure Linux 3.x 或 Red Hat Enterprise Linux(RHEL) 9 或 10 的 AMD64 或 ARM64 主机。
  • 一个唯一的主机名,且为有效的 DNS 子域名。 代理在注册节点时将其转换为小写。
  • 至少四个 vCPU,并且在 /var/lib 下至少有 8 GiB 可用。
  • 主机上具有根访问权限或无 sudo 密码访问权限的 SSH 帐户。
  • 对 AKS API 服务器、Azure 资源管理器、Microsoft Entra ID、所选弹性节点发布和项目镜像以及所需的容器注册表的网络访问。
  • 弹性节点主机网络与 AKS 托管节点网络之间的现有第 3 层连接。 主机和 AKS 群集不必位于同一Azure区域中。

Bash 环境还必须能够通过 SSH 连接到弹性节点主机。 如果具有另一个批准的管理路径,则不需要公共 IP 地址。

2.预配或选择主机和标识

仅完成 弹性节点的标识和访问概念 中所选标识选项对应的部分。 不要为同一主机配置多个持久Azure标识模式。

小窍门

连接位于 Azure 外部的计算机? 如果计算机已启用 Arc,请使用Azure Arc托管标识,或使用服务主体。 仅当弹性节点主机是Azure VM 时,才使用Azure VM 托管标识。

设置每个标识选项使用的 SSH 密钥路径:

export SSH_PRIVATE_KEY_PATH="<path-to-private-key>"
export SSH_PUBLIC_KEY_PATH="<path-to-public-key>"

每个标识选项还建立两个主机地址。 FLEX_HOST_SSH_TARGET 是 Bash 环境使用的地址。 FLEX_HOST_PRIVATE_IP 是可从 AKS 托管节点网络访问的主机地址。 请与网络管理员确认,FLEX_HOST_PRIVATE_IP 属于 FLEX_HOST_SUBNET_CIDR,并且是可从 AKS 托管的节点网络访问到的地址。 不要将单独的公共地址或仅限管理地址用作弹性节点地址。

使用Azure Arc托管标识

对于已连接到 Azure Arc 的主机,请使用此选项。如有必要,请参阅 使用已启用 Azure Arc 的服务器连接混合计算机。

设置 Arc 资源值和主机地址:

export ARC_RESOURCE_GROUP="<arc-machine-resource-group>"
export ARC_MACHINE_NAME="<arc-machine-name>"
export FLEX_HOST_SSH_TARGET="<admin-user>@<reachable-host-address>"
export FLEX_HOST_PRIVATE_IP="<private-ip-reachable-from-aks>"

检索资源 ID、连接状态和主体对象 ID:

ARC_RESOURCE_ID="/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${ARC_RESOURCE_GROUP}/providers/Microsoft.HybridCompute/machines/${ARC_MACHINE_NAME}"
export ARC_RESOURCE_ID

HOST_PRINCIPAL_OBJECT_ID="$(az resource show \
    --ids "${ARC_RESOURCE_ID}" \
    --query identity.principalId \
    --output tsv)"
export HOST_PRINCIPAL_OBJECT_ID

az resource show \
    --ids "${ARC_RESOURCE_ID}" \
    --query "{Name:name,Status:properties.status,IdentityType:identity.type,PrincipalId:identity.principalId}" \
    --output yaml

当 Status 为 Connected 且 PrincipalId 已填充时,继续。

验证主机上的 Connected Machine 代理和混合实例元数据服务:

ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}" \
    'sudo azcmagent show && systemctl is-active himdsd'

确认 azcmagent show 报告的订阅 ID、资源组和计算机名称与 ARC_RESOURCE_ID、ARC_RESOURCE_GROUP 和 ARC_MACHINE_NAME 相同。 此外,请确认是否 himdsd 处于活动状态。 如果资源不匹配,在分配访问权限之前停止并更正 Arc 资源值。

记录 Arc 和标识值:

set_flexnode_env ARC_RESOURCE_GROUP "${ARC_RESOURCE_GROUP}"
set_flexnode_env ARC_MACHINE_NAME "${ARC_MACHINE_NAME}"
set_flexnode_env ARC_RESOURCE_ID "${ARC_RESOURCE_ID}"
set_flexnode_env FLEX_HOST_SSH_TARGET "${FLEX_HOST_SSH_TARGET}"
set_flexnode_env FLEX_HOST_PRIVATE_IP "${FLEX_HOST_PRIVATE_IP}"
set_flexnode_env HOST_PRINCIPAL_OBJECT_ID "${HOST_PRINCIPAL_OBJECT_ID}"
set_flexnode_env HOST_IDENTITY_CLIENT_ID ""

使用服务主体

对另一台受支持的虚拟机或裸机主机使用此选项。 优先使用证书凭据,而非长期有效的客户端密钥。 以下步骤使用自签名证书创建专用应用程序和服务主体进行评估。 他们不创建客户端密码或分配Azure角色。 在步骤 4 中授予对目标 AKS 群集的访问权限。

在继续之前:

  • 在 Bash 环境中安装 OpenSSL,并使用支持 az login --certificate 的最新版本 Azure CLI。
  • 使用具有在与目标订阅关联的 Microsoft Entra 租户中注册应用程序并创建服务主体权限的帐户登录。 仅Azure订阅所有权不会授予这些目录权限。 如果租户限制应用程序注册,请向租户管理员寻求帮助。 请参阅使用Azure CLI创建Azure服务主体。
  • 确认你的组织允许在评估中使用自签名证书。 对于现有的已获批准身份,请使用其租户 ID、应用程序客户端 ID、服务主体对象 ID 和受保护的 PEM 文件,然后跳至 记录服务主体和主机值。

不要将凭据、私钥或凭据路径存储在共享环境文件中。 请勿打印 PEM 文件或将其包含在源代码管理中。 PEM 文件包含未加密的私钥,以便代理可以在没有交互式密码提示的情况下进行身份验证。 使用文件权限和批准的主机访问控制对其进行保护。

创建基于证书的服务主体

使用操作员帐户登录时,在 Bash 环境中运行这些命令。

  1. 确认订阅、租户和登录帐户。

    az account set --subscription "${SUBSCRIPTION_ID}"
    az account show \
        --query "{SubscriptionId:id,TenantId:tenantId,Account:user.name}" \
        --output table
    
    SP_TENANT_ID="$(az account show --query tenantId --output tsv)"
    export SP_TENANT_ID
    

    仅当订阅和租户是预期目标时才继续。

  2. 选择唯一的应用程序显示名称并创建受保护的凭据目录。

    export SP_DISPLAY_NAME="aks-flexnode-${FLEXNODE_DEPLOYMENT}-$(date -u +%Y%m%dT%H%M%SZ)"
    install -d -m 0700 "${WORK_DIR:?Load the deployment environment first.}"
    SP_CREDENTIAL_DIR="$(mktemp -d "${WORK_DIR}/sp-credential.XXXXXXXX")"
    export SP_CREDENTIAL_DIR
    export SP_CLIENT_CERTIFICATE_FILE="${SP_CREDENTIAL_DIR:?Credential directory wasn't created.}/sp-client.pem"
    
  3. 创建包含证书和私钥的 30 天证书和组合 PEM 文件。

    (
        set -e
        umask 077
    
        openssl req -x509 -newkey rsa:2048 -sha256 -days 30 -nodes \
            -keyout "${SP_CREDENTIAL_DIR}/sp-client.key" \
            -out "${SP_CREDENTIAL_DIR}/sp-client.crt" \
            -subj "/CN=${SP_DISPLAY_NAME}"
    
        cat "${SP_CREDENTIAL_DIR}/sp-client.crt" \
            "${SP_CREDENTIAL_DIR}/sp-client.key" \
            > "${SP_CLIENT_CERTIFICATE_FILE}"
        chmod 0600 "${SP_CLIENT_CERTIFICATE_FILE}"
        rm -f "${SP_CREDENTIAL_DIR}/sp-client.key"
    )
    
    openssl x509 \
        -in "${SP_CREDENTIAL_DIR}/sp-client.crt" \
        -noout -subject -dates
    stat -c '%a %n' "${SP_CLIENT_CERTIFICATE_FILE}"
    

    如果证书创建失败,请停止。 确认 PEM 权限为 600。 30 天的有效期用于评估,而不是轮换策略。 如果主机仍处于连接状态,请在凭据过期前按照经批准的流程更换凭据。

  4. 通过仅上传公共证书来创建应用程序和服务主体。

    SP_CLIENT_ID="$(az ad sp create-for-rbac \
        --name "${SP_DISPLAY_NAME}" \
        --cert "@${SP_CREDENTIAL_DIR}/sp-client.crt" \
        --query appId \
        --output tsv)"
    export SP_CLIENT_ID
    

    仅当命令成功并返回应用程序客户端 ID 时继续。 该命令可以报告它调整凭据结束日期以匹配证书的到期日期。 不要添加 --role 或 --scopes;以后的角色分配仅限于 AKS 群集。 不要针对现有应用程序重新运行创建以轮换其凭据。

  5. 检索服务主体对象 ID 并检查已注册的凭据。

    SP_OBJECT_ID="$(az ad sp show \
        --id "${SP_CLIENT_ID}" \
        --query id \
        --output tsv)"
    export SP_OBJECT_ID
    
    az ad sp show \
        --id "${SP_CLIENT_ID}" \
        --query "{ClientId:appId,ServicePrincipalObjectId:id}" \
        --output table
    
    az ad app show \
        --id "${SP_CLIENT_ID}" \
        --query "{ClientId:appId,PasswordCredentials:length(passwordCredentials),Certificates:keyCredentials[].{KeyId:keyId,Expires:endDateTime}}" \
        --output json
    

    确认服务主体对象 ID 已填入,两个客户端 ID 均与 SP_CLIENT_ID 匹配,PasswordCredentials 为 0,并且仅注册了一个证书,且其到期时间符合预期。 如果目录复制延迟查找,请短暂等待并重试查找,而不是创建另一个应用程序。

对于仅凭据测试,只需在 “验证服务主体”中运行证书身份验证检查。 无需分配Azure角色或为该检查准备主机。 测试完成后, 删除专用测试应用程序和本地凭据。

记录服务主体和主机值

设置主机地址。 如果您选择了现有身份,请先将 SP_TENANT_ID、SP_CLIENT_ID 和 SP_OBJECT_ID 设置为其标识符。

export FLEX_HOST_SSH_TARGET="<admin-user>@<reachable-host-address>"
export FLEX_HOST_PRIVATE_IP="<private-ip-reachable-from-aks>"

: "${SP_TENANT_ID:?Set the Microsoft Entra tenant ID.}"
: "${SP_CLIENT_ID:?Set the application client ID.}"
: "${SP_OBJECT_ID:?Set the service principal object ID.}"
export HOST_IDENTITY_CLIENT_ID=""
export HOST_PRINCIPAL_OBJECT_ID="${SP_OBJECT_ID}"

set_flexnode_env FLEX_HOST_SSH_TARGET "${FLEX_HOST_SSH_TARGET}"
set_flexnode_env FLEX_HOST_PRIVATE_IP "${FLEX_HOST_PRIVATE_IP}"
set_flexnode_env SP_TENANT_ID "${SP_TENANT_ID}"
set_flexnode_env SP_CLIENT_ID "${SP_CLIENT_ID}"
set_flexnode_env SP_OBJECT_ID "${SP_OBJECT_ID}"
set_flexnode_env HOST_IDENTITY_CLIENT_ID "${HOST_IDENTITY_CLIENT_ID}"
set_flexnode_env HOST_PRINCIPAL_OBJECT_ID "${HOST_PRINCIPAL_OBJECT_ID}"

SP_OBJECT_ID 是 企业应用程序的对象 ID,也称为服务主体对象 ID。 它不是应用注册的对象 ID。 确认 SP_CLIENT_ID、SP_OBJECT_ID 以及证书均属于同一服务主体。

Bootstrap 在生成的代理配置中将 SP_TENANT_ID 和 SP_CLIENT_ID 映射到 azure.servicePrincipal.tenantId 和 azure.servicePrincipal.clientId。 SP_OBJECT_ID用于Azure角色分配,而不是代理的客户端 ID。 有关证书文件字段、完整修订的配置形状和安全验证命令,请参阅 “检查呈现的服务主体配置”。

保留受保护的 PEM 文件以进行身份验证和主机启动。 在附加之前,请按照你们已批准的凭据管理流程,使其在主机上可用。 通过批准的凭据管理过程(而不是在共享环境文件中)记录其位置。 继续执行 准备并检查主机,然后分配 AKS 角色。

使用Azure虚拟机托管标识

对Azure VM 使用此选项。 通过以下快速入门创建 VM:使用Azure CLI创建 Linux 虚拟机,或选择现有 VM。 将 VM 放置在计划用于此部署的弹性节点主机网络中。 当 Bash 环境具有另一个批准的 SSH 路径时,不需要公共 IP 地址。

设置 VM 值:

export VM_RESOURCE_GROUP="<vm-resource-group>"
export VM_NAME="<vm-name>"
export VM_ADMIN_USER="<vm-admin-user>"

检索 VM 资源 ID 和主机地址。 当 VM 有公共 IP 地址时,SSH 目标使用公共 IP 地址,否则使用专用地址:

VM_RESOURCE_ID="$(az vm show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --query id \
    --output tsv)"
export VM_RESOURCE_ID

FLEX_HOST_PRIVATE_IP="$(az vm show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --show-details \
    --query privateIps \
    --output tsv)"
export FLEX_HOST_PRIVATE_IP

VM_PUBLIC_IP="$(az vm show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --show-details \
    --query publicIps \
    --output tsv)"
export VM_PUBLIC_IP

export FLEX_HOST_SSH_TARGET="${VM_ADMIN_USER}@${VM_PUBLIC_IP:-${FLEX_HOST_PRIVATE_IP}}"

确认为 VM 返回的专用地址:

az vm list-ip-addresses \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --query "[0].virtualMachine.{Name:name,PrivateAddresses:network.privateIpAddresses}" \
    --output table

仅当 FLEX_HOST_SUBNET_CIDR 包含一个属于 FLEX_HOST_PRIVATE_IP 的专用地址,且该地址可从 AKS 托管的节点网络访问时,才继续。 如果 Azure 返回多个地址,请先将 FLEX_HOST_PRIVATE_IP 设置为计划中的弹性节点地址,然后再继续。

如果 VM 没有公共 IP 地址,或者 Bash 环境通过另一个批准的管理路径到达主机,请设置为 FLEX_HOST_SSH_TARGET Bash 环境可以访问的地址或主机名。

完成以下任一托管标识选项的配置。

系统分配的托管标识

启用系统分配的托管标识:

az vm identity assign \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --output none

获取其主体对象 ID:

HOST_PRINCIPAL_OBJECT_ID="$(az vm show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --query identity.principalId \
    --output tsv)"
export HOST_PRINCIPAL_OBJECT_ID

export HOST_IDENTITY_CLIENT_ID=""

用户分配的管理标识

按照《使用 Azure CLI 管理用户分配的托管标识》中的说明创建或选择一个标识。

设置标识值:

export USER_ASSIGNED_IDENTITY_RESOURCE_GROUP="<identity-resource-group>"
export USER_ASSIGNED_IDENTITY_NAME="<identity-name>"

获取身份标识符:

USER_ASSIGNED_IDENTITY_RESOURCE_ID="$(az identity show \
    --resource-group "${USER_ASSIGNED_IDENTITY_RESOURCE_GROUP}" \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --query id \
    --output tsv)"
export USER_ASSIGNED_IDENTITY_RESOURCE_ID

HOST_PRINCIPAL_OBJECT_ID="$(az identity show \
    --resource-group "${USER_ASSIGNED_IDENTITY_RESOURCE_GROUP}" \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --query principalId \
    --output tsv)"
export HOST_PRINCIPAL_OBJECT_ID

HOST_IDENTITY_CLIENT_ID="$(az identity show \
    --resource-group "${USER_ASSIGNED_IDENTITY_RESOURCE_GROUP}" \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --query clientId \
    --output tsv)"
export HOST_IDENTITY_CLIENT_ID

将标识分配给虚拟机:

az vm identity assign \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --identities "${USER_ASSIGNED_IDENTITY_RESOURCE_ID}" \
    --output none

验证 VM 是否列出所选标识:

az vm identity show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --query "{Type:type,UserAssignedIdentities:userAssignedIdentities}" \
    --output yaml

当输出包含 USER_ASSIGNED_IDENTITY_RESOURCE_ID时继续。

记录 VM 标识

记录 VM 和标识值:

set_flexnode_env VM_RESOURCE_GROUP "${VM_RESOURCE_GROUP}"
set_flexnode_env VM_NAME "${VM_NAME}"
set_flexnode_env VM_ADMIN_USER "${VM_ADMIN_USER}"
set_flexnode_env VM_RESOURCE_ID "${VM_RESOURCE_ID}"
set_flexnode_env VM_PUBLIC_IP "${VM_PUBLIC_IP}"
set_flexnode_env FLEX_HOST_SSH_TARGET "${FLEX_HOST_SSH_TARGET}"
set_flexnode_env FLEX_HOST_PRIVATE_IP "${FLEX_HOST_PRIVATE_IP}"
set_flexnode_env HOST_PRINCIPAL_OBJECT_ID "${HOST_PRINCIPAL_OBJECT_ID}"
set_flexnode_env HOST_IDENTITY_CLIENT_ID "${HOST_IDENTITY_CLIENT_ID}"

3.准备并检查主机

连接到主机:

ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}"

在主机上,检查操作系统、体系结构、主机名、CPU 和可用存储:

source /etc/os-release
printf 'Operating system: %s %s\n' "${NAME}" "${VERSION_ID}"
printf 'Architecture: %s\n' "$(uname -m)"
printf 'Host name: %s\n' "$(hostname)"
printf 'vCPUs: %s\n' "$(nproc)"
free -h
df -h /var/lib

将结果与步骤 1 中的主机要求进行比较。 先解决所有不一致之处,然后再继续。

引导脚本要求主机上安装有 curl、jq 和 tar,如果其中任何一个缺失,脚本就会停止运行。 弹性节点代理在启动期间安装剩余的运行时包。

安装您的映像中尚未包含的三项中的任意一项:

# Ubuntu
sudo apt-get update && sudo apt-get install -y curl jq tar

# Azure Linux 3
sudo tdnf install -y curl jq tar

退出主机会话:

exit

从 Bash 环境中读取实际的 Linux 主机名:

FLEX_HOST_NAME="$(ssh \
    -i "${SSH_PRIVATE_KEY_PATH}" \
    "${FLEX_HOST_SSH_TARGET}" \
    hostname)"
export FLEX_HOST_NAME

printf 'Flex host name: %s\n' "${FLEX_HOST_NAME}"

当命令返回预期的主机名时继续。

获取 AKS API 服务器的 FQDN,并从主机验证名称解析和 HTTPS 连通性:

AKS_API_FQDN="$(az aks show \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --query '(privateFqdn || fqdn)' \
    --output tsv)"
export AKS_API_FQDN
ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}" \
    "getent hosts '${AKS_API_FQDN}' && \
    timeout 5 bash -c '</dev/tcp/${AKS_API_FQDN}/443'"

如果名称解析或 TCP 连接失败,请在继续之前更正 DNS、路由或网络控制。 公共 AKS 群集使用其公共 API FQDN。 对于专用 AKS 群集,Bash 环境和弹性节点主机网络必须解析并路由到专用 API FQDN。

记录主机值。 共享环境文件存储的是路径和非敏感标识符,而不是密钥或凭据内容。

set_flexnode_env SSH_PRIVATE_KEY_PATH "${SSH_PRIVATE_KEY_PATH}"
set_flexnode_env SSH_PUBLIC_KEY_PATH "${SSH_PUBLIC_KEY_PATH}"
set_flexnode_env FLEX_HOST_NAME "${FLEX_HOST_NAME}"

4. 分配 AKS 角色

当前预览工作流在确切的 AKS 群集范围内使用Azure Kubernetes 服务参与者角色。 这三个标识选项都使用服务主体对象 ID 进行Azure基于角色的访问控制。 使用专用主机标识,并在删除主机时删除此分配,如 “管理和删除 AKS 中的弹性节点”中所述。

显示所选主体对象 ID:

printf 'Principal object ID: %s\n' "${HOST_PRINCIPAL_OBJECT_ID}"

仅当该值已填写,且属于所选的 VM 标识、Arc 计算机或服务主体时,才继续。

检查分配是否已存在:

az role assignment list \
    --assignee-object-id "${HOST_PRINCIPAL_OBJECT_ID}" \
    --scope "${AKS_RESOURCE_ID}" \
    --fill-principal-name false \
    --query "[?roleDefinitionName=='Azure Kubernetes Service Contributor Role'].{PrincipalId:principalId,Role:roleDefinitionName,Scope:scope}" \
    --output table

如果该命令未返回任何行,请创建该分配项:

az role assignment create \
    --assignee-object-id "${HOST_PRINCIPAL_OBJECT_ID}" \
    --assignee-principal-type ServicePrincipal \
    --role "Azure Kubernetes Service Contributor Role" \
    --scope "${AKS_RESOURCE_ID}" \
    --output none

再次运行列表命令。 当主体 ID 和范围与所选标识 AKS_RESOURCE_ID匹配时继续。 角色分配传播可能需要几分钟时间。

5.验证所选标识

在启动主机之前,请确认所选标识可以进行身份验证并读取确切的目标 AKS 群集。 仅填写与您的身份验证选项对应的部分。

验证 Azure Arc 托管标识

在 Bash 环境中,将非机密 AKS 资源 ID 传递给已启用 Azure Arc 的服务器:

[[ "${AKS_RESOURCE_ID}" == /subscriptions/*/providers/Microsoft.ContainerService/managedClusters/* ]]
printf -v AKS_RESOURCE_ID_QUOTED '%q' "${AKS_RESOURCE_ID}"

ssh -t \
    -i "${SSH_PRIVATE_KEY_PATH}" \
    "${FLEX_HOST_SSH_TARGET}" \
    "export AKS_RESOURCE_ID=${AKS_RESOURCE_ID_QUOTED}; \
    exec bash -l"

在启用了Azure Arc的服务器上,从混合实例元数据服务(HIMDS)请求Azure 资源管理器令牌,并使用它读取 AKS 资源。 读取质询令牌需要 root 权限或属于 himds 组:

TOKEN_URL="${IDENTITY_ENDPOINT:-http://127.0.0.1:40342/metadata/identity/oauth2/token}?api-version=2019-11-01&resource=https%3A%2F%2Fmanagement.azure.com"

CHALLENGE_TOKEN_PATH="$(curl --silent --show-error \
    --dump-header - \
    --output /dev/null \
    --header Metadata:true \
    "${TOKEN_URL}" |
    sed -n 's/^[Ww][Ww][Ww]-[Aa]uthenticate: Basic realm=//p' |
    tr -d '\r')"

test -n "${CHALLENGE_TOKEN_PATH}"
CHALLENGE_TOKEN="$(sudo cat "${CHALLENGE_TOKEN_PATH}")"

TOKEN="$(curl --fail --silent --show-error \
    --header Metadata:true \
    --header "Authorization: Basic ${CHALLENGE_TOKEN}" \
    "${TOKEN_URL}" |
    jq -r '.access_token // empty')"

test -n "${TOKEN}"

AKS_ARM_HTTP="$(curl --silent --show-error \
    --output /dev/null \
    --write-out '%{http_code}' \
    --header "Authorization: Bearer ${TOKEN}" \
    "https://management.azure.com${AKS_RESOURCE_ID}?api-version=2025-07-01")"

unset CHALLENGE_TOKEN TOKEN
printf 'AKS_ARM_HTTP=%s\n' "${AKS_ARM_HTTP}"

预期输出: AKS_ARM_HTTP=200. 运行 exit 以退出已启用 Azure Arc 的服务器会话。

验证服务主体

在 Bash 环境中,使用服务主体准备步骤中的合并 PEM 文件。 如果启动新会话或选择了现有标识,请再次设置其受保护的路径:

export SP_CLIENT_CERTIFICATE_FILE="<protected-path-to-sp-client.pem>"
test -s "${SP_CLIENT_CERTIFICATE_FILE}"

如果文件不存在或为空,请停止。 不要将此路径添加到共享环境文件。

首先使用独立的Azure CLI配置文件验证证书身份验证。 即使命令失败且不会更改正常Azure CLI登录,子shell 也会删除其临时令牌缓存。

(
    set -e
    SP_AZURE_CONFIG_DIR="$(mktemp -d)"
    chmod 0700 "${SP_AZURE_CONFIG_DIR}"
    trap 'rm -rf -- "${SP_AZURE_CONFIG_DIR}"' EXIT
    export AZURE_CONFIG_DIR="${SP_AZURE_CONFIG_DIR}"

    az login \
        --service-principal \
        --username "${SP_CLIENT_ID}" \
        --certificate "${SP_CLIENT_CERTIFICATE_FILE}" \
        --tenant "${SP_TENANT_ID}" \
        --allow-no-subscriptions \
        --output none

    az account get-access-token \
        --resource https://management.azure.com/ \
        --query "{Tenant:tenant,ExpiresOn:expiresOn}" \
        --output table
)

确认 租户 匹配 SP_TENANT_ID 且令牌尚未过期。 此命令仅打印租户和过期时间,而不是访问令牌。 --allow-no-subscriptions允许在授予Azure访问权限之前测试身份验证。 成功的身份验证不会证明有权读取或注册到 AKS 群集。

在步骤 4 中的 AKS 角色分配传播后,验证对确切目标群集的访问权限:

(
    set -e
    SP_AZURE_CONFIG_DIR="$(mktemp -d)"
    chmod 0700 "${SP_AZURE_CONFIG_DIR}"
    trap 'rm -rf -- "${SP_AZURE_CONFIG_DIR}"' EXIT
    export AZURE_CONFIG_DIR="${SP_AZURE_CONFIG_DIR}"

    az login \
        --service-principal \
        --username "${SP_CLIENT_ID}" \
        --certificate "${SP_CLIENT_CERTIFICATE_FILE}" \
        --tenant "${SP_TENANT_ID}" \
        --output none

    az account set --subscription "${SUBSCRIPTION_ID}"

    az aks show \
        --resource-group "${RESOURCE_GROUP}" \
        --name "${CLUSTER_NAME}" \
        --query "{Name:name,ResourceId:id,ProvisioningState:provisioningState}" \
        --output table
)

仅在返回的资源 ID 匹配 AKS_RESOURCE_ID 且预配状态为 Succeeded时继续。 如果身份验证成功,但群集请求被拒绝,请在重试前验证服务主体对象 ID、确切的角色分配范围和传播。 此检查证明服务主体及其证书可以读取目标群集。 主机在 将弹性节点附加到 AKS 群集 中使用已准备好的凭据。

验证Azure VM 托管标识

在 Bash 环境中,将非机密的 AKS 资源 ID 和身份客户端 ID 传递给 Azure VM:

[[ "${AKS_RESOURCE_ID}" == /subscriptions/*/providers/Microsoft.ContainerService/managedClusters/* ]]
printf -v AKS_RESOURCE_ID_QUOTED '%q' "${AKS_RESOURCE_ID}"
printf -v HOST_IDENTITY_CLIENT_ID_QUOTED '%q' "${HOST_IDENTITY_CLIENT_ID}"

ssh -t \
    -i "${SSH_PRIVATE_KEY_PATH}" \
    "${FLEX_HOST_SSH_TARGET}" \
    "export AKS_RESOURCE_ID=${AKS_RESOURCE_ID_QUOTED}; \
    export HOST_IDENTITY_CLIENT_ID=${HOST_IDENTITY_CLIENT_ID_QUOTED}; \
    exec bash -l"

在 Azure VM 中,从所选托管标识请求 Azure 资源管理器 令牌,并使用该令牌读取 AKS 资源:

TOKEN_URL="http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F"

if [ -n "${HOST_IDENTITY_CLIENT_ID}" ]; then
    ENCODED_CLIENT_ID="$(jq -rn \
        --arg value "${HOST_IDENTITY_CLIENT_ID}" \
        '$value|@uri')"
    TOKEN_URL="${TOKEN_URL}&client_id=${ENCODED_CLIENT_ID}"
fi

TOKEN="$(curl --fail --silent --show-error \
    --header Metadata:true \
    "${TOKEN_URL}" |
    jq -r '.access_token // empty')"

test -n "${TOKEN}"

AKS_ARM_HTTP="$(curl --silent --show-error \
    --output /dev/null \
    --write-out '%{http_code}' \
    --header "Authorization: Bearer ${TOKEN}" \
    "https://management.azure.com${AKS_RESOURCE_ID}?api-version=2025-07-01")"

unset TOKEN
printf 'AKS_ARM_HTTP=%s\n' "${AKS_ARM_HTTP}"

预期输出: AKS_ARM_HTTP=200. 对于用户分配的标识,请求使用附件工作流传递给 HOST_IDENTITY_CLIENT_ID 的同一个 --msi-client-id。 运行exit以离开Azure VM 会话。

当主机使用所选标识注册其Azure计算机资源时,附件工作流将执行最终端到端检查。

后续步骤

接下来,附加并验证准备好的主机作为灵活节点。