适用于亚马逊 EKS Windows pod 的无域 Windows 身份验证

简介

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

从2022年开始,微软在2019/2022年Windows Server 上推出了 ICCGDomainAuthCreditials接口 ,允许开发人员开发一个插件,通过将加入域的主机方法替换为便携用户身份而不是主机帐户,使未加入的Windows节点能够检索GmSA证书。

亚马逊云科技 开发了自己的插件,该插件内置在亚马逊弹性 Kubernetes 服务( 亚马逊 EKS) 优化的 Windows AMI 中,解决了扩展管理开销,简化了在亚马逊 EKS 上运行基于 Windows 的容器工作负载的过程。

解决方案概述

AWS gMSA plugion workflow

  1. 首先,Windows Pod 引用了 windows.k8s.io/v1 API 中提供的 gmsacredentialSpec。 其次,gmSA 验证 webhook 可确保 Windows 容器有权引用 GmsacredentialSpec。最后,变异的 webhook 在 pod 中将 GmsacredentialSpec 扩展为完整 JSON 格式。
  2. 在 Windows 节点上运行 的 ccg.exe 进程会启动 CredSpec 在 PluginID 字段中指定的插件,然后从 亚马逊云科技 Secrets Manager 或 亚马逊云科技 S ystem Manager 参数存储中检索便携身份证书。
  3. ccg.exe 使用便携式身份凭证对 亚马逊云科技 托管 AD 或亚马逊弹性计算云 ( Amazon EC2 ) 自管 AD 进行身份验证,以检索 gmSA 密码。
  4. ccg.exe 使 gmSA 密码可用于 Windows 窗格。
  5. Windows 容器使用 gmSA 密码对 亚马逊云科技 托管 AD 或亚马逊 EC2 自管 AD 进行身份验证,以获取 Kerberos 票证授予令牌 (TGT)。
  6. 令牌被缓存,应用程序在容器中以网络服务或本地系统身份运行,这可以验证和访问域资源(即文件共享、SQL Server 数据库、IIS 站点等)

这篇文章介绍了为在亚马逊 EKS 上未加入域的 Windows 工作节点上运行的 Windows 容器配置此功能所需的步骤。

先决条件和假设:

  • 你有一个 运行 版本 1.22 或更高版本的 Amazon EKS 集群 ,带有 Windows 节点。
  • 基于亚马逊 EKS 优化的 Windows AMI 的自我管理或托管 Windows 节点。
  • 你已经在亚马逊 EC2 Linux 上正确安装和配置了 亚马逊云科技 命令行接口 (亚马逊云科技 CLI ) 和 kubectl
  • 您有一个可从亚马逊 EKS 集群访问的 Active Directory 域名服务 (AD DS)。这可以是自我管理的 AD,也可以是 亚马逊云科技 托管的微软 AD。
  • 您在亚马逊 EKS 集群中运行的 Windows 节点可以解析 AD 域 FQDN。

我们将在本文中介绍的任务概述:

  1. 创建 AD gmSA 帐户、便携式身份和群组。
  2. 在亚马逊 EKS 集群中部署 Windows GmSA 准入 Webhook 控制器。
  3. 创建 gmSA CredentialSpec 资源并使用 亚马逊云科技 密钥管理器作为凭证存储。
  4. 创建 Kubernetes 集群角色和角色绑定。
  5. 在 Windows 容器规范中配置 gmSA CreditialSpec。
  6. 在 Windows 窗格中测试 Windows 身份验证。
  7. 记录位置。
  8. (可选)使用 亚马逊云科技 系统管理器参数存储库作为凭证存储。

草率排练

1。在 Active Directory 域上创建和配置 gmSA 帐户

如果您尚未在域中创建 GmSA 服务帐户,则需要先生成密钥分发服务 (KDS) 根密钥。KDS 负责创建、轮换 gmSA 密码并将其发布给授权主机。当 ccg.exe 需要检索 gmSA 凭据时,它会联系 KDS 取回当前密码。如果您使用的是 亚马逊云科技 Managed AD,则可以直接跳到步骤 2.3。gmSA 权限是使用您的 亚马逊云科技 管理的 Microsoft AD 预先配置的。因此,您无需生成 KDS 根密钥即可生成 gmSA 密码。

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

Get-KdsRootKey

1.2 如果命令返回密钥 ID,则表示您已准备就绪。否则,请运行以下命令创建 KDS 根密钥:

Add-KdsRootKey -EffectiveImmediately

尽管该命令暗示密钥立即生效,但您需要等待 10 个小时才能复制 KDS 根密钥并在所有域控制器上使用。如果你想更好地理解 GmSA 账户,请参阅 微软官方文档

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

# Install the RSAT AD Feature
Install-WindowsFeature RSAT-AD-PowerShell

# Create the AD group - Replace Name and SamAccountName values with yours preference.
New-ADGroup -Name "Amazon EKS Authorized Portable Identity" -SamAccountName "EKSPortableIdentity" -GroupScope DomainLocal

# Create the gMSA - Replace Name value with yours preference
New-ADServiceAccount -Name "gmsaeks" -DnsHostName "gmsaeks.YOURDOMAIN_FQDN" -ServicePrincipalNames "host/gmsaeks", "host/gmsaeks.YOURDOMAIN_FQDN" -PrincipalsAllowedToRetrieveManagedPassword "EKSPortableIdentity"

# Create the portable identity user account - Replace Name value with yours preference
New-ADUser -Name "eks-portable-identity" -AccountPassword (ConvertTo-SecureString -AsPlainText "YOUR_PASSWORD" -Force) -Enabled 1 

# Add your Windows Worker Node the AD group
Add-ADGroupMember -Identity "EKSPortableIdentity" -Members "eks-portable-identity"

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

2。在亚马逊 EKS 集群中部署 Windows GmSA 准入 Webhook 控制器

Windows gmSA 存储库部署了两个 webhook, 根据 Kubernet es 文档,它们是:

  1. 一个可变的 webhook,它在 Pod 规范中将对 GMSA 的引用(按名称来自 Pod 规范)扩展为 JSON 形式的完整 凭证规范 。
  2. 经过验证的 webhook 可确保 Pod 服务帐户有权使用对 GMSA 的所有引用。

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

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
./deploy-gmsa-webhook.sh --file ./gmsa-manifests --overwrite
Note: Always check for the latest gMSA admission-webhook version on the kubernetes-sigs/windows-gmsa
         
         
         .

您的输出应如下所示:

3。创建 gmSA CredentialSpec 资源并使用 亚马逊云科技 密钥管理器作为凭证存储。

随着 gmSA 资源成功部署到亚马逊 EKS 集群中,以及用于在整个集群中填充和验证资源的 CredentialSpec CRD 和 gmSA 网络挂钩,我们现在将生成 gmSA CredentialSpec 资源并将其部署到 Amazon EKS 集群中。

gmSA CredentialSpec 包含元数据,主机节点上 的 ccg.exe 进程使用这些元数据来确定要检索哪个 gmSA 帐户、便携式身份凭证以及要使用的插件的 ID。在第一个示例中,我们将使用 亚马逊云科技 Secrets Manager 来存储可移植身份证书。

3.1 首先,让我们创建一个 亚马逊云科技 密钥管理器来存储便携式身份证书。运行以下 亚马逊云科技 CLI 命令并替换用户、密码和域名以匹配您的环境并保存 ARN 以在步骤 4.2 中使用。

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

注意:使用您的 便携式身份凭 证替换用户。 使用您在步骤 1.3 中创建 的便携式身份密码替换 YOUR_ PASSWORD。将 YOURDOMAIN_FQDN 替换为您的完全限定域 名。

3.2 其次,将以下 亚马逊云科技 身份和访问管理 (亚马逊云科技 IAM) 内联策略 添加到现有的 Windows 节点 亚马逊云科技 IAM 角色中。此 亚马逊云科技 IAM 策略允许 Windows 节点读取在上一步中创建的密钥。

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

注意:将 SECRET-ARN 替换为在 亚马逊云科技 密钥管理器上创建的秘密 ARN。

3.3 现在,让我们创建 gmSA CredentialSpec 文件并将其应用到亚马逊 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 才能允许你的 pod 使用 gmSA C red entialSpec。

4.1 创建包含以下代码的文件并将其另存为 gmsa-domainless-clusterroles.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 容器规范中配置 gmSA 凭证规范

为了测试我们的配置是否正常运行,我们需要部署一个带有规格字段 securityContext.windowSoptions.gmsacredentialSpecName 的 Windows 容器来引用我们在步骤 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 容器:

kubectl apply -f windows-auth-pod.yaml

6。在 Windows 窗格中测试 Windows 身份验证

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

kubectl exec -it PODNAME -- powershell.exe

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

6.2 在容器的 PowerShell 会话中,执行以下命令来验证 GmSA 身份和客户端名称。在这篇文章中,gmsaeks 是身份,这可以从下图中看出。

klist get krbtgt

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

nltest /sc_verify:YOURDOMAINFQDN

7。记录位置

  • 事件记录在 Microsoft-Windows-Containers-CCG 日志文件中,可以在事件查看器的 “应用程序和服务日志\ 微软\ Windows\ Containers-CCG\ 管理员” 下找到。在微软提供的指南中查看更多调试技巧: 对适用于 Windows 容器的 GMSA 进行故障排除
  • 未加入域名的 Windows 节点上插件的基本日志记录:C: /Programdata/Amazon/GMSA-Plugin/

8。(可选)使用 亚马逊云科技 系统管理器参数存储库作为凭证存储。

您可能更喜欢使用 亚马逊云科技 系统管理器参数存储库作为凭证存储,而不是 亚马逊云科技 密钥管理器。亚马逊云科技 插件支持这两个选项,但每个可移植身份只能使用一个选项。如果是这种情况,则在 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"
}

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

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

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

注意:使用要加密参数的 KMS 密钥 ARN 替换密钥 ID 值。将文件路径替换为保存 JSON 文件的路径。

8.3 将以下 亚马逊云科技 IAM 内联策略 添加到现有的 Windows 节点 亚马逊云科技 IAM 角色中。此 亚马逊云科技 IAM 策略允许 Windows 节点读取存储在 亚马逊云科技 系统管理器参数存储中的密钥。

{
    "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 使用以下命令在集群上创建指向使用参数存储的 gmSA CredentialSpec 资源,并将其另存为 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

结论

在这篇文章中,我们向您展示了一种端到端的方法,该方法可以为在亚马逊 EKS 集群中未加入域的 Windows 工作节点上运行的 Windows 容器配置 Windows 身份验证。我们的方法包括使用 亚马逊云科技 插件从 AD 中检索 gmSA 密码,然后将其兑换 Kerberos 票证,允许 Windows pod 使用 AD 资源进行身份验证。许多 ASP.NET 应用程序经过平台重组后可在亚马逊 EKS 之上运行,都可以使用此功能继续提供基于 Kerberos v5 协议的 Windows 身份验证。

进一步阅读:

亚马逊 EKS Windows 容器和服务账户上加入域的 Windows 身份验证
Windows 容器 的 GMSA
疑难解答 Windows 容器上的 GMSA 配置 Windows 容器和容器
的 GMSA(Kubernetes 官方 文档)