K3S/Mail - A (long) way to DevSecOps - Épisode 3

K3S/Mail - A (long) way to DevSecOps - Épisode 3

Rappel de la saga : A long way to DevSecOps : Épisode 1, Épisode 2, Épisode 3, Épisode 4, Épisode 5, Épisode 6, Épisode 7, Épisode 8.

Partager la donnée

Avant de déployer du service sur un cluster Kubernetes, il faut pouvoir avoir accès à un contrôleur de stockage qui sera accessible par tous les nœuds. J’ai donc choisi la simplicité dans l’environnement dans lequel je suis : un fournisseur NFS client.

Serveur NFS

Faire l’installation du serveur NFS :

sudo apt-get install nfs-kernel-server
mkdir -p /srv/nfs/kubedata && chown nobody:nogroup /srv/nfs/kubedata

Éditer le fichier /etc/exports pour donner l’accès à tous les nœuds :

/srv/nfs/kubedata <IP_ADDRESS1>(rw,sync,no_subtree_check) <IP_ADDRESS2>(rw,sync,no_subtree_check)

Désactiver le service rpcbind (pas utile pour NFS v4).

sudo systemctl mask rpcbind.service
sudo systemctl mask rpcbind.socket
systemctl disable rpcbind
systemctl stop rpcbind

Et aussi dans le fichier /etc/default/nfs-kernel-server (pour limiter le NFS au V4 et forcer à écouter sur le réseau local):

RPCNFSDOPTS="-N 2 -N 3 -H <IP_SERVER>"

Fournisseur NFS Client

Installer le fournisseur NFS :

Il suffira de déclarer dans la classe de stockage « managed-nfs-storage », pour instancier sur le partage NFS un volume.

Exemple :

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mail-storage
  namespace: mailserver
  labels:
    app: mailserver
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: managed-nfs-storage
  resources:
    requests:
      storage: 3Gi

Stratégies de déploiement

A partir d’un cluster Kubernetes, il y a plusieurs stratégies de déploiement :

YAML (Fichiers Manifest)

Si vous êtes arrivés jusqu’ici, et que vous avez lu le premier épisode, nous avons déjà utilisé des fichiers Yaml pour déployer Traefik. En gros cela explique à l’orchestrateur en langage « human readable » comment déployer le service qui est déjà pré-packagé sous forme de conteneur.

Pour rappel Kubernetes est expliquée en 3 minutes ici.

HELM

C’est en gros la même chose que précédemment. Mais pré-packagé et pré-configuré. Le Yaml c’est un peu la recette à suivre pour que l’application tourne bien, et Helm vient rajouter un peu de robot ménager pour cuisiner sans tout comprendre… C’est un bel outil, mais comme il faut que je comprenne et contrôle ce qui est effectué sur mon cluster Kubernetes je vais rester avec la première méthode. Nul doute que c’est un bel accélérateur et dans un but d’automatisation encore plus extrême ça peut être utilisé en complément à terme.

Communication

Le premier service que l’on va déployer est un serveur de mail. Celui-ci va permettre de connecter les différents services au monde réel.

J’ai testé mailu rapidement, mais par défaut il est trop lourd et fonctionne un peu bizarrement avec un Nginx interne et un Nginx pour l’Ingress pour la connexion au monde externe. Je suis parti finalement sur docker-mailserver, qui sera suffisant pour usage.

Mise à jour de Traefik

J’ai dû ajouter dans le fichier de configuration de Traefik le support de l’Ingress, car par défaut je n’avais activé que le support des IngressRoute via les CRD. L’avantage de ce dernier c’est le support des certificats Let’s Encrypt de manière « auto-magique ». Et le désavantage c’est de ne pas pouvoir forcément partager le « secret » avec les autres containers, s’il en ont besoin. J’ai donc mis à jour le code publié sur le GitHub pour traefik, il suffit de refaire un petit « apply », pour prendre en compte les modifications.

Installation de Cert-Manager

Cert-Manager (anciennement Kube-Lego) sera donc utilisé pour la gestion des certificats, et cela devrait être le cas par défaut. Celui-ci permet via la définition d’une ressource Ingress, demander un certificat (via différents protocoles comme ACME sur Let’s Encrypt, ou peut jouer le rôle de CA intermédiaire), puis le stocker dans un « Secret » qui sera encapsulé dans un objet « Certificate ».

Comme indiqué sur la doc il suffit de faire :

kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.15.1/cert-manager.yaml

Après il faut instancier un ClusterIssuer qui va pointer sur l’API Let’s Encrypt (il est possible d’utiliser un Issuer qui ne sera disponible que dans le namespace en cours d’utilisation) :

Déploiement de docker-mailserver

La documentation d’utilisation est suffisante pour installer ce package sur un cluster Kubernetes cependant :

  • Il faut patcher le fichier postfix-main.cf et enlever le nom de domaine de destination au niveau de « mysdestination »
mydestination = localhost.$mydomain localhost
  • Il faut bien mettre la clé privée Dkim encodée en base 64. On peut générer un couple de clé ici.
  • J’ai déployé en LB, cela permet d’y avoir accès sur toutes les interfaces externes des noeuds. Cela pourra être corrigé par la suite en utilisant les possibilités « Ingress » de Traefik, apportant plus de sécurité.
  • Il n’y a pas besoin de désactiver le SPF, l’IP publique présentée en externe en sortant sera la bonne. Cela dépend bien entendu de votre configuration.
  • Les enregistrements DNS ressemblent à ça :
domain.com.  0  MX  1 mail.domain.com.
mail._domainkey.domain.com. 0  TXT  "v=DKIM1;k=rsa; p=xxxx"
domain.com. 0  SPF  "v=spf1 a:mail.domain.com ~all"

Je vais publier à quoi ressemblent mes fichiers sur le GitHub prochainement. Stay tuned.

Conclusion

Nous avons vu dans cet épisode comment configurer un stockage pour notre cluster Kubernetes. Il faut noter que le nombre de volumes supporté est très important et qu’il y a toujours pleins de façon de faire. De plus nous avons déployé notre première vraie application sur le cluster avec son propre namespace. Cette application sera nécessaire par la suite car beaucoup l’utilisent comme base. Happy mailing !!!

Note : N’hésitez pas à faire part de vos commentaires sur le site ou Twitter, ça fait toujours plaisir et j’en profiterai pour améliorer les articles.