Vue lecture

Des vacances au clair de lune (ou comment faire son Geforce Now privé)

Il aura fallu beaucoup trop de temps pour que ça se produise, et je l’aurai travaillé au corps une paire de fois le gaillard, mais voilà, ceci est le premier billet invité de l’unique, l’irremplaçable Pierre-Marie ! Parce que c’était à la fois trop con comme cible de jeu, mais surtout trop rigolo vu le mix de technos abordées, parce qu’on va parler de Pokemon, de Sunshine/Moonlight (le titre ne ment pas), de wakeonlan, de Kubernetes, de Fission. Oui, tout ça en même temps. Vous comprenez mon enthousiasme ?

La puissance des algorithmes de ciblage

Au détour de mon scrolling sur X, je suis tombé sur un post parlant de jeux vidéos (l’algorithme est bien foutu) et sur une injonction à s’inscrire sur PokeMMO.
Pas fan hardcore de Pokémon, j’ai quand même bien poncé les deux premières gen et me suis tenté à la troisième.
Je fais partie des gens qui n’attendent plus grand chose de Game Freak qui, selon moi, ressort en boucle les mêmes jeux sans vraiment d’innovation.
Au contraire, côté développement non officiel, on retrouve des jeux dérivés comme Pokémon Showdown, qui malgré que ce ne soit pas mon style de jeu, attire une grande communauté et qui aurait pu donner des idées à Nintendo pour renouveler la licence.
J’ai, par exemple, plus apprécié le rom hack Pokémon Adventures Red Chapter basé sur l’excellent manga Pokémon La Grande Aventure que le remake Let’s Go Evoli.
Bref, je suis donc allé voir ce qu’était ce PokeMMO, et me suis motivé pour me lancer dessus. Ça tombe bien, je pars 2 semaines en vacances et il faudra bien occuper mes soirées au coin de la clim. (article commencé au mois de Juillet). PokeMMO propose un installer pour Windows, Linux, iOS, Android et même un package pour OS alternatif (j’ai vu pas mal de gens qui installaient ça sur une console portable de type Retroid).
Personnellement, j’ai à ma disposition une PsVita et une Switch, toutes deux libérées et qui me servent lors de mes sessions retrogaming. L’option téléphone/tablette est pour moi rédhibitoire ne possédant pas de manette compatible et aimant beaucoup trop les boutons physiques pour jouer au tactile.
Installer Android sur Switch me semblant trop fastidieux, j’ai décidé de partir sur une autre voie. Étant obligé d’être connecté pour jouer quoi qu’il arrive (le O de MMO, hein), je me penche sur Moonlight, que j’avais déjà testé il y presque 10 ans. Il y a des clients pour Switch et PsVita (et pour beaucoup d’autres OS/appareils) donc ça pourrait correspondre à mes besoins.

Installation de Sunshine/Moonlight

Moonlight, pour vulgariser, c’est un client non-officiel pour le protocole Nvidia Gamestream qui vient se connecter à un ordinateur distant pour le contrôler à distance. Il a la force de supporter les contrôleurs locaux et de transmettre au PC distant à la manière d’un Steam Link. Pour pouvoir streamer vers un client Moonlight, il faut un serveur sur la machine cible. Le logiciel Nvidia GeForce Experience permet cela mais la « nouveauté » par rapport à mon essai d’il y a 10 ans, c’est le serveur Sunshine qui permet de s’affranchir du logiciel de Nvidia.

L’installation de Sunshine se fait via l’installateur dédié à la distribution cible en quelques secondes. Une fois installé, Sushine se configure via une interface web accessible en local. Elle permet de gérer les différents clients (appairage, suppression…), les différentes applications et les options de streaming (encodage, bitrate…).

Le première étape est de créer un couple utilisateur/motdepasse pour protéger l’accès à cette interface.

Interface de configuration de Sunshine: Creation du mot de passe

Par défaut, Sunshine propose deux applications: Bureau et Steam Big Picture (même si Steam n’est pas installé sur le système)

Interface de configuration de Sunshine: Applications

J’installe donc PokeMMO et le configure comme Application dans Sunshine. Je reprends simplement les valeurs trouvées dans le raccourci Bureau qui a été crée lors de l’installation. Il détecte même la miniature automatiquement.

Interface de configuration de Sunshine: Création de l’application PokeMMO

J’installe le client Moonlight sur les deux appareils. Le client détecte automatiquement le PC supportant Sunshine et affiche un code d’appairage à entrer dans Sunshine.

Interface de Moonlight: Détection

Interface de configuration de Moonlight: Appairage

Interface de Sunshine: appairage

L’appairage se déroule sans problème et je peux tester le stream en local.

Interface de Moonlight: Écran d’accueil

Je lance l’application Bureau et ça me permet de confirmer qu’il est bien possible d’ouvrir une session Windows à distance.

Interface de Moonlight: Bureau

Pour le stream distant, il faut juste s’assurer que Upnp est activé sur le routeur et cocher une case dans la configuration de Sunshine.

Interface de configuration de Sunshine: Activation de l’Upnp

(ndr: sinon il faut définir les ports et ouvrir manuellement/créer les redirections de port; l’IP fixe pour le PC de jeu est fortement recommandée dans ce cas)

Fini ?

On aurait pu s’arrêter là, mais bon, je suis pas fan de laisser tourner le PC H24 pendant 2 semaines juste pour l’utiliser quelques heures. Moonlight propose une fonctionnalité bien pratique de Wake On LAN pour démarrer un ordinateur à distance, mais voilà, ça ne fonctionne qu’en réseau local (en même temps c’est dans le nom).
Il faut donc trouver le moyen de le faire fonctionner à distance. J’ai plusieurs dispositifs à ma disposition.
Mon routeur PfSense permet de d’envoyer des paquets WoL mais uniquement via l’interface, pas d’API disponible. Il faudrait se connecter à l’interface via VPN pour lancer la commande. C’est trop lourd et pas assez flexible.
Solution suivante, utiliser le cluster k3s qui tourne à la maison.

Utilisation de k3s

On teste la faisabilité du process en lançant un pod temporaire contenant la commande wakeonlan mais ça ne fonctionne pas car l’appareil ciblé n’est pas sur le LAN du cluster k3s comme l’est le pod.
En cherchant un peu, on trouve qu’il faut configurer le pod pour qu’il tourne dans le réseau hôte, le réseau des nœuds.

kubectl run tmp --rm -it --image nixery.dev/shell/wakeonlan -it --overrides='{"kind":"Pod", "apiVersion":"v1", "spec": {"hostNetwork":\ntrue}}' -- wakeonlan a1:b2:c3:d4:e5:f6

Et ça marche !!

Reste à trouver le moyen de lancer ça simplement, via un appel HTTP par exemple. Je viens justement de déployer un système de micro-services : Fission.
Fission permet de déployer des fonctions de micro-services à la manière d’un système Serverless comme Lambda. Ça me permettrait de recevoir une requête HTTP avec en paramètre l’adresse MAC cible et d’envoyer la requête WoL avec un simple code python.

Installation de Fission

L’installation de Fission est simple si on passe par leur chart Helm. On a juste à surcharger quelques valeurs grâce au fichier values.yml suivant.

## Fission chart configuration
##

## routerServiceType to consider while creating Fission Router service.
## For minikube, set this to NodePort, elsewhere use LoadBalancer or ClusterIP.
##
routerServiceType: ClusterIP

## defaultNamespace represents the namespace in which Fission custom resources will be created by the Fission user.
## This is different from the release namespace.
## Please consider setting `additionalFissionNamespaces` if you want more than one namespace to be used for Fission custom resources.
##
defaultNamespace: fission

# Add Fission helm repo
helm repo add fission-charts https://fission.github.io/fission-charts
# Install CRDs 
kubectl create -k "github.com/fission/fission/crds/v1?ref=v1.21.0"
# Install Fission
helm install fission fission-charts/fission-all -f values.yml -n fission --create-namespace
# Install Fission CLI binary
curl -Lo fission https://github.com/fission/fission/releases/download/v1.21.0/fission-v1.21.0-linux-amd64 && chmod +x fission && sudo mv fission /usr/local/bin/

Configuration de Fission

La documentation fission nous apprend qu’on peut modifier les spécifications des pods. Il y a même un tutoriel pour déployer un exemple.

# On créé un dossier dédié
mkdir wol-fn
cd wol-fn
# On initialise le dossier specs
fission spec init
# On créé l'environnement qui fera touner le code python
fission -n fission env create --spec --name python-wol --image ghcr.io/fission/python-env --builder ghcr.io/fission/python-builder
# On créé le dossier de la fonction
mkdir wol
# On créé un fichier requirements.txt avec le module python dont nous avons besoin
echo "wakeonlan" > wol/requirements.txt
# On créé le fichier contenant le code python à exécuter
touch wol/wol.py

from flask import request
from wakeonlan import send_magic_packet
import re

def main():
    mac = request.args.get('mac')
    if mac is None:
        return "Please send a MAC address"
    else:
        if re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", mac.lower()):
            send_magic_packet(mac)
            return "Sending magic packet to 255.255.255.255 with broadcast 255.255.255.255 MAC %s port 9" % (mac)
        else:
            return "%s is not a valid MAC format" % (mac)

On créé la spécification pour la fonction qui décrit quel code doit être exécuté et le trigger HTTP qui détermine quelle URL déclenche son exécution.

# On créé la spécification pour la fonction
fission -n fission function create --spec --name wol-fn --env python-wol --src "wol/*" --entrypoint wol.main
# On créé la spécification pour la route.
# Avec les annotations permettant de créer l'ingress rule sur Traefik
fission -n fission route create --spec --name wol-fn-get --method GET --url /wake --function wol-fn --createingress --ingressrule "test.domain.tld=/wake" --ingressannotation "kubernetes.io/ingress.class=traefik" --ingressannotation "traefik.ingress.kubernetes.io/router.entrypoints=websecure" --ingressannotation 'traefik.ingress.kubernetes.io/router.tls="true"' --ingressannotation "traefik.ingress.kubernetes.io/router.tls.certresolver=letsencrypt"

On a maintenant un dossier contenant la fonction et son environnement standard.

wol-fn
├── specs
│   ├── README
│   ├── env-python-wol.yaml
│   ├── fission-deployment-config.yaml
│   ├── function-wol-fn.yaml
│   └── route-wol-fn-get.yaml
└── wol
    ├── requirements.txt
    └── wol.py

On va modifier le fichier env-python-wol.yaml pour ajouter notre configuration spécifique.

---
apiVersion: fission.io/v1
kind: Environment
metadata:
  creationTimestamp: null
  name: python-wol
spec:
  builder:
    command: build
    container:
      name: builder
      resources: {}
    image: ghcr.io/fission/python-builder
    podspec:
      containers:
      - name: builder
        resources: {}
  imagepullsecret: ""
  keeparchive: false
  poolsize: 3
  resources: {}
  runtime:
    container:
      name: python-wol
      resources: {}
    image: ghcr.io/fission/python-env
    podspec:
      containers:
      - name: python-wol
        resources: {}
+     hostNetwork: true
+     dnsPolicy: ClusterFirstWithHostNet
  version: 3

La directive hostNetwork permet comme vu plus haut de faire tourner le pod sur le réseau hôte.
Avec juste cette modification, on a une erreur à l’exécution du code parce que le pod n’arrive pas à aller chercher l’archive contenant le code de la fonction sur le stockage partagé de Fission.

{
    "level": "error",
    "ts": "2025-08-22T15:55:03.884Z",
    "logger": "generic_pool_manager.generic_pool.fetcher_client",
    "caller": "client/client.go:114",
    "msg": "error specializing/fetching/uploading package, retrying",
    "error": "Internal error - error fetching deploy package: failed to download url : Get \"http://storagesvc.fission/v1/archive?id=%2Ffission%2Ffission-functions%2Ffc6798a9-95c3-47cb-8797-28f842162f83\": dial tcp: lookup storagesvc.fission on 9.9.9.9:53: no such host",
    "url": "http://X.X.X.X:8000/specialize",
    "stacktrace": "github.com/fission/fission/pkg/fetcher/client.sendRequest\n\tpkg/fetcher/client/client.go:114\ngithub.com/fission/fission/pkg/fetcher/client.(*client).Specialize\n\tpkg/fetcher/client/client.go:56\ngithub.com/fission/fission/pkg/executor/executortype/poolmgr.(*GenericPool).specializePod\n\tpkg/executor/executortype/poolmgr/gp.go:467\ngithub.com/fission/fission/pkg/executor/executortype/poolmgr.(*GenericPool).getFuncSvc\n\tpkg/executor/executortype/poolmgr/gp.go:553\ngithub.com/fission/fission/pkg/executor/executortype/poolmgr.(*GenericPoolManager).GetFuncSvc\n\tpkg/executor/executortype/poolmgr/gpm.go:242\ngithub.com/fission/fission/pkg/executor.(*Executor).createServiceForFunction\n\tpkg/executor/executor.go:239\ngithub.com/fission/fission/pkg/executor.(*Executor).serveCreateFuncServices.func1\n\tpkg/executor/executor.go:143"
}

On voit qu’il cherche à contacter storagesvc.fission et qu’il n’arrive pas à résoudre ce hostname, ce qui est normal étant donné qu’il s’agit d’un nom interne au cluster et que le pod tourne désormais sur le hostNetwork. La directive dnsPolicy: ClusterFirstWithHostNet permet de forcer d’essayer la résolution en interne au cluster avant de tenter en externe sur le hostNetwork et résout ce problème.

Il ne reste qu’à déployer.

# On vérifie la syntaxe
fission spec validate
# On déploie
fission spec apply --wait
# On test via Fission CLI
fission -n fission function test --name wol-fn --method GET -q "mac=a1:b2:c3:d4:e5:f6"
# On test via HTTP depuis l'extérieur
curl "https://test/domain.tld/wake?mac=a1:b2:c3:d4:e5:f6"

Pour faire simple, ajouter l’URL en raccourci sur le téléphone et en un clic, le PC est démarré. Personnellement, je l’ai intégré dans mon Home Assistant avec un bouton dédié.

Home Assistant Dashboard

Finalisation de la configuration

Celui qu’on adore détester

Il reste deux ou trois détails à régler. Par défaut, depuis Windows 10, quand on arrête le système, il se place en réalité dans un mode de veille prolongée pour permettre un démarrage plus rapide. Hors le *Wake On LAN* ne fonctionne pas sur ce mode de sommeil. Microsoft documente ça très bien ici. Il y est également expliqué comment désactiver ce mode pour pouvoir rétablir un mode d’extinction « normal ».

Je vous les remets à l’identique:

  • Dans Panneau de configuration, ouvrez l’élément Options d’alimentation
  • Sélectionnez le lien Choisir ce que les boutons d’alimentation font
  • Désactivez la case à cocher Activer le démarrage rapide (recommandé)
  • Sélectionnez Enregistrez les paramètres.

Une fois cette modification effectuée, le Wake On LAN est complètement fonctionnel.

La fin

Et donc, puisqu’on a abordé le sujet, comment se passe l’extinction ? Vous vous rappelez ? le but de tout ce foutoir, c’était d’éviter de garder le PC allumé pendant deux semaines. On a parlé du démarrage, mais quid de l’arrêt ?

Le plus simple est de lancer une session Bureau dans Moonlight et d’aller cliquer sur le menu Démarrer puis le bouton Arrêter comme à la maison. Mais on peut aussi déclarer des applications dans Sunshine et il exécutera la commande associée à cette application.

J’ai donc créer une application nommée Shutdown qui lance la commande suivante shutdown /s /f /t 0.

Interface de configuration de Sunshine: Shutdown Application

Quand elle est lancée depuis le client Moonlight, elle éteint le PC distant.

Feedback et Conclusion

Puisque je suis rentré depuis, je peux débriefer ces 2 semaines d’utilisation, ça fonctionne super, le seul défaut que j’ai eu est qu’une fois le Shutdown n’a pas fonctionné et je ne l’ai pas vu tout de suite. Les fois suivantes, j’ai juste eu à bien vérifier le status dans le menu.

Interface de Moonlight: PC démarré

Interface de Moonlight: PC éteint

À part ça, super expérience ! Bien sur je n’ai pas cherché à jouer à des jeux très performants, mais ça a suffi à mes besoins, même en 4G. Je n’ai pas non plus poussé jusqu’à tenter de jouer sur la 4G en voiture, mais je pense que ça aurait pu marcher.
Je continue à l’utiliser, même à la maison, pour jouer dans le canapé plutôt que devant le PC.

Interface de Moonlight: PokeMMO


Alors, avouez que c’est pas mal en termes de bricolages inutiles donc indispensables, il était donc nécessaire de partager ça avec le plus grand nombre ? (enfin au moins les lecteurs de ce blog)

  •  

GoBackup - Pour sauvegarder vos bases de données facilement

Vous savez, ce script bash de backup que vous avez écrit en 2018 et que vous n’osez plus toucher ? Celui avec les 150 lignes de mysqldump + tar + gzip + aws s3 cp qui marche à moitié et que vous relancez manuellement quand il plante ?

Hé bien vous allez pouvoir le foutre à la poubelle parce que maintenant y’a GoBackup !

GoBackup c’est un binaire codé en Go qui remplace tous vos scripts de backup maison d’un coup. MySQL, PostgreSQL, MongoDB, Redis, peu importe. Local, FTP, S3, Google Cloud, Azure, peu importe. Vous installez, vous configurez un fichier YAML, et c’est fini.

Ensuite, vous n’aurez plus jamais besoin de retoucher à tout ce bordel.

Avant GoBackup y’avait backup/backup, une gem Ruby qui faisait exactement ce job avec de la sauvegarde automatique, multi-bases, multi-destinations et c’était bien. Sauf que Ruby c’est lourd et les dépendances Ruby c’est l’enfer. Du coup le projet est mort tout doucement. Heureusement, huacnlee, un dev chinois, en a eu marre alors il a tout réécrit en Go. Zéro dépendance externe et un seul binaire compilé (installable aussi avec Brew pour ceux qui sont sous macOS).

Vous pouvez l’installer comme ceci (vérifiez le script) :

curl -sSL https://gobackup.github.io/install | sh

Ou via homebrew comme ceci :

brew install gobackup

Avec GoBackup, vous définissez vos bases de données, vos fichiers à archiver, vos destinations de stockage, votre planning, tout dans un fichier YAML propre et ensuite le binaire gère tout : Compression, chiffrement, upload, rotation des backups, notifications si ça échoue…etc. Bref, tout ce que vous faisiez à la main avec vos scripts pourris.

Et GoBackup est pas juste un CLI (Interface en ligne de commande). C’est un CLI + un daemon + une Web UI + un scheduler. Comme ça vous lancez “gobackup start” et ça tourne en background.

Le daemon surveille alors le planning défini dans votre config et lance les backups automatiquement. Et l’interface web vous permet de voir l’état des backups, les logs, les erreurs.

Avec GoBackup, vous remplacez littéralement 5 outils en un : votre script bash + cron + un monitoring pourri + un truc pour lire les logs + l’interface d’admin que vous avez jamais eu le temps de faire.

Votre config ressemble à ça :

models:
 mon_app:
 compress:
 type: tgz
 databases:
 mon_mysql:
 type: mysql
 host: localhost
 database: ma_base
 username: user
 password: $MYSQL_PASSWORD
 storages:
 mon_s3:
 type: s3
 bucket: mes-backups
 region: eu-west-1
 access_key_id: $AWS_KEY
 secret_access_key: $AWS_SECRET
 schedule:
 every: 1day
 at: "04:05"

Et c’est tout. Avec ce fichier, GoBackup dump votre base MySQL tous les jours à 4h05, compresse en .tar.gz, chiffre si vous voulez, et upload sur S3. Et si ça échoue vous recevez une notif. Et si ça marche vous avez les logs comme ça, pas besoin de surveiller, ni de débugger à 3h du matin parce que le backup a planté et que vous avez perdu 6 mois de données.

Notez quand même que GoBackup fait du backup classique, et pas du backup incrémental intelligent à la Restic ou à la Borg donc si vous avez 500 GB de données à backup tous les jours vous allez peut-être préférer un outil plus sophistiqué mais pour 90% des cas d’usage sysadmin standard, GoBackup suffira largement.

Votre script bash dégeu a eu une belle vie, il peut maintenant partir à la retraite.

  •  

Cyberattaque contre l’entreprise Xplain: conséquences pour fedpol et mesures prises

Cyberattaque contre l’entreprise Xplain: conséquences pour fedpol et mesures prises

Début juin 2023, il a été rendu public que l’entreprise suisse Xplain, un fournisseur de logiciels destinés aux autorités de sécurité et aux organisations d’intervention d’urgence, avait été victime d’une attaque par ransomware du groupe de cybercriminels Play. En accord avec la Confédération et les autorités de poursuite pénale, l’entreprise Xplain n’a pas répondu aux demandes de rançon des cybercriminels. À la mi-juin 2023, ceux-ci ont alors publié sur le darknet le lot de données dérobées. fedpol est concerné par cette fuite de données, tout comme d’autres unités administratives fédérales et cantonales.
L’entreprise Xplain a annoncé le cyberincident à l'Office fédéral de la cybersécurité (OFCS) et déposé une plainte auprès de la police cantonale bernoise.
Xplain a informé fedpol du vol de données le 23 mai 2023. Après avoir pris connaissance de l’incident, fedpol a déposé une plainte pénale contre inconnu auprès du Ministère public de la Confédération et a informé le Préposé fédéral à la protection des données et à la transparence (PFPDT) de la fuite de données.
Dans quelle mesure fedpol est-il concerné?

Le volume des données volées et publiées sur le darknet concernant fedpol connu à ce jour (septembre 2023) équivaut à moins de 10 % du volume total. Grâce à ses propres analyses, fedpol a constaté déjà à un stade précoce que des données opérationnelles étaient notamment concernées. Il a donc pris sans délai des mesures préventives afin de protéger les personnes, les données, les infrastructures, les objets et les procédures concernés.

D’après les connaissances actuelles, les données détournées comprennent des données personnelles (par ex. nom, prénom, date de naissance) et, dans certains cas, des données sensibles de personnes physiques (par ex. photos du visage). Les analyses ont mis au jour, parmi les données dérobées et publiées, un fichier XML remontant à 2015 qui comprend certaines données du système d’information HOOGAN. Sont enregistrées dans ce système les personnes qui ont affiché un comportement violent lors de manifestations sportives en Suisse ou à l’étranger et contre qui le canton compétent ou fedpol a prononcé une mesure en vertu de l’art. 24a de la loi fédérale du 21 mars 1997 instituant des mesures visant au maintien de la sûreté intérieure (LMSI). Le fichier XML publié sur le darknet contient un code technique avec des données concernant 766 personnes saisies dans HOOGAN en septembre 2015. Il ne contient aucune information sur des infractions ou des mesures prononcées (cf. communiqué de presse du 12 juillet 2023).


Permalien
  •  

Par où commencer Kubernetes ?

Réflexion issue d’une discussion sur le Discord de Cuistops concernant le fait que Talos pourrait ne pas être le meilleur point de départ pour s’attaquer à cette technologie d’infrastructure qui a balayé le monde de l’orchestration de containers en une petite dizaine d’années. Pour illustrer pourquoi il n’y a pas de réponse absolue à cette question, je me suis dit que vous décrire mon parcours concernant l’univers des containers et Kubernetes en particulier (aussi bien au niveau perso que pro) serait éclairant sur certains points.

Aux origines : Docker

Le moins qu’on puisse dire, c’est que mon entrée dans l’univers des containers, en particulier via docker, n’était pas brillante. Je conserve avec malice le premier billet que j’ai consacré à ce sujet en 2016 pour illustrer à quel point je me trompais sur la technologie, que je n’avais jusque là pas vraiment vu, encore moins au niveau professionnel. J’ai heureusement rattrapé cette erreur depuis, aussi bien à la faveur de formations au travail (merci Thomas Perelle 🙂 ) qu’au niveau perso, où mes propres expérimentations m’ont conduit à partager ma découverte et mon utilisation de Docker Swarm. J’ai bien rattrapé le coup, hein ?

D’ailleurs, Swarm a été pour moi la découverte de la notion d’orchestration. Que j’ai pu creuser cette fois au niveau pro en 2018 après un premier tout petit pas vers l’univers Kubernetes par la porte OpenShift à la faveur d’un workshop de deux jours par un collègue qui sera réellement un mentor pour les années suivantes, Julien Francoz. Je n’ai malheureusement pas gardé grand chose de ce workshop, étant donné que je n’avais aucune plateforme de ce type dans mon pôle client, encore moins de Kubernetes. Tout juste on commençait à avoir des clients qui cherchaient à déployer leurs applis en mode container sur des serveurs classiques, avec Docker. Sans pratique, la théorie s’efface vite, d’autant qu’en 2018, les usages « domestiques » n’étaient pas légion, donc les articles de blog non plus, encore moins autour d’Openshift. C’est en 2019 que tout change.

2019 : La découverte de Kube, de la containerisation d’applications, d’Azure, de terraform (tout en même temps)

Je vous passe le contexte de comment j’en suis arrivé à cette situation intense qui aura duré 5 mois, mais oui, j’ai découvert Kubernetes d’une façon un peu particulière : service cloud managé, sur Azure, el famoso « AKS« , à devoir migrer des applications précédemment hébergées sur des serveurs virtuels Debian dépassés, avec un cluster déployé manuellement qu’on a tenté de « terraformer » après-coup, avec toute la « qualité » de l’API d’Azure d’alors. Et je remercie encore Julien d’avoir pris autant de temps à me soutenir dans cet apprentissage express (la notion de mentor n’était pas galvaudée, clairement).

Moi pendant la migration du client sur Kubernetes

Service cloud Managé veut dire qu’on ne gère pas certains aspects importants de la vie d’un cluster : tout le control plane est masqué, vous ne voyez que les nœuds, vous ne vous occupez pas trop de certains aspects comme la rotation des certificats, les mises à jour sont automatisées (vous indiquez une version cible, le service s’occupe de la montée de version du control plane, puis des nœuds un par un), et vous bénéficiez d’intégrations avec le reste de l’infra du fournisseur, au niveau du réseau, du stockage, des capacités comme l’autoscaling (vous augmentez et réduisez automatiquement le nombre de nœuds en fonction de la charge ou des réservations de ressources des pods à déployer). L’installation se fait en trois/quatre clics via l’interface web, une ligne de commande avec l’utilitaire maison, ou un peu plus de lignes de code si on le fait via un outil d’infrastructure as code.

Bref, c’est cool, ça permet de se concentrer sur les aspects opérationnels des applications déployées, mais même comme ça, je vous avoue que AKS tel que Microsoft le proposait n’était pas toujours une sinécure. Azure lui-même était pénible, avec des VMs qui mettaient plusieurs minutes à démarrer (quand les concurrents tournaient autour de la minute). Et comme on ne gère pas le control plane, on rate tout un pan de l’architecture et de la gestion de Kubernetes et de ses composants sous-jacents. En plus à l’époque, l’image de l’OS utilisé pour les nœuds était basée sur Ubuntu, pas le plus léger et le « gaspillage » de ressources était réel, au-delà de Kubernetes lui-même.

J’aurais l’occasion de passer encore quelques années, pratiquement trois, à déployer d’autres projets AKS pour d’autres clients, ce qui m’a permis de constater, il faut savoir aussi le reconnaitre, comment Microsoft a cravaché pour amener un niveau de qualité sur le service bien plus en phase avec ce qu’on attend d’un tel fournisseur. Rotation automatique des certificats via les mises à jour (c’était pas le cas, la commande de rotation était à lancer à la main), amélioration générale d’Azure sur les temps de démarrage des nœuds, efficacité des mises à jour, intégrations avancées au niveau réseau (Calico, Istio, etc)… Ce qui n’empêche pas certains pains avec entre autres une API qui accepte certaines valeurs pourtant non supportées et qui m’ont forcé à redéployer des clusters from scratch parce que la communication entre les nœuds étaient devenue impossible (réponse du support : « on va mettre à jour la doc pour indiquer les valeurs supportées »; bravo…). Par la suite, j’ai découvert et encore plus adoré exploiter et déployer du GKE, le service équivalent de Google Cloud; il m’aura permis au passage d’apprendre comment fonctionnait ce fournisseur et tout ce qu’il fait de mieux que Microsoft (et parfois d’AWS). Au point de passer la certification « Professional Architect » au bout de 4 mois seulement de pratiques.

Kube à la maison

Cette expérience en particulier avec Azure ne m’aura pas empêché pas de tomber amoureux de la technologie, au point de remiser Docker Swarm, et de migrer sur K3S. Là aussi un choix particulier, conçu pour les machines très légères, puisque ciblant les Raspberry Pi, j’ai malgré tout fait le déploiement du flemmard, même si j’ai privilégié un déploiement semi-automatisé avec un playbook/role Ansible, et un seul nœud comme control plane (qui était le seul mode de déploiement supporté alors).

Particularité de k3s, regrouper tous les composants « core » de Kubernetes dans un seul binaire, une petite prouesse à la base de son empreinte mémoire réduite, mais pas que : un des éléments les plus critiques d’un cluster, la base de données ETCD, la « mémoire » du cluster, est remplacée par SQlite, bien plus léger, mais évidemment limité à une seul nœud, et moins enclin aux problèmes des bases de données plus complexe. Bien que le mode « multi-master » ait été implémenté par la suite, au passage à mes Raspberry Pi 4, j’ai quand même conservé le même mode de fonctionnement. J’ai eu l’occasion de détailler pas mal de choses concernant K3S sur ce blog, je ne vais donc pas m’étendre beaucoup plus.

Reste qu’à l’occasion d’une volonté de refonte, accélérée par la mort successive des cartes SD des Raspi après 4 ans de bons et loyaux services, j’ai décidé de revenir à un Kubernetes un peu moins simplifié, en partant sur un autre choix particulier, Talos Linux, qui aura fini en machine virtuelle suite à une déconvenue de matériel et de limitations électriques, que je me suis pris en pleine poire en plein live Twitch. Talos propose un déploiement Kubernetes beaucoup plus standardisé dans ses composants de base, mais dont la gestion des nœuds est très particulière : pas d’OS à proprement parler, juste le noyau et une API qui permet de pratiquer toutes les opérations sur la gestion de ces nœuds : pas de SSH, pas de CLI directe, l’utilitaire talosctl est là pour configurer les nœuds à l’envi, permettant de les ajouter/retirer d’un cluster en un clin d’œil, un aspect très important dans une gestion d’infrastructure au sens large (comprendre, en entreprise). Toute la configuration de base se fait au travers de fichiers de configuration YAML, à l’instar de Kubernetes lui-même, permettant une approche « intégration continue » et un versionnement via git.

Actuellement, je me débats avec certains paramétrages par défaut orientés sécurité entre autres qui peuvent limiter/bloquer certains usages sans attention particulière. Il est vrai que par défaut, Kubernetes est une plateforme particulièrement ouverte avec peu de gardes-fous, et c’est à chacun d’adapter cet aspect en fonction de son propre contexte, ce qui amène à devoir exploiter nombre d’extensions et contrôleurs additionnels pour y parvenir. Et comme souvent, la sécurité à un prix…

Et la question de départ ?

On le voit, au final je n’ai que peu choisi comment j’ai découvert et abordé la technologie et son déploiement « dans le monde réel », et j’ai démarré par certaines abstractions qui font que si je m’étais retrouvé face à un cluster « vanilla » (kubeadm, kubespray), et un problème lié au control plane, j’aurais été plus en peine que quelqu’un ayant directement attaqué « the hard way » (z’avez la ref ?). Et d’un certain côté c’est certainement encore le cas encore aujourd’hui, ce qui me vaudrait d’être recalé au recrutement chez Lucca ou Enix. Le livre à venir teasé par Denis Germain (qui ne s’appellera pas 50 Nuances de Kubernetes, ce qui aurait été bien trop cool comme titre) montre bien la diversité d’approches qui ont chacune leurs spécificités, avec la plupart des services dit « managés » abstrayant une bonne partie des composants et concepts de bas-niveau pour vous concentrer sur vos applications ou celles de vos clients.

Est-ce que l’une d’elles est meilleure qu’une autre ? Je considère toujours que la théorie est importante, jusqu’à un certain point, dans la mesure où si on n’a pas de le contrôle sur les éléments, ne pas savoir comment ils fonctionnent de manière sous-jacente n’est pas toujours une grosse tare : ce n’est pas de notre ressort que d’y mettre les mains. Imaginez une corruption de base ETCD sur un service managé. Ma seule préoccupation sera d’être capable éventuellement de restaurer tout ce que j’y ai mis au départ – mes déploiements d’applications, mes secrets, mes CRDs, etc- , là où la préoccupation du provider, sera de réparer cette corruption; dans le pire des cas, s’il n’aura pas été capable de restaurer le service avec un minimum de pertes, il s’agira de restaurer tout ça sur un nouveau cluster.

Nous vivons également dans un monde connecté à la plus grande base de connaissances du monde : Le Web. Je n’ai pas besoin de connaitre l’intégralité des arcanes du moindre bout de logiciel, quelque soit son niveau dans l’environnement où j’évolue, pour être capable de l’exploiter au quotidien, voire de le réparer. Les connaissances déjà acquises sont évidemment importantes, parce qu’elles permettent de définir un état d’esprit, un mode de réflexion, qui est la plupart du temps applicable aux autres technologies que vous rencontrerez. Mais si je rencontre un problème que je n’ai pas déjà vu par le passé, une recherche sur le web m’amène généralement soit à la solution, soit à une piste à creuser pour déterminer la cause. Dès lors, il n’y a pas de réponses simples à apporter à la question « par où démarrer », parce qu’elle peut dépendre aussi de la « fin ».

Par où on attaque ? 😀

Faire un cluster à la mano avec tous les composants en mode « the hard way » ne sert pratiquement à rien si après on évolue dans un contexte de service managé. À l’inverse, un service managé est intéressant en ce sens qu’il permet de gérer les interactions avec d’autres services du fournisseur, et donc le mode de fonctionnement de celui-ci. Sur Kube lui-même vous manquez des choses, mais vous avez quand même pas mal de concepts à intégrer. Est-ce moins pertinent ? Pas forcément si c’est ce que vous manipulez tous les jours. Dans le même esprit, « the hard way » est probablement la pire méthode pour gérer le quotidien sur de l’infra qu’on gère, même si pour le coup on a toutes les tripes du cluster sur la table. On privilégiera donc très vite d’autres outils plus automatisés pour la gestion habituelle. N’est-ce pas tout aussi pertinent de démarrer directement avec ces solutions pour intégrer plus rapidement leurs concepts ?

Par où commencer Kubernetes ? J’ai envie de dire, par la solution qui vous rendra curieux. C’est tout le sel de l’apprentissage, comme de la recherche scientifique, où chaque réponse qu’on trouve amène d’autres questions, tout aussi passionnantes. D’autant plus que quand on démarre, on est amené à faire, défaire, refaire, à comparer. Notre univers informatique au sens large bouge tout le temps, la « galaxie » Kubernetes n’est pas en reste, il y a toujours des dizaines d’angles d’attaque possible, et à de très rares exceptions près, il n’y en a pas nécessairement une qui est plus mauvaise qu’une autre. Et d’autres apparaitront régulièrement, ce qui représente de nouvelles réponses possibles à cette question. Il ne faut pas avoir peur de se faire plaisir de différentes manières 🙂

  •  

Certificat « SSL » : petites bricoles autour des courbes elliptiques

Les courbes elliptiques, c’est la promesse de la robustesse des communications chiffrées de TLS sans la lourdeur des tailles de clés utilisées avec l’algorithme RSA. Il ne sera pas question de mathématiques aujourd’hui (je suis trop mauvais pour ça, vous avez qu’à voir Wikipedia pour ça), juste de quelques notes sur leur utilisation, pour du certificat autosigné, de la vérification, et un micro rappel de Let’s Encrypt.

Faites une petite recherche rapide, et 99,9% des tutos pour générer un certificat, que ça soit pour de l’auto-signé, ou dans le cadre de la commande chez une autorité « classique », et vous aurez du RSA avec un panel de 2048 à 4096 bits de taille de clé. Sans faire de benchmark, je peux vous assurer que si 2048bits est assez classique, 4096 ça commence à être assez lourd à gérer. Les courbes elliptiques sont des objets mathématiques qui promettent de garder la complexité mathématique, clé de la robustesse en matière de cryptographie, mais avec une taille de clé beaucoup plus réduite, ce qui permet d’améliorer la consommation de ressources et la performance du chiffrement des communications, parce que c’est le contexte dans lequel elles ont été envisagées et déployées.

Le certificat auto-signé

Typiquement, pour déployer un virtualhost « par défaut » sur mon serveur web Nginx, j’ai voulu générer un certificat auto-signé certes, mais avec les courbes elliptiques comme base cryptographique. C’est plutôt simple au final, ça se joue en à peine plus de temps, ça repose sur l’incontournable OpenSSL, malgré les problèmes qu’il pose ces dernières années, surtout en tant que bibliothèque applicative. On commence par lister les courbes disponibles :

openssl ecparam -list_curves

Vous choisissez ce que vous voulez, pour des raisons de compatibilité, j’ai sélectionné secp384r1 qui est la plus utilisée derrière sa petite sœur en 256bits et qui est nommée prime256v1 (parce que nique la cohérence, hein). C’est au passage celle que j’utilise sur le blog 😉

Ensuite, on fait les étapes classiques pour un autosigné :

openssl ecparam -genkey -name secp384r1 -out key.pem
openssl req -new -sha256 -key key.pem -out csr.csr
openssl req -x509 -sha256 -days 365 -in csr.csr -out certificate.pem

Pendant la phase de création du CSR, vous répondez comme vous le souhaitez aux questions, comme on est sur de l’autosigné vous pouvez être créatif si ça vous chante 🙂

Et voilà, vous n’avez plus qu’à renseigner la clé et le certificat dans votre Virtualhost par défaut, comme ça, si vous interrogez l’IP de votre serveur web, c’est ce certificat « placeholder » qui apparaitra (autosigné certes, mais certificat quand même) et ça masquera le reste de vos virtualhosts, parce que sinon le serveur web présente le premier chargé dans les configurations incluses (je me demande si j’en ferai pas une démo en live tiens…).

Vérifier la correspondance clé/certificat

Oui je sais ça parait con, mais ça m’est déjà arrivé une quantité beaucoup trop importante de fois de ne pas être certain qu’un nouveau certificat à installer correspond encore à la clé qui est déjà déployée, ou si une nouvelle clé à été générée pour l’occasion. La joie de l’infogérance et des tickets traités par plusieurs admins successivement.

Idem, quand on cherche les manipulations à effectuer, on trouve quasi systématiquement la méthode basée sur le modulus. Sauf que cette méthode est propre à l’algorithme RSA, et n’est donc pas applicable pour des courbes elliptiques. Malgré tout, on peut s’en sortir. L’astuce consiste cette fois à comparer la clé publique entre la clé et le certificat. D’abord pour la clé :

openssl ec -in key.pem -pubout |openssl md5

openssl x509 -in certificate.pem -noout -pubkey |openssl md5

Si les deux résultats sont identiques, vous pouvez les charger dans le serveur web (ou dans l’interface de votre fournisseur d’infrastructure, si vous êtes dans le claude).

La génération pour Let’s Encrypt via acme.sh

Let’s Encrypt (et certainement d’autres fournisseurs) supporte les courbes elliptiques depuis un moment déjà. Personnellement, je préfère utiliser le léger acme.sh plutôt que l’officiel certbot, que je trouve particulièrement lourd. La génération est plutôt simple :

acme.sh --issue --ecc -k ec-384 -d www.domain.tld -w /var/www/ --debug

Évidemment c’est à adapter au domaine, et au dossier par lequel il va bosser le challenge. Perso je préfère ensuite faire une installation dans un dossier dédié pour inclure la commande de rechargement du serveur web derrière :

acme.sh --install-cert -d domain.tld --fullchain-file /etc/nginx/ssl/domain.tld.crt --key-file /etc/nginx/ssl/domain.tld.key --reloadcmd "systemctl reload nginx"


Voilà, comme on le voit, il ne faut pas grand chose pour passer à cette méthode cryptographique, et investiguer à son sujet est à peu près aussi simple qu’avant. Juste je trouve qu’il y a vraiment peu d’articles qui incluent les courbes dans les manipulations. Bon ben voilà 😀

  •