Times no NKP com RBAC nativo e quotas: cada dev no seu namespace
Testado emNKP 2.19Kubernetes 1.36.2Microsoft Entra ID FreeLab em Em outra versão, confira a matriz de compatibilidade e as release notes antes de aplicar.

Resumo: no artigo anterior, o Entra ID passou a dizer quem entra no NKP. Este mostra o que cada time pode fazer e quanto pode consumir, só com objetos nativos do Kubernetes: um namespace por time, um RoleBinding que liga o grupo do Entra ao papel
edite uma ResourceQuota com LimitRange. A Carla, do grupo de devs, foi barrada antes do binding, passou a criar no namespace dela e em nenhum outro lugar, e a quota segurou um deploy de 8 réplicas em 4. Antes de liberar, o admin testa o acesso se passando pelo grupo, em segundos. Para quem não deve usar o painel, o próprio cluster emite um certificado de 24 horas preso a um namespace. A receita não depende de workspaces nem de projetos, e por isso serve também a quem tem NKP Pro ou Starter.
O resultado em uma tabela
| Pergunta ao cluster | Antes do RoleBinding | Depois do RoleBinding |
|---|---|---|
| A Carla pode criar deployments no namespace do time? | no | yes |
E no default? | no | no |
| Pode criar RoleBindings (se dar mais poder)? | no | no |
| Pode listar os nós? | Forbidden | Forbidden |
| Deploy com 8 réplicas | — | 4 de 8 no ar: o resto barrado pela quota |
Pod sem resources declarados | — | Recebe 50m/64Mi de request e 200m/128Mi de limite do LimitRange |
| Acesso sem o painel (Davi) | Resultado |
|---|---|
| Certificado emitido pelo cluster | CN=davi.local, válido por 24 h |
| No namespace dele | yes: cria e publica |
default, Secrets do kube-system, nós, RoleBindings | no em todos |
Do login ao acesso por time
O login pelo Entra ID resolve a primeira pergunta: quem é você? O token que chega ao cluster traz o usuário e os grupos dele. A segunda pergunta é do Kubernetes: o que esse grupo pode fazer, e onde?
No artigo do Entra ID, a Carla recebeu acesso por um projeto do NKP, que cria o namespace e os bindings pelo painel. Workspaces e projetos são do NKP Ultimate, a licença do lab. Aqui o mesmo resultado sai com RBAC nativo do Kubernetes: três ou quatro objetos em YAML, que funcionam em qualquer edição, inclusive nos clusters onde o time prefere manter os acessos no Git.
| Workspaces e projetos (Ultimate) | RBAC nativo (todas as edições) | |
|---|---|---|
| Onde se configura | Painel do NKP, uma vez | YAML com kubectl apply, em cada cluster |
| Cluster novo herda os acessos | Sim, o NKP replica | Não: aplica-se o mesmo YAML (ou GitOps) |
| Namespace, binding e quota | O projeto cria | Um arquivo por time |
| Como manter em ordem | Painel | YAMLs no Git, com revisão |
Como o RBAC funciona: quem, onde e o quê
Toda permissão no Kubernetes é uma frase com três partes:
O RBAC só soma permissões: não existe regra de negar. Se nenhum binding deu, a resposta é Forbidden. Por isso começar sem acesso e liberar o mínimo é o caminho natural.
O Kubernetes já traz quatro papéis prontos, que cobrem a maior parte dos times:
| Papel | Pode | Não pode | Para quem |
|---|---|---|---|
view | Ler pods, deployments, services e logs | Ler Secrets; alterar qualquer coisa | Suporte, auditoria, devs em produção |
edit | Criar, alterar e apagar quase tudo no namespace | Mexer em permissões (Roles e RoleBindings) | Devs em homologação |
admin | Tudo do edit + RoleBindings no namespace | Alterar a quota; recursos do cluster | Líder técnico do time |
cluster-admin | Tudo, em todos os namespaces | — | Equipe de plataforma, pouca gente |
O papel edit lê Secrets
O papel edit permite ler os Secrets do namespace. Para um time que só deve ver o que roda, view é o ponto de partida; para quem publica, edit no namespace de homologação e view no de produção.
A combinação mais usada para times é uma ClusterRole reutilizável (edit) ligada por um RoleBinding em cada namespace. Um ClusterRoleBinding vale para o cluster inteiro, inclusive para o que for criado depois: fica para a equipe de plataforma.
O que preparar antes
| Pré-requisito | Por quê | Como conferir |
|---|---|---|
| Login com grupos funcionando (artigo do Entra ID) | O binding aponta para o grupo que chega no token | A Carla entra no painel e gera o kubeconfig (Generate Token) |
| O nome do grupo como chega no token | No NKP com Entra, é oidc: + Object ID do grupo, não o nome amigável | kubectl auth whoami com o kubeconfig da Carla |
| Kubeconfig de admin do cluster | Quem cria o namespace, a quota e o binding | kubectl auth can-i '*' '*' = yes |
| Um kubeconfig por pessoa no terminal | O Generate Token grava no kubeconfig ativo | export KUBECONFIG=~/.kube/carla.conf antes de colar os comandos |
Boa prática: guarde o grupo numa variável
O Object ID do grupo não precisa aparecer na tela nem no Git em texto puro. No lab, o YAML tem um marcador (__GRUPO_DEVS__) trocado na hora do apply pelo valor guardado num arquivo da bastion. Para conferir que é o mesmo grupo do token: kubectl auth whoami -o jsonpath='{.status.userInfo.groups}' | grep -qF "$GRUPO_DEVS" && echo OK.
1. O espaço do time: namespace, quota e padrão de recursos
Um arquivo por time. A quota é o teto do namespace; o LimitRange dá valores padrão a quem não declarar resources, o que evita que um pod seja recusado pela quota por falta de requests.
apiVersion: v1kind: Namespacemetadata: name: time-dev-demo---apiVersion: v1kind: ResourceQuotametadata: name: quota-time-dev namespace: time-dev-demospec: hard: pods: "4" requests.cpu: "1" requests.memory: 1Gi limits.cpu: "2" limits.memory: 2Gi services.loadbalancers: "0" # o time publica por Ingress, sem consumir IP do load balancer---apiVersion: v1kind: LimitRangemetadata: name: padrao-time-dev namespace: time-dev-demospec: limits: - type: Container defaultRequest: {cpu: 50m, memory: 64Mi} # para quem não declarar requests default: {cpu: 200m, memory: 128Mi} # para quem não declarar limits---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: devs-edit namespace: time-dev-demoroleRef: {apiGroup: rbac.authorization.k8s.io, kind: ClusterRole, name: edit}subjects: - {apiGroup: rbac.authorization.k8s.io, kind: Group, name: "__GRUPO_DEVS__"}Para mostrar o antes e o depois, o admin aplica primeiro tudo menos o RoleBinding:
sed "s|__GRUPO_DEVS__|$GRUPO_DEVS|" time-dev.yaml | yq 'select(.kind != "RoleBinding")' | kubectl apply -f -kubectl describe resourcequota -n time-dev-demonamespace/time-dev-demo createdresourcequota/quota-time-dev createdlimitrange/padrao-time-dev createdResource Used Hard-------- ---- ----limits.cpu 0 2limits.memory 0 2Gipods 0 4requests.cpu 0 1requests.memory 0 1Giservices.loadbalancers 0 02. Autenticada, mas sem acesso
Com o kubeconfig dela, a Carla pergunta ao cluster quem ela é e o que pode fazer:
$ kubectl auth whoamiATTRIBUTE VALUEUsername [email protected]Groups [oidc:<id> system:authenticated]
$ kubectl auth can-i create deployments -n time-dev-demono
$ kubectl get pods -n time-dev-demoError from server (Forbidden): pods is forbidden: User "[email protected]" cannot list resource "pods" in API group "" in the namespace "time-dev-demo"O Entra autenticou a Carla, com MFA. O cluster sabe quem ela é e a que grupo pertence, mas nenhum binding deu permissão a esse grupo neste namespace.
3. O acesso para o grupo, testado antes de liberar
O admin aplica o arquivo inteiro, agora com o RoleBinding, e se passa pelo grupo para perguntar ao cluster antes de avisar o time:
sed "s|__GRUPO_DEVS__|$GRUPO_DEVS|" time-dev.yaml | kubectl apply -f -kubectl auth can-i create deployments -n time-dev-demo --as=teste --as-group="$GRUPO_DEVS"kubectl auth can-i create deployments -n default --as=teste --as-group="$GRUPO_DEVS"namespace/time-dev-demo unchangedresourcequota/quota-time-dev unchangedlimitrange/padrao-time-dev unchangedrolebinding.rbac.authorization.k8s.io/devs-edit createdyesnoBoa prática: teste por impersonação antes de entregar
A impersonação (--as e --as-group) responde em segundos se o grupo vai conseguir o que precisa, e só ali. É o mesmo teste que validou os perfis do artigo do Entra ID, e evita descobrir um binding errado pelo chamado do time.
4. A Carla só no namespace dela
$ kubectl auth can-i create deployments -n time-dev-demoyes$ kubectl auth can-i create deployments -n defaultno$ kubectl auth can-i create rolebindings -n time-dev-demono$ kubectl get nodesError from server (Forbidden): nodes is forbidden: User "[email protected]" cannot list resource "nodes" in API group "" at the cluster scopeCom edit, ela cria no namespace do time, não mexe nos outros, não vê os nós e não consegue se dar mais permissão: o papel não inclui Roles nem RoleBindings. É o menor privilégio funcionando.
5. A quota segurando o consumo
A Carla publica uma aplicação sem declarar resources, e o LimitRange preenche:
kubectl create deployment podinfo --image=ghcr.io/stefanprodan/podinfo:6.7.1 -n time-dev-demokubectl -n time-dev-demo rollout status deploy/podinfokubectl get pod -n time-dev-demo -o jsonpath='{.items[0].spec.containers[0].resources}'deployment.apps/podinfo createdWaiting for deployment "podinfo" rollout to finish: 0 of 1 updated replicas are available...deployment "podinfo" successfully rolled out{"limits":{"cpu":"200m","memory":"128Mi"},"requests":{"cpu":"50m","memory":"64Mi"}}Depois pede 8 réplicas, o dobro do que a quota permite:
kubectl scale deployment podinfo --replicas=8 -n time-dev-demokubectl get deploy -n time-dev-demokubectl get events -n time-dev-demo --field-selector reason=FailedCreate | tail -1NAME READY UP-TO-DATE AVAILABLE AGEpodinfo 4/8 4 4 17s15s Warning FailedCreate replicaset/podinfo-7f5848f5f6 Error creating: pods "podinfo-7f5848f5f6-xqgr5" is forbidden: exceeded quota: quota-time-dev, requested: pods=1, used: pods=4, limited: pods=4O deployment não falha: fica em 4/8, e o motivo está nos eventos, não no deployment. Do lado do admin, a quota mostra o consumo:
Resource Used Hard-------- ---- ----limits.cpu 800m 2limits.memory 512Mi 2Gipods 4 4requests.cpu 200m 1requests.memory 256Mi 1Giservices.loadbalancers 0 0Boa prática: deixe folga na quota para o rollout
Uma atualização do deployment (rolling update) sobe pods novos antes de desligar os antigos. Com a quota de pods no limite, o pod a mais não sobe e a atualização não avança. Dimensione a quota com uma ou duas réplicas de folga, ou ajuste o maxSurge do deployment.
6. Acesso só pelo kubectl, sem o painel
Algumas pessoas não devem entrar no painel do NKP: uma automação, um fornecedor por tempo limitado, um acesso de exceção. Para elas, o próprio Kubernetes emite um certificado de cliente, pela API de CertificateSigningRequest, e o RBAC prende esse usuário a um namespace. Funciona em qualquer edição do NKP, porque é Kubernetes padrão.
O fluxo, em seis passos (o Davi é um usuário local, davi.local):
- A chave e o pedido de certificado são gerados com
CN=davi.local(o CN vira o nome do usuário). - O admin cria a
CertificateSigningRequestcom validade de 24 horas e aprova. - O kubeconfig do Davi aponta para o mesmo API server, com o certificado dele.
- O Davi autentica, mas ainda sem permissão:
can-i= no. - O admin cria o namespace
acesso-direto-demoe um RoleBindingeditsó paradavi.local. - O Davi trabalha no namespace dele e em nenhum outro lugar.
apiVersion: certificates.k8s.io/v1kind: CertificateSigningRequestmetadata: name: davi-local-demospec: request: <CSR em base64> signerName: kubernetes.io/kube-apiserver-client expirationSeconds: 86400 # 24 horas usages: [client auth]kubectl certificate approve davi-local-demokubectl create rolebinding davi-edit --clusterrole=edit --user=davi.local -n acesso-direto-demoNAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITIONdavi-local-demo 1s kubernetes.io/kube-apiserver-client kubernetes-admin 24h Approved,Issuedsubject=CN=davi.localnotAfter=Nov 11 18:31:31 2026 GMT
$ kubectl auth whoami # com o kubeconfig do Davi, antes do RoleBindingATTRIBUTE VALUEUsername davi.localGroups [system:authenticated]
can-i create deployments -n acesso-direto-demo: yes can-i create deployments -n default: no can-i get secrets -n kube-system: no can-i list nodes: no can-i create rolebindings -n acesso-direto-demo: noCertificado não se revoga
O Kubernetes não tem lista de revogação para certificados de cliente. Para tirar o acesso do Davi antes do vencimento, apaga-se o RoleBinding: o certificado continua autenticando, mas sem permissão nenhuma. Por isso a validade curta (24 horas) e o uso só para exceções. Nunca coloque system:masters no campo de organização (O=) do certificado: esse grupo tem acesso total e não passa pelo RBAC. Em ambiente de produção, aja com cautela.
Para pessoas, no dia a dia, o caminho continua sendo o login do Entra: MFA, desligamento e troca de time ficam num lugar só.
Um modelo de times para começar
Grupos do Entra de um lado, namespaces do outro, papel no meio. Nomes de exemplo:
| Grupo no Entra | Onde | Papel | Vínculo |
|---|---|---|---|
nkp-plataforma | Cluster inteiro | cluster-admin | ClusterRoleBinding |
nkp-dev-sistemax | sistemax-hml | edit | RoleBinding |
nkp-dev-sistemax | sistemax-prd | view | RoleBinding |
nkp-lider-sistemax | sistemax-hml | admin | RoleBinding |
nkp-suporte | Namespaces dos sistemas | view | RoleBinding em cada um |
Regra de ouro: permissão para grupo, nunca para pessoa. Quem entra ou sai do time muda no Entra, não no cluster.
Os números
| Medida | Valor |
|---|---|
| Objetos por time (namespace, quota, LimitRange, RoleBinding) | 4, num arquivo só |
| Do namespace criado à Carla trabalhando só no namespace dela | 2 s |
| Teste do binding por impersonação | 2 comandos, resposta no mesmo segundo |
| Ensaio completo, do namespace à limpeza | 24 s (com 15 s de espera proposital) |
| Quota do time de exemplo | 4 pods · 1 vCPU / 1 GiB de requests · 2 vCPU / 2 GiB de limites |
| Padrão do LimitRange por container | 50m / 64Mi de request · 200m / 128Mi de limite |
| Deploy pedindo 8 réplicas | 4 no ar, 4 barradas pela quota |
| Consumo com 4 réplicas | 200m de CPU e 256Mi de memória em requests (20% e 25% da quota) |
| Do pedido de certificado ao pod do Davi rodando | 5 s |
| Validade do certificado do acesso sem painel | 24 h |
| Validade do kubeconfig do Generate Token | 24 h |
O que aprendi
- Login e permissão são camadas separadas. O Entra autentica; o RoleBinding autoriza. A Carla autenticada e barrada no passo 2 é o comportamento esperado.
- O grupo do binding tem de ser o grupo do token. No NKP com Entra, é
oidc:<Object ID>. Confira comkubectl auth whoamiantes de escrever o YAML. - Teste por impersonação antes de liberar.
--as-groupresponde em segundos e mostra também o que o time não pode. edité o papel certo para devs em homologação, e não deixa o time ampliar o próprio acesso. Em produção,view.- Quota sem LimitRange recusa pods sem
resources. O LimitRange dá o padrão e deixa a quota fazer o trabalho dela. - O erro de quota aparece nos eventos, não no deployment.
kubectl get events --field-selector reason=FailedCreateé o primeiro lugar a olhar. - Acesso por certificado é exceção, com validade curta. Tirar o acesso é apagar o binding; o certificado só para de autenticar quando vence.
Checklist: um namespace por time
- Login com grupos funcionando e o nome do grupo conferido no token (
kubectl auth whoami) - Um namespace por sistema e por ambiente (
-hml,-prd) - RoleBinding para o grupo, nunca para a pessoa
-
editem homologação,viewem produção,adminsó para o líder técnico - ResourceQuota em todo namespace de time, com folga para o rollout
- LimitRange com requests e limits padrão
- Binding testado com
kubectl auth can-i --as-groupantes de avisar o time - Um YAML por time no Git, com revisão
- Acesso por certificado só para exceção: 24 h, nunca
system:masters, binding apagado ao fim - Revisão periódica: quem tem
cluster-adminhoje?
O que ainda não testei
- Usuário do Entra só pelo
kubectl, com login pelo navegador direto do terminal (kubelogin pelo Dex), sem passar pelo painel do NKP. - Os mesmos YAMLs aplicados por GitOps em vários clusters de uma vez.
- Quotas calibradas pelo consumo real depois de 30 dias de uso de um time.
- Um cluster com licença Pro ou Starter. A receita usa só objetos nativos do Kubernetes, que não dependem da edição, mas foi executada no lab, com licença Ultimate.
Referências
Nutanix
- Nutanix Kubernetes Platform: datasheet e edições
- Nutanix Kubernetes Platform Guide 2.19, seção Access Control (portal Nutanix)
Projetos e comunidade
Comentários
Os comentários usam o GitHub Discussions; é preciso ter uma conta no GitHub.