#+TITLE: Cours de virtualisation avancée: /Kubernetes/, suite
#+OPTIONS: toc:nil date:nil author:nil reveal_single_file:t timestamp:nil
#+LATEX_CLASS: article
#+LATEX_CLASS_OPTIONS: [12pt,a4paper]
#+LATEX_HEADER: \usepackage[a4paper,margin=0.5in]{geometry}
#+LATEX_HEADER: \usepackage[utf8]{inputenc}
#+LATEX_HEADER: \usepackage[inkscapelatex=false]{svg}
#+LATEX_HEADER: \usepackage[sfdefault]{AlegreyaSans}
#+LATEX_HEADER: \usepackage{multicol}
#+LATEX_HEADER: \usepackage{minted}
#+LATEX_HEADER: \usepackage{float}
#+LATEX_HEADER: \usepackage{tikz}
#+LATEX_HEADER: \usetikzlibrary{positioning}
#+LATEX_HEADER: \renewcommand\listingscaption{Exemple de code}

#+REVEAL_THEME: white
#+REVEAL_INIT_OPTIONS: slideNumber:true
#+REVEAL_EXTRA_CSS: ../../common/reveal_custom.css

* S'attacher à un /pod/
#+BEGIN_SRC bash
kubectl exec -it <nom pod> -- /bin/bash
#+END_SRC

* Récupérer les /logs/ d'un /pod/
#+BEGIN_SRC bash
kubectl logs <nom pod>
#+END_SRC

* Stocker des configurations
** /ConfigMap/
[[https://kubernetes.io/docs/concepts/configuration/configmap/][doc]]

- Utilisé pour stocker des couples clef-valeurs
- Données non protégées

Utilisé par exemple pour stocker la configuration d'une application

*** Créer une /ConfigMap/
#+BEGIN_SRC yaml
apiVersion: v1 
kind: ConfigMap  # un nouveau type
  metadata:
    name: my-app-config # on lui met un nom
  data:  # puis une liste de clefs-valeurs
    database_uri: mongodb://localhost:27017
#+END_SRC

*** Utiliser une /ConfigMap/
#+BEGIN_SRC yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
    - name: test-container
      image: my-image
      env:
        - name: DATABASE_URI
          valueFrom:
            configMapKeyRef:
              name: my-app-config
              key: database_uri
#+END_SRC

Ici, nous indiquons où aller chercher les valeurs pour les variables d’environnement.

* Stocker des fichiers
Consultez ce [[https://kubernetes.io/fr/docs/tasks/configure-pod-container/configure-persistent-volume-storage/][guide de la doc]]

- Plusieurs méthodes:
  - Statique: en local sur les nœuds;
  - Dynamique: en utilisant un serveur distant, par ex /NFS/, /Ceph/ ou autre.

- Étapes:
  - Créer un *espace* ou un *contrôleur* de stockage;
  - Créer une "demande de stockage";
  - Attacher ce stockage à un /Pod/.

#+REVEAL: split

- L'administrateur du /cluster/ doit configurer des espaces de stockage ou des contrôleurs pour les rendre disponible
- Si on fait une demande de stockage et qu'elle ne peut pas être remplie, elle reste en attente jusqu’à ce qu'elle puisse être remplie

#+REVEAL: split

Par exemple, si je demande un *volume de 10G* mais que l'administrateur n'a rendu disponible que des *volumes de 5G*, il faudra que j'attende qu'un volume de 10G soit disponible, sinon, je dois me contenter de 5G.

* Méthode *statique*
** /PersistentVolume/ (/PV/)
- Permet de rendre disponible au /cluster/ un espace de stockage;
- Attention, *ce stockage ne sera pas directement accessible par les /pods/*.

*** Créer un /PersistentVolume/
[[https://kubernetes.io/fr/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#cr%C3%A9er-un-persistentvolume][doc]]
#+BEGIN_SRC yaml
apiVersion: v1
kind: PersistentVolume  # un nouveau type
metadata:
  name: pv-volume
  labels:
    type: local
spec:
  storageClassName: manual  # la classe du stockage
  capacity:
    storage: 10Gi  # la taille du volume
  accessModes:
    - ReadWriteOnce
  hostPath:  # on veut stocker sur le nœud physique
    path: "/mnt/data"  # son emplacement sur le nœud
#+END_SRC

#+REVEAL: split

Vérifications:
#+BEGIN_SRC bash
❯ kubectl get pv pv-volume
NAME       CAPACITY   ACCESSMODES   ...   STATUS      STORAGECLASS
pv-volume  10Gi       RWO           ...   Available   manual
#+END_SRC

#+REVEAL: split

- Cette configuration rendra disponible *1* volume de *10G*, qui pourra ensuite être utilisé avec /PersistentVolumeClaim/;
- =storageClassName: manual= indique que nous utilisons un stockage "statique";
- =ReadwriteOnce= indique que *seul un nœud* pourra monter ce stockage, il sera donc disponible uniquement pour les /Pods/ tournant sur ce nœud.

** /PersistentVolumeClaim/ (/PVC/)
Permet à un /Pod/ de demander l'accès au stockage

*** Créer un /PersistentVolumeClaim/
[[https://kubernetes.io/fr/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#cr%C3%A9er-un-persistentvolumeclaim][doc]]

#+BEGIN_SRC yaml
apiVersion: v1
kind: PersistentVolumeClaim  # un nouveau type
metadata:
  name: app-pv-claim  # un nom
spec:
  storageClassName: manual  # la classe du stockage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi  # la taille demandée
#+END_SRC

#+REVEAL: split

Vérifications:
#+BEGIN_SRC bash
❯ kubectl get pvc app-pv-claim
NAME            STATUS    VOLUME     CAPACITY   ACCESSMODES   STORAGECLASS   AGE
app-pv-claim    Bound     pv-volume  10Gi       RWO           manual         30s

#+END_SRC


** Utiliser ce stockage dans un /Pod/
*** Créer le /Pod/
#+BEGIN_SRC yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  volumes:
    - name: my-app-storage  # un nom pour le volume
      persistentVolumeClaim:
        claimName: app-pv-claim  # le nom du "claim" à utiliser
  containers:
    - name: my-app
      image: nginx
      ports:
        - containerPort: 80
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"  # point de montage dans le /pod/
          name: my-app-storage  # nom du stockage
#+END_SRC

* Méthode *dynamique*
- Il faut que l'admin ait configuré un contrôleur de stockage dynamique, avec /NFS/ par exemple.

** /PersistentVolumeClaim/ (/PVC/)
#+BEGIN_SRC yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs
  resources:
    requests:
      storage: 10Gi
#+END_SRC

#+REVEAL: split

- =ReadWriteMany= indique que ce /PVC/ pourra être monté dans plusieurs /Pods/
- =storageClassName: nfs= indique que nous allons utiliser la classe de stockage /NFS/

** Utilisation dans un /Pod/
- Exactement comme vu avant, il faut cependant changer le nom du /PVC/ utilisé

* La sécurité au sein de /K8s/
** De bonnes pratiques /Docker/
*** Définir un utilisateur

- Par défaut, votre application conteneurisée sera lancée en /root/ dans le conteneur.
- Il faut créer un autre utilisateur et indiquer à /Docker/ de l’utiliser avant de déclarer la commande ou le point d'entrée

#+REVEAL: split

Un /Dockerfile/:
#+BEGIN_SRC Dockerfile
FROM debian

# ...

RUN useradd test
USER test

# CMD / ENTRYPOINT
#+END_SRC

*** /Multi-stage build/
[[https://docs.docker.com/build/building/multi-stage/][doc]]

- Permet de n'embarquer *que* l'application donc *sans ses dépendances de build*.
- Réduit la taille de l'image finale.
- Réduit la surface d'attaque en limitant le nombre de paquets intégrés.

#+REVEAL: split

Un /Dockerfile/:
#+BEGIN_SRC Dockerfile
FROM debian as builder
RUN apt install -y nodejs npm
RUN npm install && npm run build

FROM nginx
COPY --from=builder /app/dist/html /var/www/html
#+END_SRC

** Des outils spécifiques à /K8S/
*** /Trivy/
- Permet de lister les vulnérabilités connues dans les /Pods/
- Permet de lister les vulnérabilités dues à la configuration du /cluster/

#+REVEAL: split

#+BEGIN_SRC bash
trivy k8s --report=summary
#+END_SRC

[[file:./images/trivy_summary.png]]
#+REVEAL: split

#+BEGIN_SRC bash
trivy k8s --severity=CRITICAL --report=all
#+END_SRC

[[file:./images/trivy_vulns.png]]


* Aller plus loin
- https://www.redhat.com/fr/topics/containers/intro-kubernetes-security
