亚马逊AWS官方博客

Amazon EKS Windows pod 的无域 Windows 身份验证

.NET 开发人员在设计基于 Windows 的应用程序时通常会使用在加入域的服务器上运行的 Active Directory (AD) 集成,以实现服务和用户之间的身份验证和授权。由于容器无法加入域,因此在基于 Windows 的容器中运行这些应用程序需要配置群组托管服务账户 (gMSA)加入域的 Kubernetes Windows 节点webhook集群角色才能在基于 Windows 的容器上启用 Windows 身份验证。这会产生额外的管理开销,例如在每次扩缩事件时清理 Active Directory 计算机账户,以及由于域加入过程而大大增加了每个 Windows 节点上的引导时间。直到现在,还是这样。 

从 2022 年开始,Microsoft 在 Windows Server 2019/2022 上推出了 ICcgDomainAuthCredentials 接口,允许开发人员开发一个插件,使未加入域的 Windows 节点能够通过将加入域的主机方法替换为可移植的用户身份 而不是主机账户来检索 gMSA 凭证。

亚马逊云科技开发了自己的插件,现在它内置在 Amazon EKS 优化版 Windows AMI 中,解决了扩缩管理开销,简化了在 Amazon Elastic Kubernetes Service (Amazon EKS) 上运行基于 Windows 的容器工作负载的过程。

架构概览

首先,Windows Pod 引用 windows.k8s.io/v1 API 中提供的 GMSACredentialSpec。其次,gMSA 验证 webhook 确保了 Windows pod 有权引用 GMSACredentialSpec;最后,变异的 webhook 在 pod 中将 GMSACredentialSpec 扩展为完整的 JSON 格式。

在 Windows 节点上运行的 ccg.exe 进程启动 CredSpec 在 PluginID 字段中指定的插件,然后从 Amazon Secrets Manager 或 Amazon System Manager Parameter Store 中检索可移植的身份凭证。

ccg.exe 使用可移植身份凭证针对 Amazon Managed AD 或 EC2 自我管理式 Active Directory 进行身份验证,以检索 gMSA 密码。ccg.exe 使 gMSA 密码可用于 Windows pod。Windows pod 使用 gMSA 密码针对 Amazon Managed AD 或 EC2 自我管理式 Active Directory 进行身份验证,以获取 Kerberos 票证授予令牌 (TGT)。令牌被缓存,在 pod 中以网络服务或本地系统形式运行的应用程序可以验证和访问域资源,例如文件共享、SQL Server 数据库、IIS 站点等。

这篇博客文章介绍了为在 Amazon EKS 上未加入域的 Windows Worker 节点上运行的 Windows pod 配置此功能所需的步骤。

先决条件和假设

  • 您的 Amazon EKS 集群运行 1.23 或更高版本,并包含 Windows 节点。
  • 基于 Amazon EKS 优化版 Windows AMI 的自我管理式或托管式 Windows 节点。
  • 您已经在 Amazon EC2 Linux 上正确安装和配置了 Amazon CLIkubectl
  • 您有一个可以从 Amazon EKS 集群访问的 Active Directory Domain Service (AD DS),可以是自我管理的 AD,也可以是 Amazon Managed Microsoft AD。
  • 您在 Amazon EKS 集群中运行的 Windows 节点可以解析 Active Directory 域 FQDN。

我们将在本博客中介绍的任务概述

  • 创建 Active Directory gMSA 账户、可移植身份和群组。
  • 在 Amazon EKS 集群中部署 Windows gMSA 准入 Webhook 控制器。
  • 创建 gMSA CretentialSpec 资源并使用 Amazon Secret Manager 作为凭证存储区。
  • 创建 Kubernetes ClusterRole 和 RoleBinding。
  • 在 Windows pod 规范中配置 gMSA CredentialSpec。
  • 在 Windows pod 内测试 Windows 身份验证。
  • 日志记录位置
  • 可选使用 Amazon Systems Manager Parameter Store 作为凭证存储区。

1.在 Active Directory 域上创建和配置 gMSA 账户

如果您尚未在域中创建 gMSA 服务账户,则需要先生成 Key Distribution Service (KDS) 根密钥。KDS 负责创建、轮换 gMSA 密码并将其发布给授权主机。当 ccg.exe 需要检索 gMSA 凭证时,它将联系 KDS 检索当前密码。如果您使用的是 Amazon Managed AD,则可以直接跳至步骤 2.3,gMSA 权限已使用您的 Amazon Managed AD 进行了预配置。因此,您无需生成 KDS 根密钥即可生成 gMSA 密码。

1.1 要检查 KDS 根密钥是否已经创建,请使用 AD PowerShell 模块在域控制器上以域管理员权限运行以下 PowerShell cmdlet:

Get-KdsRootKey

1.2 如果命令返回密钥 ID,则一切就绪。否则,请通过运行以下命令创建 KDS 根密钥:

Add-KdsRootKey -EffectiveImmediately

尽管该命令暗示密钥将立即生效,但您需要等待 10 个小时才能复制 KDS 根密钥并可将其用于所有域控制器。如果您有兴趣更好地了解 gMSA 账户,请参阅 Microsoft 官方文档。

1.3 要创建 gMSA 账户并允许 ccg.exe 检索 gMSA 密码,请在有权访问 Active Directory 域的 Windows 服务器或客户端上运行以下 PowerShell 命令。

# 安装 RSAT AD 功能
Install-WindowsFeature RSAT-AD-PowerShell

# 创建 AD 组 - 将 Name 和 SamAccountName 值替换为您选择的值。
New-ADGroup -Name "Amazon EKS Authorized Portable Identity" -SamAccountName "EKSPortableIdentity" -GroupScope DomainLocal

# 创建 gMSA - 用您选择的值替换 Name 值
New-ADServiceAccount -Name "gmsaeks" -DnsHostName "gmsaeks.YOURDOMAIN_FQDN" -ServicePrincipalNames "host/gmsaeks", "host/gmsaeks.YOURDOMAIN_FQDN" -PrincipalsAllowedToRetrieveManagedPassword "EKSPortableIdentity"

# 创建可移植身份用户账户 - 将 Name 值替换为您选择的值
New-ADUser -Name "eks-portable-identity" -AccountPassword (ConvertTo-SecureString -AsPlainText "YOUR_PASSWORD" -Force) -Enabled 1 

# 将您的 Windows Worker 节点添加到 AD 组
Add-ADGroupMember -Identity "EKSPortableIdentity" -Members "eks-portable-identity"

注意:请将 YOURDOMAIN_FQDN 替换为您的完全限定域名。将 YOUR_PASSWORD 替换为唯一的密码,并存储在密钥存储区中,供 CCG 插件检索。替换。

2.在 Amazon EKS 集群中部署 Windows gMSA 准入 Webhook 控制器

Windows gmSA 存储库部署了两个 webhook根据 Kubernetes 文档它们分别是

一个变异的 webhook它将对 GMSA 的引用依据来自 Pod 规范的名称扩展为 Pod 规范中 JSON 形式的完整 CredentialSpec

验证 webhook 可确保所有对 GMSA 的引用都被授权由 Pod 服务账户使用。

根据 Amazon EKS 证书签名文档,所有运行 Amazon EKS 版本 1.22 或更高版本的集群都支持 Kubernetes 证书签名请求 (CSR) 的签名者 beta.eks.amazonaws.com/app-serving。因此,我们会将 gMSA 准入 webhook 证书文件中的 kubernetes.io/kubelet-serving 签名者替换为 Amazon EKS 支持的 beta.eks.amazonaws.com/app-serving 签名者。

2.1 在基于 Linux 的系统上,运行以下命令。这将部署 gMSA Webhook 准入控制器并更新签名者文件。

git clone https://github.com/kubernetes-sigs/windows-gmsa.git
cd windows-gmsa/admission-webhook/deploy
sed -i.back "s/signerName: kubernetes.io\/kubelet-serving/signerName: beta.eks.amazonaws.com\/app-serving/g" create-signed-cert.sh
K8S_GMSA_DEPLOY_DOWNLOAD_REV='v0.6.0' ./deploy-gmsa-webhook.sh --file ./gmsa-manifests --image registry.k8s.io/gmsa-webhook/k8s-gmsa-webhook:v0.6.0

注意:请务必在 kubernetes-sigs/windows-gmsa 上查看最新的 gMSA 准入 webhook 版本。

您的输出应如下所示:

3.创建 gMSA CredentialSpec 资源并使用 Amazon Secret Manager 作为凭证存储区

成功在 Amazon EKS 集群中部署 gMSA 资源,以及用于填充和验证整个集群资源的 CreditialSpec CRD 和 gMSA Webhooks 之后,我们现在将生成 gMSA CredentialSpec 资源并将其部署到 Amazon EKS 集群中。

gMSA CredentialSpec 包含元数据,主机节点上的 ccg.exe 进程使用这些元数据来确定要检索哪个 gMSA 账户、可移植身份凭证和要使用的插件 ID。在第一个示例中,我们将使用 Amazon Secrets Manager 来存储可移植身份凭证。

3.1 首先,让我们创建一个 Amazon Secret Manager 密钥来存储可移植身份凭证。运行以下 Amazon CLI 命令并替换 userpassworddomainName 以匹配您的环境并保存 “ARN” 以供在步骤 4.2 中使用

aws secretsmanager create-secret \
--name gmsa-plugin-input \
--description "Amazon EKS - gMSA Portable Identity." \
--secret-string "{\"user\":\"eks-portable-identity\",\"password\":\"YOURPASSWORD\",\"domainName\":\"YOURDOMAIN_FQDN\"}"

注意:用您的可移植身份凭证替换用户。将 YOUR_PASSWORD 可移植身份密码替换为您在步骤 1.3 中创建的密码。将 YOURDOMAIN_FQDN 替换为您的完全限定域名。

3.2 其次,将以下 IAM 内联策略添加到现有 Windows 节点 IAM 角色中。此 IAM policy 允许 Windows 节点读取在上一步中创建的密钥。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "ARN-SECRET"
        }
    ]
}

注意:用您在 Amazon Secret Manager 上创建的机密 ARN 替换 SECRET-ARN。

3.3 现在让我们创建 gMSA CredentialSpec 文件并将其应用到 Amazon EKS 集群。创建一个包含以下代码的文件并将其另存为 domainless-credspec-secretmanager.yaml

apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
  name: gmsaeks-domainless
credspec:
  CmsPlugins:
  - ActiveDirectory
  DomainJoinConfig:
    Sid: gMSA-ACCOUNT-SID
    MachineAccountName: gMSA-ACCOUNT-NAME
    Guid: gMSA-ACCOUNT-GUID
    DnsTreeName: YOURDOMAIN_FQDN
    DnsName: YOURDOMAIN_FQDN
    NetBiosName: YOURDOMAIN_NETBIOS
  ActiveDirectoryConfig:
    GroupManagedServiceAccounts:
    - Name: gMSA-ACCOUNT-NAME
      Scope: YOURDOMAIN_FQDN
    - Name: gMSA-ACCOUNT-NAME
      Scope: YOURDOMAIN_NETBIOS
    HostAccountConfig:
      PortableCcgVersion: "1"
      PluginGUID: "{859E1386-BDB4-49E8-85C7-3070B13920E1}"
      PluginInput: "{\"credentialArn\":\"ARN-SECRET\"}"

注意:替换各个值以匹配您的环境。您可以在具有 Active Directory 域访问权限的 Windows 终端中运行以下 PowerShell 命令,以便从 gMSA 账户检索 SID 和 GUID:Get-ADServiceAccount -Identity gMSA-ACCOUNT-NAME

您的文件应如下所示:

apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
  name: gmsaeks-domainless
credspec:
  CmsPlugins:
  - ActiveDirectory
  DomainJoinConfig:
    Sid: S-1-5-21-857038504-468933455-1338018723
    MachineAccountName: gmsaeks
    Guid: 59d60a02-be02-4fd3-8a7f-c7c6c0daceaa
    DnsTreeName: marciomorales.local
    DnsName: marciomorales.local
    NetBiosName: marciomorales
  ActiveDirectoryConfig:
    GroupManagedServiceAccounts:
    - Name: gmsaeks
      Scope: marciomorales.local
    - Name: gmsaeks
      Scope: marciomorales
    HostAccountConfig:
      PortableCcgVersion: "1"
      PluginGUID: "{859E1386-BDB4-49E8-85C7-3070B13920E1}"
      PluginInput: "{\"credentialArn\":\"arn:aws:secretsmanager:us-east-1:0123456789:secret:gmsa-plugin-input-tBOL0j\"}"

3.4 使用以下命令在集群上创建 gMSA CredentialSpec 资源:

kubectl create -f domainless-credspec-secretmanager.yaml

4.创建 Kubernetes ClusterRole 和 RoleBinding

需要 ClusterRole RoleBinding 才能允许您的 pod 使用 gMSA CredentialSpec

4.1 创建包含以下代码的文件并将其另存为 gmsa-domainless-clusterrole.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: eksgmsa-role-domainless
rules:
- apiGroups: ["windows.k8s.io"]
  resources: ["gmsacredentialspecs"]
  verbs: ["use"]
  resourceNames: ["gmsaeks-domainless"]
  
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: gmsa-assign-role-domainless
  namespace: default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: eksgmsa-role-domainless
  apiGroup: rbac.authorization.k8s.io

注意:如果 resourceNames 与我们指定的不同,请将其替换为步骤 4.3 中生成的名称。

4.2 使用以下命令在集群上创建 ClusterRole 和 RoleBinding:

kubectl apply -f gmsa-domainless-clusterrole.yaml

5.在 Windows pod 规范中配置 gMSA CredentialSpec

为了测试我们的配置是否有效,我们需要部署一个带有规范字段 securityContext.windowsOptions.gmsaCredentialSpecName 的 Windows pod 来引用我们在步骤 4 中创建和部署的 gMSA CredentialSpec 自定义资源。

5.1 创建包含以下代码的文件并将其另存为 windows-auth-pod.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: amazon-eks-gmsa-domainless
  name: amazon-eks-gmsa-domainless
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: amazon-eks-gmsa-domainless
  template:
    metadata:
      labels:
        run: amazon-eks-gmsa-domainless
    spec:
      securityContext:
        windowsOptions:
          gmsaCredentialSpecName: gmsaeks-domainless
      containers:
      - image: mcr.microsoft.com/windows/servercore:ltsc2019
        imagePullPolicy: Always
        name: gmsadomainless
        command:
          - "powershell.exe"
          - "-Command"
          - "while (1) { sleep 1 }"
      nodeSelector:
        kubernetes.io/os: windows

注意:将 gmsaCredentialSpecName 值替换为您在步骤 4.2 中创建的 gMSA CredentialSpec 名称。 在这篇博客中,我们使用了 gmsaeks-domainless

5.2 使用以下命令部署 Windows pod:

kubectl apply -f windows-auth-pod.yaml

6.在 Windows pod 内测试 Windows 身份验证

6.1 运行以下命令,在步骤 7.2 中的测试 pod 中打开一个 PowerShell 会话:

kubectl exec -it PODNAME -- powershell.exe

注意:将 PODNAME 替换为您的 pod 的名称。当您运行 kubectl get pod 时,您可以从输出列表中检索 pod 的名称。

6.2 在 pod 的 PowerShell 会话中,执行以下命令来验证 gMSA 身份和客户端名称。在这篇博客中,gmsaeks 是身份,可以在下图中看出。

klist get krbtgt

6.3 此外,您可以使用 nltest 通过运行以下命令验证可信 DC 连接是否成功建立:

nltest /sc_verify:YOURDOMAINFQDN

7.日志记录位置

事件记录在 Microsoft-Windows-Containers-CCG 日志文件中,可以在事件查看器的“应用程序和服务”Logs\ Microsoft\ Windows\ Containers-ccg\ Admin 下找到。在 Microsoft 提供的指南中查看更多调试技巧:Windows 容器的 gMSA 故障排除

未加入域的 Windows 节点上插件的基本日志记录:C:/programdata/Amazon/gmsa-plugin

8.(可选)使用 Amazon System Manager Parameter Store 作为凭证存储区

您可能更愿意使用 Amazon System Manager Parameter Store 而不是 Amazon Secret Manager 作为凭证存储区。亚马逊云科技插件支持这两个选项,但每个可移植身份只能使用一个。如果是这种情况,首先要做的是在 SSM 上创建参数来存储可移植身份凭证。

8.1 创建一个 JSON 文件,其中包含将构成 SSM 参数的值:

{
    "Name": "gmsa-plugin-input",
    "Value": "{\n\"username\": \"eks-portable-identity\",\n\"password\": \"YOUR_PASSWORD\",\n\"domainName\": \"YOURDOMAIN_FQDN\"\n}",
    "Type": "SecureString"
}

注意:将 username 替换为可移植身份凭证。将 YOUR_PASSWORD 可移植身份密码替换为您在步骤 1.3 中创建的密码。将 YOURDOMAIN_FQDN 替换为您的完全限定域名。

8.2 使用以下命令创建 SSM 参数:

aws ssm put-parameter \
    --type "SecureString" \
    --key-id "KMS-KEY-ARN" \
    --cli-input-json file://gmsa-json-parameterstore.json

注意:将 key-id 值替换为要用来加密参数的 KMS 密钥 ARN。将文件路径替换为您保存 json 文件的路径。

8.3 将以下 IAM 内联策略添加到现有 Windows 节点 IAM 角色中。此 IAM policy 允许 Windows 节点读取存储在 Amazon System Manager Parameter Store 中的密钥。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameters"
            ],
            "Resource": [
                "ARN-PARAMETER-STORE"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "ARN-KMS-KEY"
            ]
        }
    ]
}

8.4 使用以下命令在集群上创建指向使用 Parameter Store 的 gMSA CredentialSpec 资源,然后将其另存为 domainless-credspec-parameterstore.yaml

domainless-credspec-parameterstore.yaml
apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
  name: gmsaeks-domainless
credspec:
  CmsPlugins:
  - ActiveDirectory
  DomainJoinConfig:
    Sid: gMSA-ACCOUNT-SID
    MachineAccountName: gMSA-ACCOUNT-NAME
    Guid: gMSA-ACCOUNT-GUID
    DnsTreeName: YOURDOMAIN_FQDN
    DnsName: YOURDOMAIN_FQDN
    NetBiosName: YOURDOMAIN_NETBIOS
  ActiveDirectoryConfig:
    GroupManagedServiceAccounts:
    - Name: gMSA-ACCOUNT-NAME
      Scope: YOURDOMAIN_FQDN
    - Name: gMSA-ACCOUNT-NAME
      Scope: YOURDOMAIN_NETBIOS
    HostAccountConfig:
      PortableCcgVersion: "1"
      PluginGUID: "{859E1386-BDB4-49E8-85C7-3070B13920E1}"
      PluginInput: "{\"credentialArn\":\"ARN-PARAMETER-STORE\"}"

8.5 使用以下命令在集群上创建 gMSA CredentialSpec 资源:

kubectl create -f domainless-credspec-parameterstore.yaml

结论

在这篇博客中,我们介绍了如何为在 Amazon EKS 集群中未加入域的 Windows worker 节点上运行的 Windows pod 配置 Windows 身份验证的端到端方法。我们的方法包括使用 亚马逊云科技插件从 Active Directory 检索 gMSA 密码,然后将其换成 Kerberos 票证,从而允许 Windows pod 使用 AD 资源进行身份验证。许多更换平台以在 Amazon EKS 之上运行的 ASP.NET 应用程序可以利用此功能继续提供基于 Kerberos v5 协议的 Windows 身份验证。

延伸阅读

Amazon EKS 上加入域的 Windows 身份验证
Windows 容器和服务账户
对 Windows 容器的 gMSA 进行故障排除
为 Windows Pod 和容器配置 GMSA(Kubernetes 官方文档)