Por muito tempo, dar acesso a um cluster EKS significava editar o ConfigMap aws-auth dentro do próprio cluster. Um erro de indentação nesse YAML trancava todo mundo para fora. Com EKS access entries, o acesso passa a ser um recurso da API do EKS: você cria, lista e remove pelo AWS CLI ou pelo Terraform, sem tocar no cluster.
Este é o terceiro artigo da série artigos-eks. O primeiro já criou o cluster no modo API, e o segundo separou as cargas em node groups On-Demand e Spot. Agora vamos definir quem entra no cluster e com qual permissão: um time de plataforma com admin, um time de produto restrito ao próprio namespace e um pipeline de deploy com RBAC próprio.
Segurança: os ARNs de IAM role deste guia usam a conta fictícia 111122223333. Passe os ARNs reais por variável, nunca fixos no código de um repositório público, e prefira roles assumidas via SSO a usuários IAM com access key.
Sumário
- Como funcionam as EKS access entries
- Modo de autenticação do cluster
- Access policies gerenciadas
- EKS access entries com Terraform
- Grupos do Kubernetes com RBAC próprio
- Migrando do aws-auth para EKS access entries
- terraform plan
- Outputs do Terraform
- Conferindo o acesso
- Conclusão
- Referências oficiais
Como funcionam as EKS access entries
Uma access entry liga uma identidade IAM (role ou usuário) ao cluster. Sozinha, ela só diz “essa identidade é conhecida”. A permissão dentro do Kubernetes vem de uma de duas formas:
- Access policy: uma política gerenciada pela AWS, associada à entry, com escopo do cluster inteiro ou de namespaces específicos.
- Grupos do Kubernetes (
kubernetes_groups): a identidade entra no cluster como membro de um grupo, e você define o que esse grupo pode fazer comRoleeRoleBindingcomuns.
Dá para combinar as duas na mesma entry. O resultado é a soma das permissões.
Modo de autenticação do cluster
O cluster precisa estar num modo que aceite access entries. São três:
CONFIG_MAP: só oaws-auth. É o comportamento antigo.API_AND_CONFIG_MAP: os dois ao mesmo tempo. É o modo de transição.API: só access entries. Oaws-authé ignorado.
A mudança só anda num sentido: de CONFIG_MAP para API_AND_CONFIG_MAP e daí para API. Não há volta. No ambiente deste artigo o modo vem de uma variável, com API como padrão:
module "eks" {
source = "../../terraform-eks-modules"
name = var.cluster_name
kubernetes_version = var.kubernetes_version
subnet_ids = module.vpc.private_subnet_ids
authentication_mode = var.authentication_mode
public_access_cidrs = var.public_access_cidrs
}
Os nós dos managed node groups não precisam de entry escrita à mão: no modo API, o EKS cria sozinho a access entry da IAM role dos nós quando o node group é criado.
Access policies gerenciadas
As políticas mais usadas espelham os papéis padrão do Kubernetes:
AmazonEKSClusterAdminPolicy: equivalente aocluster-admin. Tudo, em todo o cluster.AmazonEKSAdminPolicy: equivalente aoadmin. Administra recursos, inclusive RBAC dentro do escopo.AmazonEKSEditPolicy: equivalente aoedit. Cria e altera a maioria dos objetos, sem mexer em RBAC.AmazonEKSViewPolicy: equivalente aoview. Só leitura, sem ver Secrets.
A lista completa, com os ARNs, sai pelo AWS CLI:
aws eks list-access-policies --query 'accessPolicies[].name' --output table
EKS access entries com Terraform
O módulo terraform-eks-access-entry-modules recebe um mapa de perfis. Cada perfil tem o ARN da identidade, os grupos do Kubernetes e as access policies com o escopo:
module "access" {
source = "../../terraform-eks-access-entry-modules"
cluster_name = module.eks.name
access_entries = {
plataforma = {
principal_arn = var.platform_admin_role_arn
policies = {
admin = {
policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
}
}
}
time-loja = {
principal_arn = var.team_role_arn
policies = {
edit = {
policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSEditPolicy"
scope_type = "namespace"
namespaces = ["loja"]
}
}
}
deploy-loja = {
principal_arn = var.deploy_role_arn
kubernetes_groups = ["loja-deployers"]
}
}
}
- plataforma: admin do cluster inteiro. Escopo
clusteré o padrão do módulo. - time-loja: pode criar e alterar objetos, mas só no namespace
loja. Fora dele, não enxerga nada. - deploy-loja: nenhuma access policy. A permissão vem do RBAC do grupo
loja-deployers, que veremos a seguir.
Dentro do módulo, cada par perfil e política vira um aws_eks_access_policy_association. O plan mostra a associação do time da loja com o escopo de namespace:
# module.access.aws_eks_access_policy_association.this["time-loja/edit"] will be created
+ resource "aws_eks_access_policy_association" "this" {
# (atributos calculados omitidos)
+ cluster_name = "eks-blog-castilho"
+ policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSEditPolicy"
+ principal_arn = "arn:aws:iam::111122223333:role/time-loja"
+ access_scope {
+ namespaces = [
+ "loja",
]
+ type = "namespace"
}
}
Grupos do Kubernetes com RBAC próprio
Access policies cobrem os papéis genéricos. Quando o pipeline de deploy precisa de algo bem específico, como atualizar Deployments e só ler o resto, o caminho é um grupo do Kubernetes com RBAC próprio. Salve como rbac-loja-deployers.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: loja
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployer
namespace: loja
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: loja-deployers
namespace: loja
subjects:
- kind: Group
name: loja-deployers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: deployer
apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac-loja-deployers.yaml
O nome do grupo na access entry e no RoleBinding precisa ser idêntico. Grupos que começam com system: são reservados e não podem ser usados em access entries.
Migrando do aws-auth para EKS access entries
Num cluster antigo, que ainda usa o aws-auth, a migração é feita em três passos sem derrubar ninguém:
- Mude o cluster para
API_AND_CONFIG_MAP(authentication_mode = "API_AND_CONFIG_MAP"). Oaws-authcontinua valendo. - Crie uma access entry para cada identidade que hoje está no
aws-authe teste o acesso de cada uma. - Com todas as identidades cobertas, mude para
API. A partir daí oaws-authé ignorado e pode ser apagado.
Antes do passo 3, liste o que já existe para não esquecer ninguém:
kubectl get configmap aws-auth -n kube-system -o yaml
aws eks list-access-entries --cluster-name eks-blog-castilho
terraform plan
As três roles são obrigatórias. No exemplo abaixo os ARNs usam a conta fictícia 111122223333; troque pelos da sua conta e pelo IP da sua rede:
terraform init
terraform validate
terraform plan \
-var 'public_access_cidrs=["SEU_IP/32"]' \
-var 'platform_admin_role_arn=arn:aws:iam::111122223333:role/plataforma-admin' \
-var 'team_role_arn=arn:aws:iam::111122223333:role/time-loja' \
-var 'deploy_role_arn=arn:aws:iam::111122223333:role/pipeline-deploy-loja' \
-out=tfplan
O código foi validado com terraform validate e terraform plan contra uma conta AWS real, sem apply. São 33 recursos: os 28 do cluster base mais três access entries e duas associações de policy.
# module.access.aws_eks_access_entry.this["deploy-loja"] will be created
# module.access.aws_eks_access_entry.this["plataforma"] will be created
# module.access.aws_eks_access_entry.this["time-loja"] will be created
# module.access.aws_eks_access_policy_association.this["plataforma/admin"] will be created
# module.access.aws_eks_access_policy_association.this["time-loja/edit"] will be created
...
Plan: 33 to add, 0 to change, 0 to destroy.
Outputs do Terraform
O ambiente tem três outputs. Como não houve apply, os valores abaixo vêm do bloco Changes to Outputs do plan; os ARNs das access entries só existem depois do apply:
Changes to Outputs:
+ access_entry_arns = {
+ deploy-loja = (known after apply)
+ plataforma = (known after apply)
+ time-loja = (known after apply)
}
+ cluster_name = "eks-blog-castilho"
+ kubeconfig_command = "aws eks update-kubeconfig --region us-east-1 --name eks-blog-castilho"
cluster_name: nome do cluster EKS, para usar nos comandosaws eks.access_entry_arns: o ARN de cada access entry, por perfil. Serve para auditoria e para referenciar a entry em outras automações. Veja comterraform output access_entry_arns.kubeconfig_command: o comando pronto para configurar okubectl. Rode com$(terraform output -raw kubeconfig_command).
Conferindo o acesso
Depois do apply, estes comandos mostram o que cada identidade recebeu:
aws eks list-access-entries --cluster-name eks-blog-castilho
aws eks list-associated-access-policies \
--cluster-name eks-blog-castilho \
--principal-arn arn:aws:iam::111122223333:role/time-loja
Para testar de verdade, assuma a role do time da loja, gere o kubeconfig e pergunte ao cluster o que ela pode fazer:
kubectl auth can-i create deployments -n loja # esperado: yes
kubectl auth can-i create deployments -n default # esperado: no
O custo extra deste artigo é zero: access entries e access policies não são cobradas. O cluster, o NAT Gateway e os nós custam o mesmo do primeiro artigo, então destrua o lab com terraform destroy ao terminar.
Conclusão
Com EKS access entries, o acesso ao cluster sai do YAML frágil do aws-auth e vira um recurso da API do EKS, versionado no Terraform como qualquer outro. Access policies resolvem os papéis comuns, inclusive restritos a um namespace, e grupos do Kubernetes com RBAC cobrem os casos sob medida.
Este artigo cuidou de quem acessa o cluster. O próximo da série trata do outro lado: como os pods, rodando dentro do cluster, ganham permissão para acessar serviços da AWS.
Referências oficiais
- Grant IAM users access to Kubernetes with EKS access entries — AWS Documentation
- Associate access policies with access entries — AWS Documentation
- Migrating existing aws-auth ConfigMap entries to access entries — AWS Documentation
- aws_eks_access_entry — Terraform Registry
- aws_eks_access_policy_association — Terraform Registry
Interessado em saber mais sobre esse assunto?