O blog da AWS

Domainless Windows Authentication para pods Windows no Amazon EKS

Por Marcio Morales and Hamzah Abdulla, Principal Solutions Architect e Consultor de DevOps na AWS 

Introdução

Desenvolvedores .NET geralmente projetam aplicações baseadas em Windows com integração ao Active Directory (AD), executando em servidores ingressados no domínio, para facilitar a autenticação e a autorização entre serviços e usuários. Como containers não podem ser ingressados no domínio, a execução dessas aplicações em containers baseados em Windows exigia a configuração de group Managed Service Accounts (gMSAs), nós de Kubernetes em Windows ingressados no domínio, webhooks e cluster roles para permitir Windows Authentication em containers baseados em Windows. Isso criou uma sobrecarga adicional de gerenciamento, como a limpeza da conta do computador AD em cada evento de escalabilidade, além de aumentar drasticamente o tempo de inicialização em cada nó Windows devido ao processo de ingressão no domínio. Isso foi, até agora.

A partir de 2022, em Windows Server 2019/2022, a Microsoft disponibilizou a interface ICcgDomainAuthCredentials, permitindo que desenvolvedores desenvolvam um plug-in que permite que nós Windows não ingressados no domínio recuperem credenciais gMSA substituindo a abordagem de host ingressado no domínio por uma identidade de usuário portátil em vez de uma conta de computador.

A AWS desenvolveu seu próprio plug-in, que está embutido no Amazon Elastic Kubernetes Service (Amazon EKS), e otimizou a AMI de Windows, resolvendo a sobrecarga de gerenciamento de escalabilidade e simplificando o processo de execução de cargas de trabalho de containers baseadas em Windows no Amazon EKS.

Visão geral da solução

AWS gMSA plugion workflow

  1. Primeiro, o pod Windows faz referência ao GMSACredentialSpec disponível na API windows.k8s.io/v1. Em segundo lugar, o webhook de validação do gMSA garante que o pod Windows tenha permissão para fazer referência ao GMSACredentialSpec. Finalmente, o webhook mutante expande o GMSACredentialSpec para o formato JSON completo no pod.
  2. O processo ccg.exe executado no nó Windows inicia o plug-in especificado no CredSpec no campo PluginID e, em seguida, recupera as credenciais de identidade portáteis do AWS Secrets Manager ou do AWS System Manager Parameter Store.
  3. O ccg.exe usa as credenciais de identidade portáteis para se autenticar no AWS Managed AD ou no AD executando em Amazon Elastic Compute Cloud (Amazon EC2) para recuperar a senha gMSA.
  4. ccg.exe disponibiliza a senha gMSA para o pod Windows.
  5. O pod Windows usa a senha gMSA para se autenticar no AWS Managed AD ou no AD autogerenciado em Amazon EC2 para obter um token Kerberos Ticket-Granting (TGT).
  6. O token é armazenado em cache e a aplicação é executada como Network Service ou Local System no pod, que pode autenticar e acessar recursos de domínio (ou seja, compartilhamentos de arquivos, bancos de dados SQL Server, sites de IIS etc.).

Este post aborda as etapas necessárias para configurar essa funcionalidade para pods Windows executados em nós de trabalho Windows não ingressados ao domínio no Amazon EKS.

Pré-requisitos e premissas

  • Ter um cluster Amazon EKS executando a versão 1.22 ou mais recente com nós Windows.
  • Nós Windows do tipo Self-Managed ou Managed com base na Amazon EKS Optimized Windows AMI.
  • Ter instalado e configurado corretamente a AWS Command Line Interface (AWS CLI) e o kubectl em uma instância Amazon EC2 Linux.
  • Ter Active Directory Domain Service (AD DS) que pode ser acessado a partir do cluster Amazon EKS. Isso pode ser um AD autogerenciado ou um AWS Managed Microsoft AD.
  • Nós Windows em execução no cluster Amazon EKS conseguindo resolver o FQDN do domínio AD.

Visão geral das tarefas que abordaremos nesta postagem

  1. Criar uma conta gMSA, identidade portátil e grupo no AD.
  2. Implante o Windows GMSA Admission Webhook Controller no cluster Amazon EKS.
  3. Crie recursos do GMSA CredentialSpec e use o AWS Secret Manager como um armazenamento de credenciais.
  4. Crie um Kubernetes ClusterRole e RoleBinding.
  5. Configurar o gMSA CredentialSpec na especificação do pod Windows.
  6. Testar Windows Authentication de dentro do pod Windows.
  7. Locais de logs.
  8. (Opcional) Usar o AWS System Manager Parameter Store como um armazenamento de credenciais.

Passo a passo

1. Criar e configurar a conta gMSA no domínio do Active Directory

Se você ainda não criou uma conta de serviço gMSA em seu domínio, primeiro precisará gerar uma chave raiz do Key Distribution Service (KDS). O KDS é responsável por criar, rotacionar e liberar a senha da gMSA para hosts autorizados. Quando o ccg.exe precisa recuperar as credenciais gMSA, ele entra em contato com o KDS para recuperar a senha atual. Se você estiver usando o AWS Managed AD, poderá pular diretamente para a etapa 2.3. As permissões da gMSA são pré-configuradas com seu Microsoft AD gerenciado pela AWS. Como resultado, você não precisa gerar a chave raiz do KDS para gerar as senhas gMSA.

1.1 Para verificar se a chave raiz do KDS já foi criada, execute o seguinte cmdlet de PowerShell com privilégios de administrador de domínio em um controlador de domínio usando o módulo de AD de PowerShell:

Get-KdsRootKey

1.2 Se o comando retornar um ID de chave, você está pronto. Caso contrário, crie a chave raiz do KDS executando o seguinte comando:

Add-KdsRootKey -EffectiveImmediately

Embora o comando indique que a chave entra em vigor imediatamente, você precisa esperar 10 horas antes que a chave raiz do KDS seja replicada e esteja disponível para uso em todos os controladores de domínio. Se você estiver interessado em entender melhor sobre contas gMSA, consulte a documentação oficial da Microsoft.

1.3 Para criar a conta gMSA e permitir que o ccg.exe recupere a senha gMSA, execute os seguintes comandos do PowerShell em um servidor ou cliente Windows com acesso ao domínio do AD.

# 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"

Nota: Substitua YOURDOMAIN_FQDN pelo FQDN do seu domínio. Substitua YOUR_PASSWORD por uma senha exclusiva e armazene em uma secret store para ser recuperado pelo plug-in CCG.

2. Implemente o Windows gMSA Admission Webhook Controller no Amazon EKS cluster

O repositório de Windows gMSA implementa dois webhooks. De acordo com a documentação do Kubernetes, são esses:

  1. Um webhook mutante que expande as referências a gMSAs (pelo nome de uma especificação de Pod) para o CredentialSpec completo no formato JSON dentro da especificação do Pod.
  2. Um webhook de validação garante que todas as referências aos gMSAs estejam autorizadas a serem usadas pela conta de serviço do Pod.

De acordo com a documentação de assinatura de certificados do Amazon EKS, todos os clusters que executam o Amazon EKS versão 1.22 ou mais recente oferecem suporte ao signatário beta.eks.amazonaws.com/app-serving para Certificate Signing Requests (CSR) do Kubernetes. Como resultado, substituiremos o signatário kubernetes.io/kubelet-serving no arquivo de certificado do gMSA admission webhook pelo signatário beta.eks.amazonaws.com/app-serving compatível com o Amazon EKS.

2.1 Em um sistema baseado em Linux, execute o seguinte comando. Isso implanta o gMSA Webhook Admission Controller e atualiza o arquivo do signatário.

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

Nota: Sempre verifique a versão mais recente do gMSA admission webhook no kubernetes-sigs/windows-gmsa.

Sua saída deve ter a seguinte aparência:

3. Criar recursos do gMSA CredentialSpec e usar o AWS Secret Manager como um armazenamento de credenciais.

Com os recursos de gMSA implantados com sucesso no cluster Amazon EKS, junto com os webhooks CredentialSpec CRD e gMSA para preencher e validar o recurso em todo o cluster, agora geraremos e implantaremos o recurso gMSA CredentialSpec no cluster Amazon EKS.

O gMSA CredentialSpec contém metadados que o processo ccg.exe no nó do host usa para determinar qual conta gMSA recuperar, as credenciais de identidade portáteis e o ID do plug-in a ser usado. Neste primeiro exemplo, usaremos o AWS Secrets Manager para armazenar a credencial de identidade portátil.

3.1 Primeiro, vamos criar um AWS Secrets Manager para armazenar a credencial de identidade portátil. Execute o seguinte comando na CLI da AWS e substitua o usuário, a senha e o nome de domínio para corresponder ao seu ambiente e salve o ARN a ser usado na etapa 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\"}"

Nota: Substitua o usuário pela sua credencial de identidade portátil. Substitua YOUR_PASSWORD, a senha de identidade portátil, pela que você criou na etapa 1.3. Substitua YOURDOMAIN_FQDN pelo FQDN do seu domínio.

3.2 Em segundo lugar, adicione a seguinte política em linha do AWS Identity and Access Management (AWS IAM) à role existente do AWS IAM no nó Windows. Essa política do AWS IAM permite que os nós Windows leiam o segredo criado na etapa anterior.

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

Nota: Substitua SECRET-ARN pelo ARN do secret criado no AWS Secrets Manager.

3.3 Agora, vamos criar o arquivo gMSA CredentialSpec e aplicá-lo ao cluster Amazon EKS. Crie um arquivo contendo o código abaixo e salve-o como 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\"}"

Observação: substitua os valores para corresponder ao seu ambiente. Você pode executar o seguinte comando do PowerShell em um terminal Windows com acesso ao seu domínio do Active Directory para recuperar SID e GUID da conta gMSA: Get-ADServiceAccount -Identity GMSA-Account-Name

Seu arquivo deve ter a seguinte aparência:

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 Crie o recurso gMSA CredentialSpec no cluster com o seguinte comando:

kubectl create -f domainless-credspec-secretmanager.yaml

4.Criar Kubernetes ClusterRole e RoleBinding

Uma ClusterRole e um RoleBinding são necessários para permitir que o gMSA CredentialSpec seja usado pelo seu pod.

4.1 Crie um arquivo contendo o código abaixo e salve-o como 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

Observação: substitua ResourceNames pelo gerado na etapa 4.3 se for diferente do que especificamos.

4.2 Crie ClusterRole e RoleBinding no cluster com o seguinte comando:

kubectl apply -f gmsa-domainless-clusterrole.yaml

5. Configurar o gMSA CredentialSpec na especificação do pod Windows

Para testar se nossa configuração está funcionando, precisaremos implantar um pod Windows com o campo de especificação SecurityContext.WindowsOptions.gmsACredentialSpecName para referenciar nosso recurso personalizado gMSA CredentialSpec que criamos e implantamos na etapa 4.

5.1 Crie um arquivo contendo o código abaixo e salve-o como windows-auth-pod.yaml.

piVersion: 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

Nota: Substitua o valor GMSACredentialSpecName pelo nome do gMSA CredentialSpec que você criou na etapa 4.2. Para esta postagem, usamos gmsaeks-domainless.

5.2 Implemente o pod Windows usando o seguinte comando:

kubectl apply -f windows-auth-pod.yaml

6. Testar Windows Authentication de dentro do pod Windows

6.1 Execute o seguinte comando para abrir uma sessão do PowerShell em nosso pod de teste a partir da etapa 7.2:

kubectl exec -it PODNAME -- powershell.exe

Nota: Substitua PODNAME pelo nome do seu pod. Você pode recuperar o nome do pod da lista de saídas ao executar kubectl get pods.

6.2 Na sessão do PowerShell do pod, execute o comando a seguir para verificar a identidade e o nome do cliente gMSA. Neste post, gmsaeks é a identidade, isso pode ser visto no diagrama a seguir.

klist get krbtgt

6.3 Além disso, você pode usar nltest para verificar se a conexão Trusted DC foi feita com êxito executando o seguinte comando:

nltest /sc_verify:YOURDOMAINFQDN

7. Locais de logs

  • Os eventos são registrados no arquivo de log Microsoft-Windows-Containers-CCG e podem ser encontrados no Event Viewer em Applications and Service Logs\Microsoft\Windows\Containers-CCG\Admin. Veja mais dicas de debugging no guia fornecido pela Microsoft: Solução de problemas de gMSAs para containers Windows.
  • Log básico do plug-in no nó Windows não ingressado no domínio: C:\Programdata\Amazon\GMSA-Plugin\

8. (Opcional) Usando o AWS System Manager Parameter Store como um armazenamento de credenciais.

Talvez você prefira usar o AWS System Manager Parameter Store como um armazenamento de credenciais em vez do AWS Secrets Manager. O plug-in da AWS oferece suporte a ambas opções, mas apenas uma pode ser usada por cada identidade portátil. Se for esse o caso, crie o parâmetro no SSM para armazenar a credencial de identidade portátil.

8.1 Crie um arquivo JSON que contenha os valores que irão compor o parâmetro SSM:

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

Nota: Substitua o nome de usuário pela sua credencial de identidade portátil. Substitua YOUR_PASSWORD, a senha de identidade portátil, pela que você criou na etapa 1.3. Substitua YOURDOMAIN_FQDN pelo FQDN do seu domínio.

8.2 Crie o parâmetro SSM usando o seguinte comando:

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

Nota: Substitua o valor do key-id pelo ARN da chave KMS que você deseja criptografar o parâmetro. Substitua o caminho do arquivo pelo que você salvou no arquivo JSON.

8.3 Adicione a seguinte política em linha do AWS IAM à role existente do AWS IAM no nó Windows. Essa política do AWS IAM permite que os nós Windows leiam o segredo armazenado no AWS 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 Crie o recurso gMSA CredentialSpec no cluster que aponta para o uso do Parameter Store com o comando a seguir e salve-o como 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 Crie o recurso gMSA CredentialSpec no cluster com o seguinte comando:

kubectl create -f domainless-credspec-parameterstore.yaml

Conclusão

Neste post, mostramos uma abordagem de ponta a ponta para configurar Windows Authentication para pods Windows executados em nós de trabalho Windows, não ingressados ao domínio, em um cluster Amazon EKS. Nossa abordagem incluiu o uso do plug-in da AWS para recuperar uma senha gMSA do AD e trocá-la por um ticket Kerberos, permitindo que os pods Windows se autenticassem com recursos do AD. Muitos aplicativos ASP.NET que sofrem replatform para serem executados no Amazon EKS podem usar essa funcionalidade para continuar oferecendo Windows Authentication com base no protocolo Kerberos v5.

Leitura adicional:

Windows Authentication nos pods do Amazon EKS Windows

Windows containers e contas de serviços

Solucionar problemas de gMSAs para Windows containers

Configurar gMSA para pods e containers Windows (documentação oficial do Kubernetes)

Este artigo foi traduzido do Blog da AWS em Inglês.


Sobre os Autores

Marcio Morales é Principal Solutions Architect da Amazon Web Services. Marcio é um SME global para Windows Containers e ajuda os clientes da AWS a projetar, criar, proteger e otimizar cargas de trabalho de Windows Containers na AWS.

 

 

 

 

Hamzah Abdulla é consultor de DevOps na AWS Professional Services. Aproveita sua experiência em MLOps, Kubernetes e IaC para acelerar a jornada de adoção da nuvem para clientes do setor de serviços financeiros. Está na AWS desde julho de 2021. Fora do trabalho, gosta de fazer caminhadas, viajar, ler e, atualmente, está aprendendo espanhol em seu próprio tempo.

 

 

 

 

Revisores

Luciano Bernardes trabalha atualmente como Sr Solutions Architect na AWS, especializado em workloads Microsoft. Com 16 anos de experiência no mercado, trabalhou a maior parte em consultoria técnica especializada em Microsoft, em clientes de várias verticais, com demandas voltadas para infraestrutura on-premises e em nuvem. Como SA, trabalha próximo a clientes e parceiros de consultoria em U.S. e LATAM, para apoiá-los em tomadas de decisão e revisão de arquitetura de workoads Microsoft na nuvem AWS.

 

 

 

 

Bruno Lopes é Senior Solutions Architect no time da AWS LATAM. Trabalha com soluções de TI há mais de 15 anos, tendo em seu portfólio inúmeras experiências em workloads Microsoft, ambientes híbridos e capacitação técnica de clientes como Technical Trainer e Evangelista. Agora atua como um Arquiteto de Soluções, unindo todas as capacidades para desburocratizar a adoção das melhores tecnologias afim de ajudar os clientes em seus desafios diários.