GitLab peut être utilisé comme provider OIDC. Pour cela il suffit de déclarer une “Application” cliente dans GitLab.

Dans cet exemple nous allons configurer un cluster Kubernetes k3s ainsi que l’outil en ligne de commande kubectl pour permettre à un utilisateur de s’authentifier via le provider OIDC GitLab.

Déclaration d’une nouvelle application dans GitLab

GitLab permet de déclarer une application à plusieurs niveaux différents : global, groupe ou utilisateur.

Par exemple pour créer une application au niveau d’un groupe GitLab :

  1. Allons sur la page du groupe.
  2. Dans le menu de gauche, sélectionnons Settings > Applications.
  3. Dans la case Name indiquons un nom pour l’application, par exemple mon-cluster-k3s.
  4. Dans la case Redirect URI, indiquons http://localhost:8000.
  5. Cochons la case Confidential.
  6. Cochons les Scopes suivants :
  • openid
  • profile
  • email
  1. Enregistrons le tout et notons les valeurs générées pour Application ID et Secret, nous nous en servirons ultérieurement.

Installation du cluster k3s

Sur une machine virtuelle (dans mon exemple l’adresse IP de cette machine est 35.78.143.121), installons k3s à l’aide de la commande :

sudo -i
cd /root && curl -sfL https://get.k3s.io | sh -

Toujours en tant qu’utilisateur root créons un namespace nommé foo, qui nous servira d’exemple :

kubectl create namespace foo

Configuration de k3s

Créons le fichier /etc/rancher/k3s/config.yaml pour configurer k3s avec le contenu suivant :

tls-san: 
  - 35.78.143.121 # Adresse IP du cluster k3s

kube-apiserver-arg:
  - '--oidc-issuer-url=https://gitlab.com'
  - '--oidc-client-id=<APPLICATION ID GITLAB>'
  - '--oidc-username-claim=email'
  - '--oidc-username-prefix=oidc:'
  - '--oidc-groups-claim=groups_direct'
  - '--oidc-groups-prefix=gitlab:'
  • tls-san : Indique le ou les noms d’hôtes (ou adresses IPv4/IPv6) à ajouter en tant que noms alternatifs de sujet sur le certificat TLS. Ceci permet d’éviter des erreurs TLS lors de l’utilisation du client kubectl depuis autre machine.

  • kube-apiserver-arg : Permet de spécifier les paramètres permettant de configurer l’API server de Kubernetes. Il est possible de spécifier un certain nombre de paramètres OIDC.

  • Les options --oidc-username-prefix et --oidc-groups-prefix permettent d’ajouter un prefixe permettant d’éviter les conflits avec des utilisateurs ou groupes déjà déclarés dans Kubernetes.

Redémarrons le service k3s pour prendre en compte la nouvelle configuration :

sudo systemctl restart k3s.service

Connexion d’un utilisateur au cluster

Imaginons que nous souhaitions maintenant donner un accès sur le cluster à un développeur qui a le bon goût de travailler sur une machine Ubuntu ;-)

Les pré-requis nécessaires à installer sur sa machine sont :

  • kubectl

    sudo apt-get update && sudo apt-get install -y apt-transport-https
    curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
    echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
    sudo apt-get update
    sudo apt-get install -y kubectl
    
  • kubelogin

    curl -LO https://github.com/int128/kubelogin/releases/download/v1.28.1/kubelogin_linux_amd64.zip
    unzip kubelogin_linux_amd64.zip
    rm LICENSE README.md kubelogin_linux_amd64.zip
    sudo mv kubelogin /usr/local/bin/kubectl-kubelogin
    

    Il est important de préfixer le nom du binaire avec kubectl- pour que kubectl puisse reconnaître kubelogin comme un de ses plugins.

    kubelogin est un plugin pour kubectl qui permet de faire la colle entre kubectl et un provider OIDC :

    Workflow kubelogin

Nous devons ensuite fournir à l’utilisateur un fichier kubeconfig qui lui permettra de se connecter au cluster. Pour cela nous pouvons récupérer sur le serveur k3s le fichier /etc/rancher/k3s/k3s.yaml et l’adapter pour produire le fichier suivant que l’on pourra copier sur la machine de l’utilisateur à l’emplacement ~/.kube/config après avoir remplacé les éléments figurant entre < >.

Attention à ne pas écraser un éventuel fichier ~/.kube/config pré-existant !

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <LAISSER LA VALEUR D'ORIGINE>
    server: https://35.78.143.121:6443 # URL de l'API server du cluster k3s
  name: default
contexts:
- context:
    cluster: default
    user: default
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      command: kubectl
      args:
      - kubelogin
      - get-token
      - --oidc-issuer-url=https://gitlab.com
      - --oidc-client-id=<APPLICATION ID PROVENANT DE GITLAB>
      - --oidc-client-secret=<APPLICATION SECRET PROVENANT DE GITLAB>
      - --oidc-extra-scope=email
      #- -v1 # A décommenter si on souhaite afficher du debug
      env: null
      interactiveMode: IfAvailable
      provideClusterInfo: false

Testons l’authentification avec la commande :

kubectl auth whoami 

Les pages suivantes devraient s’ouvrir dans le navigateur de l’utilisateur afin qu’il puisse s’authentifier sur GitLab :

Page d&rsquo;authentification GitLab

Login sur GitLab

Relançons la commande précédente, ça doit passer ce coup-ci :

kubectl auth whoami 
ATTRIBUTE   VALUE
Username    oidc:bob@example.com
Groups      [gitlab:k8s-permissions gitlab:k8s-permissions/foo-developers system:authenticated]

Nous sommes bien reconnus. Essayons maintenant de récupérer la liste des pods du namespace foo :

kubectl get pods -n foo
Error from server (Forbidden): pods is forbidden: User "oidc:bob@example.com" 
cannot list resource "pods" in API group "" in the namespace "foo"

Que se passe-t-il ? Nous sommes bien reconnus mais nous n’avons pas encore d’autorisations pour pouvoir réaliser cette opération.

Configurer les droits d’accès

Pour configurer ces autorisations, revenons sur le serveur k3s et créons les fichiers nécessaires pour donner un accès de type développeur à nos développeurs.

Le fichier developer.clusterrole.yaml déclare les permissions de base habituelles pour un développeur ayant besoin de déployer des applications :

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: developer
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/portforward", "services", "configmaps", "secrets"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]

Ce ClusterRole peut ensuite être référencé dans un objet de type RoleBinding pour donner accès à un utilisateur ou un groupe d’utilisateurs sur un namepace donné. Exemple de fichier pour le namespace foo que nous avons créé précédemment :

Fichier developer-foo.rolebinding.yaml :

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: foo-developer
  namespace: foo
subjects:
- kind: Group
  name: "gitlab:k8s-permissions/foo-developers"
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: developer
  apiGroup: rbac.authorization.k8s.io

Ici nous disons simplement : dans le namespace foo on donnera les permissions définies dans le ClusterRole developer aux utilisateurs déclarés dans le groupe GitLab k8s-permissions/foo-developers.

Pour que cela fonctionne avec notre utilisateur il faudra donc bien sûr l’ajouter comme membre du groupe GitLab k8s-permissions/foo-developers.

On applique la configuration :

kubectl apply -f developer.clusterrole.yaml
kubectl apply -f foo-developer.rolebinding.yaml

Test des permissions

Revenons sur la machine de notre développeur et essayons de nouveau la commande précédente :

kubectl get pods -n foo
No resources found in foo namespace.

Ca à l’air mieux ;-)

Notons que si nous essayons de lister les pods d’un autre namespace, par exemple bar nous obtiendrons logiquement un message d’erreur puisque nous n’avons autorisé que l’accès sur foo :

kubectl get pods -n bar
Error from server (Forbidden): pods is forbidden: User "oidc:bob@example.com" 
cannot list resource "pods" in API group "" in the namespace "bar"

Essayons donc maintenant de déployer une application dans le namepace foo :

kubectl create deployment wit --image xian310/who-is-there:25 -n foo
deployment.apps/wit created

Et voilà :

kubectl get pods -n foo
NAME                    READY   STATUS    RESTARTS   AGE
wit-5dcfc9b44d-597b7    1/1     Running   0          15s

Suppression des droits de l’utilisateur

Pour supprimer les droits à notre developpeur sur le namespace foo il suffira simplement de le retirer du groupe GitLab k8s-permissions/foo-developers.