wlls / devsecops / rbac-no-argocd-controlando-acesso-a-projetos
devsecops

RBAC no ArgoCD: controlando acesso a projetos

wander·27 de out.·7 min de leitura

Em ambientes com múltiplas equipes usando o mesmo cluster ArgoCD, a pergunta não é se alguém vai acessar um Application que não deveria — é quando. RBAC mal configurado no ArgoCD é um dos caminhos mais diretos para um incidente de segurança em GitOps: basta uma role genérica demais para que um time de desenvolvimento consiga sincronizar ou deletar Applications de produção que não são dele.

Este post explica o modelo de controle de acesso do ArgoCD — policy.csv, roles, grupos e o papel dos AppProjects como fronteira de isolamento — e como combinar essas peças para restringir o que cada equipe pode ver e fazer.

Premissas e limitações

Não há fontes de pesquisa específicas fornecidas para este post — isso é tratado aqui como limitação explícita, não preenchido com suposição. O conteúdo abaixo se baseia no modelo de RBAC documentado oficialmente pelo projeto ArgoCD (https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/) e no comportamento de AppProjects (https://argo-cd.readthedocs.io/en/stable/user-guide/projects/).

Outras premissas:

  • Os exemplos assumem ArgoCD na linha 2.x. A sintaxe de RBAC é estável há várias versões, mas vale confirmar na changelog da sua versão antes de aplicar em produção.
  • Os comandos e manifestos de YAML/CSV abaixo não foram executados neste ambiente. Trate-os como ponto de partida e valide em um cluster de teste antes de levar a produção.
  • Não há relato de incidente real, cliente ou ambiente específico associado a este conteúdo. Os cenários descritos são ilustrativos.

Como o RBAC do ArgoCD funciona

O ArgoCD não usa o RBAC nativo do Kubernetes para controlar quem faz o quê dentro da própria interface/API. Ele tem um sistema próprio, configurado no ConfigMap argocd-rbac-cm, baseado em três conceitos:

  • Subjects: usuários locais ou grupos vindos do seu provedor SSO/OIDC (claim groups do token).
  • Roles: conjuntos nomeados de permissões, definidos em formato CSV dentro do próprio ConfigMap.
  • Policies: linhas no formato p, subject, resource, action, object, effect que concedem ou negam uma ação sobre um recurso.

O ArgoCD já vem com duas roles embutidas: role:admin (acesso total) e role:readonly (leitura em tudo). Para qualquer cenário com mais de uma equipe, essas duas roles não bastam — você precisa de roles customizadas.

A estrutura do policy.csv

O arquivo fica dentro do ConfigMap argocd-rbac-cm, no campo policy.csv. Uma linha de política tem este formato:

p, <subject>, <resource>, <action>, <object>, <effect>

Onde:

  • resource pode ser applications, clusters, repositories, certificates, projects, accounts, logs, exec, entre outros.
  • action é algo como get, create, update, delete, sync, override, action.
  • object identifica o recurso específico, geralmente no formato <projeto>/<application> (aceita wildcard *).
  • effect é allow ou deny.

Exemplo de ConfigMap com duas roles — uma para o time de plataforma (acesso amplo ao projeto infra) e outra para um time de produto (leitura e sync apenas no próprio projeto):

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.default: role:readonly
  policy.csv: |
    p, role:platform-team, applications, *, infra/*, allow
    p, role:platform-team, clusters, get, *, allow
    p, role:platform-team, repositories, *, *, allow

    p, role:product-team-checkout, applications, get, checkout/*, allow
    p, role:product-team-checkout, applications, sync, checkout/*, allow
    p, role:product-team-checkout, applications, action/*, checkout/*, allow

    g, platform-engineers, role:platform-team
    g, checkout-devs, role:product-team-checkout
  scopes: '[groups]'

Pontos importantes nesse exemplo:

  • policy.default: role:readonly define o comportamento padrão para qualquer usuário autenticado que não bata em nenhuma regra explícita — evita que alguém sem role definida acabe sem nenhum acesso ou, pior, com acesso total por omissão.
  • As linhas g, <grupo>, <role> fazem o mapeamento entre o grupo retornado pelo seu provedor de identidade (claim groups do OIDC) e a role interna do ArgoCD. Isso é o que permite gerenciar acesso via Okta, Azure AD, Keycloak etc. sem tocar no ConfigMap a cada troca de time.
  • scopes: '[groups]' instrui o ArgoCD a usar o claim groups do token OIDC para resolver as roles — sem isso, o mapeamento de grupo não funciona mesmo que as linhas g, estejam corretas.

AppProjects como fronteira de isolamento

RBAC por si só controla quem pode fazer o quê, mas não impede, por exemplo, que um Application do time "checkout" seja criado apontando para um namespace ou cluster de outro time. Essa segunda camada de controle é o AppProject.

Um AppProject define:

  • Quais repositórios Git podem ser usados como fonte para Applications desse projeto (sourceRepos).
  • Quais clusters e namespaces de destino são permitidos (destinations).
  • Quais tipos de recurso Kubernetes podem ser criados ou sincronizados (clusterResourceWhitelist, namespaceResourceBlacklist).
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: checkout
  namespace: argocd
spec:
  description: Projeto do time de checkout
  sourceRepos:
    - "https://github.com/empresa/checkout-*"
  destinations:
    - namespace: "checkout-*"
      server: "https://kubernetes.default.svc"
  clusterResourceWhitelist: []
  namespaceResourceBlacklist:
    - group: ""
      kind: ResourceQuota
    - group: ""
      kind: LimitRange

A combinação correta é: AppProject define onde e com o quê o time pode trabalhar; RBAC define quem dentro da organização tem permissão de operar dentro desse projeto. Usar só RBAC sem AppProject segmentado é como dar a chave certa para a porta errada — a pessoa autorizada acaba conseguindo abrir mais do que devia, porque o escopo (object na policy) aponta para * ou para um projeto amplo demais.

Permissões em nível de Application: ações e recursos

Além de get, sync e delete, o ArgoCD expõe ações mais granulares sobre um Application via action/<nome-da-acao>, que correspondem aos botões de ação customizada na UI (como restart para um Rollout do Argo Rollouts). Também existe o resource applications com ações específicas:

  • applications, action, <projeto>/<app> — executar ações customizadas de recursos (ex.: resync, restart).
  • applications, override, <projeto>/<app> — sobrescrever parâmetros de sync na UI/CLI.
  • applications, exec, <projeto>/<app> — abrir terminal exec para um Pod via argocd app exec (quando habilitado) — recurso sensível, trate como acesso a shell em produção.

Vale negar explicitamente exec e override para a maioria dos times, concedendo apenas para operadores de plataforma:

p, role:product-team-checkout, exec, create, checkout/*, deny

Políticas de deny têm precedência sobre allow na avaliação do ArgoCD, então são úteis para fechar brechas sem reescrever toda a role.

Validação

Antes de confiar na configuração, valide com a própria CLI do ArgoCD, que simula a decisão de RBAC para um usuário e uma ação:

argocd account can-i sync applications checkout/checkout-api --as checkout-devs
argocd account can-i delete applications infra/vault --as checkout-devs

O primeiro comando deve retornar yes; o segundo, no, se as policies estiverem corretas. Esse comando (account can-i) é a forma documentada de testar RBAC sem precisar logar como o usuário real — essencial para revisar mudanças no policy.csv antes de aplicar em produção.

Outra verificação útil é revisar os logs do argocd-server ao reproduzir a ação negada: mensagens de permission denied mostram exatamente qual linha de policy (ou ausência dela) bloqueou a chamada, o que ajuda a diferenciar "RBAC bloqueando certo" de "AppProject bloqueando antes do RBAC ser avaliado".

Limitações e cuidados

  • RBAC do ArgoCD não substitui RBAC do Kubernetes. Um usuário pode ter sync liberado no ArgoCD e ainda assim o próprio ServiceAccount do ArgoCD precisa ter permissão no cluster de destino para aplicar os recursos.
  • Mudanças no policy.csv via ConfigMap não passam por audit trail de Git a menos que você gerencie esse ConfigMap via GitOps (o próprio ArgoCD aplicando a si mesmo) — recomendável para rastrear quem alterou o quê.
  • Grupos OIDC exigem que o claim groups seja retornado pelo provedor de identidade; nem todo provedor inclui isso por padrão nas configurações básicas — confirme esse ponto na configuração do seu SSO antes de desenhar as roles em torno de grupos.

Próximo passo

Se você já tem múltiplos AppProjects mas RBAC genérico (role:admin para todo mundo autenticado), comece revisando o policy.default do seu argocd-rbac-cm: trocar para role:readonly como padrão e então liberar ações específicas por grupo é a mudança isolada que reduz mais risco com menor esforço, antes de qualquer refino fino de roles por time.

#policy-csv#appproject#sso-oidc#deny-policy#argocd-rbac-cm