TailscaleACL

Segmentare la rete Tailscale con ACL e tag: come ho isolato il mio server VPS dai dispositivi di casa

Tailscale lo uso da anni come VPN personale: comodissima, zero-config, funziona ovunque. Ma non l’ho mai tenuta sempre attiva — la accendevo quando serviva e la spegnevo. Una precauzione un po’ rozza, lo so, ma il motivo c’era: un server VPS esposto a internet nella stessa rete dei miei dispositivi di casa mi ha sempre convinto a non lasciare tutto connesso h24 per default. A un certo punto ho deciso di fare le cose per bene, invece di affidarmi a una disciplina manuale.

1. Il problema: la rete Tailscale è flat per default

Tailscale crea una rete mesh privata tra tutti i tuoi dispositivi. Di default, ogni nodo può raggiungere ogni altro nodo su qualsiasi porta. È comodo, ma è una rete piatta — esattamente come una LAN domestica dove tutti si vedono.

Il mio scenario: un server VPS esposto a internet (con Nginx, alcune porte aperte, servizi pubblici) nella stessa rete Tailscale del mio PC di casa, dello smartphone e dei Raspberry Pi. Il rischio è evidente — per questo non tenevo Tailscale sempre attivo. Ma “lo spengo quando non serve” non è una policy: è una scusa. Basta dimenticarselo una volta, o voler accedere al monitoring alle 2 di notte, per avere la rete piatta attiva senza averci pensato.

La soluzione corretta non è spegnere e accendere, è segmentare: fare in modo che il VPS, anche se compromesso, non possa raggiungere nulla di ciò che sta dall’altra parte della rete.

2. La soluzione: Tailscale ACL e tag

Tailscale permette di definire policy di accesso tramite un file di configurazione in formato HuJSON (JSON con commenti), gestito dalla console di amministrazione. Il meccanismo si basa su due concetti:

  • Tag: etichette che si assegnano ai dispositivi (es. tag:server, tag:monitoring). I tag permettono di raggruppare i device per ruolo, indipendentemente da chi li possiede.
  • ACL (Access Control List): regole che definiscono chi può parlare con chi, su quali porte e protocolli.

Il funzionamento è whitelist: tutto ciò che non è esplicitamente permesso è bloccato. Questo è il punto di svolta rispetto alla configurazione default.

I tag si definiscono nella sezione tagOwners del file di policy: qui si specifica chi ha il diritto di assegnare quel tag a un device. Poi si assegnano i tag ai dispositivi dalla console o via tailscale set --advertise-tags sul device stesso.

3. Il design della rete

Ho strutturato la rete con cinque dispositivi, ognuno con un ruolo ben definito:

DispositivoTagRuolo
PC Desktoptag:personalMacchina di lavoro/uso quotidiano
Smartphonetag:personalDispositivo mobile personale
Raspberry Pi (generico)tag:homelabServizi interni, esperimenti
Raspberry Pi (monitoring)tag:monitoringPrometheus, Grafana, alerting
Server VPStag:serverServizi pubblici esposti a internet

La logica di accesso che volevo implementare:

  • I dispositivi personal possono raggiungere tutto (sono io che amministro)
  • Il nodo monitoring può fare scraping su tutti i nodi (porta 9100 per node_exporter)
  • Il server VPS può essere raggiunto da personal e monitoring, ma non può iniziare connessioni verso gli altri
  • L’homelab è isolato: non può essere raggiunto dal server

4. Le policy implementate

Ecco la matrice di visibilità risultante:

Da \ Versopersonalhomelabmonitoringserver
personal
homelab
monitoring✓ (9100)✓ (9100)
server

E il file HuJSON delle ACL corrispondente:

{
  // Chi può assegnare i tag
  "tagOwners": {
    "tag:personal":    ["autogroup:admin"],
    "tag:homelab":     ["autogroup:admin"],
    "tag:monitoring":  ["autogroup:admin"],
    "tag:server":      ["autogroup:admin"]
  },

  "acls": [
    // I dispositivi personali possono raggiungere tutto
    {
      "action": "accept",
      "src":    ["tag:personal"],
      "dst":    ["*:*"]
    },

    // Il monitoring può fare scraping su homelab e server (node_exporter)
    {
      "action": "accept",
      "src":    ["tag:monitoring"],
      "dst":    ["tag:homelab:9100", "tag:server:9100"]
    },

    // Il monitoring può raggiungere se stesso (es. Prometheus → Grafana)
    {
      "action": "accept",
      "src":    ["tag:monitoring"],
      "dst":    ["tag:monitoring:*"]
    },

    // L'homelab può raggiungere solo se stesso
    {
      "action": "accept",
      "src":    ["tag:homelab"],
      "dst":    ["tag:homelab:*"]
    }

    // Tutto il resto è bloccato implicitamente (whitelist)
  ]
}

Con questa configurazione, il VPS non può aprire connessioni verso nessun altro nodo. Anche se compromesso, è isolato dal resto della rete.

5. Un errore comune: i tag che non esistono sui device

Questo è l’errore in cui sono caduto la prima volta, e probabilmente ci cade chiunque si avvicini a questa configurazione.

Ho scritto la policy, l’ho salvata nella console Tailscale, e mi sono connesso via SSH al server. Tutto funzionava. Ho aspettato qualche minuto, poi ho provato di nuovo — e SSH si bloccava. Niente timeout esplicito, solo silenzio.

Il problema: avevo definito i tag nella policy ma non li avevo assegnati ai device. Un dispositivo senza tag non corrisponde a nessuna regola ACL, quindi in modalità whitelist non può fare né ricevere nulla — tranne le connessioni già attive al momento dell’applicazione della policy (che scadono dopo un po’).

La diagnosi si fa con:

tailscale status

Nella colonna dei tag, i device senza tag appaiono vuoti o con solo il nome utente. Il fix è assegnare i tag dal device stesso:

# Sul server VPS
sudo tailscale set --advertise-tags=tag:server

# Sul Raspberry Pi di monitoring
sudo tailscale set --advertise-tags=tag:monitoring

# Sul Raspberry Pi generico
sudo tailscale set --advertise-tags=tag:homelab

Oppure dalla console di amministrazione Tailscale, nella sezione Machines, cliccando sul device e modificando i tag. Dopo l’assegnazione, le regole ACL diventano operative entro pochi secondi.

Nota: per poter assegnare un tag a un device, quell’utente (o il device stesso, se usa auth key con pre-autorizzazione) deve essere elencato nella sezione tagOwners della policy.

6. Conclusione

Il principio del minimo privilegio non è solo per le applicazioni enterprise. Applicarlo alla propria rete domestica — anche con strumenti consumer come Tailscale — fa una differenza concreta.

Il risultato pratico per me è stato poter tenere Tailscale sempre attivo senza dover ragionare ogni volta su cosa è connesso a cosa. La segmentazione ha trasformato una precauzione comportamentale fragile (“ricordati di spegnerlo”) in una garanzia strutturale: il VPS è isolato per design, non per disciplina.

Qualche decina di righe di HuJSON, tag assegnati ai device, e la topologia di rete riflette finalmente quello che volevo — non quello che era comodo lasciare per default.

Se gestisci una rete Tailscale con dispositivi di diverso livello di fiducia (e un server esposto a internet lo è sicuramente meno del tuo laptop), vale la pena prendersi un pomeriggio per fare questo lavoro.

Vuoi farlo in cinque minuti? Delegalo a Claude

Se la tua rete ha più di una manciata di device, progettare tag e regole ACL a mano diventa noioso — specialmente se non conosci ancora bene la sintassi HuJSON. C’è un modo molto più rapido: esporta la lista degli host da Tailscale e falla elaborare direttamente a Claude.

Vai nella console di amministrazione Tailscale → Machines, copia la lista delle macchine con hostname e ruolo di ciascuna, poi incolla tutto in Claude con un prompt del tipo:

Ecco la lista delle macchine nella mia rete Tailscale:

- pc-casa       → PC personale, uso quotidiano
- smartphone-personale       → smartphone personale
- rpi-monitor        → Raspberry Pi con Prometheus e Grafana
- rpi-homelab        → Raspberry Pi per esperimenti
- vps-prod           → server VPS esposto a internet

Crea un file HuJSON completo per le ACL Tailscale:
- assegna tag appropriati a ogni device in base al ruolo
- definisci una policy di isolamento sensata (il server non deve poter
  raggiungere i dispositivi personali né l'homelab)
- il nodo monitoring deve poter fare scraping su tutti (porta 9100)
- aggiungi commenti esplicativi per ogni regola
- includi anche i comandi tailscale set --advertise-tags per ogni device

In risposta otterrai un file HuJSON completo e commentato, la lista dei comandi da eseguire su ogni nodo e una matrice di visibilità già compilata — tutto pronto da incollare nella sezione Access Controls della console Tailscale. Se qualcosa non ti convince, basta chiedere aggiustamenti: in pochi scambi si arriva a una policy su misura senza dover studiare la sintassi da zero o rileggere la documentazione ogni cinque minuti.