
tailsnitch v1.7
Un auditor de seguridad para configuraciones de Tailscale. Escanea tu tailnet en busca de configuraciones incorrectas, controles de acceso excesivamente permisivos y violaciones de las mejores prácticas de seguridad.
Tailsnitch
Un auditor de seguridad para configuraciones de Tailscale. Tailsnitch escanea tu tailnet en busca de 57 malas configuraciones, controles de acceso excesivamente permisivos y violaciones de mejores prácticas de seguridad.
Inicio Rápido
# 1. Configura tus credenciales de la API de Tailscale
export TS_API_KEY="tskey-api-..."
# 2. Ejecuta la auditoría
tailsnitch
# 3. Ve solo los hallazgos de severidad alta
tailsnitch --severity high
# 4. Corrige algunos problemas ~interactivamente~ modo yolo
tailsnitch --fix
Instalación
Descargar Binario Precompilado
Descarga la última versión desde GitHub Releases.
Usuarios de macOS: Elimina el atributo de cuarentena después de la descarga:
sudo xattr -rd com.apple.quarantine tailsnitch
Instalar vía Go
go install github.com/Adversis/tailsnitch@latest
Compilar desde el Código Fuente
git clone https://github.com/Adversis/tailsnitch.git
cd tailsnitch
go build -o tailsnitch .
Autenticación
Tailsnitch admite dos métodos de autenticación. Se prefiere OAuth cuando ambos están configurados.
Opción 1: Cliente OAuth (Recomendado)
Los clientes OAuth proporcionan acceso con alcance definido y auditable que no expira cuando los empleados se van.
export TS_OAUTH_CLIENT_ID="..."
export TS_OAUTH_CLIENT_SECRET="tskey-client-..."
Crea un cliente OAuth en: https://login.tailscale.com/admin/settings/oauth
Alcances requeridos para auditoría de solo lectura:
all:read lo cubre todo. Otorgar alcances individualmente:
| Alcance | Se usa para |
|---|---|
policy_file:read | Archivo de política del tailnet — ACL-, NET-, SSH-* |
devices:core:read | Lista de dispositivos — DEV-, NET-, ACL-011 |
dns:read | Configuración de DNS — DNS-001, DEV-007 |
auth_keys:read | Claves de autenticación de máquinas — AUTH-*, ACL-011 |
feature_settings:read | Configuración del tailnet — DEV-008, DEV-009, DEV-014 |
logs:network:read | Configuración de registro de flujo de red — LOG-001 |
networking_settings:read | Configuración de certificados HTTPS — NET-004 |
log_streaming:read | Destinos de transmisión de registros — LOG-002 |
webhooks:read | Endpoints de webhooks — LOG-005, LOG-012 |
oauth_keys:read | Clientes OAuth — LOG-006 |
users:read | Roles y estado de usuarios — USER-001, LOG-006 |
account_settings:read | Contacto de seguridad — LOG-011 |
devices:posture_attributes:read | Integraciones de postura — DEV-014 |
Cualquier alcance que omitas solo afecta a las comprobaciones que lo necesitan: esas comprobaciones informan que no pudieron leer la configuración en lugar de pasarla.
AUTH-005 y AUTH-006 leen las identidades federadas del tailnet, que la consola
de administración llama credenciales de confianza. Provienen de la misma lista de claves que las
claves de autenticación, por lo que se espera que auth_keys:read las cubra. Eso no se ha confirmado
contra un tailnet en vivo. Si la lista de claves no se puede leer, ambas comprobaciones informan
"no evaluado" en lugar de pasarla. Si un alcance faltante devuelve un error o
en su lugar devuelve la lista con las identidades filtradas no está confirmado; si
filtra silenciosamente, AUTH-005 informaría que no existen credenciales de confianza y
AUTH-006 no encontraría nada que comprobar.
Alcances adicionales para el modo de corrección:
devices:core- Eliminar dispositivos, modificar etiquetas (requiere selección de etiquetas)auth_keys- Eliminar claves de autenticación
Tailnet Lock
DEV-010 y DEV-012 informan sobre Tailnet Lock, que la API de Tailscale no
expone como una configuración del tailnet. Los dispositivos bloqueados por él son visibles a través de la
API, pero determinar si el bloqueo está habilitado necesita el CLI local tailscale,
que lee el daemon en la máquina que ejecuta tailsnitch. Al auditar otro
tailnet con --tailnet, trata esa parte del resultado en consecuencia. Usa
--tailscale-path si el binario está en una ubicación no estándar.
Opción 2: Clave de API
Las claves de API operan como el usuario que las creó y heredan los permisos de ese usuario.
export TS_API_KEY="tskey-api-..."
Crea una clave de API en: https://login.tailscale.com/admin/settings/keys
Ejemplos de Uso
Auditoría Básica
# Ejecuta auditoría completa
tailsnitch
# Muestra también las comprobaciones que pasan (verbose)
tailsnitch --verbose
# Salida como JSON para procesamiento
tailsnitch --json
# Audita un tailnet específico (cuando el cliente OAuth tiene acceso a varios)
tailsnitch --tailnet mycompany.com
Filtrar Resultados
# Solo muestra problemas críticos y de severidad alta
tailsnitch --severity high
# Filtrar por categoría
tailsnitch --category access # Problemas de ACL
tailsnitch --category auth # Autenticación y claves
tailsnitch --category device # Seguridad de dispositivos
tailsnitch --category network # Exposición de red
tailsnitch --category ssh # Reglas SSH
tailsnitch --category log # Registro y administración
# Ejecutar solo comprobaciones específicas
tailsnitch --checks ACL-001,AUTH-001,DEV-010
tailsnitch --checks stale-devices,tailnet-lock-not-enabled
# Listar todas las comprobaciones disponibles
tailsnitch --list-checks
Modo de Corrección Interactivo
El modo de corrección te permite remediar problemas directamente a través de la API de Tailscale:
# Modo de corrección interactivo
tailsnitch --fix
# Vista previa de lo que se corregiría (ejecución en seco)
tailsnitch --fix --dry-run
# Auto-seleccionar correcciones seguras (aún requiere confirmación)
tailsnitch --fix --auto
# Deshabilitar el registro de auditoría de las acciones de corrección
tailsnitch --fix --no-audit-log
Elementos corregibles por API:
| Comprobación | Acción |
|---|---|
| AUTH-001, AUTH-002, AUTH-003 | Eliminar claves de autenticación |
| DEV-002 | Eliminar etiquetas de dispositivos de usuario |
| DEV-004 | Eliminar dispositivos obsoletos |
| DEV-005 | Autorizar dispositivos pendientes |
El modo de corrección también proporciona enlaces directos a la consola de administración para problemas que requieren intervención manual.
Exportación de Evidencia SOC 2
Genera informes de evidencia para auditorías SOC 2 con mapeos de Criterios Comunes (CC):
# Exportar como JSON
tailsnitch --soc2 json > soc2-evidence.json
# Exportar como CSV (para hojas de cálculo)
tailsnitch --soc2 csv > soc2-evidence.csv
El informe SOC 2 incluye:
- Resultados de pruebas por recurso (cada dispositivo, clave, regla ACL probada individualmente)
- Mapeos de códigos CC (CC6.1, CC6.2, CC6.3, CC6.6, CC7.1, CC7.2, etc.)
- Estado Aprobado/Reprobado/N/A para cada prueba de control
- Marca de tiempo para la pista de auditoría
Ejemplo de salida 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
Ignorar Riesgos Conocidos
Crea un archivo .tailsnitch-ignore para suprimir hallazgos de riesgos aceptados conocidos:
# .tailsnitch-ignore
# Ignorar comprobaciones informativas
ACL-008 # Intencionalmente no usamos grupos
ACL-009 # Las ACL heredadas están bien para nuestro caso de uso
# Ignorar comprobaciones específicas de severidad media con justificación
DEV-006 # Los dispositivos externos son contratistas aprobados
LOG-001 # Los registros de flujo requieren el plan Enterprise
# Ignorar un elemento dentro de una comprobación, en lugar de silenciar toda la comprobación
ACL-011:tag:monitoring # amplio por diseño; cada otra etiqueta aún se comprueba
AUTH-001:tskey-auth-xxxx # rota automáticamente vía CI, rastreado en TICKET-123
Una línea nombra una comprobación completa (ACL-011) o un elemento dentro de ella
(CHECK-ID:item, dividido en los dos puntos - el elemento en sí puede contener
dos puntos). Una regla por elemento suprime solo ese elemento: la comprobación aún se ejecuta y
aún informa todo lo demás que encuentra. Suprimir cada elemento marcado nunca
convierte una comprobación reprobada en una aprobada - el hallazgo permanece, degradado a
Informativo, por lo que un hallazgo suprimido nunca se lee como un control satisfecho.
Ubicaciones del archivo de ignorados (verificadas en orden):
.tailsnitch-ignoreen el directorio actual~/.tailsnitch-ignoreen el directorio de inicio
Debido a que la primera ubicación es el directorio de trabajo, un archivo de ignorados puede provenir
de un repositorio en lugar de ti. Cada ejecución informa qué archivo usó
y cuántos hallazgos y elementos suprimió, y --json registra esto en
los campos ignore_file e ignored (CHECK-ID para una comprobación completa,
CHECK-ID:item para un elemento suprimido). Usa --no-ignore para omitir el archivo.
# Usar un archivo de ignorados específico
tailsnitch --ignore-file /path/to/ignore
# Deshabilitar el procesamiento del archivo de ignorados por completo
tailsnitch --no-ignore
Exportación y Procesamiento JSON
# Exportar informe completo
tailsnitch --json > audit.json
# Extraer comprobaciones reprobadas como TSV
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false))
| .[]
| [.id, .title, .severity, .remediation]
| @tsv
' > findings.tsv
# Resumen por severidad
tailsnitch --json | jq '
.suggestions
| map(select(.pass == false))
| group_by(.severity)
| map({severity: .[0].severity, count: length})
'
# Listar problemas críticos/altos con enlaces de administración
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false and (.severity == "CRITICAL" or .severity == "HIGH")))
| .[]
| "\(.id): \(.title)\n Fix: \(.fix.admin_url // "manual")\n"
'
Referencia de Comandos
| Banderas | Descripción |
|---|---|
--json | Salida como JSON |
--severity | Filtrar por severidad mínima: critical, high, medium, low, info |
--category | Filtrar por categoría: access, auth, network, ssh, log, device, dns |
--checks | Ejecutar comprobaciones específicas (IDs o slugs separados por comas) |
--list-checks | Listar todas las comprobaciones disponibles y salir |
--tailnet | Especificar tailnet a auditar (predeterminado: desde la clave de API) |
--verbose | Mostrar también las comprobaciones que pasan |
--fix | Habilitar modo de corrección interactivo |
--auto | Auto-seleccionar correcciones seguras (requiere --fix) |
--dry-run | Vista previa de acciones de corrección sin ejecutarlas (requiere --fix) |
--no-audit-log | Deshabilitar registro de auditoría de acciones de corrección |
--soc2 | Exportar evidencia SOC 2: json o csv |
--tailscale-path | Ruta al CLI de tailscale (para comprobaciones de Tailnet Lock) |
--timeout | Presupuesto de tiempo total para la auditoría (predeterminado 2m) |
--ignore-file | Ruta al archivo de ignorados |
--no-ignore | Deshabilitar procesamiento del archivo de ignorados |
--version | Mostrar información de versión |
Comprobaciones de Seguridad
Tailsnitch realiza 57 comprobaciones de seguridad en 7 categorías. Consulta docs/CHECKS.md para documentación detallada de cada comprobación.
Severidad Crítica
| ID | Comprobación | Riesgo |
|---|---|---|
| ACL-001 | Política 'permitir todo' predeterminada | Todos los dispositivos tienen acceso sin restricciones |
| ACL-002 | Mala configuración de SSH autogroup:nonroot | SSH como cualquier usuario no root |
| ACL-006 | tagOwners demasiado amplio | Escalada de privilegios mediante etiquetas |
| ACL-007 | Uso de autogroup:danger-all | Acceso otorgado a usuarios externos |
Severidad Alta
| ID | Comprobación | Riesgo |
|---|---|---|
| ACL-011 | El alcance de una etiqueta cruza un límite de confianza | Una clave reutilizable robada acuña una etiqueta que alcanza todo |
| AUTH-001 | Claves de autenticación reutilizables | Adiciones ilimitadas de dispositivos si se roban |
| AUTH-002 | Claves de autenticación con expiración larga | Ventana de exposición extendida |
| AUTH-003 | Claves preautorizadas | Omite la aprobación de dispositivos |
| AUTH-006 | Sujeto de identidad federada demasiado amplio | Cualquier principal que el emisor avale puede acuñar la etiqueta |
| DEV-001 | Dispositivos etiquetados sin expiración de clave | Acceso indefinido |
| DEV-002 | Dispositivos de usuario etiquetados | Persisten después de la eliminación del usuario |
| DEV-010 | Tailnet Lock deshabilitado | Sin protección contra claves robadas |
| DEV-012 | Firmas de Tailnet Lock pendientes | Los nodos sin firmar necesitan revisión |
| NET-001 | Exposición Funnel | Acceso a internet público |
| NET-003 | Límite de confianza del router de subred | Tráfico sin cifrar en la red local |
| SSH-002 | SSH root sin modo de verificación | No se requiere reautenticación |
Severidad Media
| ID | Comprobación | Riesgo |
|---|---|---|
| ACL-004 | Uso de autogroup:member | Usuarios externos incluidos |
| ACL-005 | AutoApprovers configurado | Omite la aprobación de rutas |
| AUTH-004 | Claves CI/CD no efímeras | Los dispositivos obsoletos se acumulan |
| AUTH-005 | Federación de identidad de cargas de trabajo no en uso | Las claves de larga duración siguen siendo robables |
| DEV-003 | Clientes desactualizados | Vulnerabilidades potenciales |
| DEV-004 | Dispositivos obsoletos | Superficie de ataque sin uso |
| DEV-005 | Dispositivos no autorizados | Cola de aprobación pendiente |
| DEV-007 | Nombres de máquinas sensibles | Exposición en registros CT |
| DEV-009 | Configuración de aprobación de dispositivos | Puede no estar habilitada |
| NET-004 | Exposición en registros CT de HTTPS | Nombres de máquinas públicos |
| NET-005 | Visibilidad del tráfico del nodo de salida | El operador ve todo el tráfico |
| NET-006 | Exposición Serve | Servicios locales en el tailnet |
| SSH-003 | Exposición de la interfaz del grabador | Sesiones visibles para la red |
Informativo
Comprobaciones para configuración de registro, configuraciones de DNS, roles de usuario y elementos de verificación manual.
Severidad que depende del hallazgo
Varias comprobaciones califican lo que encuentran en lugar de llevar una severidad fija. Tres merecen mención especial aquí:
- ACL-011 informa el alcance de cada etiqueta como Informativo. Falla solo cuando una etiqueta que una clave de autenticación puede asignar alcanza un destino comodín, una subred enrutada o la salida de un nodo de salida: Alta si una clave reutilizable asigna esa etiqueta, Media si solo una clave de un solo uso lo hace. Un recuento de dispositivos nunca establece la severidad.
- AUTH-005 informa Media cuando el tailnet no tiene credenciales de confianza en absoluto, y Baja cuando existen credenciales de confianza pero una clave reutilizable aún acuña etiquetas que ninguna de ellas cubre.
- AUTH-006 informa Alta para un sujeto que no es más que un comodín, y Baja para un comodín más restringido o una audiencia faltante.
Ejemplo de Salida
+=====================================================================+
| TAILSNITCH SECURITY AUDIT |
| Tailnet: example.com |
| Version: 1.0.0 (build: abc123) |
+=====================================================================+
Usando archivo de ignorados: .tailsnitch-ignore (3 reglas)
=== CONTROLES DE ACCESO ===============================================
[CRITICAL] ACL-001: Política 'permitir todo' predeterminada activa
Tu política ACL omite el campo 'acls'. Tailscale aplica una
política 'permitir todo' predeterminada, otorgando a todos los dispositivos acceso completo.
Remediación:
Define reglas ACL explícitas siguiendo el principio de privilegio mínimo.
Fuente: https://tailscale.com/docs/reference/examples/acls
----------------------------------------------------------------------
=== AUTENTICACIÓN Y CLAVES ============================================
[HIGH] AUTH-001: Existen claves de autenticación reutilizables
Se encontraron 2 claves de autenticación reutilizables. Pueden reutilizarse para agregar
múltiples dispositivos si se ven comprometidas.
Detalles:
- Clave tskey-auth-xxx (expira en 45 días)
- Clave tskey-auth-yyy (expira en 89 días)
Remediación:
Almacena las claves reutilizables en un administrador de secretos. Prefiere claves de un solo uso.
Fuente: https://tailscale.com/docs/features/access-control/auth-keys
----------------------------------------------------------------------
RESUMEN
======================================================================
Críticas: 1 Altas: 3 Medias: 5 Bajas: 2 Info: 8
Total de hallazgos: 19 | Aprobados: 33
Comprobaciones de Tailnet Lock
Las comprobaciones de Tailnet Lock (DEV-010, DEV-012) requieren el CLI local tailscale y se ejecutan contra el daemon de la máquina local. Al auditar un tailnet remoto mediante --tailnet, estas comprobaciones reflejan el estado local, no el del tailnet auditado.
# Especificar ruta personalizada del binario de tailscale si es necesario
tailsnitch --tailscale-path /opt/tailscale/bin/tailscale
Integración CI/CD
Ejecuta Tailsnitch en pipelines CI/CD para detectar regresiones de seguridad:
# Ejemplo de GitHub Actions
- name: Auditar Seguridad de Tailscale
env:
TS_OAUTH_CLIENT_ID: ${{ secrets.TS_OAUTH_CLIENT_ID }}
TS_OAUTH_CLIENT_SECRET: ${{ secrets.TS_OAUTH_CLIENT_SECRET }}
run: |
tailsnitch --json > audit.json
# Fallar si existen problemas de severidad crítica o alta
if tailsnitch --severity high --json | jq -e '.summary.critical + .summary.high > 0' > /dev/null; then
echo "¡Se encontraron problemas de severidad crítica o alta!"
tailsnitch --severity high
exit 1
fi
Referencias
- Guía de endurecimiento de seguridad de Tailscale
- Referencia de sintaxis ACL
- Tailscale SSH
- Registro de auditoría
- Tailnet Lock
Licencia
MIT
Contribuciones
Consulta CONTRIBUTING.md para las pautas.