← Voltar para o blog

william@devops:~$ cat ./cases/eks-workload-identity.md

Cada aplicação no EKS
com a sua própria identidade.

Como as aplicações no Kubernetes pararam de usar access key fixa para falar com a AWS, e por que mexer só na infraestrutura não bastou.

CONFIDENCIALIDADE

Isso aconteceu de verdade, no trabalho. Tirei nomes de empresa, contas, domínios, repositórios e qualquer detalhe sensível.

01 / CONTEXTO

A aplicação estava no Kubernetes, mas sua identidade ainda era uma access key.

Os microsserviços no EKS precisavam acessar S3 e secrets. Do jeito que estava, recebiam AWS_ACCESS_KEY_ID eAWS_SECRET_ACCESS_KEY por variável de ambiente. Ou seja, chave fixa, e a segurança da aplicação dependia de ninguém errar ao guardar um secret.

Com IRSA, liguei uma IAM Role ao ServiceAccount de cada aplicação. O pod passou a receber uma credencial temporária, e nenhuma chave da AWS ficou no Kubernetes nem no código.

PRINCÍPIO DO PROJETO

Cada aplicação com a sua identidade, e acesso só ao que é dela.

02 / DESAFIO

A infraestrutura estava pronta para o IRSA. A aplicação, ainda não.

Se eu apagasse as chaves antes de mexer no código, a aplicação caía. Alguns clientes da AWS eram criados passando a chave direto, sem usar o caminho padrão do SDK para buscar credencial. Tive que acertar infraestrutura, manifests e código juntos.

01

Código

O cliente da AWS tinha que pegar a credencial do ambiente, não do código.

02

Kubernetes

Cada aplicação com o seu ServiceAccount, ligado à role certa.

03

IAM

A policy só com o recurso e as ações que a aplicação usa de verdade.

04

Transição

Tirar as chaves sem derrubar nenhuma aplicação.

03 / ARQUITETURA

Do ServiceAccount até a credencial temporária.

O Kubernetes entrega ao pod um token ligado ao ServiceAccount dele. O SDK da AWS usa esse token para pedir ao STS uma sessão da role. Antes de liberar, a trust policy confere o provedor OIDC do cluster, o namespace e o nome do ServiceAccount.

01WorkloadPod no EKS
02IdentidadeServiceAccount
03TokenOIDC projetado
04ValidaçãoAWS STS
05PermissãoIAM Role

KUBERNETESO ServiceAccount diz qual aplicação é, dentro do cluster.

IAMA role tem só o que a aplicação pode fazer.

SDKO SDK busca e renova a credencial sozinho.

04 / IMPLEMENTAÇÃO

Infraestrutura e código tinham que andar juntos.

01

ServiceAccount dedicado por aplicação

Cada aplicação ganhou o seu ServiceAccount, com uma anotação apontando para a role dela. Assim duas aplicações não dividem a mesma identidade sem motivo.

service-account.yamlUM POR APLICAÇÃO
apiVersion: v1
kind: ServiceAccount
metadata:
  name: api-pagamentos
  namespace: pagamentos-dev
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<conta>:role/dev-api-pagamentos-irsa
deployment.yamlKUBERNETES
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-pagamentos
  namespace: pagamentos-dev
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: api-pagamentos
  template:
    metadata:
      labels:
        app.kubernetes.io/name: api-pagamentos
    spec:
      serviceAccountName: api-pagamentos # a identidade vem daqui
      containers:
        - name: api-pagamentos
          image: <conta>.dkr.ecr.us-east-1.amazonaws.com/api-pagamentos:1.4.2-8f3a1c2
          env:
            - name: AWS_REGION
              value: us-east-1
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi

# Nenhuma access key é injetada no pod.
02

SDK utilizando a cadeia padrão de credenciais

Tirei do código o trecho que passava access key e secret key. O cliente ficou só com a região, e o SDK encontra sozinho a credencial temporária do pod.

aws-client.tsPADRÃO
const client = new S3Client({
  region: process.env.AWS_REGION
});

// Sem accessKeyId ou secretAccessKey no código.
03

Permissão mínima no recurso correto

Montei as policies por pasta do bucket e por ação. Uma aplicação que só grava arquivo não ganha de brinde permissão para listar o bucket inteiro, apagar a pasta dos outros ou mudar a configuração do serviço.

04

Preservação das fronteiras existentes

Coloquei o IRSA sem abrir mais permissão no bucket e sem mexer na distribuição privada que já existia. A role da aplicação e a policy do bucket continuam funcionando juntas, uma reforçando a outra.

05 / MIGRAÇÃO

Só apaguei as chaves depois de testar o caminho inteiro.

  1. 01

    Mapeamento

    Levantei quais aplicações usavam chave, em quais pastas e para fazer o quê.

  2. 02

    Infraestrutura

    Criei as roles, as trust policies e os ServiceAccounts de cada ambiente.

  3. 03

    Aplicação

    Ajustei o código para o SDK buscar a credencial sozinho.

  4. 04

    Validação

    Testei subir a aplicação, ler, gravar e ver o acesso negado onde devia ser negado.

  5. 05

    Remoção

    Com tudo funcionando, apaguei as variáveis e os secrets com as chaves.

06 / RESULTADOS

Segurança em cada aplicação, não só no cluster.

Não tenho números para mostrar, então conto o que mudou.

✓

Acabaram as access keys na aplicação a credencial agora vem do ambiente e expira.

✓

Cada aplicação no seu quadrado com ServiceAccount e role próprios.

✓

Só a permissão necessária por ação, recurso e pasta.

✓

Ninguém mais troca chave a credencial se renova sozinha.

✓

Erro mais fácil de achar dá para ver se o problema é código, identidade ou permissão.

07 / APRENDIZADOS

IRSA não é só configurar o cluster.

Para funcionar, três coisas precisam estar certas ao mesmo tempo: a role na AWS, o ServiceAccount do deployment e o jeito que a aplicação cria o cliente da AWS. Se qualquer uma continuar esperando chave fixa, não funciona.

O que mais ajudou foi tratar a identidade como parte da aplicação, e não como detalhe de infraestrutura. Assim deu para apagar os secrets sensíveis sabendo exatamente qual serviço acessa cada recurso.

william@devops:~$ echo $LESSON_LEARNED

"No Kubernetes, cada aplicação deve ter a sua identidade, e nenhuma permissão a mais."
COMPARTILHAR IDEIAS

Quer trocar uma ideia sobre Cloud ou DevOps?

Mandar um e-mail ↗