
tailsnitch v1.7
Un auditeur de sécurité pour les configurations Tailscale. Analyse votre tailnet pour les mauvaises configurations, les contrôles d'accès trop permissifs et les violations des bonnes pratiques de sécurité.
Tailsnitch
Un auditeur de sécurité pour les configurations Tailscale. Tailsnitch analyse votre tailnet à la recherche de 57 mauvaises configurations, de contrôles d'accès trop permissifs et de violations des bonnes pratiques de sécurité.
Démarrage rapide
# 1. Définissez vos identifiants API Tailscale
export TS_API_KEY="tskey-api-..."
# 2. Lancez l'audit
tailsnitch
# 3. Affichez uniquement les résultats de sévérité élevée
tailsnitch --severity high
# 4. Corrigez certains problèmes ~interactivement~ mode yolo
tailsnitch --fix
Installation
Télécharger le binaire précompilé
Téléchargez la dernière version depuis GitHub Releases.
Utilisateurs macOS : Supprimez l'attribut de quarantaine après le téléchargement :
sudo xattr -rd com.apple.quarantine tailsnitch
Installer via Go
go install github.com/Adversis/tailsnitch@latest
Compiler depuis les sources
git clone https://github.com/Adversis/tailsnitch.git
cd tailsnitch
go build -o tailsnitch .
Authentification
Tailsnitch prend en charge deux méthodes d'authentification. OAuth est préféré lorsque les deux sont configurés.
Option 1 : Client OAuth (recommandé)
Les clients OAuth fournissent un accès limité et auditable qui n'expire pas lorsque des employés quittent l'entreprise.
export TS_OAUTH_CLIENT_ID="..."
export TS_OAUTH_CLIENT_SECRET="tskey-client-..."
Créez un client OAuth à l'adresse : https://login.tailscale.com/admin/settings/oauth
Portées requises pour un audit en lecture seule :
all:read couvre tout. Attribution des portées individuellement :
| Portée | Utilisée pour |
|---|---|
policy_file:read | Fichier de politique du tailnet — ACL-, NET-, SSH-* |
devices:core:read | Liste des appareils — DEV-, NET-, ACL-011 |
dns:read | Configuration DNS — DNS-001, DEV-007 |
auth_keys:read | Clés d'authentification machine — AUTH-*, ACL-011 |
feature_settings:read | Paramètres du tailnet — DEV-008, DEV-009, DEV-014 |
logs:network:read | Paramètre de journalisation des flux réseau — LOG-001 |
networking_settings:read | Paramètre des certificats HTTPS — NET-004 |
log_streaming:read | Destinations de diffusion des journaux — LOG-002 |
webhooks:read | Points de terminaison webhook — LOG-005, LOG-012 |
oauth_keys:read | Clients OAuth — LOG-006 |
users:read | Rôles et statuts des utilisateurs — USER-001, LOG-006 |
account_settings:read | Contact de sécurité — LOG-011 |
devices:posture_attributes:read | Intégrations de posture — DEV-014 |
Toute portée que vous omettez n'affecte que les vérifications qui en ont besoin : ces vérifications signalent qu'elles n'ont pas pu lire le paramètre plutôt que de le considérer comme réussi.
AUTH-005 et AUTH-006 lisent les identités fédérées du tailnet, que la console d'administration appelle les informations d'identification de confiance. Elles proviennent de la même liste de clés que les clés d'authentification, donc auth_keys:read est censé les couvrir. Cela n'a pas été confirmé sur un tailnet en production. Si la liste des clés ne peut pas être lue, les deux vérifications signalent « non évalué » plutôt que réussi. On ne sait pas si une portée manquante renvoie une erreur ou renvoie plutôt la liste avec les identités filtrées ; si elle filtre silencieusement, AUTH-005 signalerait qu'aucune information d'identification de confiance n'existe et AUTH-006 ne trouverait rien à vérifier.
Portées supplémentaires pour le mode de correction :
devices:core- Supprimer des appareils, modifier les tags (nécessite la sélection de tags)auth_keys- Supprimer les clés d'authentification
Tailnet Lock
DEV-010 et DEV-012 signalent l'état de Tailnet Lock, que l'API Tailscale n'expose pas comme paramètre du tailnet. Les appareils verrouillés par celui-ci sont visibles via l'API, mais déterminer si le verrouillage est activé nécessite le CLI local tailscale, qui lit le démon sur la machine exécutant tailsnitch. Lors de l'audit d'un autre tailnet avec --tailnet, traitez cette partie du résultat en conséquence. Utilisez --tailscale-path si le binaire se trouve dans un emplacement non standard.
Option 2 : Clé API
Les clés API opèrent en tant qu'utilisateur qui les a créées et héritent des autorisations de cet utilisateur.
export TS_API_KEY="tskey-api-..."
Créez une clé API à l'adresse : https://login.tailscale.com/admin/settings/keys
Exemples d'utilisation
Audit de base
# Lancez l'audit complet
tailsnitch
# Affichez également les vérifications réussies (mode verbeux)
tailsnitch --verbose
# Sortie au format JSON pour traitement
tailsnitch --json
# Auditez un tailnet spécifique (lorsque le client OAuth a accès à plusieurs)
tailsnitch --tailnet mycompany.com
Filtrer les résultats
# Affichez uniquement les problèmes critiques et de sévérité élevée
tailsnitch --severity high
# Filtrer par catégorie
tailsnitch --category access # Problèmes ACL
tailsnitch --category auth # Authentification et clés
tailsnitch --category device # Sécurité des appareils
tailsnitch --category network # Exposition réseau
tailsnitch --category ssh # Règles SSH
tailsnitch --category log # Journalisation et administration
# Exécutez uniquement des vérifications spécifiques
tailsnitch --checks ACL-001,AUTH-001,DEV-010
tailsnitch --checks stale-devices,tailnet-lock-not-enabled
# Listez toutes les vérifications disponibles
tailsnitch --list-checks
Mode de correction interactif
Le mode de correction vous permet de remédier directement aux problèmes via l'API Tailscale :
# Mode de correction interactif
tailsnitch --fix
# Aperçu de ce qui serait corrigé (essai à blanc)
tailsnitch --fix --dry-run
# Sélection automatique des corrections sûres (nécessite toujours une confirmation)
tailsnitch --fix --auto
# Désactivez la journalisation d'audit des actions de correction
tailsnitch --fix --no-audit-log
Éléments corrigibles via l'API :
| Vérification | Action |
|---|---|
| AUTH-001, AUTH-002, AUTH-003 | Supprimer les clés d'authentification |
| DEV-002 | Retirer les tags des appareils utilisateur |
| DEV-004 | Supprimer les appareils obsolètes |
| DEV-005 | Autoriser les appareils en attente |
Le mode de correction fournit également des liens directs vers la console d'administration pour les problèmes nécessitant une intervention manuelle.
Export de preuves SOC 2
Générez des rapports de preuves pour les audits SOC 2 avec les correspondances des critères communs (CC) :
# Export au format JSON
tailsnitch --soc2 json > soc2-evidence.json
# Export au format CSV (pour les feuilles de calcul)
tailsnitch --soc2 csv > soc2-evidence.csv
Le rapport SOC 2 comprend :
- Résultats de test par ressource (chaque appareil, clé, règle ACL testés individuellement)
- Correspondances des codes CC (CC6.1, CC6.2, CC6.3, CC6.6, CC7.1, CC7.2, etc.)
- Statut Réussi/Échoué/N/A pour chaque test de contrôle
- Horodatage pour la piste d'audit
Exemple de sortie 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
Ignorer les risques connus
Créez un fichier .tailsnitch-ignore pour supprimer les résultats concernant les risques acceptés connus :
# .tailsnitch-ignore
# Ignorez les vérifications informatives
ACL-008 # Nous n'utilisons volontairement pas de groupes
ACL-009 # Les ACL héritées conviennent à notre cas d'utilisation
# Ignorez des vérifications moyennes spécifiques avec justification
DEV-006 # Les appareils externes sont des prestataires approuvés
LOG-001 # Les journaux de flux nécessitent le plan Enterprise
# Ignorez un élément au sein d'une vérification, au lieu de désactiver toute la vérification
ACL-011:tag:monitoring # large par conception ; chaque autre tag est toujours vérifié
AUTH-001:tskey-auth-xxxx # rotation automatique via CI, suivi dans TICKET-123
Une ligne désigne soit une vérification entière (ACL-011), soit un élément au sein de celle-ci (CHECK-ID:item, séparé au premier deux-points — l'élément lui-même peut contenir des deux-points). Une règle par élément ne supprime que cet élément : la vérification s'exécute toujours et signale toujours tout le reste qu'elle trouve. Supprimer chaque élément signalé ne transforme jamais une vérification échouée en vérification réussie — le résultat demeure, rétrogradé en Informatif, donc un résultat supprimé ne se lit jamais comme un contrôle satisfait.
Emplacements des fichiers d'ignorance (vérifiés dans l'ordre) :
.tailsnitch-ignoredans le répertoire courant~/.tailsnitch-ignoredans le répertoire personnel
Comme le premier emplacement est le répertoire de travail, un fichier d'ignorance peut provenir d'un dépôt plutôt que de vous. Chaque exécution signale quel fichier elle a utilisé et combien de résultats et d'éléments elle a supprimés, et --json enregistre cela dans les champs ignore_file et ignored (CHECK-ID pour une vérification entière, CHECK-ID:item pour un élément supprimé). Utilisez --no-ignore pour ignorer le fichier.
# Utilisez un fichier d'ignorance spécifique
tailsnitch --ignore-file /path/to/ignore
# Désactivez entièrement le traitement du fichier d'ignorance
tailsnitch --no-ignore
Export et traitement JSON
# Exportez le rapport complet
tailsnitch --json > audit.json
# Extrayez les vérifications échouées au format TSV
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false))
| .[]
| [.id, .title, .severity, .remediation]
| @tsv
' > findings.tsv
# Résumé par sévérité
tailsnitch --json | jq '
.suggestions
| map(select(.pass == false))
| group_by(.severity)
| map({severity: .[0].severity, count: length})
'
# Listez les problèmes critiques/élevés avec les liens d'administration
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false and (.severity == "CRITICAL" or .severity == "HIGH")))
| .[]
| "\(.id): \(.title)\n Fix: \(.fix.admin_url // "manual")\n"
'
Référence des commandes
| Option | Description |
|---|---|
--json | Sortie au format JSON |
--severity | Filtrer par sévérité minimale : critical, high, medium, low, info |
--category | Filtrer par catégorie : access, auth, network, ssh, log, device, dns |
--checks | Exécuter des vérifications spécifiques (identifiants ou slugs séparés par des virgules) |
--list-checks | Lister toutes les vérifications disponibles et quitter |
--tailnet | Spécifier le tailnet à auditer (par défaut : depuis la clé API) |
--verbose | Afficher également les vérifications réussies |
--fix | Activer le mode de correction interactif |
--auto | Sélection automatique des corrections sûres (nécessite --fix) |
--dry-run | Aperçu des actions de correction sans les exécuter (nécessite --fix) |
--no-audit-log | Désactiver la journalisation d'audit des actions de correction |
--soc2 | Exporter les preuves SOC 2 : json ou csv |
--tailscale-path | Chemin vers le CLI tailscale (pour les vérifications Tailnet Lock) |
--timeout | Budget de temps global pour l'audit (par défaut 2m) |
--ignore-file | Chemin vers le fichier d'ignorance |
--no-ignore | Désactiver le traitement du fichier d'ignorance |
--version | Afficher les informations de version |
Vérifications de sécurité
Tailsnitch effectue 57 vérifications de sécurité réparties dans 7 catégories. Consultez docs/CHECKS.md pour la documentation détaillée de chaque vérification.
Sévérité critique
| ID | Vérification | Risque |
|---|---|---|
| ACL-001 | Politique « tout autoriser » par défaut | Tous les appareils ont un accès sans restriction |
| ACL-002 | Mauvaise configuration SSH autogroup:nonroot | SSH en tant que tout utilisateur non root |
| ACL-006 | tagOwners trop large | Élévation de privilèges via les tags |
| ACL-007 | Utilisation de autogroup:danger-all | Accès accordé aux utilisateurs externes |
Sévérité élevée
| ID | Vérification | Risque |
|---|---|---|
| ACL-011 | La portée d'un tag franchit une frontière de confiance | Une clé réutilisable volée crée un tag qui atteint tout |
| AUTH-001 | Clés d'authentification réutilisables | Ajouts d'appareils illimités en cas de vol |
| AUTH-002 | Clés d'authentification à longue expiration | Fenêtre d'exposition prolongée |
| AUTH-003 | Clés pré-autorisées | Contournement de l'approbation des appareils |
| AUTH-006 | Sujet d'identité fédérée trop large | Tout principal que l'émetteur garantit peut créer le tag |
| DEV-001 | Appareils tagués sans expiration de clé | Accès indéfini |
| DEV-002 | Appareils utilisateur tagués | Persistent après la suppression de l'utilisateur |
| DEV-010 | Tailnet Lock désactivé | Aucune protection contre les clés volées |
| DEV-012 | Signatures Tailnet Lock en attente | Les nœuds non signés nécessitent un examen |
| NET-001 | Exposition Funnel | Accès Internet public |
| NET-003 | Frontière de confiance du routeur de sous-réseau | Trafic non chiffré sur le réseau local |
| SSH-002 | SSH root sans mode de vérification | Aucune ré-authentification requise |
Sévérité moyenne
| ID | Vérification | Risque |
|---|---|---|
| ACL-004 | Utilisation de autogroup:member | Utilisateurs externes inclus |
| ACL-005 | AutoApprovers configuré | Contournement de l'approbation des routes |
| AUTH-004 | Clés CI/CD non éphémères | Les appareils obsolètes s'accumulent |
| AUTH-005 | Fédération d'identités de charge de travail non utilisée | Les clés à longue durée de vie restent volables |
| DEV-003 | Clients obsolètes | Vulnérabilités potentielles |
| DEV-004 | Appareils obsolètes | Surface d'attaque inutilisée |
| DEV-005 | Appareils non autorisés | File d'attente d'approbation en attente |
| DEV-007 | Noms de machines sensibles | Exposition aux journaux CT |
| DEV-009 | Configuration d'approbation des appareils | Peut ne pas être activée |
| NET-004 | Exposition aux journaux CT HTTPS | Noms de machines publics |
| NET-005 | Visibilité du trafic du nœud de sortie | L'opérateur voit tout le trafic |
| NET-006 | Exposition Serve | Services locaux sur le tailnet |
| SSH-003 | Exposition de l'interface d'enregistrement | Sessions visibles sur le réseau |
Informatif
Vérifications de la configuration de journalisation, des paramètres DNS, des rôles utilisateur et des éléments de vérification manuelle.
Sévérité dépendant du résultat
Plusieurs vérifications évaluent ce qu'elles trouvent plutôt que de porter une sévérité fixe. Trois méritent d'être signalées ici :
- ACL-011 signale la portée de chaque tag en Informatif. Elle échoue uniquement lorsqu'un tag qu'une clé d'authentification peut attribuer atteint une destination générique, un sous-réseau routé ou une sortie de nœud de sortie : Élevée si une clé réutilisable attribue ce tag, Moyenne si seule une clé à usage unique le fait. Un nombre d'appareils ne définit jamais la sévérité.
- AUTH-005 signale Moyenne lorsque le tailnet n'a aucune information d'identification de confiance, et Faible lorsque des informations d'identification de confiance existent mais qu'une clé réutilisable crée encore des tags qu'aucune d'elles ne couvre.
- AUTH-006 signale Élevée pour un sujet qui n'est qu'un caractère générique, et Faible pour un caractère générique plus restreint ou une audience manquante.
Exemple de sortie
+=====================================================================+
| 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
Vérifications Tailnet Lock
Les vérifications Tailnet Lock (DEV-010, DEV-012) nécessitent le CLI local tailscale et s'exécutent contre le démon de la machine locale. Lors de l'audit d'un tailnet distant via --tailnet, ces vérifications reflètent l'état local, et non le tailnet audité.
# Spécifiez un chemin de binaire tailscale personnalisé si nécessaire
tailsnitch --tailscale-path /opt/tailscale/bin/tailscale
Intégration CI/CD
Exécutez Tailsnitch dans les pipelines CI/CD pour détecter les régressions de sécurité :
# Exemple GitHub Actions
- 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
Références
- Guide de durcissement de la sécurité Tailscale
- Référence de syntaxe ACL
- Tailscale SSH
- Journalisation d'audit
- Tailnet Lock
Licence
MIT
Contribution
Consultez CONTRIBUTING.md pour les directives.