Files
SnarfCode/scripts/full_infra_audit.py

159 lines
6.0 KiB
Python

import paramiko
import urllib.request
import ssl
import json
import socket
import concurrent.futures
key_path = r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet'
def check_k8s_cluster(host, name):
res = {'name': name, 'host': host, 'errors': [], 'warnings': []}
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username='root', key_filename=key_path, timeout=10)
# Check nodes
stdin, stdout, stderr = ssh.exec_command("k3s kubectl get nodes --no-headers")
nodes_out = stdout.read().decode().strip().splitlines()
not_ready = [n for n in nodes_out if not " Ready" in n]
res['total_nodes'] = len(nodes_out)
res['not_ready_nodes'] = not_ready
# Check failing pods across all namespaces
stdin, stdout, stderr = ssh.exec_command("k3s kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded --no-headers")
failing_pods = stdout.read().decode().strip().splitlines()
res['failing_pods'] = failing_pods
# Check DNS namespace pods
stdin, stdout, stderr = ssh.exec_command("k3s kubectl get pods -n dns -o wide --no-headers")
dns_pods = stdout.read().decode().strip().splitlines()
res['dns_pods'] = dns_pods
# Check DNS service VIP
stdin, stdout, stderr = ssh.exec_command("k3s kubectl get svc -n dns -o wide --no-headers")
dns_svc = stdout.read().decode().strip().splitlines()
res['dns_svc'] = dns_svc
ssh.close()
except Exception as e:
res['errors'].append(f"SSH failed: {e}")
return res
def check_swarm():
res = {'name': 'Docker Swarm / NPM', 'host': '140.44.4.71', 'errors': []}
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='snarf', key_filename=key_path, timeout=10)
stdin, stdout, stderr = ssh.exec_command("docker node ls --format '{{.Hostname}}: {{.Status}} ({{.Availability}})'")
nodes = stdout.read().decode().strip().splitlines()
res['nodes'] = nodes
stdin, stdout, stderr = ssh.exec_command("docker ps --format '{{.Names}}: {{.Status}}'")
containers = stdout.read().decode().strip().splitlines()
res['containers'] = containers
ssh.close()
except Exception as e:
res['errors'].append(f"SSH failed: {e}")
return res
def test_dns_resolution(server_ip, domain="google.com"):
import struct
try:
# Construct raw DNS query packet
# Transaction ID: 0x1234, Flags: standard query (0x0100), Questions: 1
header = struct.pack(">HHHHHH", 0x1234, 0x0100, 1, 0, 0, 0)
qname = b"".join(bytes([len(p)]) + p.encode('ascii') for p in domain.split(".")) + b"\x00"
question = qname + struct.pack(">HH", 1, 1) # Type A, Class IN
packet = header + question
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(3.0)
sock.sendto(packet, (server_ip, 53))
data, _ = sock.recvfrom(512)
sock.close()
# Check RCODE in response
flags = struct.unpack(">H", data[2:4])[0]
rcode = flags & 0x000F
return {'status': 'OK', 'rcode': rcode, 'bytes': len(data)}
except Exception as e:
return {'status': 'FAIL', 'error': str(e)}
def check_endpoint(url):
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
req = urllib.request.Request(url, headers={'User-Agent': 'AntigravityAudit/2.0'})
try:
# Don't follow redirects to capture 302/200 properly
class NoRedirectHandler(urllib.request.HTTPRedirectHandler):
def http_error_302(self, req, fp, code, msg, headers):
return fp
http_error_301 = http_error_302
http_error_303 = http_error_302
http_error_307 = http_error_302
http_error_308 = http_error_302
opener = urllib.request.build_opener(NoRedirectHandler)
with opener.open(req, timeout=5) as resp:
code = resp.status if hasattr(resp, 'status') else resp.code
location = resp.headers.get('Location', '')
server = resp.headers.get('Server', '')
return {'url': url, 'code': code, 'location': location, 'server': server, 'ok': code in [200, 301, 302, 307, 308]}
except urllib.error.HTTPError as e:
return {'url': url, 'code': e.code, 'error': str(e), 'ok': e.code in [200, 301, 302, 307, 308, 401, 403]}
except Exception as e:
return {'url': url, 'code': 0, 'error': str(e), 'ok': False}
print("=== STARTING FULL INFRASTRUCTURE & ENDPOINT AUDIT ===")
# 1. Check K8s Clusters
aero = check_k8s_cluster('140.44.4.11', 'Aerodrome')
space = check_k8s_cluster('140.44.4.41', 'Spaceport')
swarm = check_swarm()
# 2. Check DNS Port 53 on both VIPs
dns_aero = test_dns_resolution('140.44.4.36', 'google.com')
dns_space = test_dns_resolution('140.44.4.65', 'google.com')
dns_local = test_dns_resolution('140.44.4.36', 'authentik.snarfnet.net')
# 3. Check Web Endpoints
endpoints_to_check = [
'https://authentik.snarfnet.net',
'https://pihole1.snarfnet.net/admin/',
'https://pihole2.snarfnet.net/admin/',
'https://dns1.snarfnet.net',
'https://dns2.snarfnet.net',
'https://git.snarfnet.net',
'https://vault.snarfnet.net',
'https://rancher.snarfnet.net',
'https://argocd.snarfnet.net',
'https://zabbix.snarfnet.net',
'https://semaphore.snarfnet.net',
'https://kuma.snarfnet.net',
'https://homepage.snarfnet.net',
'https://grafana.snarfnet.net'
]
endpoint_results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
endpoint_results = list(executor.map(check_endpoint, endpoints_to_check))
audit_data = {
'aerodrome': aero,
'spaceport': space,
'swarm': swarm,
'dns_vip_aerodrome': dns_aero,
'dns_vip_spaceport': dns_space,
'dns_vip_internal': dns_local,
'endpoints': endpoint_results
}
print(json.dumps(audit_data, indent=2))