为 Azure Kubernetes 服务 (AKS) 群集上的 Windows Server 节点启用组托管服务帐户 (GMSA)
组托管服务帐户 (GMSA) 是多个服务器的托管域帐户,提供自动密码管理、简化的服务主体名称 (SPN) 管理以及将管理委派给其他管理员的功能。 借助 Azure Kubernetes Service (AKS) 可以在 Windows Server 节点上启用 GMSA,使 Windows Server 节点上运行的容器能够与 GMSA 集成并由其管理。
先决条件
- Kubernetes 1.19 或更高版本。 若要检查版本,请参阅检查可用升级。 若要升级版本,请参阅升级 AKS 群集。
- Azure CLI 2.35.0 或更高版本。 运行
az --version
即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI。 - AKS 群集启用的托管标识。
- 创建或更新 Azure 密钥保管库时所需的权限。
- 在 Active Directory 域服务或本地 Active Directory 上配置 GMSA 所需的权限。
- 域控制器必须已启用 Active Directory Web 服务,并且必须可由 AKS 群集通过端口 9389 访问。
注意
Azure 还提供一个专用 PowerShell 模块用于在 AKS 上配置 gMSA。 有关详细信息,请参阅 Azure Kubernetes 服务。
在 Active Directory 域控制器上配置 GMSA
若要对 AKS 使用 GMSA,需要通过标准域用户凭据访问域控制器上配置的 GMSA 凭据。 若要在域控制器上配置 GMSA,请参阅组托管服务帐户入门。 对于标准域用户凭据,可以使用现有用户或创建新用户,前提是该用户有权访问 GMSA 凭据。
重要
必须使用 Active Directory 域服务或本地 Active Directory。 目前,无法使用 Microsoft Entra ID 通过 AKS 群集配置 GMSA。
将标准域用户凭据存储在 Azure 密钥保管库中
AKS 群集使用标准域用户凭据从域控制器访问 GMSA 凭据。 为了提供对 AKS 群集的这些凭据的安全访问,应将这些凭据存储在 Azure 密钥保管库中。
如果你没有 Azure 密钥保管库,请使用
az keyvault create
命令创建一个。az keyvault create --resource-group myResourceGroup --name myGMSAVault
使用
az keyvault secret set
命令将标准域用户凭据作为机密存储在密钥保管库中。 以下示例在 myGMSAVault 密钥保管库中存储包含密钥 GMSADomainUserCred 的域用户凭据。az keyvault secret set --vault-name myGMSAVault --name "GMSADomainUserCred" --value "$Domain\\$DomainUsername:$DomainUserPassword"
注意
请确保对域使用完全限定的域名。
可选:使用自定义 VNET 和自定义 DNS
需要通过 DNS 配置域控制器,以便 AKS 群集能够访问域控制器。 可以在 AKS 群集外部配置网络和 DNS,以允许群集访问域控制器。 或者,可以在 AKS 群集中使用 Azure CNI 配置自定义 VNet 和自定义 DNS,以提供对域控制器的访问。 有关详细信息,请参阅在 Azure Kubernetes 服务 (AKS) 中配置 Azure CNI 网络。
可选:配置多个 DNS 服务器
如果要在 AKS 群集中为 Windows GMSA 配置多个 DNS 服务器,请不要指定 --gmsa-dns-server
或 v--gmsa-root-domain-name
。 相反,可选择“自定义 DNS”并添加 DNS 服务器,在 VNet 中添加多个 DNS 服务器。
可选:为群集使用你自己的 kubelet 标识
群集 kubelet 标识需要能够访问你的密钥保管库,这样,AKS 群集才能访问你的密钥保管库。 当你创建启用了托管标识的群集时,系统会自动创建一个 kubelet 标识。
可以在创建群集后为标识授予对密钥保管库的访问权限,也可以通过以下步骤创建自己的标识,以便在创建群集之前使用:
使用
az identity create
命令创建 kubelet 标识。az identity create --name myIdentity --resource-group myResourceGroup
使用
az identity list
命令获取标识的 ID,并将其设置为名为 MANAGED_ID 的变量。MANAGED_ID=$(az identity list --query "[].id" -o tsv)
若要授予标识对密钥保管库的访问权限,请使用
az keyvault set-policy
命令。az keyvault set-policy --name "myGMSAVault" --object-id $MANAGED_ID --secret-permissions get
在新 AKS 群集中启用 GMSA
创建在群集创建期间使用的管理员凭据。 以下命令提示你输入一个用户名,并将其设置为 WINDOWS_USERNAME,供在之后的命令中使用。
echo "Please enter the username to use as administrator credentials for Windows Server nodes on your cluster: " && read WINDOWS_USERNAME
使用
az aks create
命令并指定以下参数创建 AKS 群集:--enable-windows-gmsa
:为群集启用 GMSA。--gmsa-dns-server
:DNS 服务器的 IP 地址。--gmsa-root-domain-name
:DNS 服务器的根域名。
DNS_SERVER=<IP address of DNS server> ROOT_DOMAIN_NAME="contoso.com" az aks create \ --resource-group myResourceGroup \ --name myAKSCluster \ --vm-set-type VirtualMachineScaleSets \ --network-plugin azure \ --load-balancer-sku standard \ --windows-admin-username $WINDOWS_USERNAME \ --enable-windows-gmsa \ --gmsa-dns-server $DNS_SERVER \ --gmsa-root-domain-name $ROOT_DOMAIN_NAME \ --generate-ssh-keys
注意
如果使用自定义 VNet,则需要使用
vnet-subnet-id
参数指定 VNet ID,并且可能还需要根据配置添加docker-bridge-address
、dns-service-ip
和service-cidr
参数。如果你为 kubelet 标识创建了自己的标识,请使用
assign-kubelet-identity
参数指定该标识。指定
--gmsa-dns-server
和--gmsa-root-domain-name
参数时,DNS 转发规则将添加到kube-system/coredns
ConfigMap。 此规则将$ROOT_DOMAIN_NAME
的 DNS 请求从 Pod 转发到$DNS_SERVER
。$ROOT_DOMAIN_NAME:53 { errors cache 30 log forward . $DNS_SERVER }
使用
az aks nodepool add
命令添加 Windows Server 节点池。az aks nodepool add \ --resource-group myResourceGroup \ --cluster-name myAKSCluster \ --os-type Windows \ --name npwin \ --node-count 1
在现有群集上启用 GMSA
在使用
az aks update
命令启用 Windows Server 节点和托管标识的现有群集上启用 GMSA。az aks update \ --resource-group myResourceGroup \ --name myAKSCluster \ --enable-windows-gmsa \ --gmsa-dns-server $DNS_SERVER \ --gmsa-root-domain-name $ROOT_DOMAIN_NAME
授予 kubelet 标识对密钥保管库的访问权限
注意
如果你提供了自己的标识作为 kubelet 标识,请跳过此步骤。
使用
az keyvault set-policy
命令授予 kubelet 标识对密钥保管库的访问权限。MANAGED_ID=$(az aks show -g myResourceGroup -n myAKSCluster --query "identityProfile.kubeletidentity.objectId" -o tsv) az keyvault set-policy --name "myGMSAVault" --object-id $MANAGED_ID --secret-permissions get
安装 GMSA 凭据规范
使用
az aks get-credentials
命令将kubectl
配置为连接到你的 Kubernetes 群集。az aks get-credentials --resource-group myResourceGroup --name myAKSCluster
创建名为 gmsa-spec.yaml 的新 YAML,并粘贴到以下 YAML 中。 请务必将占位符替换为你自己的值。
apiVersion: windows.k8s.io/v1 kind: GMSACredentialSpec metadata: name: aks-gmsa-spec # This name can be changed, but it will be used as a reference in the pod spec credspec: ActiveDirectoryConfig: GroupManagedServiceAccounts: - Name: $GMSA_ACCOUNT_USERNAME Scope: $NETBIOS_DOMAIN_NAME - Name: $GMSA_ACCOUNT_USERNAME Scope: $DNS_DOMAIN_NAME HostAccountConfig: PluginGUID: '{CCC2A336-D7F3-4818-A213-272B7924213E}' PortableCcgVersion: "1" PluginInput: "ObjectId=$MANAGED_ID;SecretUri=$SECRET_URI" # SECRET_URI takes the form https://$akvName.vault.azure.cn/secrets/$akvSecretName CmsPlugins: - ActiveDirectory DomainJoinConfig: DnsName: $DNS_DOMAIN_NAME DnsTreeName: $DNS_ROOT_DOMAIN_NAME Guid: $AD_DOMAIN_OBJECT_GUID MachineAccountName: $GMSA_ACCOUNT_USERNAME NetBiosName: $NETBIOS_DOMAIN_NAME Sid: $GMSA_SID
注意
AKS 已在版本 v20230903 中将 GMSACredentialSpec
的 apiVersion
从 windows.k8s.io/v1alpha1
升级到 windows.k8s.io/v1
。
创建名为 gmsa-role.yaml 的新 YAML,并粘贴到以下 YAML 中。
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: aks-gmsa-role rules: - apiGroups: ["windows.k8s.io"] resources: ["gmsacredentialspecs"] verbs: ["use"] resourceNames: ["aks-gmsa-spec"]
创建名为 gmsa-role-binding.yaml 的新 YAML,并粘贴到以下 YAML 中。
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: allow-default-svc-account-read-on-aks-gmsa-spec namespace: default subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: ClusterRole name: aks-gmsa-role apiGroup: rbac.authorization.k8s.io
使用
kubectl apply
命令应用 gmsa-spec.yaml、gmsa-role.yaml 和 gmsa-role-binding.yaml 中的更改。kubectl apply -f gmsa-spec.yaml kubectl apply -f gmsa-role.yaml kubectl apply -f gmsa-role-binding.yaml
验证 GMSA 安装
创建名为 gmsa-demo.yaml 的新 YAML,并粘贴到以下 YAML 中。
--- kind: ConfigMap apiVersion: v1 metadata: labels: app: gmsa-demo name: gmsa-demo namespace: default data: run.ps1: | $ErrorActionPreference = "Stop" Write-Output "Configuring IIS with authentication." # Add required Windows features, since they are not installed by default. Install-WindowsFeature "Web-Windows-Auth", "Web-Asp-Net45" # Create simple ASP.NET page. New-Item -Force -ItemType Directory -Path 'C:\inetpub\wwwroot\app' Set-Content -Path 'C:\inetpub\wwwroot\app\default.aspx' -Value 'Authenticated as <B><%=User.Identity.Name%></B>, Type of Authentication: <B><%=User.Identity.AuthenticationType%></B>' # Configure IIS with authentication. Import-Module IISAdministration Start-IISCommitDelay (Get-IISConfigSection -SectionPath 'system.webServer/security/authentication/windowsAuthentication').Attributes['enabled'].value = $true (Get-IISConfigSection -SectionPath 'system.webServer/security/authentication/anonymousAuthentication').Attributes['enabled'].value = $false (Get-IISServerManager).Sites[0].Applications[0].VirtualDirectories[0].PhysicalPath = 'C:\inetpub\wwwroot\app' Stop-IISCommitDelay Write-Output "IIS with authentication is ready." C:\ServiceMonitor.exe w3svc --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: gmsa-demo name: gmsa-demo namespace: default spec: replicas: 1 selector: matchLabels: app: gmsa-demo template: metadata: labels: app: gmsa-demo spec: securityContext: windowsOptions: gmsaCredentialSpecName: aks-gmsa-spec containers: - name: iis image: mcr.azk8s.cn/windows/servercore/iis:windowsservercore-ltsc2019 imagePullPolicy: IfNotPresent command: - powershell args: - -File - /gmsa-demo/run.ps1 volumeMounts: - name: gmsa-demo mountPath: /gmsa-demo volumes: - configMap: defaultMode: 420 name: gmsa-demo name: gmsa-demo nodeSelector: kubernetes.io/os: windows --- apiVersion: v1 kind: Service metadata: labels: app: gmsa-demo name: gmsa-demo namespace: default spec: ports: - port: 80 targetPort: 80 selector: app: gmsa-demo type: LoadBalancer
使用
kubectl apply
命令应用来自 gmsa-demo.yaml 的更改。kubectl apply -f gmsa-demo.yaml
使用
kubectl get service
命令获取示例应用程序的 IP 地址。kubectl get service gmsa-demo --watch
起初,
gmsa-demo
服务的EXTERNAL-IP
显示为“挂起”:NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gmsa-demo LoadBalancer 10.0.37.27 <pending> 80:30572/TCP 6s
当
EXTERNAL-IP
地址从 pending 更改为实际公共 IP 地址时,请使用CTRL-C
停止kubectl
监视进程。以下示例输出显示向服务分配了有效的公共 IP 地址:
gmsa-demo LoadBalancer 10.0.37.27 EXTERNAL-IP 80:30572/TCP 2m
打开 Web 浏览器访问
gmsa-demo
服务的外部 IP 地址。使用
$NETBIOS_DOMAIN_NAME\$AD_USERNAME
和密码进行身份验证,确认是否看到了Authenticated as $NETBIOS_DOMAIN_NAME\$AD_USERNAME, Type of Authentication: Negotiate
。
禁用现有群集上的 GMSA
使用命令“
az aks update
”在具有 Windows Server 节点的现有群集上禁用 GMSA。az aks update \ --resource-group myResourceGroup \ --name myAKSCluster \ --disable-windows-gmsa
注意
可以使用命令“az aks update”在现有群集上重新启用 GMSA。
疑难解答
加载页面时系统不提示身份验证
如果页面可加载,但系统未提示进行身份验证,请使用 kubectl logs POD_NAME
命令显示 Pod 的日志,并验证是否看到“使用身份验证的 IIS 已准备就绪”。
注意
默认情况下,Windows 容器不会在 kubectl 上显示日志。 若要使 Windows 容器能够显示日志,需要在 Windows 映像上嵌入日志监视器工具。 有关详细信息,请参阅 Windows 容器工具。
尝试加载页面时连接超时
如果在尝试加载页面时出现连接超时,请使用 kubectl get pods --watch
命令验证示例应用是否正在运行。 有时,示例应用服务的外部 IP 地址在示例应用 Pod 运行之前可用。
Pod 无法启动并且 Pod 事件中显示 winapi 错误
如果在运行 kubectl get pods --watch
命令并等待几分钟后 Pod 未启动,请使用 kubectl describe pod POD_NAME
命令。 如果 Pod 事件中显示 winapi 错误,则有可能是 GMSA 凭据规范配置中有错误。 验证 gmsa-spec.yaml 中的所有替换值是否正确,重新运行 ,然后重新部署示例应用程序。