Jeferson Fernando

Descomplicando RBAC no Kubernetes

RBAC

O que é RBAC?

RBAC é um acrônimo para Role-Based Access Control, ou Controle de Acesso Baseado em Funções. É um método de controle de acesso que permite que um administrador defina permissões específicas para usuários e grupos de usuários. Isso significa que os administradores podem controlar quem tem acesso a quais recursos e o que eles podem fazer com esses recursos.

No Kubernetes é super importante você entender como funciona o RBAC, pois é através dele que você vai definir as permissões de acesso aos recursos do cluster, como por exemplo, quem pode criar um Pod, um Deployment, um Service, etc.

Primeiro exemplo de RBAC

Vamos imaginar que precisamos dar acesso ao cluster a uma pessoa desenvolvedora da nossa empresa, mas não queremos que ela tenha acesso a todos os recursos do cluster, apenas aos recursos que ela precisa para desenvolver a sua aplicação.

Para isso, vamos criar um usuário chamado developer e vamos dar acesso a ele para criar e administrar os Pods no namespace dev.

Temos duas formas de fazer isso, a primeira e mais antiga é através da criação de um Token de acesso, e a que iremos abordar na sequência é através da criação de um certificado. O Token é mais utilizado para dar acesso a um ServiceAccount, que é um usuário que não é humano. Por exemplo, podemos ter um ServiceAccount para o Prometheus poder coletar métricas do cluster, ou um ServiceAccount para o Fluentd poder coletar os logs do cluster. E podemos ter um User para um usuário humano, como por exemplo, o usuário developer que iremos criar.

Criando um Usuário para acesso ao cluster

Bem, agora que já sabemos quais serão as permissões do nosso novo usuário, já podemos iniciar a sua criação.

Primeira coisa que precisamos é criar uma chave privada para o nosso usuário. Para isso, vamos utilizar o comando openssl:

openssl genrsa -out developer.key 2048

Com o comando acima estamos criando uma chave privadas de 2048 bits e salvando ela no arquivo developer.key. O parametro genrsa indica que queremos gerar uma chave privada, e o parametro -out indica o nome do arquivo que queremos salvar a chave.

Com a chave criada, precisa agora criar a um CSR, ou Certificate Signing Request, que é um arquivo que contém o certificado que criamos, e que será enviado para o Kubernetes assinar e gerar o certificado final.

openssl req -new -key developer.key -out developer.csr -subj "/CN=developer"

No comando acima estamos criando um certificado para o nosso usuário, utilizando a chave privada que criamos anteriormente. O parametro req indica que queremos criar um certificado, o parametro -key indica o nome do arquivo da chave privada que queremos utilizar, o parametro -out indica o nome do arquivo que queremos salvar o certificado, e o parametro -subj indica o nome do usuário que queremos criar.

Pronto, agora com os dois arquivos em mãos, já podemos iniciar a criação do nosso usuário no cluster, mas antes, precisamos criar um CSR, ou Certificate Signing Request, que é um arquivo que contém o certificado que criamos, e que será enviado para o Kubernetes assinar e gerar o certificado final.

Mas para que possamos criar o arquivo, precisamos antes ter o conteúdo do certificado em base64, para isso, vamos utilizar o comando base64:

cat developer.csr | base64 | tr -d '\n'

Com o comando acima estamos lendo o conteúdo do arquivo developer.csr, convertendo ele para base64, e removendo a quebra de linha.

O conteúdo do certificado em base64 será algo parecido com isso:

LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1dUQ0NBVUVDQVFBd0ZERVNNQkFHQTFVRUF3d0paR1YyWld4dmNHVnlNSUlCSWpBTkJna3Foa2lHOXcwQgpBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF5OFN1Y25JWjJjL0k3dXQvS0EwSXhvN0RZa0hkSUxrbmxZOWNwMkVlClJJSzRzU1NzZnA2SzBhbWZlYWtRaEdXT2NWMmFaeEtTM0xrNERNNlVmb3ZucEQvOXpidDl0em44UUpMTDZxREEKeHFxbzVSbEt4QnpEV3lQT2JkUStMWnI2VjFQZ2wxYms2c3o0d2lWek52a2NhT0doSDdlSU90QVI0U096MjNJdAowZ0xiZHBDalFITFIvNlFuSXBjY3h3bDBGa1FtL3RVeHdRa0x1NXNpSTNKOGRiUkQwcnlFdGxReWQ5elhLM29rCjBRbVpLZDVpV1p2aDU3R1lrV1kweGMzV0J5aXY5OURQYVE3WTB4MFNaWGlPL2w0bTRzazJ3RjYwa2dUa1NJZmQKdEMxN2Y1ZzVWVzhOTW02amNpMFRXeDk5Z0REcmpHanJpaExHeTBLUWdRa2p3d0lEQVFBQm9BQXdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQUllZVdLbjAwZkk5ekw3MUVQNFNpOUVxVUFNUnBYT0dkT1Aybm8rMTV2VzJ5WmpwCmhsTWpVTjMraVZubkh2QVBvWFVLKzBYdXdmaklHMjBQTjA5UEd1alU4aUFIeVZRbFZRS0VaOWpRcENXYnQybngKVlZhYUw0N0tWMUpXMnF3M1YybmNVNkhlNHdtQzVqUE9vU29vVGtrVlF5Uml4bkcyVVQrejI3M2xpaTY3RkFXegpBZ1QvczlVa3gvS1dxRjIzczVuUk9TTlZUS2xCSG5LMU40YkN6RHBqZnN5V01GUXdnazhxRCtlOXp0cTh2c1VhCi9Say9jUWNyS2wxVDMyM0xDcG1TekhnM3hDdjFqdzJUVFFINm1yWlBBa2doa2R2YlNnalp6Y1JRZWNqSEpNeTMKTzFJQXJ6V3pWbU1hRTJqeGhUV1JwbkJkcVZjZERTUERiNkNXaktVPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K%

Lembre-se de remover a quebra de linha do final do arquivo, representada pelo %.

Agora que já temos o conteúdo do certificado em base64, copie ele e cole no arquivo developer.yaml que vamos criar agora:

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
 name: developer
spec:
 request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1dUQ0NBVUVDQVFBd0ZERVNNQkFHQTFVRUF3d0paR1YyWld4dmNHVnlNSUlCSWpBTkJna3Foa2lHOXcwQgpBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF5OFN1Y25JWjJjL0k3dXQvS0EwSXhvN0RZa0hkSUxrbmxZOWNwMkVlClJJSzRzU1NzZnA2SzBhbWZlYWtRaEdXT2NWMmFaeEtTM0xrNERNNlVmb3ZucEQvOXpidDl0em44UUpMTDZxREEKeHFxbzVSbEt4QnpEV3lQT2JkUStMWnI2VjFQZ2wxYms2c3o0d2lWek52a2NhT0doSDdlSU90QVI0U096MjNJdAowZ0xiZHBDalFITFIvNlFuSXBjY3h3bDBGa1FtL3RVeHdRa0x1NXNpSTNKOGRiUkQwcnlFdGxReWQ5elhLM29rCjBRbVpLZDVpV1p2aDU3R1lrV1kweGMzV0J5aXY5OURQYVE3WTB4MFNaWGlPL2w0bTRzazJ3RjYwa2dUa1NJZmQKdEMxN2Y1ZzVWVzhOTW02amNpMFRXeDk5Z0REcmpHanJpaExHeTBLUWdRa2p3d0lEQVFBQm9BQXdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQUllZVdLbjAwZkk5ekw3MUVQNFNpOUVxVUFNUnBYT0dkT1Aybm8rMTV2VzJ5WmpwCmhsTWpVTjMraVZubkh2QVBvWFVLKzBYdXdmaklHMjBQTjA5UEd1alU4aUFIeVZRbFZRS0VaOWpRcENXYnQybngKVlZhYUw0N0tWMUpXMnF3M1YybmNVNkhlNHdtQzVqUE9vU29vVGtrVlF5Uml4bkcyVVQrejI3M2xpaTY3RkFXegpBZ1QvczlVa3gvS1dxRjIzczVuUk9TTlZUS2xCSG5LMU40YkN6RHBqZnN5V01GUXdnazhxRCtlOXp0cTh2c1VhCi9Say9jUWNyS2wxVDMyM0xDcG1TekhnM3hDdjFqdzJUVFFINm1yWlBBa2doa2R2YlNnalp6Y1JRZWNqSEpNeTMKTzFJQXJ6V3pWbU1hRTJqeGhUV1JwbkJkcVZjZERTUERiNkNXaktVPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K 
 signerName: kubernetes.io/kube-apiserver-client
 expirationSeconds: 31536000 # 1 year
 usages:
 - client auth

No arquivo acima, estamos definindo as seguintes informações:

  • apiVersion: Versão da API que estamos utilizando para criar o nosso usuário.
  • kind: Tipo do recurso que estamos criando, no caso, um CSR.
  • metadata.name: Nome do nosso usuário.
  • spec.request: Conteúdo do certificado em base64.
  • spec.signerName: Nome do assinador do certificado, que no caso é o kube-apiserver, que será o responsável por assinar o nosso certificado.
  • spec.expirationSeconds: Tempo de expiração do certificado, que no caso é de 1 ano.
  • spec.usages: Tipo de uso do certificado, que no caso é client auth.

Agora que já temos o nosso arquivo criado, vamos aplicar ele no cluster:

kubectl apply -f developer.yaml

Vamos listar os CSR's do cluster para ver o status do nosso usuário:

kubectl get csr

O resultado será algo parecido com isso:

NAME        AGE   SIGNERNAME                                    REQUESTOR                 REQUESTEDDURATION   CONDITION
csr-4zd8k   15m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-68wsv   15m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-jkm8t   15m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-r2hcr   15m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-x52kj   15m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
developer   3s    kubernetes.io/kube-apiserver-client           kubernetes-admin          365d                Pending

Perceba que o nosso usuário está com o status Pending, isso porque o kube-apiserver ainda não assinou o nosso certificado. Você pode acompanhar o status do seu usuário através do comando:

kubectl describe csr developer

O resultado será algo parecido com isso:

Name:         developer
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certificates.k8s.io/v1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"developer"},"spec":{"expirationSeconds":31536000,"request":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1dUQ0NBVUVDQVFBd0ZERVNNQkFHQTFVRUF3d0paR1YyWld4dmNHVnlNSUlCSWpBTkJna3Foa2lHOXcwQgpBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF5OFN1Y25JWjJjL0k3dXQvS0EwSXhvN0RZa0hkSUxrbmxZOWNwMkVlClJJSzRzU1NzZnA2SzBhbWZlYWtRaEdXT2NWMmFaeEtTM0xrNERNNlVmb3ZucEQvOXpidDl0em44UUpMTDZxREEKeHFxbzVSbEt4QnpEV3lQT2JkUStMWnI2VjFQZ2wxYms2c3o0d2lWek52a2NhT0doSDdlSU90QVI0U096MjNJdAowZ0xiZHBDalFITFIvNlFuSXBjY3h3bDBGa1FtL3RVeHdRa0x1NXNpSTNKOGRiUkQwcnlFdGxReWQ5elhLM29rCjBRbVpLZDVpV1p2aDU3R1lrV1kweGMzV0J5aXY5OURQYVE3WTB4MFNaWGlPL2w0bTRzazJ3RjYwa2dUa1NJZmQKdEMxN2Y1ZzVWVzhOTW02amNpMFRXeDk5Z0REcmpHanJpaExHeTBLUWdRa2p3d0lEQVFBQm9BQXdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQUllZVdLbjAwZkk5ekw3MUVQNFNpOUVxVUFNUnBYT0dkT1Aybm8rMTV2VzJ5WmpwCmhsTWpVTjMraVZubkh2QVBvWFVLKzBYdXdmaklHMjBQTjA5UEd1alU4aUFIeVZRbFZRS0VaOWpRcENXYnQybngKVlZhYUw0N0tWMUpXMnF3M1YybmNVNkhlNHdtQzVqUE9vU29vVGtrVlF5Uml4bkcyVVQrejI3M2xpaTY3RkFXegpBZ1QvczlVa3gvS1dxRjIzczVuUk9TTlZUS2xCSG5LMU40YkN6RHBqZnN5V01GUXdnazhxRCtlOXp0cTh2c1VhCi9Say9jUWNyS2wxVDMyM0xDcG1TekhnM3hDdjFqdzJUVFFINm1yWlBBa2doa2R2YlNnalp6Y1JRZWNqSEpNeTMKTzFJQXJ6V3pWbU1hRTJqeGhUV1JwbkJkcVZjZERTUERiNkNXaktVPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K","signerName":"kubernetes.io/kube-apiserver-client","usages":["client auth"]}}

CreationTimestamp:   Wed, 31 Jan 2024 11:52:24 +0100
Requesting User:     kubernetes-admin
Signer:              kubernetes.io/kube-apiserver-client
Requested Duration:  365d
Status:              Pending
Subject:
         Common Name:    developer
         Serial Number:  
Events:  <none>

Tudo certo até aqui, agora precisamos assinar o nosso certificado, para isso, vamos utilizar o comando kubectl certificate approve:

kubectl certificate approve developer

Agora vamos listar os CSR's do cluster novamente:

kubectl get csr

O resultado será algo parecido com isso:

NAME        AGE   SIGNERNAME                                    REQUESTOR                 REQUESTEDDURATION   CONDITION
csr-4zd8k   17m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-68wsv   17m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-jkm8t   17m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-r2hcr   17m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-x52kj   16m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
developer   88s   kubernetes.io/kube-apiserver-client           kubernetes-admin          365d                Approved,Issued

Pronto, o nosso certificado foi assinado com sucesso, agora podemos pegar o certificado do nosso usuário e salvar em um arquivo, para isso, vamos utilizar o comando kubectl get csr:

kubectl get csr developer -o jsonpath='{.status.certificate}' | base64 --decode > developer.crt

No comando acima, estamos pegando o certificado do nosso usuário, convertendo ele para base64, e salvando ele no arquivo developer.crt.

Para pegar o certificado, estamos usando o parametro -o jsonpath='{.status.certificate}', para que o comando retorne apenas o certificado do usuário, e não todas as informações do CSR.

Você pode conferir o conteúdo do certificado através do comando:

cat developer.crt

Pronto, agora temos o nosso certificado final criado, e podemos utilizá-lo para acessar o cluster, mas antes precisamos definir o que o nosso usuário pode fazer no cluster.

Criando um Role para o nosso usuário

Quando criamos um novo Usuário ou ServiceAccount no Kubernetes, ele não tem acesso a nada no cluster, para que ele possa acessar os recursos do cluster, precisamos criar um Role e associar ele ao usuário.

A definição da Role consiste em um arquivo onde definimos quais são as permissões que o usuário terá no cluster, e para quais recursos ele terá acesso. Dentro da Role é onde definimos:

  • Qual é o namespace que o usuário terá acesso.
  • Quais apiGroups o usuário terá acesso.
  • Quais recursos o usuário terá acesso.
  • Quais verbos o usuário terá acesso.

apiGroups

São os grupos de recursos do Kubernetes, que são divididos em core e named, você pode consultar todos os grupos de recursos do Kubernetes através do comando kubectl api-resources.

Vamos listar os grupos de recursos do Kubernetes:

kubectl api-resources

A lista é longa, mas o resultado será algo parecido com isso:

NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
bindings                                       v1                                     true         Binding
componentstatuses                 cs           v1                                     false        ComponentStatus
configmaps                        cm           v1                                     true         ConfigMap
endpoints                         ep           v1                                     true         Endpoints
events                            ev           v1                                     true         Event
limitranges                       limits       v1                                     true         LimitRange
namespaces                        ns           v1                                     false        Namespace
nodes                             no           v1                                     false        Node
persistentvolumeclaims            pvc          v1                                     true         PersistentVolumeClaim
persistentvolumes                 pv           v1                                     false        PersistentVolume
pods                              po           v1                                     true         Pod
podtemplates                                   v1                                     true         PodTemplate
replicationcontrollers            rc           v1                                     true         ReplicationController
resourcequotas                    quota        v1                                     true         ResourceQuota
secrets                                        v1                                     true         Secret
serviceaccounts                   sa           v1                                     true         ServiceAccount
services                          svc          v1                                     true         Service
mutatingwebhookconfigurations                  admissionregistration.k8s.io/v1        false        MutatingWebhookConfiguration
validatingwebhookconfigurations                admissionregistration.k8s.io/v1        false        ValidatingWebhookConfiguration
customresourcedefinitions         crd,crds     apiextensions.k8s.io/v1                false        CustomResourceDefinition
apiservices                                    apiregistration.k8s.io/v1              false        APIService
controllerrevisions                            apps/v1                                true         ControllerRevision
daemonsets                        ds           apps/v1                                true         DaemonSet
deployments                       deploy       apps/v1                                true         Deployment
replicasets                       rs           apps/v1                                true         ReplicaSet
statefulsets                      sts          apps/v1                                true         StatefulSet
tokenreviews                                   authentication.k8s.io/v1               false        TokenReview
localsubjectaccessreviews                      authorization.k8s.io/v1                true         LocalSubjectAccessReview
selfsubjectaccessreviews                       authorization.k8s.io/v1                false        SelfSubjectAccessReview
selfsubjectrulesreviews                        authorization.k8s.io/v1                false        SelfSubjectRulesReview
subjectaccessreviews                           authorization.k8s.io/v1                false        SubjectAccessReview
horizontalpodautoscalers          hpa          autoscaling/v2                         true         HorizontalPodAutoscaler
cronjobs                          cj           batch/v1                               true         CronJob
jobs                                           batch/v1                               true         Job
certificatesigningrequests        csr          certificates.k8s.io/v1                 false        CertificateSigningRequest
leases                                         coordination.k8s.io/v1                 true         Lease
endpointslices                                 discovery.k8s.io/v1                    true         EndpointSlice
events                            ev           events.k8s.io/v1                       true         Event
flowschemas                                    flowcontrol.apiserver.k8s.io/v1beta3   false        FlowSchema
prioritylevelconfigurations                    flowcontrol.apiserver.k8s.io/v1beta3   false        PriorityLevelConfiguration
ingressclasses                                 networking.k8s.io/v1                   false        IngressClass
ingresses                         ing          networking.k8s.io/v1                   true         Ingress
networkpolicies                   netpol       networking.k8s.io/v1                   true         NetworkPolicy
runtimeclasses                                 node.k8s.io/v1                         false        RuntimeClass
poddisruptionbudgets              pdb          policy/v1                              true         PodDisruptionBudget
clusterrolebindings                            rbac.authorization.k8s.io/v1           false        ClusterRoleBinding
clusterroles                                   rbac.authorization.k8s.io/v1           false        ClusterRole
rolebindings                                   rbac.authorization.k8s.io/v1           true         RoleBinding
roles                                          rbac.authorization.k8s.io/v1           true         Role
priorityclasses                   pc           scheduling.k8s.io/v1                   false        PriorityClass
csidrivers                                     storage.k8s.io/v1                      false        CSIDriver
csinodes                                       storage.k8s.io/v1                      false        CSINode
csistoragecapacities                           storage.k8s.io/v1                      true         CSIStorageCapacity
storageclasses                    sc           storage.k8s.io/v1                      false        StorageClass
volumeattachments                              storage.k8s.io/v1                      false        VolumeAttachment

Onde a primeira coluna é o nome do recurso, a segunda coluna é o nome abreviado do recurso, a terceira coluna é a versão da API que o recurso está, a quarta coluna indica se o recurso é ou não Namespaced, e a quinta coluna é o tipo do recurso.

Vamos dar uma olhada em um recurso específico, por exemplo, o recurso pods:

kubectl api-resources | grep pods

O resultado será algo parecido com isso:

NAME       SHORTNAMES   APIVERSION     NAMESPACED   KIND
pods       po           v1             true         Pod

Onde:

  • NAME: Nome do recurso.
  • SHORTNAMES: Nome abreviado do recurso.
  • APIVERSION: Versão da API que o recurso está.
  • NAMESPACED: Indica se o recurso é ou não Namespaced.
  • KIND: Tipo do recurso.

Mas o que é um recurso Namespaced? Um recurso Namespaced é um recurso que pode ser criado dentro de um namespace, por exemplo, um Pod, um Deployment, um Service, etc. Já um recurso que não é Namespaced, é um recurso que não pode ser criado dentro de um namespace, por exemplo, um Node, um PersistentVolume, um ClusterRole, etc. Fácil né?

Agora, como eu sei qual é o apiGroup de um recurso? Bem, o apiGroup de um recurso é o nome do grupo de recursos que ele pertence, por exemplo, o recurso pods pertence ao grupo de recursos core, e o recurso deployments pertence ao grupo de recursos apps. Quando o recurso é do tipo core ele não precisa ser especificado no apiGroup, pois o Kubernetes já entende que ele pertence ao grupo de recursos core, esse é o famoso apiVersion: v1.

Ja o apiVersion: apps/v1 indica que o recurso pertence ao grupo de recursos apps, e a versão da API é a v1. No apps temos recursos importantes como o deployments, replicasets, daemonsets, statefulsets, etc.

Recursos

São os recursos do Kubernetes, que são divididos em core e named, você pode consultar todos os recursos do Kubernetes através do comando kubectl api-resources.

Os recursos chamados de core são os recursos que já vem instalados no Kubernetes, e os recursos chamados de named são os recursos que são instalados através de Custom Resource Definitions, ou CRD's, como por exemplo o ServiceMonitor do Prometheus.

Vamos listar os recursos do Kubernetes:

kubectl api-resources --namespaced=false

O resultado será algo parecido com isso:

NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
componentstatuses                 cs           v1                                     false        ComponentStatus
namespaces                        ns           v1                                     false        Namespace
nodes                             no           v1                                     false        Node
persistentvolumes                 pv           v1                                     false        PersistentVolume
mutatingwebhookconfigurations                  admissionregistration.k8s.io/v1        false        MutatingWebhookConfiguration
validatingwebhookconfigurations                admissionregistration.k8s.io/v1        false        ValidatingWebhookConfiguration
customresourcedefinitions         crd,crds     apiextensions.k8s.io/v1                false        CustomResourceDefinition
apiservices                                    apiregistration.k8s.io/v1              false        APIService
tokenreviews                                   authentication.k8s.io/v1               false        TokenReview
selfsubjectaccessreviews                       authorization.k8s.io/v1                false        SelfSubjectAccessReview
selfsubjectrulesreviews                        authorization.k8s.io/v1                false        SelfSubjectRulesReview
subjectaccessreviews                           authorization.k8s.io/v1                false        SubjectAccessReview
certificatesigningrequests        csr          certificates.k8s.io/v1                 false        CertificateSigningRequest
flowschemas                                    flowcontrol.apiserver.k8s.io/v1beta3   false        FlowSchema
prioritylevelconfigurations                    flowcontrol.apiserver.k8s.io/v1beta3   false        PriorityLevelConfiguration
ingressclasses                                 networking.k8s.io/v1                   false        IngressClass
runtimeclasses                                 node.k8s.io/v1                         false        RuntimeClass
clusterrolebindings                            rbac.authorization.k8s.io/v1           false        ClusterRoleBinding
clusterroles                                   rbac.authorization.k8s.io/v1           false        ClusterRole
priorityclasses                   pc           scheduling.k8s.io/v1                   false        PriorityClass
csidrivers                                     storage.k8s.io/v1                      false        CSIDriver
csinodes                                       storage.k8s.io/v1                      false        CSINode
storageclasses                    sc           storage.k8s.io/v1                      false        StorageClass
volumeattachments                              storage.k8s.io/v1                      false        VolumeAttachment

Assim podemos saber quais são os recursos que são nativos do Kubernetes, e quais são os recursos que são instalados através de CRD's, que são os Custom Resources Definitions.

Então o nome do recurso é o nome que utilizamos para criar o recurso, por exemplo, pods, deployments, services, etc.

Verbos

Os verbos definem o que o usuário pode fazer com o recurso, por exemplo, o usuário pode criar, listar, atualizar, deletar, etc.

Para que você possa visualizar os verbos que podem ser utilizados, vamos utilizar o comando kubectl api-resources com o parametro -o wide:

kubectl api-resources -o wide

O resultado será algo parecido com isso:

NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND                             VERBS                                                        CATEGORIES
bindings                                       v1                                     true         Binding                          create                                                       
componentstatuses                 cs           v1                                     false        ComponentStatus                  get,list                                                     
configmaps                        cm           v1                                     true         ConfigMap                        create,delete,deletecollection,get,list,patch,update,watch   
endpoints                         ep           v1                                     true         Endpoints                        create,delete,deletecollection,get,list,patch,update,watch   
events                            ev           v1                                     true         Event                            create,delete,deletecollection,get,list,patch,update,watch   
limitranges                       limits       v1                                     true         LimitRange                       create,delete,deletecollection,get,list,patch,update,watch   
namespaces                        ns           v1                                     false        Namespace                        create,delete,get,list,patch,update,watch                    
nodes                             no           v1                                     false        Node                             create,delete,deletecollection,get,list,patch,update,watch   
persistentvolumeclaims            pvc          v1                                     true         PersistentVolumeClaim            create,delete,deletecollection,get,list,patch,update,watch   
persistentvolumes                 pv           v1                                     false        PersistentVolume                 create,delete,deletecollection,get,list,patch,update,watch   
pods                              po           v1                                     true         Pod                              create,delete,deletecollection,get,list,patch,update,watch   all
podtemplates                                   v1                                     true         PodTemplate                      create,delete,deletecollection,get,list,patch,update,watch   
replicationcontrollers            rc           v1                                     true         ReplicationController            create,delete,deletecollection,get,list,patch,update,watch   all
resourcequotas                    quota        v1                                     true         ResourceQuota                    create,delete,deletecollection,get,list,patch,update,watch   
secrets                                        v1                                     true         Secret                           create,delete,deletecollection,get,list,patch,update,watch   
serviceaccounts                   sa           v1                                     true         ServiceAccount                   create,delete,deletecollection,get,list,patch,update,watch   
services                          svc          v1                                     true         Service                          create,delete,deletecollection,get,list,patch,update,watch   all
mutatingwebhookconfigurations                  admissionregistration.k8s.io/v1        false        MutatingWebhookConfiguration     create,delete,deletecollection,get,list,patch,update,watch   api-extensions
validatingwebhookconfigurations                admissionregistration.k8s.io/v1        false        ValidatingWebhookConfiguration   create,delete,deletecollection,get,list,patch,update,watch   api-extensions
customresourcedefinitions         crd,crds     apiextensions.k8s.io/v1                false        CustomResourceDefinition         create,delete,deletecollection,get,list,patch,update,watch   api-extensions
apiservices                                    apiregistration.k8s.io/v1              false        APIService                       create,delete,deletecollection,get,list,patch,update,watch   api-extensions
controllerrevisions                            apps/v1                                true         ControllerRevision               create,delete,deletecollection,get,list,patch,update,watch   
daemonsets                        ds           apps/v1                                true         DaemonSet                        create,delete,deletecollection,get,list,patch,update,watch   all
deployments                       deploy       apps/v1                                true         Deployment                       create,delete,deletecollection,get,list,patch,update,watch   all
replicasets                       rs           apps/v1                                true         ReplicaSet                       create,delete,deletecollection,get,list,patch,update,watch   all
statefulsets                      sts          apps/v1                                true         StatefulSet                      create,delete,deletecollection,get,list,patch,update,watch   all
tokenreviews                                   authentication.k8s.io/v1               false        TokenReview                      create                                                       
localsubjectaccessreviews                      authorization.k8s.io/v1                true         LocalSubjectAccessReview         create                                                       
selfsubjectaccessreviews                       authorization.k8s.io/v1                false        SelfSubjectAccessReview          create                                                       
selfsubjectrulesreviews                        authorization.k8s.io/v1                false        SelfSubjectRulesReview           create                                                       
subjectaccessreviews                           authorization.k8s.io/v1                false        SubjectAccessReview              create                                                       
horizontalpodautoscalers          hpa          autoscaling/v2                         true         HorizontalPodAutoscaler          create,delete,deletecollection,get,list,patch,update,watch   all
cronjobs                          cj           batch/v1                               true         CronJob                          create,delete,deletecollection,get,list,patch,update,watch   all
jobs                                           batch/v1                               true         Job                              create,delete,deletecollection,get,list,patch,update,watch   all
certificatesigningrequests        csr          certificates.k8s.io/v1                 false        CertificateSigningRequest        create,delete,deletecollection,get,list,patch,update,watch   
leases                                         coordination.k8s.io/v1                 true         Lease                            create,delete,deletecollection,get,list,patch,update,watch   
endpointslices                                 discovery.k8s.io/v1                    true         EndpointSlice                    create,delete,deletecollection,get,list,patch,update,watch   
events                            ev           events.k8s.io/v1                       true         Event                            create,delete,deletecollection,get,list,patch,update,watch   
flowschemas                                    flowcontrol.apiserver.k8s.io/v1beta3   false        FlowSchema                       create,delete,deletecollection,get,list,patch,update,watch   
prioritylevelconfigurations                    flowcontrol.apiserver.k8s.io/v1beta3   false        PriorityLevelConfiguration       create,delete,deletecollection,get,list,patch,update,watch   
ingressclasses                                 networking.k8s.io/v1                   false        IngressClass                     create,delete,deletecollection,get,list,patch,update,watch   
ingresses                         ing          networking.k8s.io/v1                   true         Ingress                          create,delete,deletecollection,get,list,patch,update,watch   
networkpolicies                   netpol       networking.k8s.io/v1                   true         NetworkPolicy                    create,delete,deletecollection,get,list,patch,update,watch   
runtimeclasses                                 node.k8s.io/v1                         false        RuntimeClass                     create,delete,deletecollection,get,list,patch,update,watch   
poddisruptionbudgets              pdb          policy/v1                              true         PodDisruptionBudget              create,delete,deletecollection,get,list,patch,update,watch   
clusterrolebindings                            rbac.authorization.k8s.io/v1           false        ClusterRoleBinding               create,delete,deletecollection,get,list,patch,update,watch   
clusterroles                                   rbac.authorization.k8s.io/v1           false        ClusterRole                      create,delete,deletecollection,get,list,patch,update,watch   
rolebindings                                   rbac.authorization.k8s.io/v1           true         RoleBinding                      create,delete,deletecollection,get,list,patch,update,watch   
roles                                          rbac.authorization.k8s.io/v1           true         Role                             create,delete,deletecollection,get,list,patch,update,watch   
priorityclasses                   pc           scheduling.k8s.io/v1                   false        PriorityClass                    create,delete,deletecollection,get,list,patch,update,watch   
csidrivers                                     storage.k8s.io/v1                      false        CSIDriver                        create,delete,deletecollection,get,list,patch,update,watch   
csinodes                                       storage.k8s.io/v1                      false        CSINode                          create,delete,deletecollection,get,list,patch,update,watch   
csistoragecapacities                           storage.k8s.io/v1                      true         CSIStorageCapacity               create,delete,deletecollection,get,list,patch,update,watch   
storageclasses                    sc           storage.k8s.io/v1                      false        StorageClass                     create,delete,deletecollection,get,list,patch,update,watch   
volumeattachments                              storage.k8s.io/v1                      false        VolumeAttachment                 create,delete,deletecollection,get,list,patch,update,watch  

Perceba que agora temos uma nova coluna, a coluna VERBS, onde temos todos os verbos que podem ser utilizados com o recurso, e a coluna CATEGORIES, onde temos a categoria do recurso. Mas o nosso foco aqui é nos verbos, então vamos dar uma olhada neles.

Os verbos são divididos em:

  • create: Permite que o usuário crie um recurso.
  • delete: Permite que o usuário delete um recurso.
  • deletecollection: Permite que o usuário delete uma coleção de recursos.
  • get: Permite que o usuário obtenha um recurso.
  • list: Permite que o usuário liste os recursos.
  • patch: Permite que o usuário atualize um recurso.
  • update: Permite que o usuário atualize um recurso.
  • watch: Permite que o usuário acompanhe as alterações de um recurso.

Com isso, vamos pegar exemplo da linha do recurso pods:

NAME   SHORTNAMES   APIVERSION     NAMESPACED   KIND     VERBS                     CATEGORIES
pods   po           v1             true         Pod      create,delete,deletecollection,get,list,patch,update,watch   all

Com isso sabemos que o usuário pode criar, deletar, deletar uma coleção, obter, listar, atualizar e acompanhar as alterações de um Pod. Simplão demais, hein!

Criando a Role

Agora que já sabemos muito sobre os resources, apiGroups e verbs, vamos criar a nossa Role para o nosso usuário.

Para isso, vamos criar um arquivo chamado developer-role.yaml com o seguinte conteúdo:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 name: developer
 namespace: dev
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list", "update", "create", "delete"]

No arquivo acima, estamos definindo as seguintes informações:

  • apiVersion: Versão da API que estamos utilizando para criar o nosso usuário.
  • kind: Tipo do recurso que estamos criando, no caso, uma Role.
  • metadata.name: Nome da nossa Role.
  • metadata.namespace: Namespace que a nossa Role será criada.
  • rules: Regras da nossa Role.
  • rules.apiGroups: Grupos de recursos que a nossa Role terá acesso.
  • rules.resources: Recursos que a nossa Role terá acesso.
  • rules.verbs: Verbos que a nossa Role terá acesso.

Eu tenho certeza que está fácil para você fazer a leitura da Role, que é basicamente o que o nosso usuário pode fazer no cluster, mas em resumo o que estamos falando é que o usuário que estiver usando essa Role, poderá fazer tudo com o recurso pods no namespace dev. Simples como voar!

Lembre-se que essa Role pode ser reutilizada por outros usuários, e que você pode criar quantas Roles quiser, e que você pode criar Roles para outros perfis de usuários e para outros recursos, como por exemplo, deployments, services, configmaps, etc.

Ahhh, antes de mais nada, vamos criar o namespace dev:

kubectl create ns dev

Agora que já temos o nosso arquivo e a namespace criados, vamos aplicar ele no cluster:

kubectl apply -f developer-role.yaml

Para verificar se a nossa Role foi criada com sucesso, vamos listar as Roles do cluster:

kubectl get roles -n dev

A saída:

NAME        CREATED AT
developer   2024-01-31T11:32:08Z

Para ver os detalhes da Role, vamos utilizar o comando kubectl describe:

kubectl describe role developer -n dev

A saída será algo parecido com isso:

Name:         developer
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  pods       []                 []              [get watch list update create delete]

Pronto, a nossa Role já está criada, porém ainda não associamos ela ao nosso usuário, para isso, vamos criar um RoleBinding.

Criando um RoleBinding para o nosso usuário

A RoleBinding é o recurso que associa um usuário a uma Role, ou seja, é através da RoleBinding que definimos qual usuário terá acesso a qual Role, é como se tivessemos um crachá de Developer, a Role seria o crachá, e a RoleBinding seria o crachá com o nome do usuário. Faz sentindo?

Para isso, vamos criar um arquivo chamado developer-rolebinding.yaml com o seguinte conteúdo:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: DeveloperRoleBinding
  namespace: dev
subjects:
- kind: User
  name: developer
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io

No arquivo acima, estamos definindo as seguintes informações:

  • apiVersion: Versão da API que estamos utilizando para criar o nosso usuário.
  • kind: Tipo do recurso que estamos criando, no caso, um RoleBinding.
  • metadata.name: Nome da nossa RoleBinding.
  • metadata.namespace: Namespace que a nossa RoleBinding será criada.
  • subjects: Usuários que terão acesso a Role.
  • subjects.kind: Tipo do usuário, que no caso é User.
  • subjects.name: Nome do usuário, que no caso é developer.
  • roleRef: Referência da Role que o usuário terá acesso.
  • roleRef.kind: Tipo da Role, que no caso é Role.
  • roleRef.name: Nome da Role, que no caso é developer.
  • roleRef.apiGroup: Grupo de recursos da Role, que no caso é rbac.authorization.k8s.io.

Nada de outro mundo, e mais uma vez está super claro o que iremos ter, que é o usuário developer com a Role developer no namespace dev.

Agora que já temos o nosso arquivo criado, bora aplica-lo:

kubectl apply -f developer-rolebinding.yaml

Para verificar se a nossa RoleBinding foi criada com sucesso, vamos listar as RoleBindings do cluster:

kubectl get rolebindings -n dev

A saída:

NAME                   ROLE             AGE
DeveloperRoleBinding   Role/developer   9s

Para ver detalhes da RoleBinding, vamos utilizar o comando kubectl describe:

kubectl describe rolebinding DeveloperRoleBinding -n dev

A saída será algo parecido com isso:

Name:         DeveloperRoleBinding
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  Role
  Name:  developer
Subjects:
  Kind  Name       Namespace
  ----  ----       ---------
  User  developer  

Pronto, RoleBinding criada com sucesso, agora vamos testar o nosso usuário.

Adicionando o certificado do usuário no kubeconfig

Agora que já temos o nosso usuário criado, precisamos adicionar o certificado do usuário no kubeconfig, para que possamos acessar o cluster com o nosso usuário.

Para isso, vamos utilizar o comando kubectl config set-credentials:

kubectl config set-credentials developer --client-certificate=developer.crt --client-key=developer.key --embed-certs=true

O comando kubectl config set-credentials é utilizado para adicionar um novo usuário no kubeconfig, e ele recebe os seguintes parametros:

  • --client-certificate: Caminho do certificado do usuário.
  • --client-key: Caminho da chave do usuário.
  • --embed-certs: Indica se o certificado deve ser embutido no kubeconfig.

No nosso caso, estamos passando o caminho do certificado e da chave do usuário, e estamos indicando que o certificado deve ser embutido no kubeconfig.

Agora precisamos criar um contexto para o nosso usuário, para isso, vamos utilizar o comando kubectl config set-context:

kubectl config set-context developer --cluster=NOME-DO-CLUSTER --namespace=dev --user=developer

Caso você não se lembre o que é um contexto no Kubernetes, eu vou te ajudar a relembrar. Um contexto é um conjunto de configurações que definem o acesso a um cluster, ou seja, um contexto é composto por um cluster, um usuário e um namespace. Quando você cria um novo usuário, você precisa criar um novo contexto para ele, para que ele possa acessar o cluster.

Para que você possa pegar os nomes do cluster, basta utilizar o comando kubectl config get-clusters, assim você poderá pegar o nome do cluster que você quer utilizar.

Com isso, o nosso novo usuário está pronto para ser utilizado, mas antes vamos verificar se ele está funcionando.

Acessando o cluster com o novo usuário

Uma vez que o nosso usuário está criado, e que o certificado do usuário está no kubeconfig e que já temos um contexto para o usuário, podemos testar o acesso ao cluster.

Antes de mais nada, vamos listar todos os contextos do kubeconfig:

kubectl config get-contexts

O nosso novo contexto deve aparecer na lista, e deve ser algo parecido com isso:

CURRENT   NAME                CLUSTER        AUTHINFO       NAMESPACE
*         developer           kind-strigus   developer      dev
          kind-strigus        kind-strigus   kind-strigus   

Então bora o utilizar o nosso novo contexto:

kubectl config use-context developer

Pronto, nesse momento estamos utilizando o nosso novo usuário através do nosso novo contexto, agora vamos testar o acesso ao cluster:

kubectl get pods

Tudo funcionando, certo?

Perceba que o Namespace que estamos utilizando é o dev, onde ele pode fazer tudo com o recurso pods, e que ele não pode fazer nada com os outros recursos, como por exemplo, deployments, services, configmaps, etc. Isso porque a nossa Role está limitada ao recurso pods, e ao namespace dev.

Vamos testar o acesso a um recurso que ele não tem permissão:

kubectl get deployments

O resultado será algo parecido com isso:

Error from server (Forbidden): deployments.apps is forbidden: User "developer" cannot list resource "deployments" in API group "apps" in the namespace "dev"

Tudo funcionando perfeitamente! Pra finalizar, vamos criar um Pod simples do Nginx, ele deve ser criado com sucesso, pois o nosso usuário tem permissão para criar Pods no namespace dev:

kubectl run nginx --image=nginx -n dev

Criado!

Vamos listar os Pods do namespace dev:

kubectl get pods

E veremos o nosso Pod do Nginx criado:

NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          5s

Pronto! O nosso usuário está criado e funcionando perfeitamente!

ClusterRole e ClusterRoleBinding

Até agora nós criamos uma Role e uma RoleBinding, que são recursos Namespaced, ou seja, eles só podem ser criados dentro de um namespace, mas e se você quiser criar um usuário que tenha acesso a todos os namespaces do cluster? Para isso, você precisa criar um ClusterRole e um ClusterRoleBinding.

Basicamente eles são iguais a Role e RoleBinding, porém com maior escopo, pois eles refletem em todo o cluster, e não apenas em um namespace específico.

Agora, precisamos criar um novo usuário, que será do time de Platform, e que terá acesso a todos os namespaces do cluster, pois ele precisa criar e gerenciar recursos em todos os namespaces.

Ele precisa ter acesso a Deployments, Services, ConfigMaps, Secrets, Ingress e Pods, por enquanto.

Então vamos começar criando a chave privada e o CSR do usuário:

openssl genrsa -out platform.key 2048
openssl req -new -key platform.key -out platform.csr -subj "/CN=platform/O=platform"

Pegue o conteúdo do arquivo platform.csr, use o base64 para codificar o conteúdo, e cole o resultado no campo request do arquivo platform-csr.yaml:

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: platform
spec:
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2F6Q0NBVk1DQVFBd0pqRVJNQThHQTFVRUF3d0ljR3hoZEdadmNtMHhFVEFQQmdOVkJBb01DSEJzWVhSbQpiM0p0TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFyd3ZaT1NNeUlsTFlUYlR0CjEzYmNMOWtqK0hyOXl5ekpPQnU1Z1hLSUljM3NhdGg1Q1BMOHNvRFN4dzNrbkVOQklsQlE5YlYxNWRJNDQwSnoKdDRDT0ZpR1lTSGt2WGNuVFRGTlpHSlFxemwxZ2JvZ1VldlZxS0tYM0c2ZFhUZ3BrYjNaNTZQRHV2MlF3VlZ6cApYRWE1VlpLZFF6Nmd2LzdFNzV2YWdDOUhxdXVYWWtQYWN4ajRvTERZL2xxNzRpMlBlb1B2L0VNd2NsVEpSV01NCk5ESmNDZmIyLzl3bU1vVEg3N3BpYUNaRlBGWG1XOStHcmhrcGY5VDNua1dST2doL2s3b2RBcjc4ekNUVTZ3a0MKa0p3QWJNR1lkaEpaZHpJLzZWTVJPUHhxV01RckVzR005MzkzNUNPSmZVYlRzOEoreEZQb2l2eWJPbXdzQWFYMgpNM0U4clFJREFRQUJvQUF3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUdTUlRtVEU1bjBIK2VFZ2ZFdmdqWFRxCitucmdlSEJka3JvK3BlMTFOM1pONjVubVhaWEQ3cFJ0U3RZamtma2p1RG1OdDcrN0Q0NW1hOXEyeDZ1aGV2eFkKMWhCNEcxOWNCS0dTVWM1QzlBbnJNemtsY29Ic1JTYjhwZkhXcmNpak4rVEQ1MkNZWC9XMVEyY28xQ2pTMWI1bgpTWG8rRE1vdkZRVHhDbnFGdTVCMVlsVXdGWkhDVW5qOXp6SUJjQmRBekUzT3VZSVdyYWFFOXNNZUU5ZC9OVE11CkVvL3lSVVJ0THlaQUtWc3NTQ2k2NEk0dVlGV3Y3WXlKbG00RTVuUDQ1YUhJd1pzdVFlZ2RwOEZhOVVZVFBLaksKbmVjWEJGdVlhekRxYlRiWHhRN1QvUW44VWhZbGIybVZ3UUpsbUpoeTEweXYwZW1DeTVPVGFDZ2ZiUlh5bk9rPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K
 signerName: kubernetes.io/kube-apiserver-client
 expirationSeconds: 31536000 # 1 year
 usages:
 - client auth

Agora vamos aplicar:

kubectl apply -f platform-csr.yaml

Para verificar se o CSR foi criado com sucesso, vamos listar os CSR's do cluster:

kubectl get csr

A saída:

NAME        AGE   SIGNERNAME                                    REQUESTOR                 REQUESTEDDURATION   CONDITION
csr-648l9   82m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-hn4d4   82m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-qd72l   82m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-r24pf   82m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-rswk4   82m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
developer   79m   kubernetes.io/kube-apiserver-client           kubernetes-admin          365d                Approved,Issued
platform    87s   kubernetes.io/kube-apiserver-client           kubernetes-admin          365d                Pending

Vamos aprovar o CSR:

kubectl certificate approve platform

Agora vamos pegar o certificado do usuário:

kubectl get csr platform -o jsonpath='{.status.certificate}' | base64 --decode > platform.crt

Eu não vou explicar novamente tudo o que estamos fazendo, pois boa parte é igual ao que já fizemos anteriormente, então se você não se lembra, volte e leia novamente. 😄

Pronto, o que está faltando agora são os recursos ClusterRole e ClusterRoleBinding, então vamos criar o arquivo platform-clusterrole.yaml com o seguinte conteúdo:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: platform
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["deployments", "services", "configmaps", "secrets", "ingresses", "pods"]
  verbs: ["get", "watch", "list", "update", "create", "delete"]

Como pode ver, a configuração é muito parecida com a Role, porém agora estamos criando um ClusterRole. A diferença na definção da Role e do ClusterRole é que o ClusterRole o Kind é ClusterRole, e também não tem o campo namespace, pois o ClusterRole não é Namespaced.

Agora vamos criar o arquivo platform-clusterrolebinding.yaml com o seguinte conteúdo:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: PlatformClusterRoleBinding
subjects:
- kind: User
  name: platform
roleRef:
  kind: ClusterRole
  name: platform
  apiGroup: rbac.authorization.k8s.io

Mesma coisa aqui, a configuração é super parecida com a RoleBinding, mudando somente o Kind, que agora é ClusterRoleBinding, e também não tem o campo namespace.

Bora aplicar os arquivos:

kubectl apply -f platform-clusterrole.yaml
kubectl apply -f platform-clusterrolebinding.yaml

Para verificar se os recursos foram criados com sucesso, vamos listar os ClusterRoles e ClusterRoleBindings do cluster:

kubectl get clusterroles
kubectl get clusterrolebindings

Estão criados!

Agora vamos adicionar o certificado do usuário no kubeconfig:

kubectl config set-credentials platform --client-certificate=platform.crt --client-key=platform.key --embed-certs=true

Falta agora criar o contexto para o usuário:

kubectl config set-context platform --cluster=NOME-DO-CLUSTER --user=platform

E já era! Agora vamos testar o acesso ao cluster:

kubectl config use-context platform
kubectl get pods --all-namespaces

Tudo funcionando lindamente!

Agora vamos tentar listar os Nodes do cluster:

kubectl get nodes

O resultado será algo parecido com isso:

Error from server (Forbidden): nodes is forbidden: User "platform" cannot list resource "nodes" in API group "" at the cluster scope

Ou seja, o usuário platform não tem permissão para listar os Nodes do cluster, pois ele só tem permissão para listar os recursos deployments, services, configmaps, secrets, ingresses e pods conforme definido na nossa ClusterRole.

Simples como voar!

ClusterRole e ClusterRoleBinding para o usuário admin

Agora vamos criar um usuário que terá acesso total ao cluster, ou seja, ele terá acesso a todos os recursos do cluster, e a todos os namespaces do cluster.

Primeiro vamos criar a chave privada e o CSR do usuário:

openssl genrsa -out admin.key 2048
openssl req -new -key admin.key -out admin.csr -subj "/CN=admin/O=admin"

Converta o conteúdo do arquivo admin.csr para base64, e cole o resultado no campo request do arquivo admin-csr.yaml:

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
 name: admin
spec:
 request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1pUQ0NBVTBDQVFBd0lERU9NQXdHQTFVRUF3d0ZZV1J0YVc0eERqQU1CZ05WQkFvTUJXRmtiV2x1TUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBb2NtUUxVdVc1TEpKM0p4YmZFdmY1a2xGClRCdWZrb2h3SFBiS1FVYVdmNWErc3FrRzBlS2NSMXplVmhwZXNnYUh3WG9uRnVYakdzc3BHaHJnL21XcWFQSG4KNU14SE1uc1lmWE9VV2diOWIrT3VtRFV1Qmh3eE5EL0c1eSswMmhORUIybzdaTzltcUlCNkdZWlo2d3dHQ01vSgpVVGFzM2tCNVBXaUg4eXFISDZhdFhPNlBteG5Ba0Iyb3praHQ0NWp0ZlNVeDI1UzQvN00zVTVwSjhOTG9jU3N1CjE3d0wvRWdhQitpaThVa0t3MnNvZlZTM2hwQlNxNVNNbzNqZ2dCQ3R3eWN0UzhOWG9wb2M4Rlg5SzFWeFBGMXEKSnpGK2N2UFZVZHNWUUNJWm45Vkt6ZTV4T2JBT2ZYL2hrallrdFhJS0VIU2dIYTZvTXdOT0hXWlBxQVUrVndJRApBUUFCb0FBd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJeFJJeVN6TzY0Vi95ZHRoNVVSS09IcXdBM3JKb2U0CnJFc3A3Nkp2VTNjcVFtUVVFem9nR2RzdHMxWEFGVzA5cGJxZTdJa1pXTktOemp2NjZyTThkeDBnazRpSWdCdGkKeXovWDI5ZE5KUEVqRCthTW1sSWJ1VEpnZkpSYmx0a1lDYVpPN2tqWUJlMXRNNWE5U0dCQXg3bkt0RnlTNzArMwpTN2VaQmhYNlY2K080Z1FsZlEzT1ZxMzlzSzN5QnBPallYTDQxak5HZmh0TkRTcjNMWExodzd2MjhJb2xUZXQ5CnZJSUw0S3hjQ3kvUTROUTFXSnlKdkpWODZJS01BT2tabjJtUnY0UWFoUEVRM1grS21RbmxpQ01QYnFic2l3czUKL1pTKzA1QUp2QytLalhjcXpHZ016V21rbDlZOXV4RENVVE5paXdmQkJiOGhvRW9PV2lzcENHcz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==
 signerName: kubernetes.io/kube-apiserver-client
 expirationSeconds: 31536000 # 1 year
 usages:
 - client auth

Agora vamos aplicar:

kubectl apply -f admin-csr.yaml

Hora de aprovar o CSR:

kubectl certificate approve admin

Agora vamos pegar o certificado do usuário:

kubectl get csr admin -o jsonpath='{.status.certificate}' | base64 --decode > admin.crt

Agora bora criar o arquivo admin-clusterrole.yaml com o seguinte conteúdo:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: admin
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["*"]
  verbs: ["*"]

Perceba que nesse caso, nós estamos utilizando o * para indicar que o usuário terá acesso a todos os recursos do cluster, e a todos os namespaces do cluster.

Agora vamos criar o arquivo admin-clusterrolebinding.yaml com o seguinte conteúdo:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: AdminClusterRoleBinding
subjects:
- kind: User
  name: admin
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: rbac.authorization.k8s.io

Agora vamos aplicar os arquivos:

kubectl apply -f admin-clusterrole.yaml
kubectl apply -f admin-clusterrolebinding.yaml

Para verificar se os recursos foram criados com sucesso, vamos listar os ClusterRoles e ClusterRoleBindings do cluster:

kubectl get clusterroles
kubectl get clusterrolebindings

Estão lá! Hora de adicionar o certificado do usuário no kubeconfig:

kubectl config set-credentials admin --client-certificate=admin.crt --client-key=admin.key --embed-certs=true

E criar o contexto para o usuário:

kubectl config set-context admin --cluster=NOME-DO-CLUSTER --user=admin

Fim! hahahah

Agora é só testar, então vamos:

kubectl config use-context admin
kubectl get pods --all-namespaces

Você pode usar um comando super útil para saber tudo o que o usuário pode fazer no cluster:

kubectl auth can-i --list

A saída é gigante, então vou colocar somente o começo dela:

Resources                                        Non-Resource URLs   Resource Names   Verbs
leases.coordination.k8s.io                       []                  []               [create delete deletecollection get list patch update watch]
rolebindings.rbac.authorization.k8s.io           []                  []               [create delete deletecollection get list patch update watch]
roles.rbac.authorization.k8s.io                  []                  []               [create delete deletecollection get list patch update watch]
configmaps                                       []                  []               [create delete deletecollection patch update get list watch]
events                                           []                  []               [create delete deletecollection patch update get list watch]
persistentvolumeclaims                           []                  []               [create delete deletecollection patch update get list watch]
...

Um bom teste é você comparar com o usuário developer e com o usuário platform, assim você poderá ver a diferença entre eles do que eles podem fazer no cluster.

Acho que deu pra entender bem como funciona o RBAC, e como criar usuários com diferentes níveis de acesso ao cluster, e como criar Roles e ClusterRoles para diferentes perfis de usuários.

Agora é só praticar!

Removendo o usuário

Para remover o usuário é super simples, basta remover o CSR e o RoleBinding relacionado ao usuário.

kubectl delete csr NOME-DO-CSR
kubectl delete rolebinding NOME-DO-ROLEBINDING

E para remover do seu kubeconfig, basta utilizar o comando kubectl config unset:

kubectl config unset users.NOME-DO-USUARIO

Pronto, usuário removido!

Utilizando Tokens para Service Accounts

Uma das formas de autentição no Kubernetes é através de Tokens, que são utilizados para autenticar Service Accounts, que são contas de serviço utilizadas, normalmente, por aplicações que rodam no cluster ou serviços que precisam acessar o cluster.

Os Tokens são gerados automaticamente pelo Kubernetes, e são utilizados para autenticar Service Accounts, e eles são armazenados em Secrets, que são recursos do Kubernetes que armazenam informações sensíveis, como por exemplo, chaves privadas, senhas, tokens, etc.

O primeiro passo para a criação de um Service Account utilizando Tokens é criar o Service Account, então bora começar os trablahos!

Criando um Service Account

Podemos criar service accounts utilizando o comando kubectl ou através de um arquivo YAML, e é isso que vamos fazer, criar um arquivo chamado service-account.yaml com o seguinte conteúdo:

apiVersion: v1

kind: ServiceAccount

metadata:

  name: service-account-example

  namespace: default


Nada de novo acima, certo? No arquivo estamos definindo o seguinte:

  • apiVersion: Versão da API que estamos utilizando para criar o nosso Service Account.

  • kind: Tipo do recurso que estamos criando, no caso, um Service Account.

  • metadata.name: Nome do nosso Service Account.

  • metadata.namespace: Namespace que o nosso Service Account será criado.

Agora vamos aplicar o arquivo no cluster:

kubectl apply -f service-account.yaml


Caso queira criar utilizando a linha de comando, basta utilizar o comando kubectl create serviceaccount NOME-DO-SERVICE-ACCOUNT.

Agora vamos ver os detalhes da nossa Service Account:

kubectl get serviceaccounts service-account-example -o yaml


A saída será algo parecido com isso:

apiVersion: v1

kind: ServiceAccount

metadata:

  annotations:

    kubectl.kubernetes.io/last-applied-configuration: |

      {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"service-account-example","namespace":"default"}}

  creationTimestamp: "2024-02-05T10:20:19Z"

  name: service-account-example

  namespace: default

  resourceVersion: "2472"

  uid: 0d21af3f-e242-477b-8557-983533562274


Pronto, Service Account criado com sucesso!

Agora vamos criar o Secret que irá armazenar o Token do Service Account.

Criando um Secret para o Service Account

Novamente aqui podemos utilizar o comando kubectl ou um arquivo YAML, e é isso que vamos fazer, criar um arquivo chamado service-account-secret.yaml com o seguinte conteúdo:

apiVersion: v1

kind: Secret

metadata:

  name: service-account-example-token

  annotations:

    kubernetes.io/service-account.name: service-account-example

type: kubernetes.io/service-account-token


Aqui estamos falando o seguinte para o Kubernetes:

  • apiVersion: Versão da API que estamos utilizando para criar o nosso Secret.

  • kind: Tipo do recurso que estamos criando, no caso, um Secret.

  • metadata.name: Nome do nosso Secret.

  • metadata.annotations: Anotações do nosso Secret.

  • metadata.annotations.kubernetes.io/service-account.name: Nome do nosso Service Account.

  • type: Tipo do Secret, que no caso é kubernetes.io/service-account-token.

Pronto, hora de aplicar o arquivo:

kubectl apply -f service-account-secret.yaml


Vamos ver se está tudo certo com o nosso Secret:

kubectl get secrets service-account-example-token -o yaml


A saída será algo parecido com isso:

Name:         service-account-example-token

Namespace:    default

Labels:       <none>

Annotations:  kubernetes.io/service-account.name: service-account-example

              kubernetes.io/service-account.uid: 0d21af3f-e242-477b-8557-983533562274


Type:  kubernetes.io/service-account-token


Data

====

ca.crt:     1099 bytes

namespace:  7 bytes

token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IkhicVNQcnRtbVBOa0tzVm00WUJfZjMwajNMZVN1bl9peXo0WVpUUHVjSTQifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNlcnZpY2UtYWNjb3VudC1leGFtcGxlLXRva2VuIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InNlcnZpY2UtYWNjb3VudC1leGFtcGxlIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMGQyMWFmM2YtZTI0Mi00NzdiLTg1NTctOTgzNTMzNTYyMjc0Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6c2VydmljZS1hY2NvdW50LWV4YW1wbGUifQ.B_N9F9gTucLFryhyTMNJxjCoEAa1q5NmbtUJ95RUNwEUUKY3KapDxezrFMZCA7VG-I7YbukRdYKusYmtWnZLvlgm2UHw1CY4dmzlqBwu3-XhOms8OHVAu1JVbGujgjljPEQy8jPFrkYRz356L_5FUzka9Noj3i2pj5R1wOrJz1O2KAw99RhKI1ctKtXnk4O0VJJ4fdmDUf0Ox0PQt4oNgGr28ZRIpyZkB0RSjhO3Wb6QgsGPoTBKHYnRo3zcCNymEkF8iJBGyyv4WyMx5zr4prCUpeSHqg-2m6vI_KZ9pu0pCJVJ1wV25vU6WOsyY56UR87a7jeBh83m-sOM8SAqOA


Já era! Secret está lá e com o Token do Service Account.
Nós não precisamos gerar o Token, isso foi feito automaticamente pelo Kubernetes, pois quando criamos a nossa Secret, nós informamos que a Secret é do tipo kubernetes.io/service-account-token, e também informamos o nome do nosso Service Account. Com isso o Kubernetes gerou automaticamente o Token para o nosso Service Account especificado e armazenou na Secret. Simples como voar!

Agora, para acessar o nosso Token, uma forma que eu gosto bastante é utilizando o comando kubectl get secret, e com o comando kubectl get secret NOME-DO-SECRET -o jsonpath='{.data.token}' | base64 --decode, assim você consegue pegar o Token do Service Account.

Olha o comando completo:

kubectl get secret service-account-example-token -ojsonpath='{.data.token}'| base64 --decode


Dessa forma você consegue pegar o Token do Service Account, já decodificado, e utilizar para autenticar a sua aplicação ou serviço no cluster.

Agora precisamos criar uma Role para o nosso Service Account.

Aqui não temos nada de novo, pois já vimos como criar Roles, então vamos criar um arquivo chamado service-account-role.yaml com o seguinte conteúdo:

apiVersion: rbac.authorization.k8s.io/v1

kind: Role

metadata:

  name: service-account-role

  namespace: default

rules:

-apiGroups:[""]

  resources:["pods"]

  verbs:["get","list","watch"]


Com a definição da Role acima, estamos falando que quem utilizar essa Role terá permissão para get, list e watch nos recursos pods do namespace default, somente!

Vamos aplicar o arquivo:

kubectl apply -f service-account-role.yaml


Agora precisamos criar um RoleBinding para o nosso Service Account.

Vamos criar um arquivo chamado service-account-rolebinding.yaml com o seguinte conteúdo:

apiVersion: rbac.authorization.k8s.io/v1

kind: RoleBinding

metadata:

  name: service-account-rolebinding

  namespace: default

subjects:

-kind: ServiceAccount

  name: service-account-example

  namespace: default

roleRef:

  kind: Role

  name: service-account-role

  apiGroup: rbac.authorization.k8s.io


Aqui estamos conectando a nossa Role com o nosso Service Account, e estamos dizendo que o nosso Service Account terá todas as permissões definidas na Role service-account-role no namespace default.

Vamos aplicar o arquivo:

kubectl apply -f service-account-rolebinding.yaml


Vamos listar as Roles e RoleBindings do namespace default:

kubectl get roles

kubectl get rolebindings


Estão lá, mais uma etapa concluída!

Agora que temos tudo o que precisamos, a nossa Service Account está pronta para ser utilizada.

Utilizando o Token do Service Account

Para o nossa exemplo, vamos criar um Pod que irá utilizar o Token do Service Account para acessar o cluster.

Vamos criar um arquivo chamado pod-service-account.yaml com o seguinte conteúdo:

apiVersion: v1

kind: Pod

metadata:

  name: pod-service-account

  namespace: default

spec:

  serviceAccountName: service-account-example

  containers:

  -name: curl-container

    image: curlimages/curl

    command:["sleep","infinity"]


A informação nova que temos nessa definição de Pod é o campo serviceAccountName, que é onde informamos o nome do nosso Service Account.

Vamos aplicar o arquivo:

kubectl apply -f pod-service-account.yaml


Agora vamos listar os Pods do namespace default:

NAME                  READY   STATUS    RESTARTS   AGE

pod-service-account   1/1     Running   0          6s


Os Tokens são montados dentro do container do Pod no caminho /var/run/secrets/kubernetes.io/serviceaccount, e o Token do Service Account está no arquivo token, vamos confirmar isso:

kubectl exec-it pod-service-account -- ls /var/run/secrets/kubernetes.io/serviceaccount


A saída será algo parecido com isso:

ca.crt     namespace  token


Onde:

  • ca.crt: É o certificado do cluster.

  • namespace: É o namespace do Pod.

  • token: É o Token do Service Account.

Vamos dar uma olhada no conteúdo do arquivo token:

kubectl exec-it pod-service-account -- cat /var/run/secrets/kubernetes.io/serviceaccount/token


Agora temos o nosso Token:

eyJhbGciOiJSUzI1NiIsImtpZCI6IkhicVNQcnRtbVBOa0tzVm00WUJfZjMwajNMZVN1bl9peXo0WVpUUHVjSTQifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzM4NjY1OTY3LCJpYXQiOjE3MDcxMjk5NjcsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJwb2Qtc2VydmljZS1hY2NvdW50IiwidWlkIjoiY2MyNmQ1MTUtZjYwMS00MTU3LWIzNDAtZDUzM2Q0OTdhZjE5In0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJzZXJ2aWNlLWFjY291bnQtZXhhbXBsZSIsInVpZCI6IjBkMjFhZjNmLWUyNDItNDc3Yi04NTU3LTk4MzUzMzU2MjI3NCJ9LCJ3YXJuYWZ0ZXIiOjE3MDcxMzM1NzR9LCJuYmYiOjE3MDcxMjk5NjcsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnNlcnZpY2UtYWNjb3VudC1leGFtcGxlIn0.O-XrTx9b1ZqvFpedKH6lBsQeHeP2qn3bEuL1WVKjCgMhd2TtjKAJOgDJH2Spye-7BQF1bwa2KyAwoWCauDDZ4I0XqwjVRSUF8dUahFmbAL9fMzrieEA2oPkNuPnwCCF57Csls52J-1z9GdIElgG-Z48aksrl0iIB1l7y5TBKS3Za7W2XDBdl1sFx1fKsAlz6k_NPaC49I21NJlmk9i3LxwctvDn6oxMjbCjBVk4fFVnK3y1HsdR_3trCLKH-FDgy59jD96Ume4VPgQMfmXNigObyJ6t3qcL53IRnqdY0xrFNOwHjwIMxBqQSTGSf42xUBWVjfKHZ_gMTX_Va-Nyk9A%


Agora vamos fazer um bom teste utilizando o nosso Token.

No Kubernetes é possível listar os recursos do cluster utilizando a API do Kubernetes, e para isso podemos utilizar o comando curl, mas antes vamos entender como funciona a autenticação com o Token.

Para autenticar com o Token, precisamos enviar o Token no header Authorization da requisição, e o valor do header Authorization deve ser Bearer seguido do Token.

Vamos entender o endereco da API do Kubernetes, que é https://kubernetes.default.svc, e o recurso que queremos listar, que é pods, e o namespace que queremos listar, que é default, então a URL da nossa requisição será:

https://kubernetes.default.svc/api/v1/namespaces/default/pods

Se eu quiser listar todos os Services do namespace default, a URL será:

https://kubernetes.default.svc/api/v1/namespaces/default/services

Se for em um namespace específico, basta trocar o default pelo nome do namespace.

Agora vamos fazer a requisição utilizando o curl, mas antes precisamos entrar no container do Pod, então vamos fazer isso:

kubectl exec-it pod-service-account -- sh


Agora vamos fazer a requisição utilizando o curl:

curl-k-H"Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/api/v1/namespaces/default/pods


Com isso estamos utilizando o curl para fazer a requisição para a API do Kubernetes, passando o Token do Service Account no header Authorization, e estamos listando os Pods do namespace default.

Eu não vou colar a saída aqui, pois ela é gigante, então faça o teste e veja os detalhes dos Pods do namespace default.

Se você tentar listar os Pods de outro namespace, você não terá permissão, pois a Role que criamos para o nosso Service Account é somente para o namespace default, e a mesma coisa para os outros recursos do cluster como Services, Deployments, etc.

Vamos tentar listar os Services do namespace default:

curl-k-H"Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/api/v1/namespaces/default/services


Recebemos um erro, pois o nosso Service Account não tem permissão para listar os Services do namespace default.

{

  "kind":"Status",

  "apiVersion":"v1",

  "metadata":{},

  "status":"Failure",

  "message":"services is forbidden: User \"system:serviceaccount:default:service-account-example\" cannot list resource \"services\" in API group \"\" in the namespace \"default\"",

  "reason":"Forbidden",

  "details":{

    "kind":"services"

  },

  "code":403

}


Pronto, com isso o nosso teste está completo, e vimos como utilizar o Token do Service Account para autenticar na API do Kubernetes.

Agora é só praticar e ficar uma pessoa expert no assunto!

Removendo o Service Account

Para remover o Service Account é super simples, basta remover o Service Account, o Secret e a RoleBinding relacionado ao Service Account.

kubectl delete serviceaccount NOME-DO-SERVICE-ACCOUNT

kubectl delete secret NOME-DO-SECRET

kubectl delete rolebinding NOME-DO-ROLEBINDING


Pronto, cluster limpo!