Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

03 - Service Accounts e OIDC

#cicd#federacao#irsa#oidc#service-account
video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

Service Accounts e OIDC

Workloads também são identidades: uma API em Kubernetes, um job de CI/CD e uma função serverless precisam provar quem são para chamar outros sistemas, e essa prova não pode ser uma senha gravada em arquivo de configuração. Service accounts são as identidades nativas de workloads, e a federação OIDC (OpenID Connect) é o mecanismo que elimina credenciais estáticas desse cenário, permitindo que o workload apresente um token de curta duração assinado que um provedor de nuvem troca por credenciais temporárias. Em produção, a combinação das duas técnicas é o que separa arquiteturas onde o vazamento de um repositório é um incidente de arquiteturas onde o vazamento não concede nada. O tema é central no módulo porque ataca a maior fonte de incidentes em nuvem: chaves de acesso de longa duração espalhadas por pipelines e contêineres.

Identidade de workload

Identidade humana e identidade de workload têm dinâmicas diferentes e não devem compartilhar modelo. Humanos autenticam por sessão interativa com MFA; workloads autenticam milhares de vezes por minuto, sem pessoa presente, e suas credenciais vivem onde qualquer dump de memória ou commit descuidado pode expor. Por isso, o desenho de identidade de workload persegue duas propriedades: ausência de segredo de longa duração e vínculo verificável entre o contexto de execução e a permissão.

A federação atende às duas propriedades. O workload nunca guarda segredo compartilhado; ele recebe do provedor de identidade um token JWT assinado, cujo payload descreve o contexto, como repositório, branch e ambiente de execução. O provedor de nuvem valida a assinatura contra as chaves públicas publicadas no endpoint OIDC e emite credenciais temporárias com o escopo mapeado. O segredo vira um artefato efêmero, renovado a cada execução.

Service accounts no Kubernetes

No Kubernetes, a ServiceAccount é o objeto que representa a identidade de um workload, e todo pod roda sob uma delas, explicitamente ou sob a default do namespace. A conta por si só não concede privilégio nenhum; o que autoriza é a combinação da ServiceAccount com RBAC, que liga a conta a roles de cluster ou de namespace. Boa prática estrutural: uma ServiceAccount por serviço e por finalidade, nunca a default, para que o escopo do pod seja legível no manifesto e auditável no cluster.

# ServiceAccount dedicada ao serviço de faturamento, sem automount genérico
apiVersion: v1
kind: ServiceAccount
metadata:
  name: faturamento-api
  namespace: producao
  annotations:
    # IRSA: mapeia a ServiceAccount para a role IAM no EKS
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/faturamento-api-prod
automountServiceAccountToken: true
---
# RBAC: a conta só pode ler configmaps do próprio namespace
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: faturamento-api-leitura
  namespace: producao
subjects:
  - kind: ServiceAccount
    name: faturamento-api
    namespace: producao
roleRef:
  kind: Role
  name: leitor-configmap
  apiGroup: rbac.authorization.k8s.io

O token projetado no pod fica em um arquivo montado pelo kubelet, com expiração e audiência definidas, e renovação automática pelo TokenRequest API. O annotation no exemplo é a ponte do IRSA, tratada na sequência.

IRSA e Pod Identity

O IAM Roles for Service Accounts (IRSA) resolve o problema clássico do EKS: todos os pods no mesmo node compartilham a identidade IAM da instância, a menos que o cluster exponha um provedor OIDC que permita trocar o token da ServiceAccount por credenciais da role específica do pod. O fluxo tem quatro passos: o cluster tem um provedor OIDC registrado na conta; a ServiceAccount carrega a annotation com o ARN da role; a trust policy da role confia no provedor OIDC do cluster com condições de namespace e ServiceAccount; o SDK do workload usa o token montado para assumir a role e recebe credenciais temporárias.

  • Escopo por pod: cada serviço ganha role própria, encerrando o antipadrão de instância com permissão para tudo.
  • Sem segredo estático: nenhuma Access Key no pod, no env var ou no configmap; a credencial nasce e morre com a sessão.
  • Auditoria precisa: o CloudTrail registra a role usada e a ServiceAccount de origem, o que liga chamada de API ao serviço exato.
  • Menos blast radius horizontal: comprometer um pod não herda as permissões dos vizinhos no mesmo node.

O EKS Pod Identity é a alternativa mais recente ao IRSA: em vez de provedor OIDC por cluster, o agente do EKS troca o token por credenciais usando uma associação gerenciada entre ServiceAccount e role, com menos passos de configuração. A escolha entre eles é operacional; o princípio é o mesmo, identidade de pod mapeada a role temporária.

Federação OIDC para CI/CD

Pipelines são o caso mais frequente de chave estática mal cuidada: o deploy precisa de credenciais, e a solução rápida é gravar a Access Key como secret do repositório. Com federação OIDC, o GitHub Actions (ou GitLab CI, ou qualquer runner que emita token OIDC) apresenta um token assinado por referência ao provedor OIDC da conta, e assume a role de deploy sem segredo algum cadastrado. A trust policy condição o token por repositório e por branch, de modo que nem um fork rodando o workflow consegue assumir a role.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ConfiarSomenteNoWorkflowDeDeploy",
      "Effect": "Allow",
      "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:empresa/faturamento:ref:refs/heads/main"
        }
      }
    }
  ]
}
# Pipeline GitHub Actions assumindo role AWS por OIDC, sem secrets de chave
permissions:
  id-token: write   # único permissionamento necessário para a federação
  contents: read
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Assumir role de deploy
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy-ci
          aws-region: sa-east-1
      - name: Aplicar infraestrutura
        run: terraform -chdir=infra apply -auto-approve

A role assumida pelo pipeline deve ser a mais estreita possível, com permissão apenas sobre os recursos que o deploy toca. A rotação é automática por desenho: o token vale minutos, e as credenciais emitidas expiram junto.

Rotação automática de credenciais

O benefício silencioso da federação é eliminar a tarefa humana de rotação. Credenciais estáticas exigem agendamento, coordenação com sistemas consumidores e janela de risco no momento da troca; na prática, muitas organizações simplesmente não rotacionam, e a chave de dois anos atrás continua válida. Com OIDC, a rotação é propriedade do mecanismo: cada execução recebe token novo, assinado pelas chaves rotativas do provedor de identidade, e cada sessão STS expira sozinha.

Onde credencial estática é inevitável, por limitação de um fornecedor legado, o mínimo aceitável é rotação automatizada por segredo gerenciado, com o Secret Manager do provedor renovando e distribuindo, e alerta para qualquer credencial acima da idade máxima definida pela política. O objetivo é que credencial de longa duração seja anomalia com alarme, e não configuração corrente.

Armadilhas de credencial embutida

  • Chave de acesso em variável de ambiente de contêiner: aparece em dump, em log de crash e em inspeção de pod por qualquer pessoa com acesso de leitura.
  • Credencial em arquivo no repositório: histórico do git preserva tudo, e remover o arquivo não remove o segredo do histórico.
  • Token de longa duração em secret do CI: a federação OIDC existe exatamente para eliminar esse padrão, e a secret gráfica costuma ser o ponto de partida do incidente.
  • Credencial de serviço reutilizada por vários workloads: escopa demais e impede revogação cirúrgica; identidade por workload, sempre.
  • Segredo copiado em imagem: build com credencial em camada de Dockerfile publica o segredo no registry junto com a imagem.
  • Condições fracas na trust policy OIDC: confiar no provedor GitHub inteiro sem restringir sub permite que qualquer repositório público assuma a role de deploy.

Comparações

Critério Access Key estática Federação OIDC IRSA / Pod Identity
Duração da credencial Permanente até rotação Minutos, por execução Minutos, por sessão de pod
Segredo armazenado Sim, em secret ou arquivo Não Não
Rotação Manual e agendada Automática por execução Automática por sessão
Auditabilidade Principal genérico Contexto de repo e branch ServiceAccount e namespace
Risco de vazamento em git Alto Sem segredo para vazar Sem segredo para vazar
Adequação Legado sem alternativa CI/CD e runners externos Workloads em EKS

Erros comuns

  • Usar a ServiceAccount default em produção, que costuma acumular permissões de conveniência de namespace; conta dedicada por serviço é o ponto de partida.
  • Trust policy OIDC sem restrição de sub, aceitando qualquer repositório da organização ou da internet; a condição por repositório e branch é o que torna a federação segura.
  • Role de deploy com permissão de IAM quando o pipeline só aplica infraestrutura de rede e compute; o excesso vira prêmio para quem comprometer o workflow.
  • Automount herdado por pods que não usam API do Kubernetes, ampliando superfície sem necessidade; desligue automountServiceAccountToken onde não se usa.
  • Misturar identidade humana e de workload na mesma role, o que quebra a análise de uso e a separação de deveres.
  • Esquecer a expiração do token em jobs longos: sessões de build que ultrapassam a validade falham com erro de credencial; dimensione a sessão STS para a duração real do job.

Boas práticas em produção

Inventarie e extermine: rode uma varredura por Access Keys ativas e por secrets de CI contendo credenciais AWS, e substitua cada uma por federação OIDC ou por role de workload, mantendo chave estática só onde o fornecedor não oferece alternativa. Padronize a criação de ServiceAccount e role por serviço em módulos de IaC, com trust policy condicionada por namespace e por conta, para que o padrão seguro seja o caminho fácil.

Meça a maturidade por três indicadores: número de credenciais estáticas ativas na conta, idade da credencial mais antiga e percentual de workloads com identidade dedicada. Publique esses números no dashboard da plataforma, porque essa visibilidade é o que mantém a extinção de chaves estáticas como projeto contínuo e não como campanha única.