Tailscale ACL

Segmenter le réseau Tailscale avec ACL et tags : comment j’ai isolé mon serveur VPS de mes appareils domestiques

J’utilise Tailscale depuis des années comme VPN personnel : incroyablement pratique, zéro configuration, fonctionne partout. Mais je ne l’ai jamais gardé toujours actif — je l’activais quand j’en avais besoin et je l’éteignais ensuite. Une précaution un peu rudimentaire, je sais, mais il y avait une raison : un serveur VPS exposé à internet se trouvant dans le même réseau que mes appareils domestiques m’a toujours incité à ne pas tout laisser connecté en permanence par défaut. À un moment donné, j’ai décidé de faire les choses correctement, plutôt que de compter sur une discipline manuelle.

1. Le problème : le réseau Tailscale est plat par défaut

Tailscale crée un réseau mesh privé entre tous vos appareils. Par défaut, chaque nœud peut atteindre chaque autre nœud sur n’importe quel port. C’est pratique, mais c’est un réseau plat — exactement comme un réseau domestique où tout le monde peut voir tout le monde.

Ma configuration : un serveur VPS exposé à internet (géré avec Traefik comme reverse proxy) dans le même réseau Tailscale que mon PC de bureau, mon smartphone et mes Raspberry Pi. Le risque est évident — c’est pourquoi je ne gardais pas Tailscale toujours actif. Mais “je l’éteins quand je n’en ai pas besoin” n’est pas une politique : c’est une excuse. Il suffit d’oublier une fois, ou de vouloir consulter le monitoring à 2h du matin, pour avoir le réseau plat actif sans y avoir pensé.

La bonne solution n’est pas d’activer et désactiver — c’est de segmenter : faire en sorte que le VPS, même s’il est compromis, ne puisse atteindre rien de l’autre côté du réseau.

2. La solution : ACL et tags Tailscale

Tailscale permet de définir des politiques d’accès via un fichier de configuration au format HuJSON (JSON avec commentaires), géré depuis la console d’administration. Le mécanisme repose sur deux concepts :

  • Tags : étiquettes attribuées aux appareils (ex. tag:server, tag:monitoring). Les tags permettent de regrouper les appareils par rôle, indépendamment de leur propriétaire.
  • ACL (Access Control List) : règles qui définissent qui peut communiquer avec qui, sur quels ports et protocoles.

Le système fonctionne en liste blanche : tout ce qui n’est pas explicitement autorisé est bloqué. C’est la différence clé avec la configuration par défaut.

Les tags sont définis dans la section tagOwners du fichier de politique, qui spécifie qui a le droit d’attribuer ce tag à un appareil. Les tags sont ensuite attribués aux appareils depuis la console d’administration ou via tailscale set --advertise-tags sur l’appareil lui-même.

3. Le design du réseau

J’ai structuré le réseau avec cinq appareils, chacun ayant un rôle bien défini :

AppareilTagRôle
PC de bureautag:personalMachine de travail / usage quotidien
Smartphonetag:personalAppareil mobile personnel
Raspberry Pi (générique)tag:homelabServices internes, expériences
Raspberry Pi (monitoring)tag:monitoringPrometheus, Grafana, alerting
Serveur VPStag:serverServices publics exposés à internet

La logique d’accès que je voulais mettre en place :

  • Les appareils personal peuvent atteindre tout (c’est moi qui administre)
  • Le nœud monitoring peut faire du scraping sur tous les nœuds (port 9100 pour node_exporter)
  • Le server VPS peut être atteint depuis personal et monitoring, mais ne peut pas initier de connexions vers les autres
  • L’homelab est isolé : il ne peut pas être atteint depuis le serveur

4. Les politiques mises en place

Voici la matrice de visibilité résultante :

De Verspersonalhomelabmonitoringserver
personal
homelab
monitoring✓ (9100)✓ (9100)
server

Et le fichier HuJSON des ACL correspondant :

{
  // Qui peut attribuer les tags
  "tagOwners": {
    "tag:personal":    ["autogroup:admin"],
    "tag:homelab":     ["autogroup:admin"],
    "tag:monitoring":  ["autogroup:admin"],
    "tag:server":      ["autogroup:admin"]
  },

  "acls": [
    // Les appareils personnels peuvent atteindre tout
    {
      "action": "accept",
      "src":    ["tag:personal"],
      "dst":    ["*:*"]
    },

    // Le monitoring peut scraper homelab et server (node_exporter)
    {
      "action": "accept",
      "src":    ["tag:monitoring"],
      "dst":    ["tag:homelab:9100", "tag:server:9100"]
    },

    // Le monitoring peut s'atteindre lui-même (ex. Prometheus → Grafana)
    {
      "action": "accept",
      "src":    ["tag:monitoring"],
      "dst":    ["tag:monitoring:*"]
    },

    // L'homelab ne peut atteindre que lui-même
    {
      "action": "accept",
      "src":    ["tag:homelab"],
      "dst":    ["tag:homelab:*"]
    }

    // Tout le reste est implicitement bloqué (liste blanche)
  ]
}

Avec cette configuration, le VPS ne peut pas ouvrir de connexions vers d’autres nœuds. Même s’il est compromis, il est isolé du reste du réseau.

5. Une erreur fréquente : les tags non attribués aux appareils

C’est l’erreur que j’ai commise la première fois, et c’est probablement ce que fait quiconque s’approche de cette configuration.

J’ai écrit la politique, je l’ai enregistrée dans la console Tailscale, et je me suis connecté via SSH au serveur. Tout fonctionnait. J’ai attendu quelques minutes, puis j’ai réessayé — et SSH se bloquait. Pas de timeout explicite, juste le silence.

Le problème : j’avais défini les tags dans la politique mais je ne les avais pas attribués aux appareils. Un appareil sans tag ne correspond à aucune règle ACL, donc en mode liste blanche il ne peut ni envoyer ni recevoir quoi que ce soit — sauf les connexions déjà actives au moment de l’application de la politique (qui expirent après un moment).

Le diagnostic se fait avec :

tailscale status

Dans la colonne des tags, les appareils sans tag apparaissent vides ou ne montrent que le nom d’utilisateur. Le correctif consiste à attribuer les tags depuis l’appareil lui-même :

# Sur le serveur VPS
sudo tailscale set --advertise-tags=tag:server

# Sur le Raspberry Pi de monitoring
sudo tailscale set --advertise-tags=tag:monitoring

# Sur le Raspberry Pi générique
sudo tailscale set --advertise-tags=tag:homelab

Ou depuis la console d’administration Tailscale, dans la section Machines, en cliquant sur l’appareil et en modifiant ses tags. Après attribution, les règles ACL deviennent effectives en quelques secondes.

6. Conclusion

Le principe du moindre privilège n’est pas réservé aux applications d’entreprise. L’appliquer à votre réseau domestique — même avec des outils grand public comme Tailscale — fait une vraie différence.

Le résultat pratique pour moi a été de pouvoir garder Tailscale toujours actif sans avoir à réfléchir à chaque fois à ce qui est connecté à quoi. La segmentation a transformé une précaution comportementale fragile (“n’oublie pas de l’éteindre”) en une garantie structurelle : le VPS est isolé par conception, pas par discipline.

Quelques dizaines de lignes de HuJSON, des tags attribués aux appareils, et la topologie réseau reflète enfin ce que je voulais — pas ce qui était commode de laisser par défaut.

Si vous gérez un réseau Tailscale avec des appareils de différents niveaux de confiance (et un serveur exposé à internet l’est certainement moins que votre ordinateur portable), ça vaut la peine de passer un après-midi à faire ce travail correctement.

Vous voulez le faire en cinq minutes ? Déléguez à Claude

Si votre réseau a plus d’une poignée d’appareils, concevoir des tags et des règles ACL à la main devient fastidieux — surtout si vous ne connaissez pas encore bien la syntaxe HuJSON. Il y a une façon beaucoup plus rapide : exportez la liste des hôtes depuis Tailscale et faites-la traiter directement par Claude.

Allez dans la console d’administration Tailscale → Machines, copiez la liste des machines avec le nom d’hôte et le rôle de chacune, puis collez tout dans Claude avec un prompt du type :

Voici la liste des machines de mon réseau Tailscale :

- pc-bureau         → PC personnel, usage quotidien
- smartphone-perso  → smartphone personnel
- rpi-monitor       → Raspberry Pi avec Prometheus et Grafana
- rpi-homelab       → Raspberry Pi pour expériences
- vps-prod          → serveur VPS exposé à internet

Crée un fichier HuJSON complet pour les ACL Tailscale :
- attribue des tags appropriés à chaque appareil selon son rôle
- définis une politique d'isolation sensée (le serveur ne doit pas pouvoir
  atteindre les appareils personnels ni le homelab)
- le nœud monitoring doit pouvoir scraper tous les nœuds (port 9100)
- ajoute des commentaires explicatifs pour chaque règle
- inclus les commandes tailscale set --advertise-tags pour chaque appareil

En réponse vous obtiendrez un fichier HuJSON complet et commenté, la liste des commandes à exécuter sur chaque nœud, et une matrice de visibilité déjà remplie — tout prêt à coller dans la section Access Controls de la console Tailscale. Si quelque chose ne vous convient pas, demandez des ajustements : en quelques échanges vous arriverez à une politique sur mesure sans avoir à étudier la syntaxe de zéro.