无需订阅所有者权限,ARM模板+DevOps部署AKS后自动关联ACR的方案问询
我之前也碰到过一模一样的权限难题——不想给流水线的服务主体开放订阅级Owner权限,但又得自动完成AKS和ACR的关联。下面几个方案都是经过实践验证的,完全能绕开这个权限限制:
方案1:给AKS的托管身份分配ACR角色(首推)
现在AKS默认使用托管身份替代传统服务主体,我们可以直接给AKS的kubelet托管身份分配ACR的AcrPull角色,这样集群就能正常拉取镜像,整个操作只需要ACR所在资源组的权限,完全不需要订阅级Owner。
具体操作步骤:
- 获取AKS集群的kubelet托管身份对象ID:
KUBELET_ID=$(az aks show --name $(clusterName) --resource-group $(rgName) --query "identity.profile.kubeletidentity.objectId" -o tsv) - 给这个身份分配ACR的
AcrPull角色(权限范围仅限ACR资源本身):az role assignment create \ --assignee $KUBELET_ID \ --scope /subscriptions/<你的订阅ID>/resourceGroups/<ACR所在资源组>/providers/Microsoft.ContainerRegistry/registries/<ACR名称> \ --role "AcrPull"
如果你的AKS用的是用户分配的托管身份,只需要把上面的kubeletidentity.objectId换成用户分配身份的对象ID就行。
方案2:在ARM模板中内置角色分配(适配IaC场景)
既然你已经在用ARM模板部署AKS,可以直接在模板里添加角色分配资源,自动把ACR的AcrPull角色分配给AKS的托管身份。这样流水线的服务主体只需要在ACR资源或其所在资源组上拥有创建角色分配的权限(比如User Access Administrator,不需要订阅级)。
示例ARM模板片段:
{ "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "name": "[guid(parameters('clusterName'), parameters('acrName'))]", "scope": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('acrResourceGroupName'), '/providers/Microsoft.ContainerRegistry/registries/', parameters('acrName'))]", "dependsOn": [ "[resourceId('Microsoft.ContainerService/managedClusters', parameters('clusterName'))]" ], "properties": { "roleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", // AcrPull角色的固定ID "principalId": "[reference(resourceId('Microsoft.ContainerService/managedClusters', parameters('clusterName')), '2023-03-01').identity.profile.kubeletidentity.objectId]" } }
这个片段会在AKS部署完成后自动完成权限分配,全程不需要订阅级Owner权限。
方案3:使用ACR访问密钥(备选,不推荐)
如果上面的方案暂时无法实施,你可以把ACR的访问密钥存储为AKS集群内的镜像拉取Secret,部署镜像时用这个Secret来认证。不过这种方式不如托管身份安全,密钥需要手动管理和轮换,但确实不需要特殊的权限分配。
具体步骤:
- 获取ACR的访问密钥:
ACR_PASSWORD=$(az acr credential show --name $(containerRegistryName) --query "passwords[0].value" -o tsv) - 在AKS中创建镜像拉取Secret:
kubectl create secret docker-registry acr-secret \ --docker-server=$(containerRegistryName).azurecr.io \ --docker-username=$(containerRegistryName) \ --docker-password=$ACR_PASSWORD \ --docker-email=your-email@example.com - 在Deployment的Pod模板中引用这个Secret:
imagePullSecrets: - name: acr-secret
补充说明
原来的az aks update --attach-acr命令之所以需要订阅级Owner,是因为它默认会尝试在订阅范围内创建角色分配,并且需要较高权限来完成验证。而上面的方案都是把权限范围缩小到ACR资源本身,完美规避了订阅级高权限的需求。
内容的提问来源于stack exchange,提问作者kagarlickij

