O blog da AWS

Comunicação segura entre clusters no EKS com VPC Lattice e Tags de sessão IAM de Identidade do Pod

Por Sebastien Allamand.

Visão geral da solução

Quando você cria suas aplicações e deseja expor endpoints internos de API, você pode criar seus microsserviços usando diferentes opções de computação, como AWS Lambda, Amazon Elastic Container Service (Amazon ECS) e Amazon Elastic Kubernetes Service (Amazon EKS). Em seguida, você pode implantar suas aplicações em várias contas da AWS e em várias Amazon Virtual Private Clouds (VPCs), e nesse momento, você precisa de uma forma segura de conectá-las. O Amazon VPC Lattice permite o tráfego leste-oeste em todas as contas, oferece descoberta de serviços, gerenciamento de tráfego e controles de acesso. Ao trabalhar no Amazon EKS, o Amazon VPC Lattice vem com o controlador de API do AWS Gateway que implementa o API Gateway do Kubernetes.

O tráfego em toda essa arquitetura pode ser protegido usando criptografia em trânsito, e você pode habilitar autorizações granulares do AWS Identity and Access Management (IAM) em cada serviço do Amazon VPC Lattice. Para criptografia, você pode confiar no AWS Private Certificate Authority (CA) para gerenciar seu domínio privado e no AWS Certificate Manager (ACM) para criar certificados para cada um dos seus serviços. Para autorização, você pode confiar no recurso de políticas de autenticação IAM do Amazon VPC Lattice e do EKS Pod Identity, que simplifica a forma como os administradores de cluster podem configurar aplicações Kubernetes para obter permissões IAM. Agora, essas permissões podem ser configuradas com menos etapas diretamente por meio do console do Amazon EKS, APIs e CLI. O EKS Pod Identity permite reutilizar uma função IAM em vários clusters e simplifica o gerenciamento de políticas.

Você pode associar uma função IAM a uma conta de serviço do Pod com a seguinte API:

aws eks create-pod-identity-association \
  --cluster-name $CLUSTER_NAME \
  --namespace $NAMESPACE \
  --service-account $SERVICE_ACCOUNT \
  --role-arn arn:aws:iam::$AWS_ACCOUNT:role/$POD_ROLE_NAME

A função IAM $POD_ROLE_NAME precisa ter a seguinte política de confiança que permite que o serviço Amazon EKS a utilize:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Service": "pods.eks.amazonaws.com"
    },
    "Action": ["sts:AssumeRole","sts:TagSession"]
  }]
}

Quando o EKS Pod Identity assume uma função IAM, ele define tags de sessão para a sessão IAM. Essas tags contêm informações como eks-cluster-name, kubernetes-namespace e kubernetes-pod-name, que podem ser usadas para controle de acesso baseado em atributos (ABAC). O ABAC pode conceder acesso aos seus recursos da AWS somente a pods específicos do Kubernetes, e a partir de namespaces específicos em clusters EKS específicos. Esse recurso também pode ser utilizado ao acessar um serviço Amazon VPC Lattice quando habilitamos a autorização IAM, fornecendo um sistema de controle de acesso direto e rico para seus microsserviços dentro do Amazon EKS ou entre diferentes clusters do EKS.

Para acessar um serviço Amazon VPC Lattice no qual habilitamos políticas de autenticação IAM, sua solicitação de aplicação deve ser assinada com o algoritmo AWS Sigv4 (ou Sigv4A para várias regiões), o mesmo recurso usado com qualquer serviço da AWS. Você pode implementar a assinatura da solicitação usando a no código da sua aplicação (veja esses exemplos). Embora este seja o método recomendado, reconhecemos que isso significa que você precisa fazer alterações no código da sua aplicação e podemos propor uma solução alternativa. O padrão do Amazon EKS Blueprints demonstra uma abordagem alternativa que permite usar um proxy sidecar sem modificar o código da sua aplicação. Esse proxy processa automaticamente a assinatura Sigv4 para solicitações direcionadas aos serviços do Amazon VPC Lattice. Usamos o Envoy, um proxy amplamente adotado que oferece suporte ao EKS Pod Identity e ao recurso de assinatura AWS Sigv4, permitindo uma integração perfeita com os serviços da AWS a partir do cluster Kubernetes.

Além disso, para criptografia de pod-a-pod, você pode configurar seus serviços Amazon VPC Lattice com listeners HTTPS. Se o contêiner da sua aplicação não suportar a criptografia TLS para solicitações HTTPS, você poderá transferir isso para um proxy sidecar do Envoy junto com a assinatura Sigv4. Nessa configuração, seu aplicativo faz uma solicitação HTTP para um serviço Amazon VPC Lattice configurado como HTTPS, e essa solicitação é roteada para o proxy sidecar Envoy, que então emite uma solicitação HTTPS assinada para o Amazon VPC Lattice como cliente. Quando sua aplicação faz uma solicitação HTTP para um serviço Amazon VPC Lattice, a solicitação é automaticamente encaminhada para o sidecar do Envoy com uma regra iptable local. A partir daí, o Envoy cria uma assinatura Sigv4 para essa solicitação e encaminha a solicitação para o Amazon VPC Lattice em HTTPS, confiando na CA privada da AWS para validar nossos certificados de domínio privado emitidos pelo ACM.

Para facilitar ainda mais o uso do proxy, o padrão se baseia em uma anotação em nossa implantação. Isso aciona uma política de cluster Kyverno para injetar automaticamente o proxy sidecar Envoy em seu pod de aplicação.

Passo a passo

Nesta solução, nos baseamos nos padrões EKS Blueprints para Terraform. Os EKS Blueprints são uma coleção de padrões que demonstram usos específicos do Amazon EKS e de outros serviços da AWS. Aqui, usamos o padrão vpc-lattice/cross-cluster-communication.

Dividimos o padrão em três pilhas do Terraform, também mostradas no diagrama a seguir:

  1. A primeira pilha chamada environment cria recursos da AWS que são necessários para os dois clusters EKS:
  • Uma zona privada hospedada do Amazon Route 53 chamada example.com, anexada a uma VPC privada fictícia (criada somente neste estágio para ter uma zona privada hospedada).
  • Uma CA privada da AWS que gerencia o domínio privado. A partir dessa CA privada da AWS, criamos um certificado ACM curinga que é posteriormente anexado aos nossos serviços Amazon VPC Lattice.
  • Também criamos uma função IAM que é usada pelas nossas aplicações usando o EKS Pod Identity. A função tem permissão para invocar os serviços do Amazon VPC Lattice e baixar o certificado raiz do AWS Private CA, permitindo que a aplicação confie no domínio privado.

  1. As próximas duas pilhas são implantadas usando o mesmo código do Terraform no diretório do cluster. Usamos o recurso de espaço de trabalho do Terraform para instanciar a pilha de clusters duas vezes para criar dois clusters EKS: cluster1 e cluster2.

Primeiro, a pilha cria uma VPC dedicada (com CIDR sobreposto, pois tem exatamente a mesma configuração).

Em seguida, a pilha cria o cluster EKS com um grupo dedicado de nós gerenciados.

Em seguida, ela instala alguns complementos do Amazon EKS e do Kubernetes:

  • Controlador de API Gateway que gerencia a criação de objetos do Amazon VPC Lattice a partir das definições de HTTPRoute e IAMAuthPolicy.
  • Um DNS externo responsável pela criação de registros na zona privada hospedada do Route53 com base nos mesmos objetos HTTPRoute que contêm nomes de domínio personalizados.
  • E, finalmente, implantamos o Kyverno, responsável por injetar o proxy Envoy em nossos pods de aplicações.

Em seguida, instalamos dois charts Helm, o primeiro chamado platform cria os objetos GatewayClass e Gateway, que criam a rede de serviços Amazon VPC Lattice, e a política de cluster Kyverno usada para injetar o proxy Envoy na aplicação. O segundo chart do Helm chamado demo implanta a aplicação de demonstração, denominado demo-cluster1 no primeiro cluster e demo-cluster2 no segundo, conforme mostrado no diagrama a seguir.

  1. Configuração do HttpRoute
    1. Define a exposição do serviço por meio da API VPC Lattice Gateway
    2. Especifica regras de roteamento, caminhos e serviços de back-end
    3. Implementação da política do Kyverno
  2. Injeta o sidecar do proxy Envoy SigV4
    1. Assina automaticamente solicitações de API da AWS com credenciais da AWS
    2. Garante autenticação segura para comunicação de serviço a serviço
  3. Autoridade de certificação privada (PCA) da AWS
    1. Emite e gerencia certificados privados
    2. Valida nomes de domínio personalizados no VPC Lattice
    3. Permite a criptografia TLS para comunicações internas
  4. Política de autenticação do IAM
    1. Define regras de controle de acesso refinadas
    2. Especifica quem pode acessar quais serviços
    3. Implementa o modelo de segurança de menor privilégio
  5. Integração externa de DNS
    1. Monitora os recursos DNSendpoint do controlador de API Gateway
    2. Cria e atualiza automaticamente registros DNS
    3. Mantém a descoberta de serviços por meio do Route 53
  6. Fluxo de comunicação do App1 → App2
    1. Rotas por meio da rede de serviços VPC Lattice
    2. Autenticado por meio de políticas do IAM
    3. Criptografado usando certificados TLS da CA privada
  7. Fluxo de comunicação do App2 → App1
    1. Utiliza conectividade bidirecional VPC Lattice
    2. Segue os mesmos padrões de segurança e autenticação
    3. Mantém princípios consistentes de service mesh

Quando o controlador do API Gateway encontra o objeto Gateway criado a partir do chart Helm, ele cria uma associação de VPC entre sua VPC e a rede de serviço Lattice. A associação de VPC também pode incluir um grupo de segurança que define quem dentro da VPC tem permissão para fazer solicitações de entrada para a rede de serviço. Com condições diferentes, podemos restringir quem tem permissão para consumir a rede, por exemplo, restringindo também por identificadores de VPC.

Embora o Amazon VPC Lattice possa ser usado em várias contas usando o AWS Resource Access Manager (AWS RAM) para simplificar, neste padrão contamos apenas com a mesma conta da AWS.

As verificações de integridade do grupo-alvo do Amazon VPC Lattice se originam do serviço Amazon VPC Lattice. O Amazon VPC Lattice tem uma lista de prefixos gerenciados específica que precisa ser permitida no grupo de segurança do cluster EKS, o que é feito pela definição do Terraform. Se seu aplicativo Amazon EKS precisar iniciar conexões na rede de serviço, você também precisará atualizar o grupo de segurança da associação VPC para permitir o tráfego de entrada do grupo de segurança do grupo de nós nas portas apropriadas, que também estão configuradas no Terraform.

O chart Helm de demonstração cria um objeto HTTPRoute contendo a definição do serviço de demonstração e usa um nome de domínio personalizado:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: demo-cluster2
  namespace: apps
spec:
  hostnames:
  - demo-cluster2.example.com
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: lattice-gateway
    namespace: lattice-gateway
    sectionName: http-listener
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: lattice-gateway
    namespace: lattice-gateway
    sectionName: https-listener-with-custom-domain
  rules:
  - backendRefs:
    - group: ""
      kind: Service
      name: demo-cluster2-v1
      port: 80
      weight: 1
    matches:
    - path:
        type: PathPrefix
        value: /

O controlador do API Gateway cria recursos associados do Amazon VPC Lattice (serviço, listeners e grupos-alvo). Com nossa implantação, ele permite a terminação de TLS para cada serviço nos listeners, que encaminham o tráfego para os grupos-alvo associados, respeitando a rota definida para cada serviço. Os grupos-alvo são configurados como tipo IP e encaminhados diretamente para os pods associados no serviço Kubernetes de destino.

Um serviço Amazon VPC Lattice pode ser configurado para distribuir solicitações entre destinos de diferentes clusters.

Como definimos um nome de domínio personalizado, o controlador do API Gateway também cria um objeto Kubernetes DNSEndpoint:

kind: DNSEndpoint
metadata:
  name: demo-cluster1-dns
  namespace: apps
  ownerReferences:
  - apiVersion: gateway.networking.k8s.io/v1beta1
    blockOwnerDeletion: true
    controller: true
    kind: HTTPRoute
    name: app4
spec:
  endpoints:
  - dnsName: demo-cluster1.example.com
    recordTTL: 300
    recordType: CNAME
    targets:
    - demo-cluster1-apps-082dc3111b7018633.7d67968.vpc-lattice-svcs.eu-west-1.on.aws
status:
  observedGeneration: 1

O DNS externo monitora esse objeto com a extensão CRD. Configuramos o DNS externo para poder ler a definição de recurso personalizado do DNSEndpoint fornecendo esta configuração:

--source=crd --crd-source-apiversion=externaldns.k8s.io/v1alpha1 --crd-source-kind=DNSEndpoint

Quando você cria um HTTPRoute no API Gateway com um domínio personalizado especificado, o Amazon VPC Lattice cria um DNS Endpoint para essa entrada.

Com essa configuração, o DNS externo pode criar um registro CNAME dedicado do Route53 na zona privada hospedada que roteia o tráfego do nome de domínio personalizado para os endpoints do serviço Amazon VPC Lattice. Assim, seus serviços internos podem ser descobertos e acessados usando seus nomes de domínio internos.

O objeto Kubernetes Gateway também contém o nome de recurso da Amazon (ARN) do certificado ACM, que é usado pelo Amazon VPC Lattice para terminar a sessão TLS de suas solicitações.

O chart Helm de demonstração também implanta um objeto IAMAuthPolicy associado ao HTTPRoute, especificando que cada solicitação deve ser assinada com o algoritmo Sigv4 e definindo regras ABAC afirmando que, para o aplicativo demo-cluster2, somente solicitações do namespace apps do EKS cluster1 são permitidas. E para o aplicativo demo-cluster1, ele só aceita solicitações do namespace apps do EKS cluster2.

Também podemos configurar uma assinatura de log de acesso para que todas as solicitações aos serviços do Amazon VPC Lattice sejam registradas em um grupo de logs do Amazon CloudWatch.

Implantação

Você pode seguir as instruções de implantação no padrão EKS Blueprints associado.

Para uma configuração rápida, você também pode executar os seguintes passos:

# Clone EKS Blueprint repository
git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git
cd patterns/vpc-lattice/cross-cluster-pod-communication

# Deploy the environment
cd environment
terraform init
terraform apply --auto-approve

# Deploy cluster 1
cd ../cluster
./deploy.sh cluster1
eval `terraform output -raw configure_kubectl`

# Deploy cluster 2
cd ../cluster
./deploy.sh cluster2
eval `terraform output -raw configure_kubectl`

Depois que a solução for implantada corretamente com as três pilhas, você poderá executar os comandos a seguir para validar se a comunicação entre clusters está funcionando conforme o esperado.

Para isso, fazemos uma execução nos pods para executar um comando curl direcionado aos serviços em HTTP. Conforme já explicado, a solicitação é roteada para o sidecar Envoy em HTTP, que assina a solicitação e a encaminha em HTTPS usando nossos certificados de CA privada da AWS:

1. Em cluster1 app1, chame cluster2 app2 -> sucesso

$ kubectl --context eks-cluster1 exec -ti -n apps deployments/demo-cluster1-v1 \
  -c demo-cluster1-v1 -- curl demo-cluster2.example.com

Requesting to Pod(demo-cluster2-v1-c99c7bb69-2gm5f): Hello from demo-cluster2-v1

2. Em cluster2 app2, chame cluster1 app1 -> sucesso

$ kubectl --context eks-cluster2 exec -ti -n apps deployments/demo-cluster2-v1 \
  -c demo-cluster2-v1 -- curl demo-cluster1.example.com

Requesting to Pod(demo-cluster1-v1-6d7558f5b4-zk5cg): Hello from demo-cluster1-v1

Podemos ver que, se não usarmos o fluxo autorizado como nos comandos anteriores, o Amazon VPC Lattice rejeitará a solicitação como não autorizada:

3. Em cluster1 app1, chame cluster1 app1 -> proibido

$ kubectl --context eks-cluster1 exec -ti -n apps deployments/demo-cluster1-v1 \
  -c demo-cluster1-v1 -- curl demo-cluster1.example.com 

AccessDeniedException: User: arn:aws:sts::12345678910:assumed-role/vpc-lattice-sigv4-client/eks-eks-cluste-demo-clust-1b575f8d-fb77-486a-8a13-af5a2a0f78ae is not authorized to perform: vpc-lattice-svcs:Invoke on resource: arn:aws:vpc-lattice:eu-west-1:12345678910:service/svc-002349360ddc5a463/ because no service-based policy allows the vpc-lattice-svcs:Invoke action

4. Em cluster2 app2, chame cluster2 app2 -> proibido

$ kubectl --context eks-cluster2 exec -ti -n apps deployments/demo-cluster2-v1 \
-c demo-cluster2-v1 -- curl demo-cluster2.example.com

AccessDeniedException: User: arn:aws:sts::12345678910:assumed-role/vpc-lattice-sigv4-client/eks-eks-cluste-demo-clust-a5c2432b-b84a-492f-8cbc-16f1fa5053eb is not authorized to perform: vpc-lattice-svcs:Invoke on resource: arn:aws:vpc-lattice:eu-west-1:12345678910:service/svc-00b57f32ed0a7b7c3/ because no service-based policy allows the vpc-lattice-svcs:Invoke action

Você pode verificar como a política do IAM é definida no aplicativo demo-cluster1:

kubectl --context eks-cluster1 get IAMAuthPolicy -n apps demo-cluster1-iam-auth-policy  -o json | jq ".spec.policy | fromjson"

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::12345678910:root"
      },
      "Action": "vpc-lattice-svcs:Invoke",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:PrincipalTag/eks-cluster-name": "eks-cluster2",
          "aws:PrincipalTag/kubernetes-namespace": "apps"
        }
      }
    }
  ]
}

Podemos confirmar que somente solicitações iniciadas a partir do cluster eks-cluster2 no namespace apps são permitidas.

Limpeza

Para evitar cobranças futuras, exclua os recursos seguindo a seção de limpeza do padrão EKS Blueprints ou executando o seguinte trecho:

  1. Começamos excluindo a pilha Terraform do cluster2.

Observe que precisamos fazer isso em ordem, para que nossos controladores do Kubernetes possam limpar os recursos externos antes de excluir o controlador e os nós do Kubernetes.

./destroy.sh cluster2

2. Em seguida, podemos excluir a pilha Terraform do cluster1.

./destroy.sh cluster1

3. Por fim, exclua a pilha Terraform do ambiente.

cd ../environment
Terraform destroy -auto-approve

Conclusão

Com essa solução, demonstramos como você pode proteger a comunicação entre aplicações entre clusters EKS usando o Amazon VPC Lattice, com um exemplo automatizado que você pode usar como referência para adaptar à suas próprias aplicações de microsserviços.

Os principais benefícios dessa abordagem incluem o seguinte:

  • Comunicação segura: ao usar o Amazon VPC Lattice, você pode garantir que a comunicação entre seus clusters EKS seja criptografada em trânsito e protegida por políticas de autorização IAM granulares. Isso ajuda a manter a segurança e a integridade dos dados da sua aplicação, mesmo quando eles estão sendo transmitidos entre diferentes clusters ou contas.
  • Descoberta de serviços simplificada: com a integração do controlador de API Gateway e do DNS externo, você pode expor seus serviços usando nomes de domínio personalizados, facilitando a descoberta e comunicação entre serviços.
  • Escalabilidade e flexibilidade: o Amazon VPC Lattice permite que você distribua seu aplicativo em várias VPCs e contas, permitindo que você escale sua infraestrutura conforme necessário, mantendo a conectividade segura entre seus componentes.
  • Implantação automatizada: ao usar o EKS Blueprints para Terraform, você pode automatizar a implantação e a configuração de seus clusters EKS, recursos do Amazon VPC Lattice e outros serviços de suporte, reduzindo o risco de erros manuais e garantindo implantações consistentes.
  • Reutilização: a solução demonstra como usar o EKS Pod Identity e o proxy Envoy para permitir a comunicação segura sem modificar o código da sua aplicação. Essa abordagem pode ser adaptada a outras aplicações, permitindo que você reutilize os mesmos padrões e melhores práticas em toda a organização.
  • Observabilidade e monitoramento: ao configurar logs de acesso para os serviços Amazon VPC Lattice, você pode obter informações valiosas sobre o fluxo de tráfego entre seus clusters, permitindo monitorar e solucionar problemas com mais eficiência.

Em geral, essa solução fornece uma abordagem abrangente e segura para permitir a comunicação entre clusters para suas aplicações baseadas no Amazon EKS, usando o poder do Amazon VPC Lattice e de outros serviços da AWS. Seguindo os padrões e as melhores práticas demonstrados neste exemplo, você pode criar arquiteturas de microsserviços escaláveis, seguras e altamente disponíveis que atendam às demandas dos aplicações modernas nativas da nuvem.

Este blog é uma tradução do blog original em inglês (link aqui).

Autor

Sébastien Allamand é Arquiteto de Soluções Sênior especialista em contêineres com mais de 15 anos de experiência na criação de arquiteturas de produção que priorizam confiabilidade, escalabilidade e eficiência operacional. Atualmente, ele está se concentrando em infraestrutura como código, sistemas distribuídos e otimização de fluxos de trabalho de desenvolvedores na Amazon Web Services

Tradutores

Marcelo Moras é Arquiteto de Soluções na AWS atendendo clientes Enterprise com foco em mercado financeiro. Com mais de 15 anos de experiência atuando com infraestrutura, administração de sistemas, redes, containers e segurança.
Andre Mello é Arquiteto de Soluções na AWS