Ta clé SSH protégée par Touch ID, le montage pas à pas

Épisode 2. Secretive, une clé SSH dans la Secure Enclave, Touch ID à chaque connexion, le port 22 fermé et ta politique Tailscale, commande par commande.

Ta clé SSH protégée par Touch ID, le montage pas à pas
Série · épisode 2 sur 2Tes clés SSH face aux agents IA Sommaire
  1. 1 Un agent IA peut ravager ta flotte. Le verrou avec Touch ID
  2. 2 Ta clé SSH protégée par Touch ID, le montage pas à pastu es ici
Voir la page de la série →

Dans l’épisode 1, on a posé le pourquoi. Un agent IA tourne avec tes droits, hérite de tes clés SSH et peut sauter de serveur en serveur pendant que tu regardes ailleurs. La parade tenait en deux verrous, un réseau privé qui fait disparaître le port 22 et une clé enfermée dans la puce de ton Mac, qui ne signe rien sans ton doigt.

J’avais promis chaque commande. Les voilà, dans l’ordre où je les ai tapées, pièges compris, avec trois affirmations de l’épisode 1 qui ont vieilli et que je rectifie là où elles comptent.

À la fin, chaque connexion SSH vers tes serveurs exigera ton doigt sur Touch ID, et le port 22 n’existera plus pour internet. Il te faut un Mac avec Touch ID, un serveur Linux et un tailnet Tailscale. Compte une bonne heure pour le premier serveur, tests compris, nettement moins pour les suivants.


Avant de commencer

Un tuto SSH qui commence par les commandes est un tuto qui finit par un ticket au support de l’hébergeur. On prépare le terrain d’abord.

Ce qu’il te faut

  • Un Mac Apple Silicon, ou un MacBook Intel à puce T2, avec Touch ID configuré. Sur un iMac ou un Mac mini Apple Silicon, c’est le Magic Keyboard avec Touch ID qui fait le travail, il ne fonctionne pas avec les Mac Intel.
  • macOS 15 ou plus récent pour Secretive 4, la version actuelle. Sur macOS 14, reste sur Secretive 3.0.4.
  • Un serveur Linux où tu te connectes déjà en SSH avec une clé classique. Les commandes serveur visent Ubuntu, avec son pare-feu ufw.
  • Tailscale sur le Mac et sur le serveur, dans le même tailnet. L’offre gratuite suffit pour un usage personnel, et Secretive est gratuit et open source.

Si le tailnet n’existe pas encore, le tuto Tailscale te le monte en une soirée. Et si ton serveur sort à peine du carton, le socle VPS durci couvre sa mise en route, SSH de base compris.

Une précision sur les versions, puisque la crédibilité de ce tuto tient au fait que je l’ai monté pour de vrai. Mon montage a tourné en Secretive 3.0.4. La 4 est sortie le 21 septembre, et ce que j’en dis vient de ses notes de version et de son code, pas encore de mes doigts. Je le signale à chaque fois que ça compte.

Ce que ça change, et ce que ça ne change pas

Après ce tuto, tes connexions SSH interactives passent par une clé que personne ne peut copier, toi compris, et chaque signature réclame ton doigt. Tes tâches automatiques, elles, ne peuvent pas poser un doigt. Sauvegardes, synchronisations, scripts de nuit gardent un canal séparé, j’y reviens à l’étape 3, et ce canal reste ouvert jusqu’au bout du montage.

Ce qui ne change pas, c’est ta vigilance. Touch ID prouve que tu es là, pas que tu as compris ce que tu signes.

Le filet de sécurité, avant la première commande

On va toucher à la seule porte qui te donne accès à tes serveurs. Une erreur, et tu te retrouves sur le palier, les clés à l’intérieur. Trois précautions, sans négociation.

  • Garde une session SSH ouverte vers chaque serveur pendant toute la manip. Ne la ferme qu’après avoir réussi une nouvelle connexion avec la nouvelle clé.
  • Vérifie maintenant l’accès console de ton hébergeur, le KVM ou la console série de son panel. C’est ta porte de service si le réseau et SSH lâchent en même temps.
  • Prépare une clé de secours classique, qui vivra hors du Mac.
ssh-keygen -t ed25519 -a 100 -C "secours-hors-ligne" -f ./secours_ed25519

Donne-lui une phrase de passe forte. Garde le fichier secours_ed25519.pub sous la main pour l’étape 5, puis range les deux fichiers sur un support que tu ne branches qu’en cas de sinistre, et efface-les du Mac. Si ton Mac meurt, c’est elle qui te rouvre la porte, depuis un autre appareil de ton tailnet. Et si le tailnet lui-même tombe, la console de l’hébergeur prend le relais.


Le montage, étape par étape

Neuf étapes, un objectif chacune. L’ordre n’est pas un détail. La 5 et la 6 ne s’inversent pas, on dépose la clé avant de fermer les mots de passe. La 7 non plus, on se reconnecte par le tailnet avant d’allumer le pare-feu.

Étape 1, installer Secretive

Deux chemins. Le plus court passe par Homebrew.

brew install --cask secretive

Le plus vérifiable passe par la page des versions de Secretive. Tu télécharges Secretive.zip, tu compares son empreinte à celle du journal de compilation lié à la version, puis tu contrôles la signature une fois l’app rangée dans Applications.

shasum -a 256 Secretive.zip
codesign -dv --verbose=4 /Applications/Secretive.app
spctl -a -vv /Applications/Secretive.app

Ce que tu dois voir, une autorité Developer ID Application au nom de Max Goedjen côté codesign, et la mention accepted, source=Notarized Developer ID côté spctl.

Les captures de ce tuto viennent de la version 3.0.4, celle qui tourne sur mes Mac. Homebrew t’installera la 4, ou la 3.0.4 de lui-même si tu es sous macOS 14. Les libellés sont les mêmes, et ce que la 4 ajoute est signalé au fil du texte.

Lance l’app et suis son assistant de configuration. Il installe SecretAgent, le petit agent SSH qui tourne en arrière-plan et démarre avec ta session.

Assistant de configuration de Secretive au premier lancement, le bouton « Installer » attend en face de « Configurer l'agent » et l'agent n'est pas encore actif.

Clique sur « Installer », en face de « Configurer l’agent ». Le bouton vire au vert, et en haut de la fenêtre le voyant passe à « L’agent est actif ». Les deux autres lignes de l’assistant peuvent attendre, Secretive fonctionne déjà. Ferme l’assistant avec « Terminé ». Ne clique pas sur « Configurer les intégrations », il propose de brancher Secretive sur toutes tes connexions, l’étape 3 explique pourquoi on s’en passe.

L'assistant après installation, « Configurer l'agent » est passé au vert, SecretAgent tourne.

Pour les maniaques du trafic sortant, la seule requête réseau de Secretive vérifie les mises à jour sur GitHub, à peu près une fois par jour. Aucun réglage de la version 4 ne la coupe, c’est ton pare-feu sortant qui tranche si tu préfères surveiller les versions à la main.

💡 Apple a ouvert une voie native depuis macOS 26 Tahoe, avec l’outil sc_auth et la bibliothèque ssh-keychain.dylib du système. Je ne l’ai pas fait marcher de façon fiable avec l’agent SSH lors de mes essais, Secretive reste la voie que je recommande.

Étape 2, créer la clé dans la Secure Enclave

Dans Secretive, bouton « + ». Par défaut la fenêtre ne montre que le nom et deux niveaux de protection. Le type de clé et le niveau qui compte vraiment sont cachés derrière « Avancé », en bas à gauche. Clique dessus.

Fenêtre de création d'une clé dans Secretive par défaut, seuls le nom et deux niveaux de protection sont proposés, le bouton « Avancé » en bas à gauche.

Le nom. Une clé par serveur, nommée d’après lui, serveur-prod-admin par exemple. C’est la règle « jamais de passe-partout » de l’épisode 1, appliquée, et c’est ce nom que la fenêtre Touch ID t’affichera.

Le type, ECDSA P-256. Première rectification. J’écrivais que la Secure Enclave ne savait faire que du P-256. C’est devenu inexact. Depuis macOS 26, la puce signe aussi en ML-DSA, un algorithme post-quantique, et Secretive le propose depuis sa version 3. Sauf que la clé publique produite porte un type qu’aucun serveur OpenSSH standard n’accepte aujourd’hui. La puce parle post-quantique, ton serveur ne sait pas encore l’écouter. Reste en P-256.

Le champ « Attribution de la clé », affiché lui aussi en mode avancé, peut rester vide, le commentaire par défaut suffit.

Le niveau d’authentification. Le réglage le plus important du tuto, et le moins visible.

  • « Notifier », à proscrire, la clé signe sans rien demander tant que ton Mac est déverrouillé, et une notification te prévient après coup.
  • « Exiger l’authentification » accepte Touch ID, mais aussi ton Apple Watch ou le mot de passe du Mac.
  • « Données biométriques actuelles », visible seulement en mode avancé, n’accepte que Touch ID, avec les empreintes enregistrées au moment de la création.

Création de la clé serveur-prod-admin en mode avancé, niveau « Données biométriques actuelles », type ecdsa-256 et avertissement sur les empreintes.

Prends la troisième pour tes clés d’administration. J’ai d’abord tourné avec la deuxième, et je me suis aperçu qu’une Apple Watch au poignet pouvait valider à la place du doigt. Confortable, et précisément ce qu’on cherchait à empêcher, puisque le verrou repose sur un geste conscient.

Le revers existe. Ajouter une empreinte dans les Réglages invalide la clé, il faut alors en créer une nouvelle et redéployer sa clé publique.

C’est ce niveau d’authentification qui fait le « Touch ID à chaque fois » de l’épisode 1, à une condition. Quand Secretive te propose de laisser la clé déverrouillée un moment, refuse avec « Ne pas déverrouiller ». Pendant ce délai, un agent signerait sans toi.

Récupère ensuite la clé publique. Le bouton de copie de l’app suffit, range-la dans un fichier dédié.

mkdir -p ~/.ssh/secretive
pbpaste > ~/.ssh/secretive/serveur-prod-admin.pub
ssh-keygen -lf ~/.ssh/secretive/serveur-prod-admin.pub

La dernière ligne affiche l’empreinte SHA256 de la clé. Note-la, elle te servira à reconnaître la bonne ligne côté serveur. Vérifie aussi que l’agent de Secretive voit bien ta clé.

SSH_AUTH_SOCK=~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh ssh-add -L

Ce que tu dois voir, une ligne qui commence par ecdsa-sha2-nistp256 et se termine par le nom de ta clé, suivi de @secretive. et du nom de ton Mac.

Étape 3, câbler l’agent SSH, serveur par serveur

L’app te suggère de brancher Secretive sur toutes tes connexions, avec une règle globale dans ~/.ssh/config. Ne le fais pas. Tes sauvegardes et tes synchronisations passeraient aussi par lui, et un script n’a pas de doigt. Tu récolterais des échecs en série, ou pire, des fenêtres Touch ID surgies de nulle part que tu finirais par valider par lassitude.

Le bon montage se fait hôte par hôte, un bloc par serveur protégé dans ~/.ssh/config.

Host serveur-prod
    HostName serveur-prod.exemple.ts.net
    User admin
    IdentityAgent ~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh
    IdentityFile ~/.ssh/secretive/serveur-prod-admin.pub
    IdentitiesOnly yes
    ForwardAgent no
    ControlMaster no
    ControlPath none

Place ces blocs en tête du fichier, avant tout Host *. Comme sshd, ssh garde la première valeur qu’il rencontre, et un Host * placé au-dessus, avec son multiplexage ou son transfert d’agent, gagnerait en silence.

Chaque ligne a sa raison d’être.

  • HostName vise le nom du serveur dans ton tailnet, jamais une IP codée en dur.
  • IdentityAgent envoie cette connexion, et elle seule, vers Secretive. Le reste de ta vie SSH ne bouge pas.
  • IdentityFile et IdentitiesOnly désignent une seule clé, par sa clé publique. Sans eux, ssh propose toutes les clés de Secretive l’une après l’autre, et le serveur coupe au bout de six refus avant d’arriver à la bonne.
  • ForwardAgent no interdit de prêter ta clé au serveur distant, le vecteur de rebond décrit dans l’épisode 1. Pour passer par une machine intermédiaire, utilise ProxyJump, la signature reste sur ton Mac à chaque saut. Avec la politique de l’étape 8, tes serveurs ne se joignent plus entre eux par le tailnet, un rebond d’un serveur tagué vers un autre y sera donc refusé.
  • ControlMaster no et ControlPath none coupent le multiplexage, un piège sournois.

Le multiplexage garde une connexion maîtresse ouverte pour accélérer les suivantes. Pratique, sauf que tout programme qui tourne avec tes droits peut alors rouvrir une session par ce tuyau sans nouvelle signature, donc sans Touch ID. Ton verrou devient une porte de saloon.

La contrepartie se paie au déploiement. Un script qui ouvre dix connexions te demande dix fois ton doigt, et l’épisode 1 l’a dit, après cinq doigts posés à la chaîne tu ne lis plus rien, et c’est au sixième qu’un intrus glisse le sien. La parade, c’est de grouper le travail dans une seule session, un script poussé puis exécuté sur place, plutôt que dix commandes à la suite.

Pour tes automatismes, un compte de service sans droits root, sauvegarde dans la suite des exemples, avec sa propre clé disque, limitée côté serveur à une seule commande par l’option command= d’authorized_keys. Elle ne sait faire qu’une chose, et elle ne passe jamais par Secretive. C’est le compromis qui rend le montage vivable au quotidien, et les étapes 6 et 9 le préservent explicitement.

Pour vérifier ce que ssh va réellement appliquer à cet hôte, demande-lui sa configuration calculée.

ssh -G serveur-prod | grep -Ei '^(identityagent|identitiesonly|forwardagent|controlmaster) '

Ce que tu dois voir, le chemin du socket de Secretive, identitiesonly yes, forwardagent no et controlmaster false.

Étape 4, couper Tailscale SSH

Je la place avant tout test, parce qu’elle annule toutes les autres si tu l’oublies. Tailscale SSH, la fonction maison déjà épinglée dans l’épisode 1, ne se contente pas de remplacer l’authentification. Activée sur un serveur, elle intercepte tout le trafic qui arrive sur le port 22 par le tailnet. sshd ne voit jamais passer la connexion, et ton fichier authorized_keys n’est jamais lu.

Je l’ai appris de la mauvaise manière. Sur un serveur au sshd pourtant verrouillé, root interdit compris, des connexions root passaient sans clé ni mot de passe, parce que Tailscale SSH répondait à sa place. Tout le durcissement était décoratif.

Si c’est par Tailscale SSH que tu entres aujourd’hui sur ce serveur, garde la console de l’hébergeur ouverte avant de couper. Puis, sur chaque serveur, une commande.

sudo tailscale set --ssh=false

Le contrôle se fait depuis ton Mac, en interdisant toute clé et toute réutilisation de session à la connexion.

ssh -o PubkeyAuthentication=no -o ControlPath=none [email protected]

Ce que tu dois voir, une demande de mot de passe ou un refus. Si une session s’ouvre sans rien te demander, ou si on te renvoie vers une page de connexion Tailscale, Tailscale SSH répond encore, vérifie que la commande a bien été passée sur ce serveur-là. La section ssh de ta politique Tailscale sera vidée à l’étape 8, pour fermer aussi cette porte côté console.

Étape 5, déposer la clé sur le serveur

La clé privée n’existe pas sous forme de fichier, donc ssh-copy-id doit être forcé à se contenter de la clé publique, avec l’option -f.

ssh-copy-id -f -i ~/.ssh/secretive/serveur-prod-admin.pub [email protected]

J’utilise le nom complet plutôt que l’alias serveur-prod, pour que cette connexion-là passe encore par ton ancienne clé et pas par Secretive. Ajoute de la même façon la clé publique de secours, et la clé Secure Enclave de chacun de tes autres Mac. Chaque Mac a la sienne, aucune ne se copie.

Tu peux ensuite durcir la ligne ajoutée, côté serveur, dans ~/.ssh/authorized_keys, en la préfixant de trois options.

from="100.64.0.0/10,fd7a:115c:a1e0::/48",restrict,pty ecdsa-sha2-nistp256 AAAA... [email protected]

from= n’accepte la clé que depuis les plages d’adresses de Tailscale. restrict coupe le transfert d’agent, de ports et d’affichage. pty rétablit le terminal interactif, que restrict avait coupé au passage. Sur un serveur qui te sert de rebond pour ProxyJump, ajoute aussi port-forwarding après restrict, sinon le saut échoue.

Puis le test, depuis une nouvelle fenêtre de terminal, ta session de secours toujours ouverte.

ssh serveur-prod

Ce que tu dois voir, une fenêtre Touch ID où SecretAgent demande à signer une requête de Terminal avec la clé serveur-prod-admin. Tu poses le doigt, tu es connecté. Recommence en cliquant sur « Refuser ». La signature est refusée, et ssh te proposera un mot de passe si ton sshd les accepte encore, ce que l’étape suivante règle. Le refus net Permission denied (publickey) viendra après.

Fenêtre Touch ID, SecretAgent demande à signer une requête de Terminal avec le secret serveur-prod-admin.

Deuxième rectification. J’écrivais que Secretive ne savait pas vers quel serveur tu te connectes. Selon les notes de sa version 4, il en dit désormais un peu plus. Après une signature, sa notification affiche l’utilisateur et le serveur visés, tout comme son panneau des requêtes en attente.

Deux conditions, le serveur doit figurer en clair dans ton known_hosts et les deux côtés doivent tourner en OpenSSH 8.9 ou plus. Petit bémol si ton Mac est en français, la traduction de cette notification n’affiche pas encore le nom du serveur. Et je n’ai pas pu le vérifier moi-même, puisque j’utilise encore la version 3.0.4, qui ne fait pas ça. La fenêtre Touch ID, elle, ne montre toujours que l’app qui demande et le nom de la clé.

Étape 6, verrouiller sshd

Si tu as monté ton serveur avec le socle VPS, la moitié est déjà en place. Les lignes en plus ferment les voies secondaires. Côté serveur, crée un fichier à part, /etc/ssh/sshd_config.d/01-durcissement.conf.

PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
PermitRootLogin no
AllowAgentForwarding no
AllowUsers admin sauvegarde

Ajoute à AllowUsers le compte de tes automatismes, sinon tes sauvegardes de la nuit se cognent à la porte sans que personne ne t’en parle.

Pourquoi ce 01 dans le nom ? sshd retient la première valeur qu’il rencontre pour la plupart des réglages, et Ubuntu lit ces fichiers par ordre alphabétique, avant la configuration principale. Une image cloud dépose souvent un 50-cloud-init.conf qui réactive les mots de passe. Passer devant lui règle la question.

Si tu dois vraiment entrer en root directement, remplace PermitRootLogin no par prohibit-password et ajoute root à AllowUsers. La clé Secure Enclave suffira alors, mais toute vieille clé oubliée dans les authorized_keys de root aussi, sans le moindre doigt.

Vérifie avant de recharger, jamais après.

sudo sshd -t
sudo sshd -T | grep -Ei 'passwordauth|kbdinteractive|permitrootlogin|authenticationmethods|allowagentforwarding'
sudo systemctl reload ssh

La première ligne contrôle la syntaxe. La deuxième affiche les valeurs réellement appliquées, les seules qui comptent. La troisième recharge le service, qui s’appelle ssh sur Ubuntu et sshd sur d’autres distributions.

Ce que tu dois voir, aucune sortie pour sshd -t, puis passwordauthentication no, kbdinteractiveauthentication no, permitrootlogin no, authenticationmethods publickey et allowagentforwarding no pour sshd -T.

Étape 7, fermer le port 22 public

Si tu sors du socle VPS, ton pare-feu est déjà dans cet état, passe directement au test depuis l’extérieur. Pour les autres, l’ordre des commandes est vital. Connecte-toi d’abord au serveur par son nom dans le tailnet, pas par son IP publique, sinon ufw enable te coupera la branche sur laquelle tu es assis.

sudo ufw allow in on tailscale0 to any port 22 proto tcp
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable
sudo ufw status numbered

Si d’autres services tournent sur ce serveur, garde leurs règles ufw sur tailscale0, on ne touche qu’au 22. Si une ancienne règle ouvre encore le 22 à tout le monde, 22/tcp ou OpenSSH dans la liste, retire-la selon son nom et relis l’état final.

sudo ufw delete allow 22/tcp
sudo ufw delete allow OpenSSH
sudo ufw status verbose

Le test se fait depuis l’extérieur, Tailscale coupé sur le Mac et le partage de connexion de ton téléphone allumé.

nc -vz -w 5 IP_PUBLIQUE_DU_SERVEUR 22

Ce que tu dois voir, un délai dépassé. Rallume Tailscale, ssh serveur-prod doit toujours passer. Si ton hébergeur propose un pare-feu réseau dans son panel, refuse aussi le 22 entrant là-bas. Deux cadenas sur la même porte, c’est rarement de trop quand elle mène à root.

Tu seras peut-être tenté de faire écouter sshd sur la seule adresse du tailnet, avec la directive ListenAddress. Sur Ubuntu récent, c’est systemd qui ouvre le port à la place de sshd. La directive ne s’applique pas par un simple rechargement, et lier sshd à l’adresse du tailnet peut échouer au démarrage si Tailscale n’est pas encore monté. Le pare-feu fait le travail, et sudo ss -tlnp te dit toujours qui écoute quoi.

Côté Mac, laisse Session à distance désactivée dans Réglages Système > Général > Partage, c’est l’état par défaut. Si un de tes Mac doit recevoir du SSH, ListenAddress y est ignoré aussi, et le restreindre au tailnet passe par pf, le filtre de paquets du système, un chantier à part entière.

Étape 8, écrire ta politique Tailscale

Troisième rectification. J’écrivais que Tailscale refuse par défaut. C’est vrai des règles, pas d’un tailnet neuf. Un tailnet fraîchement créé est livré avec une politique qui laisse tout le monde joindre tout le monde, sur tous les ports. Le refus par défaut ne joue qu’une fois cette politique remplacée par la tienne. Si tu n’y as jamais touché, ton tailnet est un open space sans cloisons.

Avant de remplacer quoi que ce soit, fais l’inventaire de ce qui circule déjà sur ton tailnet. Partage d’écran et fichiers entre tes Mac, agents de ton SIEM vers leur manager, dashboard en 443, sauvegardes entre machines. Chaque flux que tu veux garder a besoin de sa ligne dans grants. Sinon il meurt à la sauvegarde de la politique, et tu le découvres le lendemain.

La politique se rédige dans la console d’administration Tailscale, rubrique « Access controls », page « JSON editor ». Commence par y ajouter le bloc tagOwners de l’exemple ci-dessous, sauvegarde, puis tague chaque serveur. Le plus simple passe par la page des machines de la console, menu de la machine, « Edit tags ». En ligne de commande, tailscale set ne sait pas poser de tag, la voie documentée réauthentifie le serveur.

sudo tailscale up --advertise-tags=tag:serveur --force-reauth

Elle affiche un lien de connexion à ouvrir sur ton Mac, et si elle réclame de répéter tes autres réglages, elle te donne la commande complète à reprendre. Fais-le depuis la console de l’hébergeur ou avec ta session de secours ouverte, le serveur décroche du tailnet le temps de se réauthentifier.

Une fois tes serveurs tagués, remplace la politique par celle-ci, adaptée à ton adresse et complétée des flux de ton inventaire.

{
  "groups": {
    "group:admins": ["[email protected]"],
  },
  "tagOwners": {
    "tag:serveur": ["group:admins"],
  },
  "grants": [
    // Tes appareils joignent le SSH des serveurs
    {"src": ["group:admins"], "dst": ["tag:serveur"], "ip": ["tcp:22"]},
    // Tes appareils entre eux, comme avant (partage d'écran, fichiers)
    {"src": ["group:admins"], "dst": ["group:admins"], "ip": ["*"]},
    // Exemple, un dashboard en 443 sur tes serveurs, à décommenter si tu en as un
    // {"src": ["group:admins"], "dst": ["tag:serveur"], "ip": ["tcp:443"]},
    // Aucune règle entre serveurs, donc refus
  ],
  "ssh": [],
  "tests": [
    {"src": "[email protected]", "accept": ["tag:serveur:22"], "deny": ["tag:serveur:3389"]},
    {"src": "tag:serveur", "deny": ["tag:serveur:22"]},
  ],
}

Lecture rapide. Tes appareils, ceux de ton groupe, joignent le port 22 des serveurs tagués et continuent de se parler entre eux. Les serveurs ne se joignent pas entre eux, donc un serveur compromis ne sert plus de tremplin. La section ssh est vide, Tailscale SSH n’a plus aucune règle sur laquelle s’appuyer.

Le reste de ton inventaire suit le même moule, une ligne par flux, limitée à son port. Si tu as monté le SIEM de la série, tes agents Wazuh joignent leur manager sur 1514 et 1515, une ligne du tag de tes serveurs vers la machine du manager. Si deux serveurs doivent se parler pour une sauvegarde, une ligne aussi, et rien de plus large.

Le bloc tests est ton filet anti-régression. Tailscale l’évalue à chaque sauvegarde et refuse toute politique qui le casse. Le jour où tu ouvres trop grand par mégarde, c’est lui qui t’arrête. Ses ports sont des exemples à adapter. Le 3389 sert ici de port que personne n’ouvre, et si un test contredit un flux que tu as voulu garder, c’est le test qu’on corrige.

Tu peux aussi taguer tes Mac, mais un appareil tagué perd son rattachement à ton compte et sa clé n’expire plus par défaut. Un Mac tagué perdu se révoque dans la console, tout de suite. Laisser tes Mac rattachés à ton compte, comme ici, évite le problème.

Ce que tu dois voir, la politique acceptée à la sauvegarde sans test en échec, et ton serveur affiché avec son tag dans la liste des machines.

Éditeur JSON de la console Tailscale avec la politique de l'article, groupes, tags, grants et bloc tests.

Étape 9, tout vérifier, puis retirer l’ancienne clé

La liste de contrôle, sur chaque serveur.

  • ssh serveur-prod, Touch ID, connexion.
  • Touch ID annulé, connexion refusée.
  • La même connexion lancée par ton agent IA, la fenêtre Touch ID affiche l’app qui demande, ton terminal si l’agent y tourne. C’est pour ça que l’agent doit annoncer chaque connexion avant de la demander, comme dit dans l’épisode 1. Une demande qu’il n’a pas annoncée, tu la refuses, connexion refusée.
  • Depuis internet, hors tailnet, le port 22 ne répond pas.
  • D’un serveur vers un autre, SSH bloqué par la politique Tailscale.
  • ssh -o PubkeyAuthentication=no -o ControlPath=none [email protected] répond Permission denied (publickey), aucune voie par mot de passe.
  • Tes automatismes, la sauvegarde de la nuit passe toujours, avec sa clé à part.
  • Tes autres flux du tailnet, partage d’écran, SIEM, dashboard, chacun répond comme avant.
  • La clé de secours, testée une fois depuis un autre appareil de ton tailnet, puis rangée. Si le tailnet lui-même tombe, c’est la console de l’hébergeur qui prend le relais.
  • La console de l’hébergeur, testée elle aussi.

Reste le geste qui donne son sens à tout le reste. Tant que ton ancienne clé, ~/.ssh/id_ed25519 par exemple, figure dans les authorized_keys d’un serveur, n’importe quel programme sur ton Mac peut s’en servir sans toi. Le verrou Touch ID devient une porte blindée à côté d’une fenêtre ouverte.

Liste les clés autorisées sur chaque serveur, pour ton utilisateur et pour root.

ssh-keygen -lf ~/.ssh/authorized_keys
sudo ssh-keygen -lf /root/.ssh/authorized_keys

Compare-les à celle notée à l’étape 2, à celles des clés de tes autres Mac et à celle de ta clé de secours. Ne garde que les clés Secure Enclave de tes Mac, la clé de secours et tes clés d’automatisme bridées par command=, supprime le reste. Côté Mac, vide l’agent système avec ssh-add -D, puis déplace l’ancienne clé hors du Mac ou supprime-la. Ferme enfin ta session de secours.

Un dernier réflexe, qui vaut toutes les commandes. Une fenêtre Touch ID que tu n’as pas provoquée, tu la refuses. Ça m’est arrivé, une demande surprise venait d’une autre session de mon agent, lancée en arrière-plan. Refuser était la bonne réponse, et ça n’a rien cassé. D’après ses notes de version, Secretive 4 peut aussi grouper plusieurs requêtes identiques sous un seul Touch ID. Lis le libellé, et refuse tout lot que tu n’attendais pas.


Si ça ne marche pas

La fenêtre Touch ID ne s’affiche jamais

Secretive charge parfois mal ses clés après un redémarrage. Ouvre l’app, ça règle le problème la plupart du temps. Sinon, relance la commande ssh-add -L de l’étape 2, puis ssh -v serveur-prod. Le mode bavard te montre quel agent et quelle clé ssh propose réellement.

Le serveur répond « Too many authentication failures »

Il manque IdentitiesOnly yes dans le bloc de l’hôte, ou un Host * placé au-dessus l’écrase. Sans lui, ssh présente toutes les clés de Secretive à la suite et le serveur coupe avant d’arriver à la bonne.

La connexion passe sans Touch ID

Quatre suspects, dans cet ordre. Tailscale SSH encore actif sur le serveur (étape 4). Une ancienne clé encore autorisée (étape 9). Une connexion maîtresse de multiplexage restée ouverte (étape 3). Une clé laissée déverrouillée dans Secretive. Dans l’immense majorité des cas, c’est l’un des quatre.

Ta clé ne marche plus du jour au lendemain

Tu as ajouté une empreinte dans les Réglages, ou réinstallé ton Mac. Avec « Données biométriques actuelles », la clé est perdue, et elle ne reviendra pas. Entre avec ta clé de secours ou depuis un autre Mac, crée une nouvelle clé, redéploie sa clé publique et retire l’ancienne ligne.

Ton Mac tourne sous liste blanche d’exécution

Si tu filtres l’exécution avec Santa en mode Lockdown, Secretive et ses composants doivent être autorisés par identifiant de signature. La version 4 ajoute un service, SecretAgentHostsfileReader, qui lit ton fichier known_hosts et qu’il faut autoriser en plus des autres.


Pour les pressés

Ce que fait cet article. Il enferme ta clé SSH d’administration dans la Secure Enclave de ton Mac avec Secretive, exige Touch ID à chaque signature, retire SSH de l’internet public et cloisonne ton tailnet, sans casser tes automatismes ni tes autres flux.

Concrètement, la marche à suivre.

  1. Avant tout, une session SSH de secours ouverte, la console de l’hébergeur testée, une clé ed25519 de secours rangée hors du Mac.
  2. brew install --cask secretive, puis l’assistant de configuration.
  3. Dans Secretive, une clé par serveur, ECDSA P-256, niveau « Données biométriques actuelles », derrière le bouton « Avancé ». « Laisser déverrouillé », toujours non.
  4. Dans ~/.ssh/config, un bloc par hôte, avant tout Host *, avec le socket de Secretive en IdentityAgent, la clé publique en IdentityFile, IdentitiesOnly yes, ForwardAgent no, ControlMaster no.
  5. Tes automatismes sous un compte de service, avec leur propre clé disque bridée par command=, hors Secretive.
  6. Sur chaque serveur, sudo tailscale set --ssh=false.
  7. ssh-copy-id -f -i avec la clé publique de chaque Mac et celle de secours.
  8. Un /etc/ssh/sshd_config.d/01-durcissement.conf sans mot de passe ni root, AuthenticationMethods publickey, AllowAgentForwarding no, et AllowUsers avec ton compte et celui de tes automatismes. Puis sshd -t, sshd -T, et seulement ensuite le rechargement.
  9. ufw, le 22 autorisé sur tailscale0 seulement, refus entrant par défaut, ancienne règle publique supprimée.
  10. Politique Tailscale, inventaire des flux d’abord, puis tagOwners, tag des serveurs, et enfin les grants avec tcp:22 vers tag:serveur, une ligne par flux à garder, ssh vide et des tests adaptés.
  11. Dans authorized_keys, ne restent que les clés Secure Enclave, la clé de secours et les clés d’automatisme bridées. ssh-add -D sur le Mac.

À lire aussi, ce que la Secure Enclave change vraiment sur Apple Silicon.

Des termes techniques ? Consulte le glossaire.


Sources

Secretive

  • Secretive sur GitHub, le code et le README de l’app de Max Goedjen, installation, clés non exportables, une clé par Mac.
  • FAQ de Secretive, transfert d’agent, absence d’import et d’export, requête réseau de mise à jour.
  • Versions de Secretive, notes de la version 4.0.0 du 21 septembre 2026 et de la version 3.0.

OpenSSH

Tailscale

Apple