
tailsnitch v1.7
Un auditor di sicurezza per le configurazioni di Tailscale. Analizza la tua tailnet alla ricerca di configurazioni errate, controlli di accesso eccessivamente permissivi e violazioni delle best practice di sicurezza.
Tailsnitch
Un auditor di sicurezza per le configurazioni Tailscale. Tailsnitch analizza la tua tailnet alla ricerca di 57 misconfigurazioni, controlli di accesso eccessivamente permissivi e violazioni delle best practice di sicurezza.
Avvio Rapido
# 1. Imposta le credenziali API Tailscale
export TS_API_KEY="tskey-api-..."
# 2. Esegui l'audit
tailsnitch
# 3. Mostra solo i risultati ad alta gravità
tailsnitch --severity high
# 4. Correggi alcuni problemi ~interattivamente~ modalità yolo
tailsnitch --fix
Installazione
Scarica il Binario Precompilato
Scarica l'ultima release da GitHub Releases.
Utenti macOS: Rimuovi l'attributo di quarantena dopo il download:
sudo xattr -rd com.apple.quarantine tailsnitch
Installa tramite Go
go install github.com/Adversis/tailsnitch@latest
Compila dal Codice Sorgente
git clone https://github.com/Adversis/tailsnitch.git
cd tailsnitch
go build -o tailsnitch .
Autenticazione
Tailsnitch supporta due metodi di autenticazione. OAuth è preferito quando entrambi sono configurati.
Opzione 1: Client OAuth (Consigliato)
I client OAuth forniscono accesso con ambiti definiti e verificabile che non scade quando i dipendenti lasciano l'azienda.
export TS_OAUTH_CLIENT_ID="..."
export TS_OAUTH_CLIENT_SECRET="tskey-client-..."
Crea un client OAuth su: https://login.tailscale.com/admin/settings/oauth
Ambiti richiesti per audit in sola lettura:
all:read copre tutto. Concessione degli ambiti singolarmente:
| Ambito | Utilizzato per |
|---|---|
policy_file:read | File policy della tailnet — ACL-, NET-, SSH-* |
devices:core:read | Elenco dispositivi — DEV-, NET-, ACL-011 |
dns:read | Configurazione DNS — DNS-001, DEV-007 |
auth_keys:read | Chiavi di autenticazione macchina — AUTH-*, ACL-011 |
feature_settings:read | Impostazioni tailnet — DEV-008, DEV-009, DEV-014 |
logs:network:read | Impostazione registrazione flusso di rete — LOG-001 |
networking_settings:read | Impostazione certificato HTTPS — NET-004 |
log_streaming:read | Destinazioni streaming log — LOG-002 |
webhooks:read | Endpoint webhook — LOG-005, LOG-012 |
oauth_keys:read | Client OAuth — LOG-006 |
users:read | Ruoli e stato utenti — USER-001, LOG-006 |
account_settings:read | Contatto di sicurezza — LOG-011 |
devices:posture_attributes:read | Integrazioni posture — DEV-014 |
Qualsiasi ambito che tralasci influisce solo sui controlli che ne hanno bisogno: quei controlli segnalano di non aver potuto leggere l'impostazione anziché superare.
AUTH-005 e AUTH-006 leggono le identità federate della tailnet, che la console
amministrativa chiama credenziali di trust. Arrivano dallo stesso elenco di chiavi delle
chiavi di autenticazione, quindi ci si aspetta che auth_keys:read le copra. Ciò non è stato
confermato su una tailnet live. Se l'elenco delle chiavi non può essere letto, entrambi i controlli
segnalano "non valutato" anziché superare. Se un ambito mancante restituisce un errore o
restituisce invece l'elenco con le identità filtrate non è confermato; se
filtra silenziosamente, AUTH-005 segnalerebbe che non esistono credenziali di trust e
AUTH-006 non troverebbe nulla da controllare.
Ambiti aggiuntivi per la modalità di correzione:
devices:core- Elimina dispositivi, modifica tag (richiede selezione tag)auth_keys- Elimina chiavi di autenticazione
Tailnet Lock
DEV-010 e DEV-012 segnalano Tailnet Lock, che l'API Tailscale non
espone come impostazione della tailnet. I dispositivi bloccati da esso sono visibili tramite
l'API, ma determinare se il lock è abilitato richiede la CLI locale tailscale,
che legge il daemon sulla macchina che esegue tailsnitch. Quando si esegue l'audit di un'altra
tailnet con --tailnet, considera quella parte del risultato di conseguenza. Usa
--tailscale-path se il binario si trova in una posizione non standard.
Opzione 2: Chiave API
Le chiavi API operano come l'utente che le ha create ed ereditano i permessi di quell'utente.
export TS_API_KEY="tskey-api-..."
Crea una chiave API su: https://login.tailscale.com/admin/settings/keys
Esempi di Utilizzo
Audit di Base
# Esegui audit completo
tailsnitch
# Mostra anche i controlli superati (verbose)
tailsnitch --verbose
# Output come JSON per l'elaborazione
tailsnitch --json
# Audita una tailnet specifica (quando il client OAuth ha accesso a più tailnet)
tailsnitch --tailnet mycompany.com
Filtra i Risultati
# Mostra solo problemi critici e ad alta gravità
tailsnitch --severity high
# Filtra per categoria
tailsnitch --category access # Problemi ACL
tailsnitch --category auth # Autenticazione e chiavi
tailsnitch --category device # Sicurezza dispositivi
tailsnitch --category network # Esposizione di rete
tailsnitch --category ssh # Regole SSH
tailsnitch --category log # Registrazione e amministrazione
# Esegui solo controlli specifici
tailsnitch --checks ACL-001,AUTH-001,DEV-010
tailsnitch --checks stale-devices,tailnet-lock-not-enabled
# Elenca tutti i controlli disponibili
tailsnitch --list-checks
Modalità di Correzione Interattiva
La modalità di correzione ti consente di rimediare ai problemi direttamente tramite l'API Tailscale:
# Modalità di correzione interattiva
tailsnitch --fix
# Anteprima di cosa verrebbe corretto (prova a secco)
tailsnitch --fix --dry-run
# Auto-selezione delle correzioni sicure (richiede comunque conferma)
tailsnitch --fix --auto
# Disabilita la registrazione audit delle azioni di correzione
tailsnitch --fix --no-audit-log
Elementi correggibili tramite API:
| Controllo | Azione |
|---|---|
| AUTH-001, AUTH-002, AUTH-003 | Elimina chiavi di autenticazione |
| DEV-002 | Rimuovi tag dai dispositivi utente |
| DEV-004 | Elimina dispositivi obsoleti |
| DEV-005 | Autorizza dispositivi in attesa |
La modalità di correzione fornisce anche collegamenti diretti alla console amministrativa per i problemi che richiedono intervento manuale.
Esportazione Prove SOC 2
Genera report di prove per audit SOC 2 con mappature dei Criteri Comuni (CC):
# Esporta come JSON
tailsnitch --soc2 json > soc2-evidence.json
# Esporta come CSV (per fogli di calcolo)
tailsnitch --soc2 csv > soc2-evidence.csv
Il report SOC 2 include:
- Risultati dei test per risorsa (ogni dispositivo, chiave, regola ACL testata singolarmente)
- Mappature codici CC (CC6.1, CC6.2, CC6.3, CC6.6, CC7.1, CC7.2, ecc.)
- Stato Superato/Non Superato/N/D per ogni test di controllo
- Timestamp per la traccia di audit
Esempio di output CSV:
resource_type,resource_id,resource_name,check_id,check_title,cc_codes,status,details,tested_at
device,node123,prod-server,DEV-001,Tagged devices with key expiry disabled,CC6.1;CC6.3,PASS,Tags: [tag:server] key expiry enabled,2025-01-05T10:30:00Z
key,tskey-auth-xxx,tskey-auth-xxx,AUTH-001,Reusable auth keys exist,CC6.1;CC6.2;CC6.3,FAIL,Reusable key expires in 45 days,2025-01-05T10:30:00Z
Ignora Rischi Noti
Crea un file .tailsnitch-ignore per sopprimere i risultati per rischi noti e accettati:
# .tailsnitch-ignore
# Ignora controlli informativi
ACL-008 # Non usiamo intenzionalmente i gruppi
ACL-009 # Gli ACL legacy vanno bene per il nostro caso d'uso
# Ignora controlli medi specifici con giustificazione
DEV-006 # I dispositivi esterni sono appaltatori approvati
LOG-001 # I log di flusso richiedono il piano Enterprise
# Ignora un singolo elemento all'interno di un controllo, invece di silenziare l'intero controllo
ACL-011:tag:monitoring # ampio di proposito; ogni altro tag viene comunque controllato
AUTH-001:tskey-auth-xxxx # ruota automaticamente tramite CI, tracciato in TICKET-123
Una riga identifica o un intero controllo (ACL-011) o un singolo elemento al suo interno
(CHECK-ID:item, diviso sul primo due punti - l'elemento stesso può contenere
due punti). Una regola per singolo elemento sopprime solo quell'elemento: il controllo continua
a essere eseguito e segnala comunque tutto il resto che trova. Sopprimere ogni elemento segnalato non
trasforma mai un controllo non superato in uno superato - il risultato rimane, declassato a
Informativo, quindi un risultato soppresso non viene mai letto come un controllo soddisfatto.
Posizioni dei file di ignore (controllate in ordine):
.tailsnitch-ignorenella directory corrente~/.tailsnitch-ignorenella home directory
Poiché la prima posizione è la directory di lavoro, un file di ignore può provenire
da un repository anziché da te. Ogni esecuzione segnala quale file ha utilizzato
e quanti risultati ed elementi ha soppresso, e --json registra questo nei
campi ignore_file e ignored (CHECK-ID per un intero controllo,
CHECK-ID:item per un singolo elemento soppresso). Usa --no-ignore per saltare il file.
# Usa un file di ignore specifico
tailsnitch --ignore-file /path/to/ignore
# Disabilita completamente l'elaborazione del file di ignore
tailsnitch --no-ignore
Esportazione ed Elaborazione JSON
# Esporta report completo
tailsnitch --json > audit.json
# Estrai controlli non superati come TSV
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false))
| .[]
| [.id, .title, .severity, .remediation]
| @tsv
' > findings.tsv
# Riepilogo per gravità
tailsnitch --json | jq '
.suggestions
| map(select(.pass == false))
| group_by(.severity)
| map({severity: .[0].severity, count: length})
'
# Elenca problemi critici/ad alta gravità con collegamenti amministrativi
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false and (.severity == "CRITICAL" or .severity == "HIGH")))
| .[]
| "\(.id): \(.title)\n Fix: \(.fix.admin_url // "manual")\n"
'
Riferimento Comandi
| Flag | Descrizione |
|---|---|
--json | Output come JSON |
--severity | Filtra per gravità minima: critical, high, medium, low, info |
--category | Filtra per categoria: access, auth, network, ssh, log, device, dns |
--checks | Esegui controlli specifici (ID o slug separati da virgola) |
--list-checks | Elenca tutti i controlli disponibili ed esci |
--tailnet | Specifica la tailnet da audire (predefinito: dalla chiave API) |
--verbose | Mostra anche i controlli superati |
--fix | Abilita la modalità di correzione interattiva |
--auto | Auto-selezione delle correzioni sicure (richiede --fix) |
--dry-run | Anteprima delle azioni di correzione senza eseguirle (richiede --fix) |
--no-audit-log | Disabilita la registrazione audit delle azioni di correzione |
--soc2 | Esporta prove SOC 2: json o csv |
--tailscale-path | Percorso della CLI tailscale (per controlli Tailnet Lock) |
--timeout | Budget di tempo complessivo per l'audit (predefinito 2m) |
--ignore-file | Percorso del file di ignore |
--no-ignore | Disabilita l'elaborazione del file di ignore |
--version | Mostra informazioni sulla versione |
Controlli di Sicurezza
Tailsnitch esegue 57 controlli di sicurezza in 7 categorie. Vedi docs/CHECKS.md per la documentazione dettagliata di ogni controllo.
Gravità Critica
| ID | Controllo | Rischio |
|---|---|---|
| ACL-001 | Policy 'allow all' predefinita | Tutti i dispositivi hanno accesso illimitato |
| ACL-002 | Misconfigurazione SSH autogroup:nonroot | SSH come qualsiasi utente non root |
| ACL-006 | tagOwners troppo ampio | Escalation di privilegi tramite tag |
| ACL-007 | Utilizzo di autogroup:danger-all | Accesso concesso a utenti esterni |
Gravità Alta
| ID | Controllo | Rischio |
|---|---|---|
| ACL-011 | La portata dei tag attraversa un confine di trust | Una chiave riutilizzabile rubata crea un tag che raggiunge tutto |
| AUTH-001 | Chiavi di autenticazione riutilizzabili | Aggiunte illimitate di dispositivi se rubate |
| AUTH-002 | Chiavi di autenticazione con scadenza lunga | Finestra di esposizione estesa |
| AUTH-003 | Chiavi pre-autorizzate | Bypass dell'approvazione dei dispositivi |
| AUTH-006 | Soggetto di identità federata troppo ampio | Qualsiasi principal garantito dall'emittente può creare il tag |
| DEV-001 | Dispositivi con tag senza scadenza chiave | Accesso indefinito |
| DEV-002 | Dispositivi utente con tag | Persistono dopo la rimozione dell'utente |
| DEV-010 | Tailnet Lock disabilitato | Nessuna protezione contro chiavi rubate |
| DEV-012 | Firme Tailnet Lock in sospeso | I nodi non firmati richiedono revisione |
| NET-001 | Esposizione Funnel | Accesso internet pubblico |
| NET-003 | Confine di trust del router di sottorete | Traffico non crittografato sulla rete locale |
| SSH-002 | SSH root senza modalità di verifica | Nessuna ri-autenticazione richiesta |
Gravità Media
| ID | Controllo | Rischio |
|---|---|---|
| ACL-004 | Utilizzo di autogroup:member | Utenti esterni inclusi |
| ACL-005 | AutoApprovers configurati | Bypass dell'approvazione delle route |
| AUTH-004 | Chiavi CI/CD non effimere | I dispositivi obsoleti si accumulano |
| AUTH-005 | Federazione identità workload non in uso | Le chiavi a lunga durata restano rubabili |
| DEV-003 | Client obsoleti | Potenziali vulnerabilità |
| DEV-004 | Dispositivi obsoleti | Superficie di attacco inutilizzata |
| DEV-005 | Dispositivi non autorizzati | Coda di approvazione in sospeso |
| DEV-007 | Nomi macchina sensibili | Esposizione nei log CT |
| DEV-009 | Configurazione approvazione dispositivi | Potrebbe non essere abilitata |
| NET-004 | Esposizione log CT HTTPS | Nomi macchina pubblici |
| NET-005 | Visibilità traffico nodo di uscita | L'operatore vede tutto il traffico |
| NET-006 | Esposizione Serve | Servizi locali sulla tailnet |
| SSH-003 | Esposizione interfaccia registratore | Sessioni visibili alla rete |
Informativo
Controlli per configurazione di registrazione, impostazioni DNS, ruoli utente ed elementi di verifica manuale.
Gravità che dipende dal risultato
Diversi controlli valutano ciò che trovano anziché avere una gravità fissa. Tre meritano di essere menzionati:
- ACL-011 segnala la portata di ogni tag come Informativo. Fallisce solo quando un tag che una chiave di autenticazione può assegnare raggiunge una destinazione wildcard, una sottorete instradata o l'egress del nodo di uscita: Alta se una chiave riutilizzabile assegna quel tag, Media se solo una chiave monouso lo fa. Un conteggio di dispositivi non determina mai la gravità.
- AUTH-005 segnala Medio quando la tailnet non ha alcuna credenziale di trust, e Basso quando le credenziali di trust esistono ma una chiave riutilizzabile crea ancora tag che nessuna di esse copre.
- AUTH-006 segnala Alto per un soggetto che è solo un wildcard, e Basso per un wildcard più ristretto o un audience mancante.
Esempio di Output
+=====================================================================+
| TAILSNITCH SECURITY AUDIT |
| Tailnet: example.com |
| Version: 1.0.0 (build: abc123) |
+=====================================================================+
Using ignore file: .tailsnitch-ignore (3 rules)
=== ACCESS CONTROLS ===================================================
[CRITICAL] ACL-001: Default 'allow all' policy active
Your ACL policy omits the 'acls' field. Tailscale applies a
default 'allow all' policy, granting all devices full access.
Remediation:
Define explicit ACL rules following least privilege principle.
Source: https://tailscale.com/docs/reference/examples/acls
----------------------------------------------------------------------
=== AUTHENTICATION & KEYS =============================================
[HIGH] AUTH-001: Reusable auth keys exist
Found 2 reusable auth key(s). These can be reused to add
multiple devices if compromised.
Details:
- Key tskey-auth-xxx (expires in 45 days)
- Key tskey-auth-yyy (expires in 89 days)
Remediation:
Store reusable keys in a secrets manager. Prefer one-off keys.
Source: https://tailscale.com/docs/features/access-control/auth-keys
----------------------------------------------------------------------
SUMMARY
======================================================================
Critical: 1 High: 3 Medium: 5 Low: 2 Info: 8
Total findings: 19 | Passed: 33
Controlli Tailnet Lock
I controlli Tailnet Lock (DEV-010, DEV-012) richiedono la CLI locale tailscale e vengono eseguiti sul daemon della macchina locale. Quando si audita una tailnet remota tramite --tailnet, questi controlli riflettono lo stato locale, non quello della tailnet auditata.
# Specifica un percorso binario tailscale personalizzato se necessario
tailsnitch --tailscale-path /opt/tailscale/bin/tailscale
Integrazione CI/CD
Esegui Tailsnitch nelle pipeline CI/CD per individuare regressioni di sicurezza:
# GitHub Actions example
- name: Audit Tailscale Security
env:
TS_OAUTH_CLIENT_ID: ${{ secrets.TS_OAUTH_CLIENT_ID }}
TS_OAUTH_CLIENT_SECRET: ${{ secrets.TS_OAUTH_CLIENT_SECRET }}
run: |
tailsnitch --json > audit.json
# Fail if critical or high severity issues exist
if tailsnitch --severity high --json | jq -e '.summary.critical + .summary.high > 0' > /dev/null; then
echo "Critical or high severity issues found!"
tailsnitch --severity high
exit 1
fi
Riferimenti
Licenza
MIT
Contributi
Vedi CONTRIBUTING.md per le linee guida.