Pular para o conteúdo
10 min de leitura

RBAC no Kubernetes: Quem Pode o Quê, e Por Que Ninguém Devia Ser cluster-admin

Por Equipe Nebular ·

Role, ClusterRole, bindings e ServiceAccounts explicados de verdade. Aprenda a aplicar menor privilégio, evitar escalonamento e auditar quem acessa o quê no cluster.

Neste artigo

Pergunte a um time que roda Kubernetes há algum tempo quem tem acesso de cluster-admin e observe o silêncio desconfortável. Na prática, a resposta costuma ser "todo mundo", porque em algum momento alguém precisou depurar um problema, ganhou acesso total "só por enquanto" e esse "enquanto" virou permanente. O cluster que começou com controle vira, sem ninguém decidir isso, um lugar onde qualquer pessoa e qualquer aplicação pode fazer qualquer coisa.

Esse é exatamente o cenário que o RBAC — Role-Based Access Control — existe para evitar. Ele é o subsistema do Kubernetes que decide, para cada requisição que chega à API, se o solicitante tem permissão para fazer aquela operação naquele recurso. E, ao contrário da rede ou do armazenamento, o RBAC não depende de plugin externo: vem ligado e é o guardião de tudo que passa pelo kube-apiserver.

O problema é que o modelo tem quatro tipos de objeto que se combinam de formas sutis, e é fácil configurar algo que parece restrito mas na verdade é uma porta escancarada. Este guia destrincha as peças, mostra onde mora o perigo do escalonamento de privilégio e ensina a auditar o que já existe.

As quatro peças do quebra-cabeça#

O RBAC do Kubernetes se apoia em quatro tipos de recurso, que se dividem em dois pares. De um lado, os que definem permissões; de outro, os que concedem essas permissões a alguém.

Definindo permissões:

  • Role — um conjunto de permissões válido dentro de um namespace. "Pode

ler pods e listar configmaps no namespace app."

  • ClusterRole — o mesmo, mas com alcance de cluster inteiro. Serve tanto

para recursos que não pertencem a namespace nenhum (nós, PersistentVolumes, namespaces em si) quanto como um molde reutilizável em vários namespaces.

Concedendo permissões:

  • RoleBinding — amarra uma Role (ou uma ClusterRole) a um ou mais sujeitos,

válido dentro de um namespace.

  • ClusterRoleBinding — amarra uma ClusterRole a sujeitos com alcance de

cluster inteiro.

A regra de combinação que confunde: um RoleBinding pode referenciar uma ClusterRole. Quando faz isso, ele "empresta" as permissões daquela ClusterRole, mas limitadas ao namespace do binding. É o padrão que permite definir uma ClusterRole genérica como "leitor" uma única vez e concedê-la, namespace a namespace, sem duplicar a definição. Já um ClusterRoleBinding da mesma ClusterRole daria aquele acesso de leitura em todos os namespaces de uma vez — uma diferença enorme, causada por trocar uma palavra no kind.

O que uma Role realmente diz#

Uma Role é uma lista de regras, e cada regra combina três dimensões: apiGroups (a qual grupo de API o recurso pertence), resources (quais recursos) e verbs (quais operações). Um exemplo concreto:

```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: app name: leitor-de-pods rules:

  • apiGroups: [""] # "" = grupo core (pods, services, configmaps...)

resources: ["pods", "pods/log"] verbs: ["get", "list", "watch"] ```

Os verbs são o vocabulário das ações: get, list e watch são leitura; create, update, patch e delete são escrita; deletecollection apaga em lote. Repare em pods/log: é um subrecurso. Dar acesso a pods não dá acesso automático ao log deles nem ao pods/exec (que abre um shell dentro do container). Esses precisam ser concedidos explicitamente — e pods/exec é um dos verbos mais perigosos que existem, porque quem o tem entra em qualquer container selecionado.

Há ainda o campo opcional resourceNames, que restringe a regra a objetos nomeados específicos: "pode dar get no secret chamado db-prod, e só nele". É um nível a mais de granularidade, útil quando um workload precisa de um único recurso e nada além dele.

ServiceAccounts: o sujeito que mais importa#

Os bindings concedem permissões a sujeitos, e existem três tipos: User, Group e ServiceAccount. Aqui está o detalhe que muita gente demora a internalizar: User e Group não são objetos do Kubernetes. Não existe um recurso "usuário" que você cria com kubectl. Eles são apenas strings que vêm de uma camada de autenticação externa — um certificado, um provedor OIDC, um token de alguma integração. O cluster confia que essa camada já autenticou e apenas lê o nome.

O ServiceAccount, por outro lado, é um objeto de verdade, e é o sujeito que domina o dia a dia. Todo pod roda associado a uma ServiceAccount, e é com a identidade dela que o código dentro do pod fala com a API do Kubernetes. Se a sua aplicação precisa listar pods, ler um configmap ou criar um job, quem carrega essa permissão é a ServiceAccount montada no pod.

```yaml apiVersion: v1 kind: ServiceAccount metadata: name: worker namespace: app automountServiceAccountToken: false --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: worker-le-configmaps namespace: app subjects:

  • kind: ServiceAccount

name: worker namespace: app roleRef: kind: Role name: leitor-de-pods apiGroup: rbac.authorization.k8s.io ```

Duas boas práticas aparecem nesse manifesto. A primeira: crie uma ServiceAccount dedicada por workload em vez de usar a default do namespace. A ServiceAccount default tende a acumular permissões ao longo do tempo, e tudo que a usa herda o excesso. A segunda: automountServiceAccountToken: false. Por padrão, o Kubernetes monta um token da ServiceAccount dentro de todo pod, mesmo que o código nunca fale com a API. Esse token é exatamente o que um atacante procura ao comprometer um container — é a chave para se autenticar no cluster. Se o workload não precisa falar com a API, desligue o automount e feche essa porta.

Escalonamento de privilégio: quando o RBAC vira a arma#

O maior risco do RBAC não é dar acesso demais a um recurso de dados; é dar acesso a permissões que permitem conceder mais permissões. Alguns verbs são especiais justamente por isso, e precisam ser tratados como ouro:

  • escalate sobre roles: sem ele, você não pode criar uma Role com mais

permissões do que você mesmo tem (o Kubernetes bloqueia por padrão para impedir auto-promoção). Com ele, essa trava some.

  • bind: permite criar bindings para roles que você não possui, concedendo a

outros — ou a si mesmo — permissões que você não tinha.

  • impersonate: permite agir como se fosse outro usuário ou grupo,

inclusive um administrador. Quem tem impersonate sobre grupos consegue, na prática, virar qualquer um.

Há caminhos menos óbvios também. Quem pode criar pods em um namespace pode montar nesse pod uma ServiceAccount privilegiada e, a partir do container, usar o token dela — herdando permissões que não tinha diretamente. Quem controla um ValidatingWebhook ou pode editar nós tem vetores próprios. A lição é que "permissão de escrita sobre objetos de RBAC" e "permissão de criar workloads que usam ServiceAccounts poderosas" são, na prática, permissões de administrador disfarçadas. Trate-as como tal.

Isso explica por que cluster-admin distribuído a esmo é tão grave. Não é só que a pessoa pode apagar o cluster; é que qualquer credencial dela, se vazar, entrega tudo. Menor privilégio não é preciosismo — é a diferença entre um incidente contido e um cluster inteiro comprometido.

Auditando o que já existe#

Você não precisa (e não deve) raciocinar sobre RBAC só na cabeça. O próprio kubectl responde a pergunta central — "esse sujeito pode fazer isso?" — com o subcomando auth can-i:

```bash # Eu posso deletar deployments no namespace app? kubectl auth can-i delete deployments -n app

# E a ServiceAccount worker, pode ler secrets? kubectl auth can-i get secrets -n app \ --as=system:serviceaccount:app:worker

# Listar tudo que eu posso fazer em um namespace kubectl auth can-i --list -n app ```

O --as é a chave da auditoria: ele usa impersonation (que você precisa ter permissão para usar) para simular a pergunta na pele de outro sujeito. Com ele, você valida hipóteses de segurança sem precisar de credenciais reais de cada ServiceAccount. Para investigações mais amplas — "quem consegue ler secrets em todo o cluster?" —, ferramentas de comunidade como rbac-lookup e kubectl-who-can invertem a busca, partindo do recurso para os sujeitos, o que é muito mais difícil de fazer só com os objetos crus.

Vale lembrar o que o RBAC não faz. Ele controla quem pode chamar a API e com quais verbos, mas não valida o conteúdo do que é criado. Ele não impede que um pod autorizado rode como root, monte o filesystem do host ou peça privilégios perigosos — isso é trabalho de admission control (políticas de admissão, Pod Security). RBAC e admission são camadas complementares; confundir uma com a outra deixa buracos.

Agregação: montando ClusterRoles como peças de Lego#

Um recurso do RBAC que costuma passar despercebido é a agregação de ClusterRoles. Em vez de escrever uma ClusterRole gigante à mão, você pode declarar que ela é a soma automática de todas as ClusterRoles que carregam um determinado label. O Kubernetes mantém o conjunto de regras atualizado sozinho conforme peças entram e saem.

```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: monitoramento aggregationRule: clusterRoleSelectors:

  • matchLabels:

rbac.exemplo.com/aggregate-to-monitoramento: "true" rules: [] # preenchido automaticamente pela agregação ```

A partir daí, qualquer ClusterRole marcada com aquele label é absorvida. É assim que as roles embutidas do próprio Kubernetes (view, edit, admin) se estendem quando você instala uma CRD que traz suas próprias permissões: a nova peça se encaixa sem que ninguém edite a role central. O padrão mantém a definição modular — cada componente declara o que precisa, e o todo se compõe. É o oposto da ClusterRole monolítica que ninguém tem coragem de mexer.

Vale conhecer também as roles padrão que vêm de fábrica. view dá leitura na maioria dos recursos de um namespace (sem ver secrets); edit permite modificar a maior parte dos objetos, mas não mexer em RBAC; admin administra um namespace inteiro, inclusive suas roles e bindings, mas sem alcançar o cluster. Muitas vezes, conceder uma dessas via RoleBinding namespaced resolve a necessidade sem inventar uma role nova — e sem cair na tentação do cluster-admin.

Um RBAC sadio na prática#

Colocar ordem no controle de acesso de um cluster que já roda não é um projeto de um dia, mas segue princípios claros:

  • Menor privilégio como default. Comece de nada e adicione só o que cada

identidade comprovadamente precisa. É mais trabalhoso que dar cluster-admin, mas é a única postura que envelhece bem.

  • Uma ServiceAccount por workload, nunca a default, e com o token desmontado

quando o workload não fala com a API.

  • Prefira Roles namespaced a ClusterRoles. Alcance de cluster só quando o

recurso realmente é de cluster ou quando você conscientemente quer o acesso em todo lugar.

  • **Trate escalate, bind, impersonate e a criação de pods como equivalentes

a admin.** Se conceder, saiba exatamente por quê.

  • Wildcards são bandeira vermelha. verbs: [""] ou resources: [""] quase

sempre são preguiça, não necessidade. Cada um deles esconde permissões que você não pretendia dar.

  • Versione tudo no Git e revise. Objetos de RBAC criados à mão no cluster são

acessos que ninguém consegue explicar seis meses depois. Como qualquer outra configuração, eles pertencem ao repositório e passam por revisão de par.

O objetivo não é transformar o cluster em uma burocracia onde ninguém consegue trabalhar. É garantir que, quando algo der errado — uma credencial vazada, um pod comprometido, um script malicioso —, o estrago fique confinado ao mínimo que aquela identidade específica podia tocar. Um RBAC bem desenhado é invisível no dia bom e decisivo no dia ruim. Vale o trabalho de construí-lo antes que o dia ruim chegue.

Leituras relacionadas

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly