Proteger o acesso ao Kubernetes com RBAC

KubernetesBeginner
Pratique Agora

Introdução

A autenticação do Kubernetes identifica quem está fazendo uma solicitação; a autorização determina o que essa identidade pode fazer. O RBAC expressa permissões como verbos aplicados a recursos da API e as associa a usuários, grupos ou ServiceAccounts.

Você criará um leitor com escopo limitado ao namespace, associará sua identidade às permissões e comprovará, por meio de impersonação, tanto os limites permitidos quanto os negados.

O RBAC fica mais fácil de entender quando é analisado a partir de três perguntas: Quem? (ServiceAccount), O que essa identidade pode fazer? (Role) e Quem recebe essas permissões? (RoleBinding). Criar apenas um ou dois desses objetos não completa o fluxo de autorização.

Criar uma identidade ServiceAccount

Nesta etapa, crie uma ServiceAccount com escopo de namespace para um componente da aplicação.

Uma ServiceAccount é uma identidade da API do Kubernetes destinada a cargas de trabalho e automações. Ela não é um usuário Linux dentro do contêiner. Atribuir a este exemplo uma identidade dedicada evita que ele herde a ServiceAccount default do namespace.

cd /home/labex/project/rbac-access
kubectl create serviceaccount inventory-reader -n practice-rbac
kubectl get serviceaccount inventory-reader -n practice-rbac -o yaml

Sua identidade completa é system:serviceaccount:practice-rbac:inventory-reader. Criar uma identidade, por si só, não concede permissões à aplicação.

Na saída YAML, os metadados confirmam o namespace e o nome. Não espere que um Secret de token de longa duração apareça automaticamente; as versões modernas do Kubernetes projetam tokens de curta duração nos Pods quando necessário.

O objeto retornado contém o nome e o namespace dedicados, mas nenhum Secret de token gerado automaticamente:

kind: ServiceAccount
metadata:
  name: inventory-reader
  namespace: practice-rbac

Definir permissões limitadas ao namespace

Nesta etapa, crie uma Role que permita apenas a leitura de Pods e ConfigMaps em practice-rbac.

Cada regra combina grupos de API, recursos e verbos. Para recursos principais, como Pods e ConfigMaps, apiGroups: [""] usa uma cadeia de caracteres vazia. Os verbos get, list e watch representam leituras individuais, leituras de coleções e acompanhamento de alterações.

cd /home/labex/project/rbac-access
cat <<'EOF' > inventory-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: {name: inventory-reader, namespace: practice-rbac}
rules:
  - apiGroups: [""]
    resources: [pods, configmaps]
    verbs: [get, list, watch]
EOF

Aplique e descreva a Role. O comando describe apresenta as regras de política em uma tabela, que é mais fácil de revisar do que o YAML bruto:

kubectl apply -f inventory-role.yaml
kubectl describe role inventory-reader -n practice-rbac

O grupo de API vazio seleciona os recursos principais. Uma Role nunca concede acesso fora do próprio namespace.

Observe também o que não está presente: não há create, update, patch nem delete. O privilégio mínimo é definido tanto pelas permissões omitidas quanto pelas concedidas.

Resources   Non-Resource URLs  Resource Names  Verbs
---------   -----------------  --------------  -----
configmaps  []                 []              [get list watch]
pods        []                 []              [get list watch]

A tabela expande a regra combinada do YAML em uma linha por recurso. As duas linhas têm os mesmos três verbos somente de leitura.

Associar a Role à identidade

Nesta etapa, associe a Role à ServiceAccount usando uma RoleBinding.

O comando imperativo é compacto porque os dois objetos já existem. --role indica a origem das permissões, enquanto --serviceaccount usa o formato namespace:name para identificar o sujeito.

cd /home/labex/project/rbac-access
kubectl create rolebinding inventory-reader -n practice-rbac --role=inventory-reader --serviceaccount=practice-rbac:inventory-reader
kubectl get rolebinding inventory-reader -n practice-rbac -o yaml

roleRef identifica as permissões; subjects identifica as identidades que as recebem. Neste caso, ambos permanecem limitados ao namespace.

Uma Role e uma ServiceAccount com o mesmo nome continuam não relacionadas até que essa associação exista. Os nomes servem para facilitar a identificação humana; a RoleBinding é a conexão efetiva de autorização.

No YAML, acompanhe a conexão de roleRef.name: inventory-reader até o sujeito cujo tipo é ServiceAccount, cujo nome é inventory-reader e cujo namespace é practice-rbac.

Testar ações permitidas e negadas

Nesta etapa, use kubectl auth can-i com --as para fazer impersonação da ServiceAccount.

Os testes de autorização precisam incluir casos positivos e negativos. Um resultado yes comprova que a operação necessária é possível, enquanto um resultado no confirma que o acesso destrutivo e o acesso entre namespaces não foram concedidos por engano.

cd /home/labex/project/rbac-access
IDENTITY=system:serviceaccount:practice-rbac:inventory-reader
kubectl auth can-i list pods -n practice-rbac --as="$IDENTITY"
kubectl auth can-i get configmaps -n practice-rbac --as="$IDENTITY"
kubectl auth can-i delete pods -n practice-rbac --as="$IDENTITY" || true
kubectl auth can-i list pods -n default --as="$IDENTITY" || true

As duas primeiras respostas devem ser yes; a exclusão e a listagem entre namespaces devem retornar no. A impersonação permite testar a autorização sem expor nem criar um token.

kubectl auth can-i retorna um status diferente de zero no shell junto com a resposta no. Os dois sufixos || true permitem que o teste de negação intencional continue; eles não alteram a decisão de autorização.

yes
yes
no
no

Interprete esses resultados como duas capacidades necessárias seguidas por dois limites protegidos. Um teste contendo apenas respostas yes não demonstraria o princípio do privilégio mínimo.

O usuário atual do laboratório tem permissão para fazer impersonação dessa ServiceAccount durante os testes. --as altera a identidade avaliada pelo servidor da API para aquele comando; ele não muda o usuário do seu shell nem troca permanentemente as credenciais do kubectl.

Resumo

Você criou uma ServiceAccount, definiu permissões de leitura limitadas ao namespace por meio de uma Role, atribuiu essas permissões com uma RoleBinding e comprovou, usando impersonação, tanto as ações permitidas quanto as negadas.