Sanitized mirror from private repository - 2026-03-21 08:56:04 UTC
This commit is contained in:
372
ansible/playbooks/tailscale_management.yml
Normal file
372
ansible/playbooks/tailscale_management.yml
Normal file
@@ -0,0 +1,372 @@
|
||||
---
|
||||
- name: Tailscale Network Management
|
||||
hosts: all
|
||||
gather_facts: yes
|
||||
vars:
|
||||
tailscale_timestamp: "{{ ansible_date_time.iso8601 }}"
|
||||
tailscale_report_dir: "/tmp/tailscale_reports"
|
||||
|
||||
tasks:
|
||||
- name: Create Tailscale reports directory
|
||||
file:
|
||||
path: "{{ tailscale_report_dir }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
|
||||
- name: Check if Tailscale is installed
|
||||
shell: command -v tailscale >/dev/null 2>&1
|
||||
register: tailscale_available
|
||||
changed_when: false
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Skip Tailscale tasks if not available
|
||||
set_fact:
|
||||
skip_tailscale: "{{ tailscale_available.rc != 0 }}"
|
||||
|
||||
- name: Get Tailscale status
|
||||
shell: |
|
||||
if ! command -v tailscale >/dev/null 2>&1; then
|
||||
echo "Tailscale not installed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== TAILSCALE STATUS ==="
|
||||
tailscale status --json 2>/dev/null || tailscale status 2>/dev/null || echo "Tailscale not accessible"
|
||||
register: tailscale_status
|
||||
changed_when: false
|
||||
when: not skip_tailscale
|
||||
|
||||
- name: Get Tailscale network information
|
||||
shell: |
|
||||
if ! command -v tailscale >/dev/null 2>&1; then
|
||||
echo "Tailscale not installed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== TAILSCALE NETWORK INFO ==="
|
||||
|
||||
# Get IP addresses
|
||||
echo "Tailscale IPs:"
|
||||
tailscale ip -4 2>/dev/null || echo "IPv4 not available"
|
||||
tailscale ip -6 2>/dev/null || echo "IPv6 not available"
|
||||
echo ""
|
||||
|
||||
# Get peer information
|
||||
echo "Peer Status:"
|
||||
tailscale status --peers 2>/dev/null || echo "Peer status not available"
|
||||
echo ""
|
||||
|
||||
# Get routes
|
||||
echo "Routes:"
|
||||
tailscale status --self=false 2>/dev/null | grep -E "^[0-9]" | head -10 || echo "Route information not available"
|
||||
echo ""
|
||||
|
||||
# Check connectivity to key peers
|
||||
echo "Connectivity Tests:"
|
||||
key_peers="100.83.230.112 100.103.48.78 100.125.0.20" # atlantis, calypso, setillo
|
||||
for peer in $key_peers; do
|
||||
if ping -c 1 -W 2 "$peer" >/dev/null 2>&1; then
|
||||
echo "✅ $peer - reachable"
|
||||
else
|
||||
echo "❌ $peer - unreachable"
|
||||
fi
|
||||
done
|
||||
register: tailscale_network
|
||||
changed_when: false
|
||||
when: not skip_tailscale
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Check Tailscale service health
|
||||
shell: |
|
||||
if ! command -v tailscale >/dev/null 2>&1; then
|
||||
echo "Tailscale not installed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== TAILSCALE SERVICE HEALTH ==="
|
||||
|
||||
# Check daemon status
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
echo "Service Status:"
|
||||
systemctl is-active tailscaled 2>/dev/null || echo "tailscaled service status unknown"
|
||||
systemctl is-enabled tailscaled 2>/dev/null || echo "tailscaled service enablement unknown"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Check authentication status
|
||||
echo "Authentication:"
|
||||
if tailscale status --json 2>/dev/null | grep -q '"BackendState":"Running"'; then
|
||||
echo "✅ Authenticated and running"
|
||||
elif tailscale status 2>/dev/null | grep -q "Logged out"; then
|
||||
echo "❌ Not logged in"
|
||||
else
|
||||
echo "⚠️ Status unclear"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check for exit node status
|
||||
echo "Exit Node Status:"
|
||||
if tailscale status --json 2>/dev/null | grep -q '"ExitNodeID"'; then
|
||||
echo "Using exit node"
|
||||
else
|
||||
echo "Not using exit node"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check MagicDNS
|
||||
echo "MagicDNS:"
|
||||
if tailscale status --json 2>/dev/null | grep -q '"MagicDNSSuffix"'; then
|
||||
suffix=$(tailscale status --json 2>/dev/null | grep -o '"MagicDNSSuffix":"[^"]*"' | cut -d'"' -f4)
|
||||
echo "✅ Enabled (suffix: $suffix)"
|
||||
else
|
||||
echo "❌ Disabled or not available"
|
||||
fi
|
||||
register: tailscale_health
|
||||
changed_when: false
|
||||
when: not skip_tailscale
|
||||
|
||||
- name: Analyze Tailscale configuration
|
||||
shell: |
|
||||
if ! command -v tailscale >/dev/null 2>&1; then
|
||||
echo "Tailscale not installed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== TAILSCALE CONFIGURATION ==="
|
||||
|
||||
# Get preferences
|
||||
echo "Preferences:"
|
||||
tailscale debug prefs 2>/dev/null | head -20 || echo "Preferences not accessible"
|
||||
echo ""
|
||||
|
||||
# Check for subnet routes
|
||||
echo "Subnet Routes:"
|
||||
tailscale status --json 2>/dev/null | grep -o '"AdvertiseRoutes":\[[^\]]*\]' || echo "No advertised routes"
|
||||
echo ""
|
||||
|
||||
# Check ACL status (if accessible)
|
||||
echo "ACL Information:"
|
||||
tailscale debug netmap 2>/dev/null | grep -i acl | head -5 || echo "ACL information not accessible"
|
||||
echo ""
|
||||
|
||||
# Check for Tailscale SSH
|
||||
echo "Tailscale SSH:"
|
||||
if tailscale status --json 2>/dev/null | grep -q '"SSH"'; then
|
||||
echo "SSH feature available"
|
||||
else
|
||||
echo "SSH feature not detected"
|
||||
fi
|
||||
register: tailscale_config
|
||||
changed_when: false
|
||||
when: not skip_tailscale
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Tailscale network diagnostics
|
||||
shell: |
|
||||
if ! command -v tailscale >/dev/null 2>&1; then
|
||||
echo "Tailscale not installed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== NETWORK DIAGNOSTICS ==="
|
||||
|
||||
# Check DERP (relay) connectivity
|
||||
echo "DERP Connectivity:"
|
||||
tailscale netcheck 2>/dev/null | head -10 || echo "Network check not available"
|
||||
echo ""
|
||||
|
||||
# Check for direct connections
|
||||
echo "Direct Connections:"
|
||||
tailscale status --json 2>/dev/null | grep -o '"CurAddr":"[^"]*"' | head -5 || echo "Connection info not available"
|
||||
echo ""
|
||||
|
||||
# Interface information
|
||||
echo "Network Interfaces:"
|
||||
ip addr show tailscale0 2>/dev/null || echo "Tailscale interface not found"
|
||||
echo ""
|
||||
|
||||
# Routing table
|
||||
echo "Tailscale Routes:"
|
||||
ip route show | grep tailscale0 2>/dev/null || echo "No Tailscale routes found"
|
||||
register: tailscale_diagnostics
|
||||
changed_when: false
|
||||
when: not skip_tailscale
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Create Tailscale report
|
||||
set_fact:
|
||||
tailscale_report:
|
||||
timestamp: "{{ tailscale_timestamp }}"
|
||||
hostname: "{{ inventory_hostname }}"
|
||||
tailscale_available: "{{ not skip_tailscale }}"
|
||||
status: "{{ tailscale_status.stdout if not skip_tailscale else 'Not available' }}"
|
||||
network: "{{ tailscale_network.stdout if not skip_tailscale else 'Not available' }}"
|
||||
health: "{{ tailscale_health.stdout if not skip_tailscale else 'Not available' }}"
|
||||
configuration: "{{ tailscale_config.stdout if not skip_tailscale else 'Not available' }}"
|
||||
diagnostics: "{{ tailscale_diagnostics.stdout if not skip_tailscale else 'Not available' }}"
|
||||
|
||||
- name: Display Tailscale report
|
||||
debug:
|
||||
msg: |
|
||||
|
||||
==========================================
|
||||
🌐 TAILSCALE REPORT - {{ inventory_hostname }}
|
||||
==========================================
|
||||
|
||||
📊 AVAILABILITY: {{ 'Available' if tailscale_report.tailscale_available else 'Not Available' }}
|
||||
|
||||
📡 STATUS:
|
||||
{{ tailscale_report.status }}
|
||||
|
||||
🔗 NETWORK INFO:
|
||||
{{ tailscale_report.network }}
|
||||
|
||||
🏥 HEALTH CHECK:
|
||||
{{ tailscale_report.health }}
|
||||
|
||||
⚙️ CONFIGURATION:
|
||||
{{ tailscale_report.configuration }}
|
||||
|
||||
🔍 DIAGNOSTICS:
|
||||
{{ tailscale_report.diagnostics }}
|
||||
|
||||
==========================================
|
||||
|
||||
- name: Generate JSON Tailscale report
|
||||
copy:
|
||||
content: |
|
||||
{
|
||||
"timestamp": "{{ tailscale_report.timestamp }}",
|
||||
"hostname": "{{ tailscale_report.hostname }}",
|
||||
"tailscale_available": {{ tailscale_report.tailscale_available | lower }},
|
||||
"status": {{ tailscale_report.status | to_json }},
|
||||
"network": {{ tailscale_report.network | to_json }},
|
||||
"health": {{ tailscale_report.health | to_json }},
|
||||
"configuration": {{ tailscale_report.configuration | to_json }},
|
||||
"diagnostics": {{ tailscale_report.diagnostics | to_json }},
|
||||
"recommendations": [
|
||||
{% if not tailscale_report.tailscale_available %}
|
||||
"Install Tailscale for network connectivity",
|
||||
{% endif %}
|
||||
{% if 'Not logged in' in tailscale_report.health %}
|
||||
"Authenticate Tailscale client",
|
||||
{% endif %}
|
||||
{% if 'unreachable' in tailscale_report.network %}
|
||||
"Investigate network connectivity issues",
|
||||
{% endif %}
|
||||
"Regular Tailscale health monitoring recommended"
|
||||
]
|
||||
}
|
||||
dest: "{{ tailscale_report_dir }}/{{ inventory_hostname }}_tailscale_{{ ansible_date_time.epoch }}.json"
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Tailscale management operations (when action is specified)
|
||||
block:
|
||||
- name: Validate action parameter
|
||||
fail:
|
||||
msg: "Invalid action. Supported actions: status, login, logout, up, down, ping"
|
||||
when: tailscale_action not in ['status', 'login', 'logout', 'up', 'down', 'ping']
|
||||
|
||||
- name: Execute Tailscale action
|
||||
shell: |
|
||||
case "{{ tailscale_action }}" in
|
||||
"status")
|
||||
tailscale status --peers
|
||||
;;
|
||||
"login")
|
||||
echo "Login requires interactive authentication"
|
||||
tailscale login --timeout=30s
|
||||
;;
|
||||
"logout")
|
||||
tailscale logout
|
||||
;;
|
||||
"up")
|
||||
tailscale up {{ tailscale_args | default('') }}
|
||||
;;
|
||||
"down")
|
||||
tailscale down
|
||||
;;
|
||||
"ping")
|
||||
if [ -n "{{ tailscale_target | default('') }}" ]; then
|
||||
tailscale ping "{{ tailscale_target }}"
|
||||
else
|
||||
echo "Error: tailscale_target required for ping action"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
register: tailscale_action_result
|
||||
when: not skip_tailscale
|
||||
|
||||
- name: Display action result
|
||||
debug:
|
||||
msg: |
|
||||
|
||||
🔧 Tailscale action '{{ tailscale_action }}' completed on {{ inventory_hostname }}
|
||||
|
||||
Result:
|
||||
{{ tailscale_action_result.stdout }}
|
||||
|
||||
{% if tailscale_action_result.stderr %}
|
||||
Errors:
|
||||
{{ tailscale_action_result.stderr }}
|
||||
{% endif %}
|
||||
|
||||
when: tailscale_action is defined and not skip_tailscale
|
||||
|
||||
- name: Generate network topology map (run once)
|
||||
shell: |
|
||||
cd "{{ tailscale_report_dir }}"
|
||||
|
||||
echo "# Tailscale Network Topology" > network_topology.md
|
||||
echo "" >> network_topology.md
|
||||
echo "**Generated:** {{ tailscale_timestamp }}" >> network_topology.md
|
||||
echo "" >> network_topology.md
|
||||
|
||||
# Process all Tailscale JSON reports
|
||||
for json_file in *_tailscale_*.json; do
|
||||
if [ -f "$json_file" ]; then
|
||||
hostname=$(basename "$json_file" | cut -d'_' -f1)
|
||||
echo "## 🖥️ $hostname" >> network_topology.md
|
||||
echo "" >> network_topology.md
|
||||
|
||||
# Extract key information
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
available=$(jq -r '.tailscale_available' "$json_file" 2>/dev/null || echo "unknown")
|
||||
echo "- **Tailscale:** $available" >> network_topology.md
|
||||
|
||||
# Try to extract IP if available
|
||||
if [ "$available" = "true" ]; then
|
||||
echo "- **Status:** Connected" >> network_topology.md
|
||||
else
|
||||
echo "- **Status:** Not available" >> network_topology.md
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "- **Report:** [$json_file](./$json_file)" >> network_topology.md
|
||||
echo "" >> network_topology.md
|
||||
fi
|
||||
done
|
||||
|
||||
echo "---" >> network_topology.md
|
||||
echo "*Auto-generated by Ansible tailscale_management.yml playbook*" >> network_topology.md
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
|
||||
- name: Summary message
|
||||
debug:
|
||||
msg: |
|
||||
|
||||
🌐 Tailscale management complete for {{ inventory_hostname }}
|
||||
📄 Report saved to: {{ tailscale_report_dir }}/{{ inventory_hostname }}_tailscale_{{ ansible_date_time.epoch }}.json
|
||||
🗺️ Network topology: {{ tailscale_report_dir }}/network_topology.md
|
||||
|
||||
{% if tailscale_action is defined %}
|
||||
🔧 Action performed: {{ tailscale_action }}
|
||||
{% endif %}
|
||||
|
||||
💡 Use -e tailscale_action=<action> for management operations
|
||||
💡 Supported actions: status, login, logout, up, down, ping
|
||||
💡 Use -e tailscale_target=<ip> with ping action
|
||||
Reference in New Issue
Block a user