Logo
Overview
Un Talos européen sécurisé de qualité à coût maîtrisé

Un Talos européen sécurisé de qualité à coût maîtrisé

October 31, 2025
21 min read (171 min read total)
10 subposts
Note (Dernière mise à jour le 26/05/2026)

Guide remis à jour pour Talos v1.13.3 et Kubernetes v1.36.1, ainsi que l’ensemble des charts Helm à date.

Talos devient au fil du temps la solution de choix pour déployer des clusters Kubernetes cloud ou bare metal hautement sécurisés et performants. Zéro SSH, API-REST first, à peine une douzaine de binaires embarqués, support chiffrement complet, cet OS est entièrement construit de manière conteneurisée et bootstrappé depuis le projet stagex, permettant un build entièrement reproductible et théoriquement insensible aux attaques supply-chain. Nous allons ici tenter de mettre en place un cluster kubernetes Talos sur des Cloud Service Providers européens (non GAFAM), le plus proche possible du production-grade, sans coût délirant.

Pour qui et pourquoi ? 🤔

Ce guide s’adresse aux devs à fortes inspirations DevOps/GitOps, principalement européens, adeptes du self-hosting, souhaitant s’affranchir des VPS à la papa et s’extirper de notre dépendance aux GAFAM, notamment :

  • De leurs coûts délirants, inhérents aux modèles économiques de ces hyperscalers.
  • De leur main mise sur nos données du fait du Cloud Act.
  • De leur opacité et aspect vendor-locking, du fait de l’intégration dans leur écosystème propriétaire, alors que l’écosystème standardisé Kubernetes offre de sérieuses alternatives via de puissants opérateurs.

En bref :

  • Vous pensez avoir avez fait le tour de Dokploy et/ou de tout ce qui est possible de faire à partir des solutions type Docker Swarm, qui reste toujours parfaitement adapté aux besoins simples.
  • Vous souhaitez passer au niveau supérieur, basé sur des solutions Kubernetes et vous rapprochez de ce qui se fait de mieux chez les hyperscalers sans pour autant en subir le coût*.
  • Aller plus loin que les solutions classiques type k3s / kubeadm montées à l’arrache vite fait sur des Debian abandonnées, et monter votre infra complète entièrement contrôlée en mode GitOps.
  • Avoir une chaîne de déploiement CI/CD complète, incluant tous les outils d’observabilité nécessaires.
Note (Coûts)

(*) En termes de coûts pour suivre ce guide, nous parlons ici d’un billet de ~65€/mois au minimum pour avoir quelque chose de potable, sinon partez plutôt sur du ~125€/mois pour du production-grade.

Le but ici est donc de se rapprocher raisonnablement et à notre échelle de ces hyperscalers sur le triptyque suivant :

  • La sécurité, via Zero Trust, chiffrement des données, mTLS, WAF (nous voulons aussi éviter les solutions de facilité tel que Cloudflare).
  • La résilience, via haute disponibilité, backups et Plan de Reprise d’Activité (PRA).
  • L’observabilité, à tous les niveaux, métriques, logs, traces.

Le sacrifice en échange ?

  • Des efforts et du temps…
  • Une plus grande part de responsabilité technique.

Les bénéfices :

  • Une maîtrise de la stack logicielle complète, infra incluse, du build jusqu’au run.
  • Un juste milieu entre les VPS à la papa et les hyperscalers.
  • Des coûts 100% maitrisés, aux rapports performances/prix d’un niveau sur lequel aucun CSP ne peut réellement rivaliser.

Et les solutions type OVHcloud ou Scaleway alors ? Très bien, c’est un vrai pas dans la bonne direction, et un excellent compromis entre le GAFAM et le cluster kube tout géré à la main. Si cela répond parfaitement à votre besoin alors nickel, vous pouvez déjà vous arrêter ici !

Mais il reste encore la problématique du coût, que ces Cloud Services Providers ont bien naturellement besoin de marger aux clients du fait du nombre toujours grandissant de services cloud proposés.

Comment ? 🛤️

Ici, ce guide se focalisera sur une seule ressource principale et essentielle : ce bon vieux VPS, mais cuisiné aux petits oignons. Exit les grands CSP multi-services managés, en dehors des S3, DNS, TEM (email transactionnel).

Sur tout ce que j’ai testé, Hetzner Cloud reste le leader incontestable du marché du VPS Cloud européen au rapport performance/prix imbattable, tout en disposant d’une interface UX et API/CLI simple et sans fioritures, uniquement centrée autour des VPS et des volumes. Il ne propose pratiquement aucun autre service managé mis à part le Load Balancer (l’Object Storage n’est d’ailleurs arrivé que très récemment), et c’est à peu près tout ce qu’on lui demande ! Il inclut également un provider terraform simple qui fait super bien son taf sans 15000 ressources à connaître (coucou les providers AWS/AZ).

Comme il est de rigueur, nous n’allons pas mettre tous nos œufs dans le même panier, et utiliserons à ce titre 2 cloud providers différents :

  • Hetzner Cloud : l’infrastructure principale, VPS / volumes / Load Balancers
  • Scaleway : pour la partie DNS, TEM (serveur de mail transactionnel), et S3, qui sera utilisé pour la partie stockage long-terme (logs / traces) et backups. Scaleway propose depuis très récemment SSE-ONE, un équivalent SSE-KMS assurant le chiffrement automatique côté serveur.
Proposition (Providers)

Pour faciliter le suivi de ce guide, vous devriez avoir un compte actif sur chacun ces 2 services. Seul Hetzner Cloud est réellement indispensable, L’autre étant fonction de vos préférences, qu’il faudra adapter. Mais vous devez à minima avoir un S3, un DNS, et un TEM prêt à l’emploi sous la main.

Les objectifs 🎯

  • Monter un cluster Talos fonctionnel européen sécurisé, résiliant, et totalement monitoré.
  • Tout en self-hosted ou presque, on maîtrise toute la brique infra logicielle.
  • Déploiement 100% GitOps via Terraform/OpenTofu puis FluxCD
  • Afin de comprendre et maîtriser chaque étape du processus, l’infra est construite en mode pas à pas, sans raccourci ni utilisation d’outil tout-en-un qui fait tout tel que terraform-hcloud-kubernetes.
  • Zero Trust de bout en bout, via l’utilisation de Tailscale.
  • Cluster construit avec la notion de worker pools, comme chez tous les providers d’infra cloud proposant du kube managé.
  • Chiffrement à tous les niveaux (volumes systèmes et externes, backups, s3, réseau pod à pod, mTLS).
  • Intégration de Cilium sur la couche réseau physique de l’infra Hetzner.
  • Intégration cloud (Network, Nodes et Load-Balancer) avec Hetzner Cloud Controller Manager.
  • Solution de volumes distribués et backups via Longhorn.
  • Du Ingress avec tout l’attirail qui va bien (cert-manager, Traefik, et CrowdSec en tant que solution WAF incluant analyse comportementale du trafic).
  • Un Ingress avec endpoint public via Load Balancer et endpoint privé à travers le réseau Tailscale pour l’accès aux outils internes.
  • Un cluster primary/replica PostgreSQL des familles via CloudNativePG, avec backup barman cloud sur s3 chiffré.
  • Un cluster Dragonfly (équivalent Redis).
  • Observabilité à tous les niveaux, monitoring complet via Prometheus/Grafana, logging et tracing distribué via Loki et Tempo en passant par le collecteur Alloy.
  • Mis en place d’une logistique CI/CD via Gitea Action et Flux, avec analyse de code via SonarQube, incluant l’observabilité post-déploiement, au travers d’un exemple de projet .NET API.

Un sacré programme, be brave.

Remark (Tailscale)

Petit aparté sur Tailscale :

  • Bien que boîte canadienne à la base, je ne connais pas de réel équivalent européen au niveau en termes de simplicité/efficacité pour mettre en place du Zero Trust.
  • Le client Tailscale est installable absolument partout, dont l’extension Talos officielle.
  • Toute la partie cliente est en Open Source.
  • Le réseau est chiffré de bout en bout via Wireguard, avec communication pair-à-pair, et les clés privées ne sont pas connues de Tailscale, le site central n’étant qu’un serveur de coordination.
  • Possibilité d’utiliser à la place headscale pour du self-hosted, mais ce ne sera pas le sujet de ce guide.
  • Pour les plus paranos, la feature Tailnet Lock permet même d’empêcher un client de rejoindre le réseau tailnet sans avoir été accepté par un autre client signataire de ce même tailnet. Tout est donc géré côté client et non plus par le serveur de coordination. À ce titre, même un serveur Tailscale compromis ne saurait donc forcer de lui-même un nouveau client malveillant au sein de notre réseau privé tailnet. Le corollaire étant de bien conserver les clés de lock au risque de perdre le contrôle du tailnet définitivement.

Pré-requis 🛠️

Déjà niveau prérequis ça va demander pas mal d’effort avant de commencer quoi que ce soit :

  • Un compte Hetzner Cloud.
  • Un compte Tailscale et être connecté sur votre tailnet de travail. Activer Tailnet Lock en option pour le maximum de sécurité, sinon activer au moins l’approbation manuelle d’un nouvel appareil.
  • Un service S3 avec fonction de chiffrement SSE-C. Un équivalent SSE-KMS en plus sera idéal, car certains services de backup comme barman cloud ne supporte pas le chiffrement client. On utilisera ici Scaleway. Activer le versioning pour être moins vulnérable aux ransomwares.
  • Un nom de domaine avec un accès admin au DNS (on partira sur ohmytalos.io ici). On réservera un sous-domaine int.ohmytalos.io pour l’accès aux outils internes.
  • Un compte de mail transactionnel, déjà actif et pré-paramétré sur votre nom de domaine, avec SPF/DKIM et tout le bousin. Si vous n’utiliser pas Scaleway pour la partie DNS, il faudra adapter le provider DNS-01 en fonction pour le challenge ACME.
  • Un environnement bash/zsh avec une belle brochette d’outils CLI préinstallés suivants : mise, fnox, sops, age, hcloud, talosctl, kubectl, helm, terraform, packer, flux. On n’est pas là pour déconner. L’utilisation de brew ou encore mieux mise est vivement recommandé pour les installer et mettre à jour facilement.
  • Outils complémentaires optionnels pour la productivité sur kube : cilium, cmctl, cnpg (plugin krew), k9s, ktop, kube-capacity, oh-my-zsh avec plugin kubectl pour les alias.
Warning (Gestion des secrets)

Pour des raisons de simplifications, nous n’utiliserons pas de secret manager à proprement parler dans ce guide, bien que ce soit la méthode recommandée pour la gestion des secrets dans Kubernetes en production, à des fins d’auditabilité et de possibilité de rotations.

Les secrets terraform seront chiffrés sur git localement via age + fnox, puis chiffrés at rest via etcd (le cas par défaut sur Talos), mais seront donc inévitablement visibles en clair dans le state Terraform (qui sera certe chiffré en SSE-C sur le bucket S3).

Pour la production, si vous êtes déjà chez Scaleway, je recommande Scaleway Secret Manager associé à EOS, pour une gestion centralisée et automatisée des secrets, déchiffrés uniquement au runtime.

Snapshots 💽

Nous allons avoir besoin d’uploader des images Talos prête à l’emploi pour la création à la volée de nos VPS. Un peu comme propose l’outil hcloud-upload-image, mais je préfère utiliser packer pour une approche plus GitOps.

La 1ère chose à faire est d’aller sur le site officiel de Talos Image Factory afin de construire vos images Talos personnalisées. Vous pouvez également créer un fichier de définition des extensions offline comme nous allons le faire ici.

Dans ce guide, nous allons avoir besoin de 2 types d’images :

  1. Une dédiée pour les control planes, contenant l’extension Tailscale pour accéder à nos nodes en mode zero-trust.
  2. Une dédiée par défaut pour les workers, sans Tailscale car l’on passera par les control planes pour y accéder, mais avec les extensions nécessaires au bon fonctionnement de Longhorn (iSCSI, util-linux-tools).

Créez-vous un nouveau répertoire projet ohmytalos-cluster puis les 2 fichiers suivants :

packer/schematic-cp.yaml
customization:
systemExtensions:
officialExtensions:
- siderolabs/tailscale

Récupérer les hashs d’identifiant de l’image comme suit :

Terminal window
curl -s -X POST --data-binary @schematic-cp.yaml https://factory.talos.dev/schematics | jq .id
# 4a0d65c669d46663f377e7161e50cfd570c401f26fd9e7bda34a0216b6f1922b
curl -s -X POST --data-binary @schematic-wk.yaml https://factory.talos.dev/schematics | jq .id
# 613e1592b2da41ae5e265e8789429f22e121aab91cb4deb6bc3c0b6262961245

2 infos importantes à retenir à partir de ce hash :

Pour chaque image, il faut prévoir une pour l’archi amd64, et une autre pour arm64, car l’on pourrait très bien imaginer des node pools sous différentes architectures. Rajouter autant de schematics que nécessaire, par exemple une contenant les drivers spécifiques pour des clusters de nodes GPU. On reflète tout cela dans le fichier packer suivant :

packer/hcloud.pkr.hcl
packer {
required_plugins {
hcloud = {
source = "github.com/hetznercloud/hcloud"
version = "~> 1"
}
}
}
variable "hcloud_token" {
type = string
default = env("HCLOUD_TOKEN")
sensitive = true
}
variable "schematic_id" {
type = string
default = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
}
variable "image_name" {
type = string
default = "default"
}
variable "talos_version" {
type = string
default = "v1.13.3"
}
variable "arch" {
type = string
}
variable "server_location" {
type = string
default = "nbg1"
}
locals {
server_types = {
amd64 = "cpx22"
arm64 = "cax11"
}
image = "https://factory.talos.dev/image/${var.schematic_id}/${var.talos_version}/hcloud-${var.arch}.raw.xz"
}
source "hcloud" "talos" {
rescue = "linux64"
image = "debian-13"
location = var.server_location
server_type = local.server_types[var.arch]
ssh_username = "root"
snapshot_name = "talos system disk - ${var.image_name} - ${var.arch} - ${var.talos_version}"
snapshot_labels = {
type = "infra",
os = "talos",
version = var.talos_version,
arch = var.arch,
name = var.image_name
}
token = var.hcloud_token
}
build {
sources = ["source.hcloud.talos"]
provisioner "shell" {
inline = [
"apt-get install -y wget",
"wget -O /tmp/talos.raw.xz ${local.image}",
"xz -d -c /tmp/talos.raw.xz | dd of=/dev/sda && sync",
]
}
}

Il nous est maintenant possible de construire notre image Talos personnalisée pour chaque architecture. Pour cela, nous allons avoir besoin de préparer notre token API Hcloud secrète dans notre environnement.

1er secret avec fnox et age 🔐

Nous utiliserons fnox pour la gestion de nos secrets locaux, notamment les secrets terraform qui seront chiffrés localement avant d’être poussés sur git. fnox supporte nativement age pour le chiffrement asymétrique, ce qui est idéal pour un cas d’usage simple, et nous allons l’utiliser pour générer notre paire de clés.

Terminal window
# 1. On génère notre clé privée et publique, à conserver précieusement dans votre gestionnaire de mot de passe
age-keygen -o ~/.config/fnox/age.txt
# 2. Récupérer la clé publique pour la config de fnox
grep "public key:" ~/.config/fnox/age.txt

Créer le fichier suivant à la racine de votre projet ohmytalos-cluster en y indiquant votre clé publique.

fnox.toml
[providers.age]
type = "age"
recipients = ["age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]

Créer un nouveau projet dédié sur Hcloud, générez-y une clé API read/write puis inscrivez-la dans votre environnement.

packer
fnox set HCLOUD_TOKEN "xxxxxxxxxxxxxxxxxxxxx" --provider age

Vérifier avec echo $HCLOUD_TOKEN pour vous assurer que la variable d’environnement est correctement définie.

Note (Team workflow)

À chaque intégration d’un nouveau membre d’équipe possédant sa propre clé privé age, il sera nécessaire de rajouter sa clé publique dans ce fichier puis refaire un fnox set sur chaque secret. Commande pratique pour tout rechiffrer :

Terminal window
fnox list | awk '/provider \(age\)/ {print $1}' | while read env_key; do
fnox set "$env_key" "$(fnox get "$env_key")" --provider age
done

Nous allons maintenant utiliser mise pour automatiser le build de nos images pour nos control planes et workers, créer le fichier suivant pour enregistrer nos tâches de build :

mise.toml
[tasks.install]
run = "packer init ."
[tasks.amd64-cp]
run = "packer build -var arch=amd64 -var image_name=cp -var schematic_id=4a0d65c669d46663f377e7161e50cfd570c401f26fd9e7bda34a0216b6f1922b ."
[tasks.arm64-cp]
run = "packer build -var arch=arm64 -var image_name=cp -var schematic_id=4a0d65c669d46663f377e7161e50cfd570c401f26fd9e7bda34a0216b6f1922b ."
[tasks.build-cp]
depends = ["amd64-cp", "arm64-cp"]
[tasks.amd64-wk]
run = "packer build -var arch=amd64 -var image_name=wk -var schematic_id=613e1592b2da41ae5e265e8789429f22e121aab91cb4deb6bc3c0b6262961245 ."
[tasks.arm64-wk]
run = "packer build -var arch=arm64 -var image_name=wk -var schematic_id=613e1592b2da41ae5e265e8789429f22e121aab91cb4deb6bc3c0b6262961245 ."
[tasks.build-wk]
depends = ["amd64-wk", "arm64-wk"]
[tasks.build]
depends = ["amd64-cp", "arm64-cp", "amd64-wk", "arm64-wk"]
Note (schematic_id)

Les hash schematic_id sont ceux récupérés précédemment depuis le site Talos Factory depuis l’exemple ci-dessus. Pensez à les modifier si vous avez créé vos propres images personnalisées.

Plus qu’à lancer mise build et c’est parti pour la construction de tous nos snapshots images Talos en parallèle. À la fin de l’opération, vous devriez obtenir 4 snapshots d’image prêt à l’emploi, visible dans l’onglet “Servers/Snapshots” sur Hetzner Cloud ou plus directement côté CLI via hcloud image list -t snapshot. Pour l’utilisation du CLI, pensez à créer puis activer le contexte auparavant via hcloud context create ohmytalos-dev puis hcloud context use ohmytalos-dev, une clé API uniquement en lecture suffira si vous choisissez la voie 100% terraform à la section 2 de ce guide.

Architecture cloud 🏭

Comme toute architecture kube qui se respecte, et à l’image des kubes managés des hyperscalers, notre IaC devra exprimer la notion de node pools, dans lesquels on indiquera les caractéristiques (type de machine par défaut, volumes, talos config, etc.) puis la liste des hosts. Chaque pool sera dédié à un type de workload spécifique. Dans ce guide, nous allons créer 2 node pools :

  1. Un pool de worker : dédié aux workloads applicatifs, dont les nœuds ferons également office de reverse proxy traefik et seront rattachés à un load balancer Hcloud dédié au trafic public.
  2. Un pool de stockage : dédié aux workloads type base de données, ainsi que backends de métriques, logs et traces, il sera composé de nœuds avec des volumes rattachés à haute capacité.

Architecture cluster

Remark (Node pool monitoring)

Afin d’optimiser les coûts, nous mélangeons ici dans les nœuds de storage du workload de base de données et de monitoring. Bien que largement suffisant pour un besoin standard, ce n’est pas forcément idéal en termes de scalabilité.

Au niveau production, il peut rapidement être préférable de mettre en place un pool de monitoring dédié à Prometheus/Loki/Tempo (au moins 2 serveurs pour le côté HA), ce qui permet de bien meilleure flexibilité en termes de dimensionnement horizontal. Vous n’aurez qu’à adapter le guide en fonction.

Côté choix du type de VPS, l’essentiel est de partir sur 4 Go de RAM (minimum requis) pour les control planes (3 fois pour HA), puis 8 Go de RAM pour les 5 workers, répartis sur les 2 node pools. Ensuite, vous aurez principalement le choix entre 2 typologies niveau performance/prix :

Type VPSCoût mensuel HT pour un clusterAvantages
cx23/cx33~60€Intel Skylake, option ultra-compétitive pour du kube pas trop dégueux.
cpx22/cpx32~120€AMD Genoa, plus recommandable pour du pro. Deux fois plus cher que la 1ère option, pour ~2.5 fois plus de performance par cœur.

Il faudra y inclure le load balancer lb11 à 6,57€ HT

En imaginant un cluster de staging utilisant l’option 1, et un cluster de production sur l’option 2, vous arriverez très grossièrement à un coût total mensuel TTC de ~200€ en comptant tout. À ce tarif, vous pouvez être certain d’avoir bien plus de performance sous le capot tout en étant largement 10 fois moins cher qu’un équivalent anémique chez les hyperscalers. Le tout en étant maître de votre infra de A à Z, avec les avantages, mais aussi disons-le, les inconvénients que cela comporte.

Architecture réseau 🌐

Avant de continuer, il est vital de bien poser l’architecture réseau de notre cluster. Il s’agit du système nerveux de Kubernetes, difficile de le changer après coup sans douleur, sinon à part le recréer. Nous allons dédier un subnet pour nos control planes et chaque node pool. Ce qui nous donne l’architecture suivante :

Adresse IP CIDRDescriptionNote
10.0.0.0/10Réseau principalPlage 10.0.0.0 → 10.63.x.x pour tout notre cluster
10.0.0.0/24Sous-réseau control planesPlage 10.0.0.x pour les control planes
10.0.1.0/24Sous-réseau node pool workerPlage 10.0.1.x pour les nœuds de workload principal
10.0.2.0/24Sous-réseau node pool storagePlage 10.0.2.x pour les nœuds de storage / DB
10.42.0.0/16Plage des pods kubePlage 10.42.x.x pour les pods kube
10.43.0.0/16Plage des services kubePlage 10.43.x.x pour les services kube
Warning (Route Controller)

Nous activerons plus tard le route-controller intégré dans hcloud-cloud-controller-manager afin de créer automatiquement les routes “physiques” dans le réseau privé hcloud pour chaque nœud, permettant la communication entre les pods, sans overhead au niveau OS.

La plage utilisée pour chaque route découlera de la plage choisie pour les pods, donc ici nécessairement de type 10.42.x.0/24 (allocation /24 par défaut dans kubernetes/CNI). Dans cette configuration le nombre maximum de nœuds possibles dans le cluster serait de 255, tous pools confondus, avec maximum ~250 pods par nœud (selon les adresses déjà réservées par kube).

Note (Exemples)

Tout découle de l’adresse du réseau principal. On utilise ici 10.0.0.0/10 afin de libérer de la place pour d’autres usages à côté du cluster. Cela laisse la place pour d’autres clusters à côté, par exemple sur 10.64.0.0/10, 10.128.0.0/10 et/ou 10.192.0.0/10. Exemple pour 10.64.0.0/10 :

Adresse IP CIDRDescription
10.64.0.0/10Réseau principal
10.64.0.0/24Sous-réseau control planes
10.64.1.0/24Sous-réseau node pool worker
10.64.2.0/24Sous-réseau node pool storage
10.106.0.0/16Plage des pods kube
10.107.0.0/16Plage des services kube

Si vous êtes certain de n’avoir besoin que d’un seul cluster par projet Hcloud, vous pouvez directement partir sur 10.0.0.0/8. Cela donnerai :

Adresse IP CIDRDescription
10.0.0.0/8Réseau principal
10.0.0.0/24Sous-réseau control planes
10.0.1.0/24Sous-réseau node pool worker
10.0.2.0/24Sous-réseau node pool storage
10.244.0.0/16Plage des pods kube (valeur par défaut)
10.96.0.0/12Plage des services kube (valeur par défaut)

Côté configuration Talos, il faudra bien préciser la plage des pods et services dans la section cluster.network :

cluster:
network:
cni:
name: none
podSubnets:
- 10.42.0.0/16
serviceSubnets:
- 10.43.0.0/16
proxy:
disabled: true
externalCloudProvider:
enabled: true

* Ne faite rien pour le moment, il s’agit juste d’un élément à garder en tête pour la prochaine section du guide.

Warning (CNI)

On désactivera le CNI natif flannel de Talos en indiquant cni.name à none, de même pour le proxy natif de kube. Le tout sera remplacé par Cilium, permettant de bénéficier nativement de eBPF.

On précisera cluster.externalCloudProvider.enabled à true puisque l’on utilisera le CCM externe Hetzner Cloud Controller Manager.

Architecture storage 🗄️

Chiffrement des disques 🔐

Le chiffrement sera effectué à tous les niveaux, non seulement côté Longhorn mais aussi côté système grâce au support de chiffrement natif de Talos via LUKS. Nous utiliserons la config indiquée dans la doc officielle. Il existe trois types de volumes à chiffrer, les 2 volumes système STATE et EPHEMERAL, valable sur tous les nœuds, ainsi que le volume utilisateur longhorn spécifique aux volumes Hetzner que l’on rattachera aux nœuds du pool de stockage. Nous aurons donc besoin de déclarer jusqu’à 3 configurations de volumes dans notre fichier de configuration Talos :

apiVersion: v1alpha1
kind: VolumeConfig
name: STATE
encryption:
keys:
- nodeID: {}
slot: 0
---
apiVersion: v1alpha1
kind: VolumeConfig
name: EPHEMERAL
encryption:
keys:
- static:
passphrase: supersecret
slot: 0
lockToSTATE: true
---
apiVersion: v1alpha1
kind: UserVolumeConfig
name: longhorn
encryption:
keys:
- static:
passphrase: supersecret
slot: 0
lockToSTATE: true

* De même cette partie sera traitée dans la prochaine section.

Nous utilisons des clés statiques en dehors du volume STATE afin de permettre la rotation des clés. Nouveauté de Talos 1.11, nous activons également lockToSTATE pour mixer la clé de chiffrement du volume EPHEMERAL et Longhorn avec un salt propre au volume STATE (utilisation d’une fonction de dérivation au niveau de la clé de déchiffrement). L’intérêt est que ces volumes soient indéchiffrables en cas de perte du volume STATE.

C’est le mode le plus sécurisé possible (en tout cas sur Hetzner Cloud à date), mais le moindre problème ou changement matériel entraînant une éventuelle modification de nodeID peut vous faire perdre l’ensemble des données du nœud. Toutefois l’utilisation de replicas Longhorn limite l’impact de la perte d’un nœud. Comme toujours un vrai backup externe sera toujours d’autant plus indispensable (naturellement chiffré). N’indiquez pas lockToSTATE (false par défaut) si vous préférez garder la possibilité de récupérer vos volumes en cas de perte du volume STATE.

Warning (Chiffrement des disques)

Les VPS disponibles par Hcloud ne supportent ni Secure Boot ni TPM à date. On se limite ici à une pass-phrase statique sur les volumes EPHEMERAL et Longhorn. Cette pass-phrase sera stocké dans le volume STATE lui-même chiffré via une clé unique spécifique au nœud.

Ne pas utiliser de pass-phrase statique sur les volumes STATE, cela rendrait tout le chiffrement inutile. En effet, la partition META, contenant notamment la config de la partition STATE dont la configuration du chiffrement, est forcément en clair.

Paramétrage Longhorn 🛠️

Pour automatiser au mieux la configuration des volumes pour Longhorn lors de son installation plus tard, le mieux est de préconfigurer les nodes en amont, via des labels et annotations spécifiques. Ils seront logiquement différents selon que ce soit un nœud de workload ou un nœud de stockage avec disque externe rattaché. Voici ce qu’on est en droit d’attendre comme labels et annotations pour chaque node pool selon notre schéma d’archi :

machine:
nodeLabels:
node.longhorn.io/create-default-disk: config
nodeAnnotations:
node.longhorn.io/default-disks-config: '[{"allowScheduling":true,"name":"system","path":"/var/lib/longhorn","tags":["local"]}]'
node.longhorn.io/default-node-tags: '["worker"]'

On s’assure que seuls les nœuds workers soient rattachés aux loads balancers via le label node.kubernetes.io/exclude-from-external-load-balancers sur les autres pools.

Le label node.longhorn.io/create-default-disk: config permet de personnaliser la configuration par défaut des disques Longhorn via l’annotation node.longhorn.io/default-disks-config. On indique ici au format json que l’on souhaite un disque system local sur chaque nœud et un disque volume supplémentaire sur les nœuds de stockage. Ce dernier devra être monté au préalable sur /var/mnt/longhorn côté Hcloud.

On précise le tag local vs volume pour différencier les types de disques dans Longhorn, notamment pour l’aspect performance. On veut s’assurer en effet que les workloads à forts besoins en IOPS (base de données, etc) soient bien placés sur les disques locaux, plus performant que les disques externe.

On rajoute enfin node.longhorn.io/default-node-tags pour faciliter le placement des futurs volumes.

Conclusion

Voilà pour la partie préparatif, il est temps de commencer pour de vrai à la prochaine section.