RBAC do Kubernetes por projeto, com members e owners
TLDR: Substituir a ServiceAccount compartilhada
sa-developerpor ServiceAccounts por projeto, para que cada dev só acesse os namespaces dos projetos a que pertence — com os owners ganhandoexecem produção.
Contexto
Todos os desenvolvedores compartilhavam uma única ServiceAccount sa-developer, com acesso a todos os namespaces de staging e read-only em produção em todos os projetos. Não havia isolamento: um dev do trgclub também lia os pods do onion. A única distinção era o contexto developer-owner-<project>, que usava o mesmo token e só mudava o namespace default.
Problema secundário: o próprio repo infrastructure não tinha proteção de merge — qualquer pessoa podia fazer merge de PR que muda RBAC, secrets e configuração de cluster.
Objetivos
- Campo
memberspor projeto noconfig/access.yml(quem acessa os namespaces do cluster). - ServiceAccounts por projeto:
sa-<project>(member) esa-<project>-owner. - Member: total em staging + read-only em produção, sem
exec. - Owner: total em staging + total em produção, com
exec. make k8s.initcria contexto só para os projetos do usuário..github/CODEOWNERSgerado a partir da listainfra, para que só membros de infra aprovem PR neste repo.
Fora de escopo
- Remover a
sa-developer. Ela fica intacta nesta mudança e sai num apply de follow-up, depois de todas as máquinas terem rodadomake k8s.init.
Mudanças
config/access.yml
yaml
projects:
onion:
apps: [onion-backend, onion-mobile]
members: [porpino, filipe]
owners: [porpino]
src/shared/kubernetes/terraform/rbac.tf
- Mapa
locals.projectsespelhando oaccess.yml— hardcoded de propósito: muda raramente e evita parsear YAML em tempo de plan. locals.project_staging_pairselocals.project_production_pairs, achatados para uso emfor_each.- ClusterRole
dev-production-owner, compods/execpermitido. - Por projeto, via
for_eachsobrelocal.projects:kubernetes_service_account.project_deveproject_owner, oskubernetes_secretde token de cada uma, ClusterRoleBindings denamespace-readeremetrics-readerpara ambas, e RoleBindings de staging (admin para as duas), produção read-only (member) e produção total comexec(owner).
commons — scripts de contexto
context/setup.sh: helper_save_single_saextraído;_save_sa_tokensitera os projetos do usuário lidos doaccess.ymlem vez de lista fixa;_cleanup_owner_contextsvirou_cleanup_project_contexts(limpa tododeveloper-*); contextoinfrasó se o usuário estiver na listainfra; contexto default é o primeirodeveloper-<project>não-owner.context/summary.shecontext/change.sh: loop dinâmico e cor por padrão de nome —developer-*-owneramarelo,developer-*verde,infravermelho.
Proteção do repo
.project/shell/tasks/ci/github/sync-codeowners.sh(novo) — lê os aliases deinfra, resolveusers.<alias>.githube escreve* @<username>em.github/CODEOWNERS..github/workflows/infra.yml— chama o script depois dosync-environment-reviewers.sh.- A regra de branch protection em
mainexigindo review de CODEOWNER é configurada uma vez, à mão ou viagh api.
Sequência de migração
- PR 1 (esta mudança):
membersnoaccess.yml+ SAs novas no terraform + scripts atualizados. make shared.kubernetes.apply— aditivo, sem interrupção.- Todos os devs rodam
make k8s.inite recebem os contextos por projeto. - PR 2 (follow-up): remover a
sa-developere seus bindings.
Como verificar
terraform planmostra só adições, nenhum destroy.make k8s.initproduzdeveloper-<project>conforme a lista de members edeveloper-<project>-ownerpara os projetos que o usuário possui.kubectl --context=developer-onion get pods -n onion-backend--staging→ funciona.kubectl --context=developer-onion get pods -n trgclub-api--staging→Forbidden.kubectl --context=developer-onion-owner exec -it <pod> -n onion-backend--production -- sh→ funciona.kubectl --context=developer-onion exec ...no mesmo namespace →Forbidden..github/CODEOWNERScontém apenas usuários de infra.- Abrir PR neste repo passa a exigir aprovação de um usuário de infra.
Documentação
- Guia de acesso — campo
members, tabela de contexto no modelo por projeto, e o fato de a listainfracontrolar o CODEOWNERS deste repo.
Nota histórica: o modelo de token de ServiceAccount de longa duração descrito aqui foi substituído por IAM roles + EKS Access Entries — ver acesso de desenvolvedor ao EKS via IAM, que também eliminou a duplicação entre
locals.projectse oaccess.yml.