Quelques mots sur Cilium…#
Cilium est un projet open source de l’entreprise Isovalent qui apporte une couche réseau à votre cluster tout en permettant de garantir la sécurité et la supervision de l’ensemble des flux réseau au sein de Kubernetes.
Il se base sur une technologie présente dans les noyaux Linux (depuis la version 4.4) : eBPF (extended Berkeley Packet Filter).
Cette technologie a un avantage assez important : il n’est plus nécessaire de modifier le code source du noyau ou d’ajouter des modules complémentaires pour exécuter des programmes. Tout s’exécute dans un espace dédié, appelé sandbox, au niveau du noyau qui permet d’exécuter du bytecode eBPF.
Ce qui permet dans le cas de Cilium, d’obtenir une meilleure observabilité et sécurité lors du filtrage des paquets au niveau du réseau, car tout se joue au niveau du noyau Linux.
Enfin, Cilium est devenu depuis le 13 octobre 2021, un projet CNCF au niveau “Incubating”.
L’objectif de cet article est d’installer Cilium au sein de Kubernetes et de découvrir ce qu’il apporte en matière de fonctionnalités.
Pourquoi adopter Cilium ?#
Quand on utilise Kubernetes, l’ensemble des règles réseaux est géré par le composant qui s’appelle kube-proxy
. C’est ce composant qui pilote iptables sur l’ensemble des noeuds du cluster.
Néanmoins, même si iptables est très répandu dans l’environnement GNU/Linux. Il dispose de quelques limitations dues à sa conception.
En effet, lorsque iptables souhaite mettre à jour une règle, il doit recréer et mettre à jour l’ensemble des règles en une seule transaction. Ce qui est un vrai problème quand un cluster dispose d’un nombre significatif de noeuds et de Pod qui s’exécutent sur celui-ci.
De plus, cet outil est capable de filtrer que ce soit sur les adresses IP ou sur les ports, mais pas sur d’éventuels chemins ou méthodes HTTP. Ce qui est un peu gênant dans un monde Kubernetes où beaucoup d’applications sont des API.
Enfin, iptables est généralement un consommateur important de CPU lorsqu’il s’exécute avec Kubernetes.
Vous l’aurez compris, la plupart des défauts d’iptables sont gommés avec Cilium. Il peut filtrer sur la couche 7 (application) du modèle OSI et permet de répondre aux problématiques de mise à l’échelle qu’iptables avait beaucoup de mal à adresser.
eBPF un peu plus en détail#
Comme dit plus haut, eBPF est la technologie sur laquelle s’appuie Cilium. Il est important de comprendre comment cette technologie s’exécute au sein du noyau, c’est ce qui sera introduit dans cette partie.
En ce qui concerne le développement de programme eBPF, il existe plusieurs outils :
- LLVM Clang qui permet de compiler le code en C en bytecode eBPF ;
- La boite à outils BCC qui rend la création de programme eBPF plus simple avec la possibilité d’analyser les performances et contrôler le trafic réseau.
En ce qui concerne la sécurité, l’ensemble des programmes eBPF s’exécute dans une sandbox ce qui permet d’assurer l’intégrité du code du noyau Linux. De plus, avant l’exécution d’un programme eBPF, il y a une étape de vérification.
Le but du vérificateur est d’assurer que le programme eBPF n’altère pas le fonctionnement du noyau et du système ou d’empêcher l’exécution de code malveillant (boucle infinie par exemple).
Installation de Cilium dans Kubernetes#
Prérequis#
Avant d’installer Cilium, il est important de désactiver votre plugin réseau lors de l’installation d’un nouveau cluster ou le désinstaller pour un cluster existant. Que ce soit Calico, flannel ou un autre.
En ce qui concerne le système d’exploitation, le noyau et différentes dépendances, la liste des prérequis est disponible à cette adresse.
Installation#
Dans la suite de cet article, je vais essentiellement parler de l’installation de Cilium sur un cluster déployé avec Kubeadm. Néanmoins, plusieurs guides d’installation existent en fonction du produit utilisé de GKE à k3s.
Se séparer du kube-proxy#
Pour utiliser toute la puissance de Cilium, il faut notamment se passer des iptables et donc du composant kube-proxy. Il est important de désactiver leur initialisation au sein de kubeadm.
Pour cela, il suffit d’ajouter le paramètre --skip-phases=addon/kube-proxy
lors de la commande kubeadm init
.
Dans le cas où le composant kube-proxy est déjà initialisé, il est possible de les retirer avec cette suite d’instruction :
# Supprime le DaemonSet contenant les kube-proxy
kubectl -n kube-system delete ds kube-proxy
# Supprime la configmap de kube-proxy pour éviter que celui-ci soit réinstallé lors d'une mise à jour de kubeadm
kubectl -n kube-system delete cm kube-proxy
# A jouer sur l'ensemble de vos noeuds
# Cela réinitialise les instructions iptables définies par le kube-proxy
iptables-save | grep -v KUBE | iptables-restore
L’installation du Chart Helm#
Pour installer Cilium, il est nécessaire de déployer un chart Helm comprenant l’opérateur Cilium et différents CRD (Custom Resource Definitions) dont notamment l’objet CiliumNetworkPolicy
qui sera abordé plus tard dans cet article.
Si vous aimez Ansible pour déployer vos Charts Helm, voici un exemple de Playbook à adapter selon les besoins :
- hosts: master # Le nom du groupe de la machine qui dispose de Helm pour installer le chart sur votre cluster
gather_facts: true
become: true
vars:
cilium_chart_version: 1.12.1
tasks:
- name: Install Cilium chart
kubernetes.core.helm:
release_name: cilium
chart_ref: cilium
chart_version: "{{ cilium_chart_version }}"
chart_repo_url: https://helm.cilium.io/
release_namespace: kube-system
create_namespace: false
values:
kubeProxyReplacement: strict
k8sServiceHost: 10.0.0.10
k8sServicePort: 6443
ipam:
mode: "cluster-pool"
operator:
clusterPoolIPv4PodCIDRList:
- "10.244.0.0/16"
become: false
Sinon la manière classique consiste à déployer le chart Helm directement en ligne de commande :
# Ajoute le repository à Helm
helm repo add cilium https://helm.cilium.io/
# Permet de mettre à jour l'ensemble des repo
helm repo update
# Crée le fichier cilium-values.yaml
cat > cilium-values.yaml <<EOF
kubeProxyReplacement: strict
k8sServiceHost: 10.0.0.10
k8sServicePort: 6443
ipam:
mode: "cluster-pool"
operator:
clusterPoolIPv4PodCIDRList:
- "10.244.0.0/16"
EOF
# Installe Cilium
helm install --version 1.12.1 --namespace=kube-system cilium cilium/cilium --values=./cilium-values.yaml
Un point sur les valeurs définies dans le Chart :
kubeProxyReplacement
représente le mode choisi pour faire fonctionner Cilium avec ou sans kube-proxy. Ici, le mode strict n’utilisera pas l’iptables des kube-proxy ;k8sServiceHost
est l’IP de l’API du master ou controlplane ;k8sServicePort
est le port de l’API du master ou controlplane ;ipam
(IP Address Management) permet de configurer le pool d’adresses IP allouées aux points de terminaison du réseau gérés par Cilium. Différentes méthodes existent en fonction du cas d’utilisation.
En ce qui concerne le choix de la plage d’adresses IP avec le paramètre clusterPoolIPv4PodCIDRList
. Il faut être vigilant de ne pas entrer en conflit avec le réseau de votre cluster.
Vérifier que tout fonctionne correctement#
Cilium dispose d’un outil CLI qui permet de valider l’installation et le bon fonctionnement de tout ce qui a été installé dans votre cluster Kubernetes.
Pour Linux, quelques lignes de commande sont à exécuter :
curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-amd64.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz{,.sha256sum}
La ligne ci-dessous va vérifier l’installation et afficher différentes informations de votre cluster :
cilium status --wait
De mon côté, j’ai eu ce retour :
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Hubble: disabled
\__/¯¯\__/ ClusterMesh: disabled
\__/
Deployment cilium-operator Desired: 2, Ready: 2/2, Available: 2/2
DaemonSet cilium Desired: 2, Ready: 2/2, Available: 2/2
Containers: cilium Running: 2
cilium-operator Running: 2
Cluster Pods: 2/2 managed by Cilium
Image versions cilium quay.io/cilium/cilium:v1.12.1@sha256:ea2db1ee21b88127b5c18a96ad155c25485d0815a667ef77c2b7c7f31cab601b: 2
cilium-operator quay.io/cilium/operator-generic:v1.12.1@sha256:93d5aaeda37d59e6c4325ff05030d7b48fabde6576478e3fdbfb9bb4a68ec4a1: 2
Les composants Cilium et Operator sont au statut OK.
Pour terminer l’étape de vérification, il est possible d’analyser via le lancement d’une batterie de tests, les fonctionnalités réseaux de Cilium avec la commande :
cilium connectivity test
Cette dernière étape prend plus de temps que la première, il faut dire qu’il y a beaucoup de tests :
✅ All 23 tests (118 actions) successful, 0 tests skipped, 0 scenarios skipped.
L’installation est totalement fonctionnelle !
L’objet CiliumNetworkPolicy#
Cilium permet de reprendre le concept des NetworkPolicy
qui sont intégrés dans Kubernetes en ajoutant la prise en charge de la couche 7 du modèle OSI, comme expliqué dans la deuxième partie de cet article, ce qui permet de contrôler plus finement le chemin ou la méthode d’une API.
Voici un exemple simple où l’on peut souhaite limiter l’appel d’une API depuis un Pod
de test à la méthode GET et au chemin /.
# Création de deux Pod de test, dont un qui va simuler une API
kubectl run test-l7 --image=nginx --labels=app=test-l7
kubectl run fake-api --image=nginx --labels=app=fake-api
kubectl expose pod fake-api --port=80
# Mise en place de la CiliumNetworkPolicy
cat <<EOF | kubectl create -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "allow-get-to-fake-api"
specs:
- endpointSelector:
matchLabels:
app: fake-api
ingress:
- fromEndpoints:
- matchLabels:
app: test-l7
toPorts:
- ports:
- port: "80"
protocol: "TCP"
rules:
http:
- method: "GET"
path: "/"
EOF
Dans ce cas-ci, c’est l’instruction rules
associée à http
qui permet de définir la méthode et le chemin que l’on souhaite autoriser.
Voici le résultat :
# Test de l'appel de fake-api
$ kubectl exec -it test-l7 -- curl fake-api
<!DOCTYPE html>
<html>
(...)
</html>
# Test de l'appel de fake-api avec un chemin en plus /test
$ kubectl exec -it test-l7 -- curl fake-api/test
Access denied
# Test de l'appel de fake-api avec la méthode POST
$ kubectl exec -it test-l7 -- curl -X POST fake-api
Access denied
De plus, il est notamment possible de filtrer par nom de domaine. Dans cet exemple, il est possible d’atteindre depuis le Pod
test-dns uniquement les adresses google.fr ou les sous domaines comme www.google.fr.
# Création d'un Pod de test
kubectl run test-dns --image=nginx --labels=app=test-dns
# Mise en place de la CiliumNetworkPolicy
cat <<EOF | kubectl create -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "allow-only-google-fr"
spec:
endpointSelector:
matchLabels:
app: test-dns
egress:
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
"k8s:k8s-app": kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
- toFQDNs:
- matchPattern: "*.google.fr"
- matchName: "google.fr"
EOF
Dans la section egress
, il y a deux parties :
- La première permet aux
Pod
ayant le labelapp: test-dns
d’accéder au service kube-dns. L’instructionrules
indique à Cilium d’analyser les requêtes DNS et dans ce cas-ci, de les accepter toutes ; - La seconde permet de définir les noms de domaine qui seront accessibles pour les
Pod
possédant le labelapp: test-dns
.
Voici le résultat :
# Test avec google.fr
$ kubectl exec -it test-dns -- curl google.fr
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.fr/">here</A>.
</BODY></HTML>
# Test avec cilium.io
$ kubectl exec -it test-dns -- curl cilium.io
(Pas de réponse)
Pour les personnes qui utilisent Kafka, il faut savoir qu’il est possible de filtrer par rôle et par topic. Néanmoins, cette fonctionnalité est toujours en beta lors de l’écriture de l’article.
L’objet CiliumNetworkPolicy
permet d’aller beaucoup plus loin et se révèle incontournable dans le monde Kubernetes pour venir renforcer la sécurité au niveau de la couche 7.
Quelques mots pour conclure#
Comme vous l’avez au cours de l’article, Cilium permet de répondre à beaucoup de limitations d’iptables que ce soit au niveau de la mise à l’échelle ou pour filtrer la couche 7 du modèle OSI.
Depuis mon retour de la KubeCon et après m’être renseigné sur le produit, je dois avouer que je déploie Cilium à chaque fois que j’ai besoin d’un cluster Kubernetes.
Pour finir, Cilium permet d’aller beaucoup plus loin en ajoutant une vraie couche d’observabilité des flux réseaux avec Hubble sans parler de Tetragon qui permet de détecter les menaces en terme de sécurité ou même de Cilium Service Mesh, un service mesh sans sidecar. Cela fera sûrement l’objet de futurs articles !