Aller au contenu principal

Kubernetes et les RBAC - Partie 1

· 7 minutes de lecture
Stéphane ROBERT
Consultant DevOps

Le contrôle d'accès basé sur les rôles (RBAC) est un mécanisme de sécurité dans lequel chaque autorisation d'accès est basée sur des rôles qui sont attribués à un utilisateur. Avec ce système, il est donc possible de restreindre l'accès aux ressources d'un cluster Kubernetes (namespaces, pods, jobs) à des applications ou des utilisateurs.

remarque

Je vais reprendre le même principe que j'ai appliqué pour le billet sur l'écriture des premiers manifests. Nous utiliserons le mode dry-run de la commande kubectl associé à la sortie au format yaml pour les générer. Je vous rappelle que les commandes kubectl explain <ressource> et kubectl <command> --help sont vos amies.

Kubernetes RBAC : concepts

Dans Kubernetes, les stratégies RBAC peuvent être utilisées pour gérer aussi bien les droits d'accès d'un utilisateur système (User ou Group) que ceux des comptes de service (Service Account).

Un rôle permet de définir des autorisations d'accès via des verbes sur certains objets de l'API de Kubernetes, tels que des pods, des nodes, des deployments, des ConfigMaps, ....

Kubernetes possède quatre objets liés aux RBAC qui peuvent être combinés pour définir les autorisations d'accès aux ressources du cluster. Il s'agit de Role, ClusterRole, RoleBinding et ClusterRoleBinding.

Role et ClusterRole

Comme leur nom l'indique, ces objets définissent les types d'accès que vous attribuez aux rôles.

  • Le Role est là pour gérer les autorisations pour accéder aux ressources d'un espace de noms uniquement.
  • Le ClusterRole est lui sans espaces de noms et donc permet de définir des autorisations à des ressources à l'échelle du cluster.

RoleBinding et ClusterRoleBinding

Les Binding's permettent d'attribuer des rôles (Role et ClusterRole) à des

Création des ressources RBAC

Je ne documenterai pour le moment la création du role et du rolebinding. Avant vérifions que RBAC est bien activé sur le cluster :

kubectl get cm -n kube-system kubeadm-config -o yaml | grep RBAC
        authorization-mode: Node,RBAC

Oui, c'est le cas. Nous avons bien RBAC dans authorization-mode.

Création d'un Role

Commençons par la création d'un rôle avec la commande kubectl create role. Cette commande ne fonctionne que si on lui indiquons les deux options --verb et --resource. Je ne connais pas les verbes pour le moment donc je mets "*"

Avant comme nous manipulons des rôles, nous allons créer un namespace de test.

kubectl create namespace test
kubectl -n test create role pod-read --dry-run=client --verb=* --resource=pod -o yaml

La commande create role ne fonctionne que si on lui donne les deux options --verb et --resource. Ici j'ai mis une étoile sur verbe, car je ne connais pas les verbes qui lui sont attachés (pour le moment). Ce qui donne :

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: pod-read
  namespace: test
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - '*'

On voit que nous devons définir les apiGroup, les resources et les verbs.

Pour retrouver la liste des api nous allons utiliser la commande kubectl api-ressources -o wide permet de lister l'ensemble des ressources et les verbes associés. Par exemple listons les ressources de l'apiGroup "", dont fait partie la ressource pods, qui peuvent être utilisé dans le cas d'un rôle (namespaced) :

kubectl api-resources --api-group="" --namespaced -o wide |grep pod
NAME                     SHORTNAMES   APIVERSION   NAMESPACED   KIND                    VERBS
pods                     po           v1           true         Pod                     [create delete deletecollection get list patch update watch]
podtemplates                          v1           true         PodTemplate             [create delete deletecollection get list patch update watch]

Donc nous voyons que la ressource pods est lié à l'api Core de Kubernetes, celle sans nom (""). On peut restreindre les verbes de cette ressource parmi : create, delete, deletecollection, get, list, patch, update et watch.

Par exemple si nous voulons que notre utilisateur ne puisse que lister les pods nous lui donnerions l'autorisation d'utiliser le verbe list. Pour en afficher le contenu get et ainsi de suite ....

Pour mon exemple je vais lui donner les droits list et get :

kubectl -n test create role pod-read --dry-run=client --verb=get,list

Création d'un RoleBinding

Je vais créer le rolebinding permettant d'attribuer le role pod-read à un utilisateur système bob que je créerai par la suite :

kubectl -n test create rolebinding pod-read-bob --role=pod-read --user=bob --dry-run=client -o yaml

Ce qui donne :

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  creationTimestamp: null
  name: pod-read-bob
  namespace: test
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-read

- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: bob

Donc on peut voir que le rôle est défini avec la clé roleRef et que les droits sont donnés à des subjects. Ces sujets peuvent être de type kind : user, group ou serviceaccount.

Créons notre rolebinding :

kubectl -n test create rolebinding pod-read-bob --role=pod-read --user=bob
rolebinding.rbac.authorization.k8s.io/pod-read-bob created

Création d'un user système ayant seulement accès à un namespace

Nous allons voir comment il est possible de créer un utilisateur système en ne lui donnant à notre namespace test. J'utilise ma Sandbox pour cet exemple.

Sur ma VM controller je vais commencer par créer un user bob :

ssh controller
sudo useradd --create-home -s /bin/bash bob
sudo mkdir -p  /home/bob/.kube

Maintenant je dois lui créer sa configuration (KUBECONFIG). Je me connecte sur le nœud master, car je vais utiliser les commandes kubectl et kubeadm pour créer et signer cette configuration. Cette méthode est bien plus rapide que de créer à la main le certificat avec openssl :

ssh master1
export KUBECONFIG=/etc/kubernetes/admin.conf
kubectl get cm -n kube-system kubeadm-config -o jsonpath='{ .data.ClusterConfiguration }' > cluster-configuration.yaml
sudo kubeadm kubeconfig user --client-name bob --config=cluster-configuration.yaml

À la sortie nous obtenons bien une configuration qu'il faut donner à notre user :

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data:
    ...
    server: https://10.240.0.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: bob
  name: bob@kubernetes
current-context: bob@kubernetes
kind: Config
preferences: {}
users:
- name: bob
  user:
    client-certificate-data:
    ...
    client-key-data:
    ...

J'ai enlevé les clés des certificats que cela n'apporte rien à notre exemple. On retourne sur notre node controller où nous avons créé le user bob. Nous allons lui donner cette configuration en la copiant/collant dans le fichier ~/.kube/config. Ensuite nous modifierons le context pour qu'il pointe sur le namespace test:

ssh controller
vagrant@controller:~$sudo su - bob
bob@controller:~$ vi ~/.kube/config # copier/coller le fichier généré au dessus

Maintenant testons notre accès :

bob@controller:~$ kubectl get pod
Error from server (Forbidden): pods is forbidden: User "bob" cannot list resource "pods" in API group "" in the namespace "default"

On voit que le user bob n'a pas les autorisations de lister les ressources de type pods de l'apiGroup "" du namespace default. Changeons de namespaces et relançons :

bob@controller:~$ kubectl config set-context --current --namespace=test
Context "bob@kubernetes" modified.
bob@controller:~$ kubectl get pod
No resources found in test namespace.

Cette fois, nous avons bien les droits. Essayons de créer un pod.

bob@controller:~$ kubectl run busybox --image=busybox
Error from server (Forbidden): pods is forbidden: User "bob" cannot create resource "pods" in API group "" in the namespace "test": RBAC: role.rbac.authorization.k8s.io "pod-read" not found

Donc si on devait lui donner les droits de création de pods il faudrait écrire ce rôle en plus et l'attribuer via le rolebinding :

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: pod-write-bob
  namespace: test
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - create
  - update
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  creationTimestamp: null
  name: pod-write-bob
  namespace: test
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-write

- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: bob

Voilà pour aujourd'hui en espérant que cela est clair pour vous désormais. Dans un prochain billet je reviendrais sur ClusterRole et ClusterRoleBinding.