talosctl-oidc : ajouter le SSO à Talos Linux
Si vous me lisez régulièrement, vous savez que j’ai une vraie affection pour Talos Linux. C’est l’OS que je recommande sans hésitation pour faire tourner Kubernetes : immuable, minimaliste, sans SSH, avec une API gRPC pour tout administrer. En bref, c’est ce que devrait être un OS cloud-native.
Mais il y a un truc qui m’a toujours un peu gêné : l’authentification. Talos utilise du mTLS (mutual TLS) pour protéger son API. Concrètement, pour qu’un utilisateur puisse lancer talosctl, il a besoin d’un certificat client signé par la CA de Talos. Ce certificat, c’est vous qui le générez et le distribuez manuellement.
Pour un homelab en solo, c’est acceptable. Mais dès qu’on est en équipe, ça devient vite un cauchemar : gérer des certificats par personne, les révoquer quand quelqu’un quitte l’équipe, s’assurer que personne ne partage le même cert… Tout ça à la main. En big 2026. Alors que mon cluster fait déjà tourner un GoAuthentik avec du SSO partout.
Alors j’ai construit talosctl-oidc.
Le problème avec les certificats Talos
Pour administrer un cluster Talos, chaque utilisateur a besoin d’un fichier ~/.talos/config (appelé talosconfig) qui contient :
- L’adresse des nœuds Talos
- La CA du cluster (pour vérifier le serveur)
- Un certificat client + clé privée (pour s’authentifier)
context: mon-cluster
contexts:
mon-cluster:
endpoints:
- 192.168.0.10
ca: LS0tLS1CRUdJTi...
crt: LS0tLS1CRUdJTi...
key: LS0tLS1CRUdJTi...
Ces certificats sont générés lors de l’installation du cluster et ont une durée de vie d’un an par défaut. Le problème : si vous avez 5 développeurs dans votre équipe, vous devez générer 5 certificats distincts, les distribuer de façon sécurisée, avoir une méthode pour les renouveler. Et si quelqu’un quitte l’équipe ? Vous ne pouvez pas révoquer un seul certificat — vous devez regénérer la CA entière et redistribuer à tout le monde.
# La façon "classique" de donner accès à un nouveau collaborateur
talosctl config new --roles os:admin collaborateur.yaml
C’est exactement le genre de gestion manuelle et fragile qu’il faut essayer d’éviter dans une infrastructure de production 😅. Vous n’avez pas envie d’avoir une checklist de ce qu’il faut révoquer au départ d’un collègue.
Et normalement, dans un monde idéal, vous ne gérez pas les accès aux applications de manière individuelle. Vous avez un système d’identité centralisé (un IDP comme Authentik, Keycloak, Dex…) qui gère les utilisateurs, les groupes et quel population à le droit d’aller sur quelle application.
Si c’est assez facile à intégrer dans l’API Kubernetes ( cf cet article sur Authentik où je configure l’API de Kubernetes), en revanche ça n’est pas possible sur Talos, à moins que vous ne gérez vos clusters via Omni, l’excellent produit pour gérer plusieurs clusters Talos at scale. Mais si vous avec des environnements minimalistes et airgapped, Omni n’est pas forcément la solution idéale.
Je me suis alors creusé les méninges pour trouver une solution qui puisse faire le pont entre l’OIDC et le mTLS de Talos, sans devoir toucher à Talos lui-même (je n’ai clairement pas les compétences pour maintenir un fork de Talos).
La solution : un serveur d’échange de certificats
L’idée de talosctl-oidc est simple : construire un pont entre le monde OIDC (votre IdP, Authentik, Keycloak, Dex…) et le monde mTLS de Talos.
Voici comment ça fonctionne :
Le certificat généré dure 5 minutes. Passé ce délai, il faut se réauthentifier — ou utiliser le mode --watch qui renouvelle automatiquement en arrière-plan.
Installation
Concrètement, talosctl-oidc est une application Go qui expose une API HTTPS pour échanger des ID tokens OIDC contre des certificats client Talos. C’est un bête binaire qui tourne quelque part (installable via un Docker, Helm, ou systemd) et qui détient la CA de Talos pour signer les certificats. De votre coté, ce même binaire sera utilisé pour faire le login, interagir avec le serveur et mettre à jour votre talosconfig.
Les binaires sont disponibles sur GitHub. Pour macOS et Linux :
# macOS Apple Silicon
brew install qjoly/tap/talosctl-oidc
# Linux x86_64
curl -sL -o talosctl-oidc \
https://github.com/qjoly/talosctl-oidc/releases/latest/download/talosctl-oidc-linux-amd64
chmod +x talosctl-oidc
sudo mv talosctl-oidc /usr/local/bin/
# Vérification
talosctl-oidc version
talosctl-oidc 0.0.4
commit: 0.0.4
built: 2026-04-05T19:37:26Z
Configuration et démarrage du serveur
Comme dit plus haut, je ne maintiens qu’un seul binaire talosctl-oidc qui peut fonctionner en mode serveur (serve) ou client (login, status, logout), cette approche est surtout plus simple à maintenir (et le binaire ne fait que 10Mo, pas de soucis de poids).
Le serveur talosctl-oidc serve est le composant central. Il tourne quelque part accessible par les utilisateurs (dans le cluster, sur un VPS, dans votre homelab…) et détient la CA de Talos pour signer les certificats ( et on va voir de suite pour lui donner accès à la CA).
Récupérer la CA de Talos
Pour configurer le serveur, il nous faut la CA de Talos (certificat + clé privée) pour pouvoir signer les certificats clients. Si vous avez installé votre cluster avec talosctl, vous avez déjà un fichier controlplane.yaml qui contient la CA encodée en base64 (et si vous n’avez qu’un talosconfig et que votre cluster est déjà installé, vous pouvez utiliser talosctl get mc -n $NODE -o yaml pour obtenir le controlplane.yaml).
# Extraire la CA depuis le secret Talos (si vous utilisez talosctl)
yq '.machine.ca.crt' controlplane.yaml | base64 -d > talos-ca.crt
yq '.machine.ca.key' controlplane.yaml | base64 -d > talos-ca.key
Avertissement
La clé privée de la CA Talos est extrêmement sensible. Elle permet de signer des certificats avec n’importe quel rôle. Traitez-la comme un secret de production : stockez-la dans un coffre-fort (Vault, Sealed Secrets, SOPS…) et ne la partagez JAMAIS.
Maintenant, on a ce qu’il faut coté Talos. Le serveur talosctl-oidc n’interagira jamais directement avec l’API de Talos, il se contente de signer des certificats avec la CA ( Ce qui veut aussi dire que la machine avec talosctl-oidc serve n’a pas besoin d’avoir accès à vos clusters Talos pour fonctionner).
Créer un client OIDC dans votre IdP
Quel que soit votre IdP, il faut lui déclarer un client OIDC avec ces paramètres :
- Client ID : identifiant libre, par ex.
talosctl-oidc - Public client (pas de
client_secret) - Redirect URI :
http://127.0.0.1:8900/callback— c’est là que le clienttalosctl-oidc loginintercepte le code d’autorisation après le login - Scopes :
openid,profile,email,offline_access(ce dernier pour le refresh token)
Pour illustrer concrètement, voici la config d’un client Authentik — un IdP OIDC open-source très flexible que j’utilise pour mon homelab.

On peut maintenir déployer talosctl-oidc en local pour tester avec notre IdP.
Fichier de configuration
Créez un fichier config.yaml pour le serveur :
# config.yaml
issuer_url: https://oidc.home.une-tasse-de.cafe/application/o/talos-oidc/
client_id: talosctl_oidc
ca_cert: ./talos-ca.crt
ca_key: ./talos-ca.key
listen: ":8443"
endpoints:
- 192.168.0.124
cert_ttl: "5m"
roles:
- os:admin
Information
Pour que le programme soit configurable de partout, toutes les options de configuration peuvent être passées via des variables d’environnement. Par exemple, issuer_url peut être configuré avec la variable d’environnement TALOSCTL_OIDC_ISSUER_URL. Les clés sont détaillées dans la documentation officielle du projet sur GitHub, mais en gros : TALOSCTL_OIDC_ + nom de la clé en majuscules + _ à la place des points.
Démarrer le serveur
Une fois la configuration en place, on peut démarrer le serveur :
talosctl-oidc serve --config config.yaml
Voici ce que le serveur affiche au démarrage :
talosctl-oidc serve --config config_oidc.yaml
2026/04/05 22:03:41 Configuration loaded from file: config_oidc.yaml (env vars override)
2026/04/05 22:03:41 Loaded Talos CA from ./talos-ca.crt
2026/04/05 22:03:41 Audit log: stdout
2026/04/05 22:03:41 Admin API: disabled (set admin_token / TALOSCTL_OIDC_ADMIN_TOKEN to enable)
2026/04/05 22:03:41 Rate limiting: disabled
2026/04/05 22:03:41 IP allowlist: disabled
2026/04/05 22:03:41 RBAC: disabled (using static roles: [os:admin])
2026/04/05 22:03:41 Cert exchange server listening on :8443
2026/04/05 22:03:41 OIDC issuer: https://oidc.home.une-tasse-de.cafe/application/o/talos-oidc/
2026/04/05 22:03:41 Certificate TTL: 5m0s
2026/04/05 22:03:41 Roles: [os:admin]
2026/04/05 22:03:41 Endpoints: [192.168.0.124]
2026/04/05 22:03:41 TLS mode: generating self-signed certificate
2026/04/05 22:03:41 Self-signed CA fingerprint (SHA-256): 77ea5763a39629c9594f99285d4bd002293869b9bab61f1f161176bb375c3ef3
2026/04/05 22:03:41 Self-signed CA PEM (use with --server-ca on the login command):
-----BEGIN CERTIFICATE-----
MIIBvjCCAWSgAwIBAgIQflYwrB5fbBTHALlBCSQXMzAKBggqhkjOPQQDAjA/MRYw
FAYDVQQKEw10YWxvc2N0bC1vaWRjMSUwIwYDVQQDExx0YWxvc2N0bC1vaWRjIHNl
bGYtc2lnbmVkIENBMB4XDTI2MDQwNTIwMDI0MVoXDTM2MDQwMjIwMDM0MVowPzEW
MBQGA1UEChMNdGFsb3NjdGwtb2lkYzElMCMGA1UEAxMcdGFsb3NjdGwtb2lkYyBz
ZWxmLXNpZ25lZCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBV/WSiaIrso
9EEKsJdbQ8f1OZZD4kUpjj4nw93R8HaBs/QBViUv3hC3T2v/idFqHsCrc+GHQfus
w1uxdUpJC5ijQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
A1UdDgQWBBTnTNFqdLlNGgBWTv5L+9pcyw400jAKBggqhkjOPQQDAgNIADBFAiEA
x0ishJkUcmYRdWVpHBZ/0ezUCv0dEc0GuHds07f7CD4CIE9Jvw5oRR+ydcvysdDp
T1F1zDdIBdX8grhKcs8lLNsN
-----END CERTIFICATE-----
Par défaut, le serveur génère un certificat TLS auto-signé. Vous pouvez fournir les vôtres :
# config.yaml — avec un vrai certificat TLS
tls_cert: ./server.crt
tls_key: ./server.key
Si vous utilisez un certificat auto-signé généré par le serve (comme dans la configuration d’exemple), il nous faudra récupérer la clé publique de ce certificat pour la fournir au client lors du login (option --server-ca), afin que le client puisse vérifier l’identité du serveur. Vous pouvez aussi indiquer à talosctl-oidc de conserver le certificat auto-signé généré au démarrage (au lieu d’en générer un nouveau à chaque fois) en fournissant un chemin de stockage :
data_dir: ./data # Ou via la variable d'environnement TALOSCTL_OIDC_DATA_DIR
Nous créons donc un fichier server-ca.crt contenant la partie publique du certificat auto-signé qui sera utilisé par le client.
-----BEGIN CERTIFICATE-----
MIIBvjCCAWSgAwIBAgIQflYwrB5fbBTHALlBCSQXMzAKBggqhkjOPQQDAjA/MRYw
FAYDVQQKEw10YWxvc2N0bC1vaWRjMSUwIwYDVQQDExx0YWxvc2N0bC1vaWRjIHNl
bGYtc2lnbmVkIENBMB4XDTI2MDQwNTIwMDI0MVoXDTM2MDQwMjIwMDM0MVowPzEW
MBQGA1UEChMNdGFsb3NjdGwtb2lkYzElMCMGA1UEAxMcdGFsb3NjdGwtb2lkYyBz
ZWxmLXNpZ25lZCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBV/WSiaIrso
9EEKsJdbQ8f1OZZD4kUpjj4nw93R8HaBs/QBViUv3hC3T2v/idFqHsCrc+GHQfus
w1uxdUpJC5ijQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
A1UdDgQWBBTnTNFqdLlNGgBWTv5L+9pcyw400jAKBggqhkjOPQQDAgNIADBFAiEA
x0ishJkUcmYRdWVpHBZ/0ezUCv0dEc0GuHds07f7CD4CIE9Jvw5oRR+ydcvysdDp
T1F1zDdIBdX8grhKcs8lLNsN
-----END CERTIFICATE-----
Il y a plein d’options de configuration pour personnaliser le comportement du serveur, nous en verrons quelques-unes plus loin. Pour l’instant, le serveur est en route et prêt à recevoir des demandes d’authentification.
Authentification côté client
Premier login
Une fois le serveur en route, les utilisateurs peuvent s’authentifier :
talosctl-oidc login \
--provider https://oidc.home.une-tasse-de.cafe/application/o/talos-oidc/ \
--client-id talosctl_oidc \
--server https://localhost:8443 \
--server-ca ./server-ca.crt # si le serveur utilise un cert auto-signé
Un navigateur s’ouvre automatiquement sur votre IdP.

Après authentification, le terminal affiche :
Waiting for authentication callback...
2026/04/05 22:11:56 Keychain unavailable (data passed to Set was too big), using file-based token cache
2026/04/05 22:11:56 Token cached in /Users/qjoly/Library/Application Support/talosctl-oidc/tokens.json
Authentication successful.
Exchanging token with cert server at https://localhost:8443...
Received ephemeral certificate (TTL: 300s)
Talosconfig updated: context "oidc" set with endpoints [192.168.0.124]
Config written to: /Users/qjoly/.talos/config
Certificate expires in 5m0s
Et voilà, talosctl fonctionne :
talosctl --context oidc version -n 192.168.0.124
Client:
Tag: v1.12.6
SHA: undefined
Built: 2026-03-19T12:51:43Z
Go version: go1.26.1
OS/Arch: darwin/arm64
Server:
NODE: 192.168.0.124
Tag: v1.12.6
SHA: a1b8bd61
Built:
Go version: go1.25.8
OS/Arch: linux/amd64
Enabled: RBAC
Maitenant, on peut faire n’importe quelle commande talosctl en utilisant le contexte oidc qui a été créé… pendant 5 minutes (configurable). Parce qu’après passé ce délais.. dehors !
talosctl-oidc status
Context: oidc
--- OIDC Token ---
Issuer: https://oidc.home.une-tasse-de.cafe/application/o/talos-oidc/
Client ID: talosctl_oidc
Status: expired (at 2026-04-05T22:16:56+02:00)
Refresh: available
--- Talosconfig ---
Path: /Users/qjoly/.talos/config
Status: context "oidc" exists
Endpoints: [192.168.0.124]
Active: yes (current context)
Client cert: present
Mais 5 minutes, c’est pas très long pour faire des opérations sur le cluster. C’est là que le mode --watch entre en jeu.
Renouvellement automatique en arrière-plan
Si vous avez ajouté le claim offline_access dans les scopes du client OIDC, le serveur vous fournit un refresh token en plus de l’ID token. Ce refresh token permet au client de demander un nouvel ID token sans que l’utilisateur ait à se réauthentifier sur Authentik. Ainsi, on peut rajouter un mode de login --watch qui tourne en arrière-plan et renouvelle le certificat automatiquement avant son expiration.
# Lance le renouvellement en arrière-plan
talosctl-oidc login \
--provider https://oidc.home.une-tasse-de.cafe/application/o/talos-oidc/ \
--client-id talosctl_oidc \
--server https://localhost:8443 \
--server-ca ./server-ca.crt \
--watch
Le mode --watch utilise le refresh token pour renouveler l’ID token sans intervention utilisateur, puis échange ce nouveau token contre un certificat frais avant expiration.
Astuce
Pour les utilisateurs de MacOS, vous verrez probablement ce log :
2026/04/05 23:10:09 [DEBUG] Attempting to store in keychain (size: 3497 bytes)
2026/04/05 23:10:09 Keychain unavailable (data passed to Set was too big), using file-based token cache
Malheureusement, le trousseau de MacOS a une limite de taille d’entrée qui est souvent dépassée par les tokens OIDC (surtout avec les refresh tokens). talosctl-oidc gère ce cas en basculant automatiquement vers un cache de tokens basé sur des fichiers, mais cela signifie que les tokens sont stockés en clair sur le disque. C’est un compromis que j’ai dû faire pour assurer la compatibilité avec MacOS, mais soyez conscient que cela peut présenter un risque de sécurité si d’autres utilisateurs ont accès à votre compte utilisateur.
Le refresh-token a une durée de vie plus longue (configurable côté IdP, souvent plusieurs jours ou semaines). Tant que le refresh token est valide, le client peut continuer à renouveler le certificat sans que l’utilisateur ait à se reconnecter.
Information
Et quand vous avez terminé et que vous ne voulez pas attendre l’expiration du certificat, vous pouvez simplement faire un logout pour effacer le token du cache et supprimer le contexte du talosconfig :
talosctl-oidc logout
Cached token cleared.
Context "oidc" removed from talosconfig.
Révoquer un certificat
Pour la révocation, il faut absolument passer par l’IdP. Comme les certificats sont éphémères, il suffit de révoquer le refresh token de l’utilisateur dans l’IdP pour que tous les certificats émis à partir de ce token deviennent invalides à leur expiration (5 minutes max). Pas besoin de toucher à la CA ou de regénérer des certificats pour toute l’équipe.

Gestion des accès avec le RBAC
C’est là que ça devient vraiment intéressant. Jusqu’ici, tous les utilisateurs qui s’authentifient reçoivent le même rôle (os:admin dans notre config). Mais Talos supporte plusieurs rôles avec des niveaux d’accès différents :
| Rôle | Accès |
|---|---|
os:admin | Accès complet |
os:operator | Opérations courantes (reboot, etc.) |
os:reader | Lecture seule |
os:etcd:backup | Backup etcd uniquement |
Avec talosctl-oidc, vous pouvez mapper des claims OIDC à des rôles Talos. Par exemple, si votre IdP remplit un claim groups dans le token JWT, vous pouvez écrire :
# config.yaml
roles: [] # pas de rôle par défaut = deny si aucune règle ne matche
rbac:
rules:
- claim: groups
value: platform-admins
roles:
- os:admin
- claim: groups
value: developers
roles:
- os:reader
- claim: groups
value: system-team
roles:
- os:operator
- os:etcd:backup
Un utilisateur membre du groupe developers reçoit uniquement os:reader — il peut inspecter le cluster mais pas le modifier. Un membre de platform-admins obtient os:admin. Les règles se cumulent : un utilisateur dans les deux groupes obtient l’union des rôles.
Information
Le claim OIDC peut être une chaîne de caractères ou un tableau. talosctl-oidc supporte les deux formats automatiquement. Vérifiez ce que votre IdP envoie avec jwt.io en décodant votre ID token.
Interface d’administration
Le serveur expose une API d’admin (protégée par un token Bearer) pour monitorer les certificats émis :
# config.yaml
admin_token: mon-token-secret
data_dir: ./data # stockage des stats
# Lister les certificats actifs
curl -H "Authorization: Bearer VivLeCafe" \
https://localhost:8443/admin/certs -k
[
{
"subject": "goauthentik@une-pause-cafe.fr",
"email": "goauthentik@une-pause-cafe.fr",
"issued_at": "2026-04-05T20:43:14.941923Z",
"expires_at": "2026-04-05T22:48:14.941874+02:00",
"client_ip": "[::1]:59853",
"roles": [
"os:admin"
],
"ttl": "5m0s",
"fingerprint": "417ea770c83cd6332d7f3d3d40abc1d1ca2b0cb5d734844e8b8a833649a23374"
},
# ...
# Statistiques globales
curl -H "Authorization: Bearer VivLeCafe" \
https://localhost:8443/admin/stats -k
{"started_at":"2026-04-05T20:23:50.096935Z","uptime":"8m53s","total_certs_issued":39,"active_certs":22,"total_auth_successes":39,"total_auth_failures":0,"total_cert_errors":0}
L’usage de l’IA dans ce projet
Ce projet open-source a été développé par mes soins, mais j’ai beaucoup utilisé l’IA pour accélérer certaines tâches. Si je pense être capable de faire du Go, de comprendre le protocole OIDC ainsi que son implémentation, de construire une application web, je suis loin d’être capable de faire tout ça rapidement et de manière robuste sans un coup de pouce de l’IA.
C’est aussi pour moi un énorme bac à sable pour expérimenter avec les capacités de l’IA dans le développement logiciel. Pour les curieux, j’ai un abonnement à Claude qui m’a été assez utile pour implémenter certaines features. L’IA a été un bon compagnon de pair-programming qui m’a aussi aidé à organiser les issues sur GitHub, à rédiger la documentation et à la mettre à jour au fur et à mesure du développement.
Et si vous pensez qu’il s’agit d’un énième projet open-source totalement vibe-codé : détrompez-vous car j’ai appris beaucoup en construisant ce projet et même si l’IA a participé, il n’y a pas une ligne de code que je n’ai pas controlée, pas une PR que je n’ai pas relue, pas une issue que je n’ai pas triée. L’IA est un outil, pas un substitut à ma réflexion.
Conclusion
Voilà, c’est le projet sur lequel je travaille depuis quelques semaines. L’idée de départ est simple — un serveur d’échange de certificats — mais il y a beaucoup de détails à soigner pour que ça soit réellement utilisable en équipe.
Ce que j’apprécie dans cette approche, c’est qu’elle ne touche pas à Talos lui-même. On respecte le design de l’OS tout en ajoutant une couche de gestion des identités moderne par-dessus. Les certificats éphémères de 5 minutes sont d’ailleurs bien plus sécurisés que les certificats annuels qu’on distribuait avant.
Si ce projet vous intéresse, je vous invite à aller jeter un œil sur le repo GitHub : github.com/qjoly/talosctl-oidc, et si vous le souhaitez : contrtibuez ! Que ce soit pour ajouter des features, améliorer la documentation, ou simplement tester et faire du feedback, toute contribution est la bienvenue et grandement appréciée.
Bon kawa à tous ☕
