feat: add various infrastructure and service diagnostic scripts
This commit is contained in:
Submodule homelab-gitops-repo updated: 9525cdbe95...d349834550
11
scripts/check_aero_pihole_auth.py
Normal file
11
scripts/check_aero_pihole_auth.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- curl -s -X POST "http://localhost/api/auth" -H "Content-Type: application/json" -d \'{"password":"snarfnetadmin"}\'')
|
||||
print("Aerodrome API auth test:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
11
scripts/check_api_status.py
Normal file
11
scripts/check_api_status.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/status"')
|
||||
print("api/status response:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
11
scripts/check_apiurl.py
Normal file
11
scripts/check_apiurl.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- curl -s "http://localhost/admin/login" | grep -i "data-apiurl"')
|
||||
print("data-apiurl:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
16
scripts/check_app_dll.py
Normal file
16
scripts/check_app_dll.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- ls -la /app')
|
||||
print("/app contents:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Search for AddAuthentication in dlls
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- strings /app/DnsServerApp.dll /app/DnsServerCore.dll 2>/dev/null | grep -i -C 3 "AddAuthentication"')
|
||||
print("AddAuthentication strings:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
14
scripts/check_cert1.py
Normal file
14
scripts/check_cert1.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect("140.44.4.71", username="root", key_filename=key_path, timeout=5)
|
||||
|
||||
stdin, stdout, stderr = c.exec_command("ls -la /var/lib/docker/volumes/nginx-proxy-manager_nginx-letsencrypt/_data/live/npm-1/")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
c.close()
|
||||
|
||||
11
scripts/check_divloginsso.py
Normal file
11
scripts/check_divloginsso.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- grep -rn "divLoginSso" /opt/technitium/ 2>/dev/null || true')
|
||||
print("grep divLoginSso:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
@@ -1,20 +1,44 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
def check_cluster(host, name):
|
||||
print(f"=== Checking {name} ({host}) ===")
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect(host, username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect("140.44.4.11", username="root", key_filename=key_path, timeout=5)
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl get pods -n dns -o wide')
|
||||
print("Pods:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
stdin, stdout, stderr = c.exec_command("k3s kubectl -n dns get pods,svc")
|
||||
print("=== PODS & SVCS ===")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- pihole -v')
|
||||
print("Pihole version:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
stdin, stdout, stderr = c.exec_command("k3s kubectl -n dns describe svc pihole-dns-vip | grep -E 'Events:|Message|Failed'")
|
||||
print("=== SERVICE EVENTS ===")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
# Set password explicitly
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- pihole setpassword snarfnetadmin')
|
||||
out = stdout.read().decode()
|
||||
err = stderr.read().decode()
|
||||
print("Set password with pihole setpassword:")
|
||||
print(out)
|
||||
if err:
|
||||
print("ERR:", err)
|
||||
|
||||
c.close()
|
||||
if "Unknown" in out or "invalid" in out.lower() or err:
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- pihole -a -p snarfnetadmin')
|
||||
print("Fallback pihole -a -p:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
# Check Technitium login via API
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/user/login?user=admin&pass=snarfnetadmin"')
|
||||
login_res = stdout.read().decode()
|
||||
print("Technitium API Login:", login_res)
|
||||
|
||||
# Check Technitium SSO config
|
||||
stdin, stdout, stderr = ssh.exec_command("k3s kubectl exec -n dns deployment/technitium-dns -- cat /etc/dns/auth.config 2>/dev/null || echo 'No auth.config'")
|
||||
print("Technitium auth.config:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
|
||||
check_cluster('140.44.4.11', 'Aerodrome')
|
||||
check_cluster('140.44.4.41', 'Spaceport')
|
||||
|
||||
11
scripts/check_etc_dns.py
Normal file
11
scripts/check_etc_dns.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- ls -la /etc/dns/')
|
||||
print("/etc/dns listing:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
16
scripts/check_ftl_config.py
Normal file
16
scripts/check_ftl_config.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- pihole-FTL --config webserver.api.password')
|
||||
print("Current config webserver.api.password:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check pihole-FTL --config --help or options
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- pihole-FTL --config 2>&1 || true')
|
||||
print("pihole-FTL --config:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:1500])
|
||||
|
||||
ssh.close()
|
||||
11
scripts/check_login_js_lines.py
Normal file
11
scripts/check_login_js_lines.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- sed -n "20,60p" /var/www/html/admin/scripts/js/login.js')
|
||||
print("login.js lines 20-60:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
11
scripts/check_login_js_lines2.py
Normal file
11
scripts/check_login_js_lines2.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- sed -n "60,110p" /var/www/html/admin/scripts/js/login.js')
|
||||
print("login.js lines 60-110:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
11
scripts/check_mainjs.py
Normal file
11
scripts/check_mainjs.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- sed -n "40,65p" /opt/technitium/dns/www/js/main.js')
|
||||
print("main.js lines 40-65:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
21
scripts/check_max_id.py
Normal file
21
scripts/check_max_id.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect("140.44.4.71", username="root", key_filename=key_path, timeout=5)
|
||||
|
||||
py_cmd = """python3 -c "
|
||||
import sqlite3
|
||||
conn = sqlite3.connect('/var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite')
|
||||
c = conn.cursor()
|
||||
c.execute('SELECT MAX(id) FROM proxy_host')
|
||||
print('MAX ID:', c.fetchone()[0])
|
||||
" """
|
||||
stdin, stdout, stderr = c.exec_command(py_cmd)
|
||||
print(stdout.read().decode('utf-8'))
|
||||
c.close()
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.71', username='snarf', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
def run(cmd):
|
||||
print(f"=== {cmd} ===")
|
||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||
print(stdout.read().decode())
|
||||
|
||||
run("sudo docker service ps nginx-proxy-manager_app --filter 'desired-state=running'")
|
||||
ssh.close()
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect("140.44.4.71", username="root", key_filename=key_path, timeout=5)
|
||||
|
||||
stdin, stdout, stderr = c.exec_command("docker service ps nginx-proxy-manager_app")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
c.close()
|
||||
|
||||
20
scripts/check_opt_pihole.py
Normal file
20
scripts/check_opt_pihole.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -rn "setFTLConfigValue" /opt/pihole/')
|
||||
print("grep setFTLConfigValue in /opt/pihole/:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- sed -n "1,50p" /opt/pihole/COL_TABLE')
|
||||
print("head /opt/pihole/COL_TABLE or similar scripts:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check files in /opt/pihole/
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- ls -la /opt/pihole/')
|
||||
print("ls /opt/pihole/:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
12
scripts/check_pihole_ftl.py
Normal file
12
scripts/check_pihole_ftl.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Check pihole-FTL options for hashing password
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- pihole-FTL --help')
|
||||
print("pihole-FTL --help:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:1000])
|
||||
|
||||
ssh.close()
|
||||
16
scripts/check_pihole_login_js.py
Normal file
16
scripts/check_pihole_login_js.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -rn "Wrong password" /var/www/ 2>/dev/null || true')
|
||||
print("Wrong password grep in /var/www/:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
# Check html/login.js
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- find / -name "*login*.js" 2>/dev/null || true')
|
||||
print("login.js locations:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
18
scripts/check_pihole_password_details.py
Normal file
18
scripts/check_pihole_password_details.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Check how pihole setpassword works
|
||||
# Let's inspect /usr/local/bin/pihole around setFTLConfigValue
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -n -A 20 "setFTLConfigValue()" /usr/local/bin/pihole')
|
||||
print("setFTLConfigValue function:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check pihole-FTL CLI options for setting or hashing password
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- pihole-FTL --help 2>&1')
|
||||
print("pihole-FTL help:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:1500])
|
||||
|
||||
ssh.close()
|
||||
11
scripts/check_pihole_pw_func.py
Normal file
11
scripts/check_pihole_pw_func.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- sed -n "200,280p" /usr/local/bin/pihole')
|
||||
print("pihole script lines 200-280:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
16
scripts/check_pihole_script.py
Normal file
16
scripts/check_pihole_script.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -rn "setpassword" /opt/pihole/ /usr/local/bin/ 2>/dev/null || true')
|
||||
print("setpassword references:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check how WEBPASSWORD or FTLCONF is handled during container start in entrypoint
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- cat /entrypoint.sh 2>/dev/null || cat /start.sh 2>/dev/null || ls -l /')
|
||||
print("Entrypoint check:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:1500])
|
||||
|
||||
ssh.close()
|
||||
25
scripts/check_pihole_toml.py
Normal file
25
scripts/check_pihole_toml.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import paramiko
|
||||
|
||||
def check_pihole_toml(host, name):
|
||||
print(f"=== {name} ({host}) ===")
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect(host, username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -A 10 "\[webserver" /etc/pihole/pihole.toml 2>/dev/null || true')
|
||||
print("webserver section in pihole.toml:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -rn "pwhash" /etc/pihole/ 2>/dev/null || true')
|
||||
print("pwhash matches:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Let's test logging into pihole API with curl using password "snarfnetadmin"
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- curl -s -X POST "http://localhost/api/auth" -H "Content-Type: application/json" -d \'{"password":"snarfnetadmin"}\'')
|
||||
print("API auth test:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
|
||||
check_pihole_toml('140.44.4.11', 'Aerodrome')
|
||||
check_pihole_toml('140.44.4.41', 'Spaceport')
|
||||
@@ -1,14 +1,11 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect("140.44.4.11", username="root", key_filename=key_path, timeout=5)
|
||||
|
||||
stdin, stdout, stderr = c.exec_command("ps aux | grep kubectl")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
c.close()
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- ps aux')
|
||||
print("ps aux:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
|
||||
11
scripts/check_setwebpassword.py
Normal file
11
scripts/check_setwebpassword.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -n -A 30 "SetWebPassword()" /usr/local/bin/pihole')
|
||||
print("SetWebPassword implementation:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
11
scripts/check_sso_err.py
Normal file
11
scripts/check_sso_err.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- tail -n 25 /var/log/technitium/dns/2026-11-06.log')
|
||||
print("Recent logs:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
17
scripts/check_sso_frontend.py
Normal file
17
scripts/check_sso_frontend.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Test SSO login redirect
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s -I "http://localhost:5380/sso/login"')
|
||||
print("SSO login redirect response:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check index.html or what API the frontend calls
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- grep -n -C 5 "divLoginSso" /app/www/index.html 2>/dev/null || grep -n -C 5 "divLoginSso" /app/www/js/app.js 2>/dev/null || true')
|
||||
print("divLoginSso in app:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:1500])
|
||||
|
||||
ssh.close()
|
||||
16
scripts/check_technitium_config.py
Normal file
16
scripts/check_technitium_config.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- cat /etc/dns/log.config')
|
||||
print("log.config:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check where logs are saved or what log.config says
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- python3 -c "import json; print(open(\"/etc/dns/auth.config\", \"rb\").read())" 2>/dev/null || od -c /etc/dns/auth.config | head -n 30')
|
||||
print("auth.config raw:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
16
scripts/check_technitium_dotnet.py
Normal file
16
scripts/check_technitium_dotnet.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- strings /opt/technitium/dns/DnsServerApp.dll /opt/technitium/dns/DnsServerCore.dll | grep -i -C 3 "AddAuthentication"')
|
||||
print("AddAuthentication:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Also search for "ssoEnabled" or how SSO config is checked during startup
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- strings /opt/technitium/dns/DnsServerCore.dll | grep -i -C 3 "AddOpenIdConnect"')
|
||||
print("AddOpenIdConnect:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
16
scripts/check_technitium_logs.py
Normal file
16
scripts/check_technitium_logs.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl logs -n dns deployment/technitium-dns --tail=100')
|
||||
print("Technitium container logs:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check /etc/dns/logs if any
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- ls -la /etc/dns/logs 2>/dev/null || true')
|
||||
print("/etc/dns/logs:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
15
scripts/check_technitium_logs2.py
Normal file
15
scripts/check_technitium_logs2.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- ls -la /var/log/technitium/ 2>/dev/null || true')
|
||||
print("ls /var/log/technitium:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- tail -n 50 /var/log/technitium/dns.log 2>/dev/null || tail -n 50 /var/log/technitium/* 2>/dev/null || true')
|
||||
print("logs:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:2000])
|
||||
|
||||
ssh.close()
|
||||
16
scripts/check_technitium_logs3.py
Normal file
16
scripts/check_technitium_logs3.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- ls -la /var/log/technitium/dns/ 2>/dev/null || true')
|
||||
print("ls /var/log/technitium/dns:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Also let's check what SSO error occurred by querying the web service or error log
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- tail -n 50 /var/log/technitium/dns/* 2>/dev/null || true')
|
||||
print("files:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:2000])
|
||||
|
||||
ssh.close()
|
||||
11
scripts/check_utils.py
Normal file
11
scripts/check_utils.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- sed -n "130,175p" /opt/pihole/utils.sh')
|
||||
print("utils.sh lines 130-175:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
50
scripts/configure_spaceport_technitium.py
Normal file
50
scripts/configure_spaceport_technitium.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import paramiko
|
||||
import json
|
||||
import time
|
||||
|
||||
def configure_spaceport_technitium():
|
||||
print("=== Configuring Spaceport Technitium SSO ===")
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Login to get token
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/user/login?user=admin&pass=snarfnetadmin"')
|
||||
data = json.loads(stdout.read().decode())
|
||||
token = data['token']
|
||||
print("Spaceport Technitium Token:", token)
|
||||
|
||||
url = (
|
||||
f'"http://localhost:5380/api/admin/sso/set?token={token}'
|
||||
'&ssoEnabled=true'
|
||||
'&ssoAuthority=https://authentik.snarfnet.net/application/o/dns2/'
|
||||
'&ssoClientId=technitium2-dns-oidc'
|
||||
'&ssoClientSecret=SnarfNetTechnitiumOIDC2026!'
|
||||
'&ssoMetadataAddress=https://authentik.snarfnet.net/application/o/dns2/.well-known/openid-configuration'
|
||||
'&ssoScopes=openid,profile,email'
|
||||
'&ssoAllowSignup=true'
|
||||
'&ssoAllowSignupOnlyForMappedUsers=false'
|
||||
'&ssoGroupMap=authentik%20Admins|Administrators"'
|
||||
)
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s {url}')
|
||||
print("SSO set response:", stdout.read().decode())
|
||||
|
||||
print("Restarting deployment/technitium-dns on Spaceport...")
|
||||
ssh.exec_command('k3s kubectl rollout restart deployment/technitium-dns -n dns')
|
||||
time.sleep(12)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl wait --for=condition=Ready pod -l app=technitium-dns -n dns --timeout=30s')
|
||||
print("Pod wait:", stdout.read().decode())
|
||||
|
||||
# Check api/status
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/status"')
|
||||
print("api/status:", stdout.read().decode())
|
||||
|
||||
# Check SSO login redirect
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s -v -H "Host: dns2.snarfnet.net" -H "X-Forwarded-Proto: https" "http://localhost:5380/sso/login"')
|
||||
print("SSO redirect test:")
|
||||
print(stderr.read().decode('utf-8', errors='ignore')[:1000])
|
||||
|
||||
ssh.close()
|
||||
|
||||
configure_spaceport_technitium()
|
||||
88
scripts/create_technitium2_oidc.py
Normal file
88
scripts/create_technitium2_oidc.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import urllib.request
|
||||
import ssl
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
|
||||
token = "SnarfNetPermanentAutomationToken2026"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
def api_call(url, method="GET", payload=None):
|
||||
data = json.dumps(payload).encode('utf-8') if payload else None
|
||||
req = urllib.request.Request(url, headers=headers, data=data, method=method)
|
||||
try:
|
||||
with urllib.request.urlopen(req, context=ctx, timeout=8) as resp:
|
||||
return json.loads(resp.read().decode('utf-8'))
|
||||
except urllib.error.HTTPError as e:
|
||||
err = e.read().decode('utf-8')
|
||||
print(f"API Error {e.code} on {method} {url}: {err}")
|
||||
return None
|
||||
|
||||
print("1. Creating OAuth2 Provider for Technitium DNS 2...")
|
||||
p25_payload = {
|
||||
"name": "Technitium DNS 2 SSO (Spaceport)",
|
||||
"authorization_flow": "38a86ef3-f43a-4756-8f54-ca008a8eef6e",
|
||||
"invalidation_flow": "7a8145b8-2476-4636-9901-825f826df805",
|
||||
"client_type": "confidential",
|
||||
"client_id": "technitium2-dns-oidc",
|
||||
"client_secret": "SnarfNetTechnitiumOIDC2026!",
|
||||
"redirect_uris": [
|
||||
{"url": "https://dns2.snarfnet.net/sso/callback", "matching_mode": "strict"},
|
||||
{"url": "https://dns2.snarfnet.net/", "matching_mode": "strict"}
|
||||
],
|
||||
"signing_key": "6d48ba88-4b51-428f-903c-93334988a941",
|
||||
"property_mappings": [
|
||||
"f521356c-080d-4bd6-b19a-68ab159a5aef", # openid
|
||||
"8395b909-8e8d-4fc1-a620-5592e10df8fe", # email
|
||||
"85b89b43-92d8-425c-b9cc-8e00038cad37", # profile
|
||||
"d2248142-6be2-4833-94f8-e02f5d293b02" # groups
|
||||
],
|
||||
"sub_mode": "hashed_user_id",
|
||||
"issuer_mode": "per_provider",
|
||||
"include_claims_in_id_token": True
|
||||
}
|
||||
|
||||
prov = api_call("https://authentik.snarfnet.net/api/v3/providers/oauth2/", method="POST", payload=p25_payload)
|
||||
if not prov:
|
||||
# Check if exists
|
||||
res = api_call("https://authentik.snarfnet.net/api/v3/providers/oauth2/?search=Technitium+DNS+2")
|
||||
prov_pk = res['results'][0]['pk']
|
||||
else:
|
||||
prov_pk = prov['pk']
|
||||
|
||||
print(f"Provider created/found: PK {prov_pk}")
|
||||
|
||||
print("\n2. Creating Application 'Technitium DNS 2 (Spaceport)'...")
|
||||
app2_payload = {
|
||||
"name": "Technitium DNS 2 (Spaceport)",
|
||||
"slug": "dns2",
|
||||
"provider": prov_pk,
|
||||
"group": "Networking & Edge",
|
||||
"meta_launch_url": "https://dns2.snarfnet.net",
|
||||
"meta_description": "Authoritative & Recursive DNS Server with DoH & Local Resolution (Spaceport Secondary)",
|
||||
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/technitium.png",
|
||||
"open_in_new_tab": True
|
||||
}
|
||||
|
||||
app = api_call("https://authentik.snarfnet.net/api/v3/core/applications/", method="POST", payload=app2_payload)
|
||||
if app:
|
||||
print(f"Created Application: {app.get('name')} (slug: {app.get('slug')})")
|
||||
else:
|
||||
api_call("https://authentik.snarfnet.net/api/v3/core/applications/dns2/", method="PATCH", payload=app2_payload)
|
||||
print("Updated Application dns2")
|
||||
|
||||
print("\n3. Listing all DNS applications in Authentik App Library:")
|
||||
final_apps = api_call("https://authentik.snarfnet.net/api/v3/core/applications/?page_size=100")
|
||||
for a in sorted(final_apps.get('results', []), key=lambda x: x['name']):
|
||||
if a['slug'] in ['pihole1', 'pihole2', 'dns1', 'dns2']:
|
||||
print(f" [{a['group']}] {a['name']}")
|
||||
print(f" Slug: {a['slug']} | URL: {a['meta_launch_url']} | Provider PK: {a['provider']}")
|
||||
|
||||
34
scripts/inspect_authentik_dns_apps.py
Normal file
34
scripts/inspect_authentik_dns_apps.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import urllib.request
|
||||
import ssl
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
|
||||
token = "SnarfNetPermanentAutomationToken2026"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
req = urllib.request.Request("https://authentik.snarfnet.net/api/v3/core/applications/", headers=headers)
|
||||
with urllib.request.urlopen(req, context=ctx, timeout=8) as resp:
|
||||
data = json.loads(resp.read().decode('utf-8'))
|
||||
print("Applications matching pihole / technitium / dns:")
|
||||
for app in data.get('results', []):
|
||||
name = app.get('name', '').lower()
|
||||
slug = app.get('slug', '').lower()
|
||||
if 'pihole' in name or 'pihole' in slug or 'technitium' in name or 'technitium' in slug or 'dns' in name or 'dns' in slug:
|
||||
print(f" Name: {app.get('name')}")
|
||||
print(f" Slug: {app.get('slug')}")
|
||||
print(f" PK: {app.get('pk')}")
|
||||
print(f" Provider: {app.get('provider')}")
|
||||
print(f" Launch URL: {app.get('meta_launch_url')}")
|
||||
print(f" Group: {app.get('group')}")
|
||||
print(f" Icon: {app.get('meta_icon')}")
|
||||
print()
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
# Check pihole config in /etc/pihole
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -i password /etc/pihole/pihole.toml 2>/dev/null || true')
|
||||
print("pihole.toml password:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
def check(host, ns, name):
|
||||
print(f"\n=================== {name} ({host}) ===================")
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect(host, username="root", key_filename=key_path, timeout=10)
|
||||
|
||||
print("\n--- Pods in ns " + ns + " ---")
|
||||
stdin, stdout, stderr = c.exec_command(f"k3s kubectl -n {ns} get pods -o wide")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
|
||||
print("\n--- Pihole Pod describe/logs ---")
|
||||
stdin, stdout, stderr = c.exec_command(f"k3s kubectl -n {ns} describe deploy/pihole | grep -E 'Image:|Environment|Mounts|Volumes'")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
|
||||
print("\n--- Technitium Pod describe/logs ---")
|
||||
stdin, stdout, stderr = c.exec_command(f"k3s kubectl -n {ns} describe deploy/technitium-dns | grep -E 'Image:|Environment|Mounts|Volumes'")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
|
||||
c.close()
|
||||
# Check pihole env
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- env | grep -E "WEBPASSWORD|FTLCONF"')
|
||||
print("pihole env:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
check("140.44.4.11", "infra", "Aerodrome")
|
||||
check("140.44.4.41", "infrastructure", "Spaceport")
|
||||
# Let's test pihole web login via curl inside the pod or to localhost:80
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- curl -s -I http://localhost/admin/')
|
||||
print("curl localhost/admin/ header:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check Technitium SSO settings via API using the valid token
|
||||
token = "8d22b3ee9fe8ccbb317679afdbc86959d0ceea8261e0f0c7957d4325a7987d78"
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/admin/sso/get?token={token}"')
|
||||
print("Technitium SSO get:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check Technitium info or settings
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/settings/get?token={token}"')
|
||||
print("Technitium settings get (sample):")
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:300])
|
||||
|
||||
ssh.close()
|
||||
|
||||
17
scripts/inspect_login_html.py
Normal file
17
scripts/inspect_login_html.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import urllib.request
|
||||
import re
|
||||
|
||||
url = "http://140.44.4.36:5380/"
|
||||
with urllib.request.urlopen(url, timeout=5) as resp:
|
||||
html = resp.read().decode('utf-8')
|
||||
|
||||
# Search for login modal or sso in html
|
||||
lines = html.splitlines()
|
||||
for i, line in enumerate(lines):
|
||||
if 'modalLogin' in line or 'btnSSO' in line or 'btnModalLogin' in line or 'Single Sign-On' in line or 'sso' in line.lower():
|
||||
start = max(0, i-5)
|
||||
end = min(len(lines), i+15)
|
||||
print(f"--- Around line {i} ---")
|
||||
for j in range(start, end):
|
||||
print(f"{j:4}: {lines[j]}")
|
||||
print()
|
||||
@@ -24,3 +24,4 @@ if data:
|
||||
print("Mounts:", [m.get('Source') + " -> " + m.get('Destination') for m in c_info.get('Mounts', [])])
|
||||
|
||||
c.close()
|
||||
|
||||
|
||||
@@ -14,3 +14,4 @@ for cid in [3, 43, 52, 53]:
|
||||
print(stdout.read().decode('utf-8'))
|
||||
|
||||
c.close()
|
||||
|
||||
|
||||
11
scripts/read_today_log.py
Normal file
11
scripts/read_today_log.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- tail -n 50 /var/log/technitium/dns/2026-11-06.log')
|
||||
print("2026-11-06.log:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
51
scripts/remove_npm_unused.py
Normal file
51
scripts/remove_npm_unused.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect("140.44.4.71", username="root", key_filename=key_path, timeout=10)
|
||||
|
||||
print("1. Updating database.sqlite: removing ID 3, 51, 54...")
|
||||
py_script = """import sqlite3
|
||||
|
||||
conn = sqlite3.connect("/var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite")
|
||||
cur = conn.cursor()
|
||||
|
||||
# Remove proxy hosts 3, 51, 54
|
||||
cur.execute("DELETE FROM proxy_host WHERE id IN (3, 51, 54)")
|
||||
print(f"Deleted {cur.rowcount} rows from proxy_host (IDs 3, 51, 54)")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
"""
|
||||
|
||||
cmd_db = "cat << 'EOF' > /tmp/remove_npm.py\n" + py_script + "\nEOF\npython3 /tmp/remove_npm.py\n"
|
||||
stdin, stdout, stderr = c.exec_command(cmd_db)
|
||||
print(stdout.read().decode('utf-8'))
|
||||
err = stderr.read().decode('utf-8')
|
||||
if err: print("DB err:", err)
|
||||
|
||||
print("2. Removing unused configuration files...")
|
||||
remove_files_cmd = "rm -f /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/proxy_host/3.conf /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/proxy_host/51.conf /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/proxy_host/54.conf"
|
||||
stdin, stdout, stderr = c.exec_command(remove_files_cmd)
|
||||
stdout.channel.recv_exit_status()
|
||||
print("Removed 3.conf, 51.conf, 54.conf")
|
||||
|
||||
print("3. Testing Nginx configuration syntax inside container...")
|
||||
test_cmd = "docker exec $(docker ps -q -f name=nginx-proxy-manager_app | head -n1) nginx -t"
|
||||
stdin, stdout, stderr = c.exec_command(test_cmd)
|
||||
test_out = stdout.read().decode('utf-8')
|
||||
test_err = stderr.read().decode('utf-8')
|
||||
print("nginx -t:\n", test_out, test_err)
|
||||
|
||||
if "successful" in test_err or "successful" in test_out:
|
||||
print("4. Reloading Nginx...")
|
||||
stdin, stdout, stderr = c.exec_command("docker exec $(docker ps -q -f name=nginx-proxy-manager_app | head -n1) nginx -s reload")
|
||||
stdout.channel.recv_exit_status()
|
||||
print("Nginx reloaded successfully!")
|
||||
|
||||
c.close()
|
||||
|
||||
29
scripts/restart_and_test_technitium.py
Normal file
29
scripts/restart_and_test_technitium.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import paramiko
|
||||
import time
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Delete the pod so deployment restarts it
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl rollout restart deployment/technitium-dns -n dns')
|
||||
print("Restart technitium:", stdout.read().decode())
|
||||
|
||||
time.sleep(10)
|
||||
|
||||
# Check pods
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl get pods -n dns -l app=technitium-dns')
|
||||
print("Pods:", stdout.read().decode())
|
||||
|
||||
# Test GET /sso/login
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s -v -I "http://localhost:5380/sso/login"')
|
||||
print("GET /sso/login response:")
|
||||
print(stderr.read().decode('utf-8', errors='ignore'))
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check logs for startup
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- tail -n 30 /var/log/technitium/dns/2026-11-06.log 2>/dev/null || true')
|
||||
print("Recent logs:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
27
scripts/restart_and_verify_sso.py
Normal file
27
scripts/restart_and_verify_sso.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import paramiko
|
||||
import time
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
print("Restarting deployment/technitium-dns...")
|
||||
ssh.exec_command('k3s kubectl rollout restart deployment/technitium-dns -n dns')
|
||||
time.sleep(12)
|
||||
|
||||
# Wait for pod ready
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl wait --for=condition=Ready pod -l app=technitium-dns -n dns --timeout=30s')
|
||||
print("Wait condition:", stdout.read().decode())
|
||||
|
||||
# Test GET /sso/login
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -v "http://localhost:5380/sso/login"')
|
||||
print("GET /sso/login result:")
|
||||
print(stderr.read().decode('utf-8', errors='ignore'))
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check recent logs
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- tail -n 25 /var/log/technitium/dns/2026-11-06.log 2>/dev/null || true')
|
||||
print("Recent logs:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
98
scripts/run_db_update.py
Normal file
98
scripts/run_db_update.py
Normal file
@@ -0,0 +1,98 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect("140.44.4.71", username="root", key_filename=key_path, timeout=10)
|
||||
|
||||
remote_script = """import sqlite3, json, datetime
|
||||
|
||||
conn = sqlite3.connect("/var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite")
|
||||
cur = conn.cursor()
|
||||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
updates = [
|
||||
(3, json.dumps(["pihole.snarfnet.net"]), "140.44.4.34", 443, "https"),
|
||||
(43, json.dumps(["pihole2.snarfnet.net"]), "140.44.4.62", 443, "https"),
|
||||
(51, json.dumps(["pihole3.snarfnet.net"]), "140.44.4.62", 443, "https"),
|
||||
(52, json.dumps(["dns1.snarfnet.net"]), "140.44.4.34", 443, "https"),
|
||||
(53, json.dumps(["dns2.snarfnet.net"]), "140.44.4.62", 443, "https"),
|
||||
]
|
||||
|
||||
for pid, dnames, host, port, scheme in updates:
|
||||
cur.execute('''UPDATE proxy_host
|
||||
SET domain_names = ?, forward_host = ?, forward_port = ?, forward_scheme = ?,
|
||||
certificate_id = 1, ssl_forced = 1, allow_websocket_upgrade = 1, http2_support = 1,
|
||||
hsts_enabled = 1, hsts_subdomains = 1, advanced_config = "", modified_on = ?
|
||||
WHERE id = ?''', (dnames, host, port, scheme, now, pid))
|
||||
print(f"Updated proxy host {pid} -> {host}:{port} ({scheme})")
|
||||
|
||||
meta_json = json.dumps({"nginx_online": True, "nginx_err": None})
|
||||
|
||||
cur.execute("SELECT id FROM proxy_host WHERE id = 54")
|
||||
if not cur.fetchone():
|
||||
cur.execute('''INSERT INTO proxy_host (
|
||||
id, created_on, modified_on, owner_user_id, is_deleted,
|
||||
domain_names, forward_host, forward_port, access_list_id,
|
||||
certificate_id, ssl_forced, caching_enabled, block_exploits,
|
||||
advanced_config, meta, allow_websocket_upgrade, http2_support,
|
||||
forward_scheme, enabled, locations, hsts_enabled, hsts_subdomains,
|
||||
trust_forwarded_proto
|
||||
) VALUES (
|
||||
54, ?, ?, 1, 0,
|
||||
?, "140.44.4.34", 443, 0,
|
||||
1, 1, 0, 1,
|
||||
"", ?, 1, 1,
|
||||
"https", 1, "[]", 1, 1,
|
||||
0
|
||||
)''', (now, now, json.dumps(["technitium.snarfnet.net"]), meta_json))
|
||||
print("Inserted proxy host 54: technitium.snarfnet.net -> 140.44.4.34:443")
|
||||
else:
|
||||
cur.execute('''UPDATE proxy_host
|
||||
SET domain_names = ?, forward_host = "140.44.4.34", forward_port = 443, forward_scheme = "https",
|
||||
certificate_id = 1, ssl_forced = 1, allow_websocket_upgrade = 1, http2_support = 1,
|
||||
hsts_enabled = 1, hsts_subdomains = 1, modified_on = ?
|
||||
WHERE id = 54''', (json.dumps(["technitium.snarfnet.net"]), now))
|
||||
print("Updated proxy host 54: technitium.snarfnet.net")
|
||||
|
||||
cur.execute("SELECT id FROM proxy_host WHERE id = 55")
|
||||
if not cur.fetchone():
|
||||
cur.execute('''INSERT INTO proxy_host (
|
||||
id, created_on, modified_on, owner_user_id, is_deleted,
|
||||
domain_names, forward_host, forward_port, access_list_id,
|
||||
certificate_id, ssl_forced, caching_enabled, block_exploits,
|
||||
advanced_config, meta, allow_websocket_upgrade, http2_support,
|
||||
forward_scheme, enabled, locations, hsts_enabled, hsts_subdomains,
|
||||
trust_forwarded_proto
|
||||
) VALUES (
|
||||
55, ?, ?, 1, 0,
|
||||
?, "140.44.4.34", 443, 0,
|
||||
1, 1, 0, 1,
|
||||
"", ?, 1, 1,
|
||||
"https", 1, "[]", 1, 1,
|
||||
0
|
||||
)''', (now, now, json.dumps(["pihole1.snarfnet.net"]), meta_json))
|
||||
print("Inserted proxy host 55: pihole1.snarfnet.net -> 140.44.4.34:443")
|
||||
else:
|
||||
cur.execute('''UPDATE proxy_host
|
||||
SET domain_names = ?, forward_host = "140.44.4.34", forward_port = 443, forward_scheme = "https",
|
||||
certificate_id = 1, ssl_forced = 1, allow_websocket_upgrade = 1, http2_support = 1,
|
||||
hsts_enabled = 1, hsts_subdomains = 1, modified_on = ?
|
||||
WHERE id = 55''', (json.dumps(["pihole1.snarfnet.net"]), now))
|
||||
print("Updated proxy host 55: pihole1.snarfnet.net")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
"""
|
||||
|
||||
# Write script to /tmp/update_npm_db.py
|
||||
cmd = "cat << 'EOF' > /tmp/update_npm_db.py\n" + remote_script + "\nEOF\npython3 /tmp/update_npm_db.py\n"
|
||||
stdin, stdout, stderr = c.exec_command(cmd)
|
||||
print("Output:\n", stdout.read().decode('utf-8'))
|
||||
err = stderr.read().decode('utf-8')
|
||||
if err: print("Err:\n", err)
|
||||
|
||||
c.close()
|
||||
126
scripts/sync_authentik_apps.py
Normal file
126
scripts/sync_authentik_apps.py
Normal file
@@ -0,0 +1,126 @@
|
||||
import urllib.request
|
||||
import ssl
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
|
||||
token = "SnarfNetPermanentAutomationToken2026"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
def api_call(url, method="GET", payload=None):
|
||||
data = json.dumps(payload).encode('utf-8') if payload else None
|
||||
req = urllib.request.Request(url, headers=headers, data=data, method=method)
|
||||
try:
|
||||
with urllib.request.urlopen(req, context=ctx, timeout=8) as resp:
|
||||
return json.loads(resp.read().decode('utf-8'))
|
||||
except urllib.error.HTTPError as e:
|
||||
err = e.read().decode('utf-8')
|
||||
print(f"API Error {e.code} on {method} {url}: {err}")
|
||||
return None
|
||||
|
||||
print("1. Updating OAuth2 Provider 23 (Technitium)...")
|
||||
p23_payload = {
|
||||
"name": "Technitium DNS SSO",
|
||||
"redirect_uris": [
|
||||
{"url": "https://dns1.snarfnet.net/sso/callback", "matching_mode": "strict"},
|
||||
{"url": "https://dns2.snarfnet.net/sso/callback", "matching_mode": "strict"},
|
||||
{"url": "https://dns1.snarfnet.net/", "matching_mode": "strict"},
|
||||
{"url": "https://dns2.snarfnet.net/", "matching_mode": "strict"},
|
||||
{"url": "https://dns.*\\.snarfnet\\.net.*", "matching_mode": "regex"}
|
||||
]
|
||||
}
|
||||
api_call("https://authentik.snarfnet.net/api/v3/providers/oauth2/23/", method="PATCH", payload=p23_payload)
|
||||
print("Updated Provider 23 redirect URIs.")
|
||||
|
||||
print("\n2. Updating Applications in Authentik App Library...")
|
||||
|
||||
# Target applications definition:
|
||||
apps_target = [
|
||||
{
|
||||
"name": "Pi-hole 1 (Aerodrome)",
|
||||
"slug": "pihole1",
|
||||
"provider": 24,
|
||||
"group": "Networking & Edge",
|
||||
"meta_launch_url": "https://pihole1.snarfnet.net",
|
||||
"meta_description": "Network-wide Ad & Tracker Blocking (Aerodrome Primary)",
|
||||
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/pi-hole.png",
|
||||
"open_in_new_tab": True
|
||||
},
|
||||
{
|
||||
"name": "Pi-hole 2 (Spaceport)",
|
||||
"slug": "pihole2",
|
||||
"provider": 12,
|
||||
"group": "Networking & Edge",
|
||||
"meta_launch_url": "https://pihole2.snarfnet.net",
|
||||
"meta_description": "Network-wide Ad & Tracker Blocking (Spaceport Secondary)",
|
||||
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/pi-hole.png",
|
||||
"open_in_new_tab": True
|
||||
},
|
||||
{
|
||||
"name": "Technitium DNS 1 (Aerodrome)",
|
||||
"slug": "dns1",
|
||||
"provider": 23,
|
||||
"group": "Networking & Edge",
|
||||
"meta_launch_url": "https://dns1.snarfnet.net",
|
||||
"meta_description": "Authoritative & Recursive DNS Server with DoH & Local Resolution (Aerodrome Primary)",
|
||||
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/technitium.png",
|
||||
"open_in_new_tab": True
|
||||
},
|
||||
{
|
||||
"name": "Technitium DNS 2 (Spaceport)",
|
||||
"slug": "dns2",
|
||||
"provider": 23,
|
||||
"group": "Networking & Edge",
|
||||
"meta_launch_url": "https://dns2.snarfnet.net",
|
||||
"meta_description": "Authoritative & Recursive DNS Server with DoH & Local Resolution (Spaceport Secondary)",
|
||||
"meta_icon": "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/technitium.png",
|
||||
"open_in_new_tab": True
|
||||
}
|
||||
]
|
||||
|
||||
# Fetch current applications
|
||||
current_apps = api_call("https://authentik.snarfnet.net/api/v3/core/applications/?page_size=100")
|
||||
current_slugs = {a['slug']: a for a in current_apps.get('results', [])}
|
||||
|
||||
# Delete obsolete slugs if they exist (e.g., 'technitium' or old 'pihole' if we recreate as 'pihole2')
|
||||
if 'technitium' in current_slugs and 'dns1' not in current_slugs:
|
||||
print("Renaming app 'technitium' to 'dns1'...")
|
||||
api_call("https://authentik.snarfnet.net/api/v3/core/applications/technitium/", method="PATCH", payload=apps_target[2])
|
||||
elif 'technitium' in current_slugs:
|
||||
print("Removing obsolete 'technitium' app...")
|
||||
api_call("https://authentik.snarfnet.net/api/v3/core/applications/technitium/", method="DELETE")
|
||||
|
||||
if 'pihole' in current_slugs:
|
||||
print("Renaming app 'pihole' to 'pihole2'...")
|
||||
api_call("https://authentik.snarfnet.net/api/v3/core/applications/pihole/", method="PATCH", payload=apps_target[1])
|
||||
|
||||
# Refresh apps list
|
||||
current_apps = api_call("https://authentik.snarfnet.net/api/v3/core/applications/?page_size=100")
|
||||
current_slugs = {a['slug']: a for a in current_apps.get('results', [])}
|
||||
|
||||
for target in apps_target:
|
||||
slug = target['slug']
|
||||
if slug in current_slugs:
|
||||
print(f"Updating app '{target['name']}' ({slug})...")
|
||||
res = api_call(f"https://authentik.snarfnet.net/api/v3/core/applications/{slug}/", method="PATCH", payload=target)
|
||||
if res: print(f" ✓ Updated {slug}")
|
||||
else:
|
||||
print(f"Creating app '{target['name']}' ({slug})...")
|
||||
res = api_call("https://authentik.snarfnet.net/api/v3/core/applications/", method="POST", payload=target)
|
||||
if res: print(f" ✓ Created {slug}")
|
||||
|
||||
print("\n3. Verifying final state in Authentik App Library...")
|
||||
final_apps = api_call("https://authentik.snarfnet.net/api/v3/core/applications/?page_size=100")
|
||||
for a in sorted(final_apps.get('results', []), key=lambda x: x['name']):
|
||||
if a['slug'] in ['pihole1', 'pihole2', 'dns1', 'dns2', 'pihole', 'technitium']:
|
||||
print(f" [{a['group']}] {a['name']}")
|
||||
print(f" Slug: {a['slug']} | URL: {a['meta_launch_url']} | Provider PK: {a['provider']}")
|
||||
|
||||
18
scripts/test_authentik_reachability.py
Normal file
18
scripts/test_authentik_reachability.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Curl authentik from inside technitium pod
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -v https://authentik.snarfnet.net/application/o/dns1/.well-known/openid-configuration')
|
||||
print("Curl from technitium pod:")
|
||||
print(stderr.read().decode('utf-8', errors='ignore'))
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check DNS resolution inside technitium pod
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- cat /etc/resolv.conf')
|
||||
print("/etc/resolv.conf inside technitium pod:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
@@ -22,3 +22,4 @@ for host, ip, path in [
|
||||
print(f"{host} -> {ip}: {status_line} {loc}")
|
||||
|
||||
c.close()
|
||||
|
||||
|
||||
@@ -23,3 +23,4 @@ for host in ['140.44.4.70', '140.44.4.71']:
|
||||
except Exception as e:
|
||||
print(f" Conn error on {host}: {e}")
|
||||
break
|
||||
|
||||
|
||||
21
scripts/test_pihole_web_login.py
Normal file
21
scripts/test_pihole_web_login.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Test login to pihole web interface via curl from the host
|
||||
cmd = 'curl -s -c /tmp/cookies.txt -b /tmp/cookies.txt -X POST "http://140.44.4.65/api/auth" -H "Content-Type: application/json" -d \'{"password":"snarfnetadmin"}\''
|
||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||
print("Spaceport /api/auth via 140.44.4.65:", stdout.read().decode())
|
||||
|
||||
cmd = 'curl -s -c /tmp/cookies.txt -b /tmp/cookies.txt "http://140.44.4.65/api/auth"'
|
||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||
print("Spaceport check session /api/auth:", stdout.read().decode())
|
||||
|
||||
# Check pihole FTL log for any error
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- tail -n 25 /var/log/pihole/FTL.log 2>/dev/null || true')
|
||||
print("FTL.log:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
17
scripts/test_sso_after_restart.py
Normal file
17
scripts/test_sso_after_restart.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s -v "http://localhost:5380/sso/login"')
|
||||
print("GET /sso/login header/body:")
|
||||
print(stderr.read().decode('utf-8', errors='ignore'))
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Also check index.html from curl to see if sso button is shown
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/" | grep -C 5 "divLoginSso"')
|
||||
print("divLoginSso in index.html:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
24
scripts/test_sso_and_ftl.py
Normal file
24
scripts/test_sso_and_ftl.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- grep -n -A 25 "setFTLConfigValue()" /usr/local/bin/pihole')
|
||||
print("setFTLConfigValue:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Also let's check what Technitium API call sets SSO
|
||||
# In Technitium: /api/admin/sso/set
|
||||
# Let's inspect /api/admin/sso/set with token
|
||||
token = "8d22b3ee9fe8ccbb317679afdbc86959d0ceea8261e0f0c7957d4325a7987d78"
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/admin/sso/set?token={token}&ssoEnabled=true&ssoClientId=technitium-dns-oidc&ssoClientSecret=SnarfNetTechnitiumOIDC2026!&ssoMetadataAddress=https://authentik.snarfnet.net/application/o/dns1/.well-known/openid-configuration&ssoAllowSignup=true&ssoAllowSignupOnlyForMappedUsers=false"')
|
||||
print("Technitium SSO set test:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Check get after set
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/admin/sso/get?token={token}"')
|
||||
print("Technitium SSO get after set:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
39
scripts/test_sso_authority.py
Normal file
39
scripts/test_sso_authority.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import paramiko
|
||||
import json
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Check Technitium local DNS resolution for authentik.snarfnet.net
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- dig @127.0.0.1 authentik.snarfnet.net +short')
|
||||
print("Dig authentik.snarfnet.net from Technitium DNS:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
# Get fresh token
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/user/login?user=admin&pass=snarfnetadmin"')
|
||||
data = json.loads(stdout.read().decode())
|
||||
token = data['token']
|
||||
print("Fresh token:", token)
|
||||
|
||||
# Now call api/admin/sso/set with ssoAuthority set as well!
|
||||
url = (
|
||||
f'"http://localhost:5380/api/admin/sso/set?token={token}'
|
||||
'&ssoEnabled=true'
|
||||
'&ssoAuthority=https://authentik.snarfnet.net/application/o/dns1/'
|
||||
'&ssoClientId=technitium-dns-oidc'
|
||||
'&ssoClientSecret=SnarfNetTechnitiumOIDC2026!'
|
||||
'&ssoMetadataAddress=https://authentik.snarfnet.net/application/o/dns1/.well-known/openid-configuration'
|
||||
'&ssoScopes=openid,profile,email'
|
||||
'&ssoAllowSignup=true'
|
||||
'&ssoAllowSignupOnlyForMappedUsers=false'
|
||||
'&ssoGroupMap=authentik%20Admins|Administrators"'
|
||||
)
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s {url}')
|
||||
print("SSO set result:", stdout.read().decode())
|
||||
|
||||
# Check get after set
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/admin/sso/get?token={token}"')
|
||||
print("SSO get after set:", stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
16
scripts/test_sso_forwarded.py
Normal file
16
scripts/test_sso_forwarded.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s -v -H "Host: dns1.snarfnet.net" -H "X-Forwarded-Proto: https" "http://localhost:5380/sso/login"')
|
||||
print("SSO login with Host and X-Forwarded-Proto:")
|
||||
print(stderr.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
# Also check index.html with Host: dns1.snarfnet.net
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s -H "Host: dns1.snarfnet.net" "http://localhost:5380/" | grep -C 5 "divLoginSso"')
|
||||
print("divLoginSso check:")
|
||||
print(stdout.read().decode('utf-8', errors='ignore'))
|
||||
|
||||
ssh.close()
|
||||
13
scripts/test_sso_get.py
Normal file
13
scripts/test_sso_get.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# GET sso/login
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s -v -L "http://localhost:5380/sso/login"')
|
||||
print("SSO login GET:")
|
||||
print(stderr.read().decode('utf-8', errors='ignore'))
|
||||
print(stdout.read().decode('utf-8', errors='ignore')[:1000])
|
||||
|
||||
ssh.close()
|
||||
18
scripts/test_technitium_auth_status.py
Normal file
18
scripts/test_technitium_auth_status.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
for host, label in [('140.44.4.36', 'Aerodrome (dns1)'), ('140.44.4.65', 'Spaceport (dns2)')]:
|
||||
print(f"=== Testing {label} ({host}:5380) ===")
|
||||
for pwd in ['snarfnetadmin', 'admin', 'password']:
|
||||
url = f"http://{host}:5380/api/user/login?user=admin&pass={pwd}"
|
||||
try:
|
||||
with urllib.request.urlopen(url, timeout=4) as resp:
|
||||
data = json.loads(resp.read().decode('utf-8'))
|
||||
tok = data.get('token')
|
||||
tok_str = tok[:10] if tok else None
|
||||
print(f" pass={pwd}: status={data.get('status')}, msg={data.get('errorMessage')}, token={tok_str}")
|
||||
except Exception as e:
|
||||
print(f" pass={pwd}: error={e}")
|
||||
38
scripts/test_technitium_sso_set.py
Normal file
38
scripts/test_technitium_sso_set.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import paramiko
|
||||
import json
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.11', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
# Get fresh token
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/user/login?user=admin&pass=snarfnetadmin"')
|
||||
data = json.loads(stdout.read().decode())
|
||||
token = data['token']
|
||||
print("Fresh token:", token)
|
||||
|
||||
# Now call api/admin/sso/get
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/admin/sso/get?token={token}"')
|
||||
get_res = stdout.read().decode()
|
||||
print("SSO get:", get_res)
|
||||
|
||||
# Now call api/admin/sso/set
|
||||
url = (
|
||||
f'"http://localhost:5380/api/admin/sso/set?token={token}'
|
||||
'&ssoEnabled=true'
|
||||
'&ssoClientId=technitium-dns-oidc'
|
||||
'&ssoClientSecret=SnarfNetTechnitiumOIDC2026!'
|
||||
'&ssoMetadataAddress=https://authentik.snarfnet.net/application/o/dns1/.well-known/openid-configuration'
|
||||
'&ssoScopes=openid,profile,email'
|
||||
'&ssoAllowSignup=true'
|
||||
'&ssoAllowSignupOnlyForMappedUsers=false'
|
||||
'&ssoGroupMap=authentik%20Admins:Administrators"'
|
||||
)
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s {url}')
|
||||
print("SSO set result:", stdout.read().decode())
|
||||
|
||||
# Check get again
|
||||
stdin, stdout, stderr = ssh.exec_command(f'k3s kubectl exec -n dns deployment/technitium-dns -- curl -s "http://localhost:5380/api/admin/sso/get?token={token}"')
|
||||
print("SSO get after set:", stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
11
scripts/test_totp_null.py
Normal file
11
scripts/test_totp_null.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import paramiko
|
||||
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command('k3s kubectl exec -n dns deployment/pihole -- curl -s -X POST "http://localhost/api/auth" -H "Content-Type: application/json" -d \'{"password":"snarfnetadmin","totp":null}\'')
|
||||
print("Auth with totp null:")
|
||||
print(stdout.read().decode())
|
||||
|
||||
ssh.close()
|
||||
208
scripts/update_npm_dns_entries.py
Normal file
208
scripts/update_npm_dns_entries.py
Normal file
@@ -0,0 +1,208 @@
|
||||
import paramiko
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
key_path = r"C:\Users\Snarf\.ssh\id_ed25519_snarfnet"
|
||||
c = paramiko.SSHClient()
|
||||
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
c.connect("140.44.4.71", username="root", key_filename=key_path, timeout=10)
|
||||
|
||||
print("1. Creating safe backups of database and config files...")
|
||||
backup_cmd = """
|
||||
cp /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite.bak.dns
|
||||
cp -r /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/proxy_host /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/proxy_host_bak_dns
|
||||
"""
|
||||
stdin, stdout, stderr = c.exec_command(backup_cmd)
|
||||
stdout.channel.recv_exit_status()
|
||||
print("Backups created successfully.")
|
||||
|
||||
print("2. Updating database.sqlite...")
|
||||
py_script = """
|
||||
import sqlite3, json, datetime
|
||||
|
||||
conn = sqlite3.connect("/var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite")
|
||||
cur = conn.cursor()
|
||||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
updates = [
|
||||
(3, json.dumps(["pihole.snarfnet.net"]), "140.44.4.34", 443, "https"),
|
||||
(43, json.dumps(["pihole2.snarfnet.net"]), "140.44.4.62", 443, "https"),
|
||||
(51, json.dumps(["pihole3.snarfnet.net"]), "140.44.4.62", 443, "https"),
|
||||
(52, json.dumps(["dns1.snarfnet.net"]), "140.44.4.34", 443, "https"),
|
||||
(53, json.dumps(["dns2.snarfnet.net"]), "140.44.4.62", 443, "https"),
|
||||
]
|
||||
|
||||
for pid, dnames, host, port, scheme in updates:
|
||||
cur.execute('''UPDATE proxy_host
|
||||
SET domain_names = ?, forward_host = ?, forward_port = ?, forward_scheme = ?,
|
||||
certificate_id = 1, ssl_forced = 1, allow_websocket_upgrade = 1, http2_support = 1,
|
||||
hsts_enabled = 1, hsts_subdomains = 1, advanced_config = "", modified_on = ?
|
||||
WHERE id = ?''', (dnames, host, port, scheme, now, pid))
|
||||
print(f"Updated proxy host {pid} -> {host}:{port} ({scheme})")
|
||||
|
||||
cur.execute("SELECT id FROM proxy_host WHERE id = 54")
|
||||
if not cur.fetchone():
|
||||
cur.execute('''INSERT INTO proxy_host (
|
||||
id, created_on, modified_on, owner_user_id, is_deleted,
|
||||
domain_names, forward_host, forward_port, access_list_id,
|
||||
certificate_id, ssl_forced, caching_enabled, block_exploits,
|
||||
advanced_config, meta, allow_websocket_upgrade, http2_support,
|
||||
forward_scheme, enabled, locations, hsts_enabled, hsts_subdomains,
|
||||
trust_forwarded_proto
|
||||
) VALUES (
|
||||
54, ?, ?, 1, 0,
|
||||
?, "140.44.4.34", 443, 0,
|
||||
1, 1, 0, 1,
|
||||
"", "{\\"nginx_online\\":true,\\"nginx_err\\":null}", 1, 1,
|
||||
"https", 1, "[]", 1, 1,
|
||||
0
|
||||
)''', (now, now, json.dumps(["technitium.snarfnet.net"])))
|
||||
print("Inserted proxy host 54: technitium.snarfnet.net -> 140.44.4.34:443")
|
||||
else:
|
||||
cur.execute('''UPDATE proxy_host
|
||||
SET domain_names = ?, forward_host = "140.44.4.34", forward_port = 443, forward_scheme = "https",
|
||||
certificate_id = 1, ssl_forced = 1, allow_websocket_upgrade = 1, http2_support = 1,
|
||||
hsts_enabled = 1, hsts_subdomains = 1, modified_on = ?
|
||||
WHERE id = 54''', (json.dumps(["technitium.snarfnet.net"]), now))
|
||||
print("Updated proxy host 54: technitium.snarfnet.net")
|
||||
|
||||
cur.execute("SELECT id FROM proxy_host WHERE id = 55")
|
||||
if not cur.fetchone():
|
||||
cur.execute('''INSERT INTO proxy_host (
|
||||
id, created_on, modified_on, owner_user_id, is_deleted,
|
||||
domain_names, forward_host, forward_port, access_list_id,
|
||||
certificate_id, ssl_forced, caching_enabled, block_exploits,
|
||||
advanced_config, meta, allow_websocket_upgrade, http2_support,
|
||||
forward_scheme, enabled, locations, hsts_enabled, hsts_subdomains,
|
||||
trust_forwarded_proto
|
||||
) VALUES (
|
||||
55, ?, ?, 1, 0,
|
||||
?, "140.44.4.34", 443, 0,
|
||||
1, 1, 0, 1,
|
||||
"", "{\\"nginx_online\\":true,\\"nginx_err\\":null}", 1, 1,
|
||||
"https", 1, "[]", 1, 1,
|
||||
0
|
||||
)''', (now, now, json.dumps(["pihole1.snarfnet.net"])))
|
||||
print("Inserted proxy host 55: pihole1.snarfnet.net -> 140.44.4.34:443")
|
||||
else:
|
||||
cur.execute('''UPDATE proxy_host
|
||||
SET domain_names = ?, forward_host = "140.44.4.34", forward_port = 443, forward_scheme = "https",
|
||||
certificate_id = 1, ssl_forced = 1, allow_websocket_upgrade = 1, http2_support = 1,
|
||||
hsts_enabled = 1, hsts_subdomains = 1, modified_on = ?
|
||||
WHERE id = 55''', (json.dumps(["pihole1.snarfnet.net"]), now))
|
||||
print("Updated proxy host 55: pihole1.snarfnet.net")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
"""
|
||||
|
||||
stdin, stdout, stderr = c.exec_command(f"python3 -c '{py_script}'")
|
||||
print(stdout.read().decode('utf-8'))
|
||||
err = stderr.read().decode('utf-8')
|
||||
if err: print("DB Update Err:", err)
|
||||
|
||||
print("3. Generating Nginx configuration files in proxy_host/...")
|
||||
|
||||
conf_template = """# ------------------------------------------------------------
|
||||
# {domains}
|
||||
# ------------------------------------------------------------
|
||||
|
||||
map $scheme $hsts_header {{
|
||||
https "max-age=63072000;includeSubDomains; preload";
|
||||
}}
|
||||
|
||||
server {{
|
||||
set $forward_scheme {scheme};
|
||||
set $server "{host}";
|
||||
set $port {port};
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
|
||||
server_name {domains};
|
||||
http2 on;
|
||||
|
||||
# Let's Encrypt SSL
|
||||
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||
include conf.d/include/ssl-cache.conf;
|
||||
include conf.d/include/ssl-ciphers.conf;
|
||||
ssl_certificate /etc/letsencrypt/live/npm-1/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/npm-1/privkey.pem;
|
||||
|
||||
# Asset Caching
|
||||
include conf.d/include/assets.conf;
|
||||
|
||||
# Block Exploits
|
||||
include conf.d/include/block-exploits.conf;
|
||||
|
||||
# HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
|
||||
add_header Strict-Transport-Security $hsts_header always;
|
||||
|
||||
# Force SSL
|
||||
set $trust_forwarded_proto "F";
|
||||
include conf.d/include/force-ssl.conf;
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
access_log /data/logs/proxy-host-{pid}_access.log proxy;
|
||||
error_log /data/logs/proxy-host-{pid}_error.log warn;
|
||||
|
||||
location / {{
|
||||
# HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
|
||||
add_header Strict-Transport-Security $hsts_header always;
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}}
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}}
|
||||
"""
|
||||
|
||||
configs = [
|
||||
(3, "pihole.snarfnet.net", "140.44.4.34", 443, "https"),
|
||||
(43, "pihole2.snarfnet.net", "140.44.4.62", 443, "https"),
|
||||
(51, "pihole3.snarfnet.net", "140.44.4.62", 443, "https"),
|
||||
(52, "dns1.snarfnet.net", "140.44.4.34", 443, "https"),
|
||||
(53, "dns2.snarfnet.net", "140.44.4.62", 443, "https"),
|
||||
(54, "technitium.snarfnet.net", "140.44.4.34", 443, "https"),
|
||||
(55, "pihole1.snarfnet.net", "140.44.4.34", 443, "https"),
|
||||
]
|
||||
|
||||
for pid, dom, host, port, scheme in configs:
|
||||
cfg = conf_template.format(pid=pid, domains=dom, host=host, port=port, scheme=scheme)
|
||||
remote_path = f"/var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/proxy_host/{pid}.conf"
|
||||
cmd_write = f"cat << 'EOF' > {remote_path}\n{cfg}\nEOF\n"
|
||||
stdin, stdout, stderr = c.exec_command(cmd_write)
|
||||
stdout.channel.recv_exit_status()
|
||||
print(f"Wrote {remote_path} ({dom} -> {host}:{port})")
|
||||
|
||||
print("\n4. Testing Nginx configuration syntax inside container...")
|
||||
test_cmd = "docker exec $(docker ps -q -f name=nginx-proxy-manager_app | head -n1) nginx -t"
|
||||
stdin, stdout, stderr = c.exec_command(test_cmd)
|
||||
test_out = stdout.read().decode('utf-8')
|
||||
test_err = stderr.read().decode('utf-8')
|
||||
print("nginx -t stdout:", test_out)
|
||||
print("nginx -t stderr:", test_err)
|
||||
|
||||
if "successful" in test_err or "successful" in test_out:
|
||||
print("\n5. Reloading Nginx across Swarm service...")
|
||||
reload_cmd = "docker service update --force nginx-proxy-manager_app"
|
||||
stdin, stdout, stderr = c.exec_command(reload_cmd)
|
||||
print(stdout.read().decode('utf-8'))
|
||||
print("NPM service reloaded successfully!")
|
||||
else:
|
||||
print("\nWARNING: Nginx test failed! Please check configuration.")
|
||||
|
||||
c.close()
|
||||
58
scripts/verify_npm_live.py
Normal file
58
scripts/verify_npm_live.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import ssl
|
||||
import socket
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
active_hosts = [
|
||||
'pihole1.snarfnet.net',
|
||||
'pihole2.snarfnet.net',
|
||||
'dns1.snarfnet.net',
|
||||
'dns2.snarfnet.net',
|
||||
]
|
||||
|
||||
removed_hosts = [
|
||||
'pihole.snarfnet.net',
|
||||
'pihole3.snarfnet.net',
|
||||
'technitium.snarfnet.net',
|
||||
]
|
||||
|
||||
npm_vip = '140.44.4.70'
|
||||
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
|
||||
print(f"=== Active Endpoints via NPM VIP ({npm_vip}:443) ===")
|
||||
for host in active_hosts:
|
||||
path = '/admin/' if 'pihole' in host else '/'
|
||||
try:
|
||||
sock = socket.create_connection((npm_vip, 443), timeout=5)
|
||||
ssock = ctx.wrap_socket(sock, server_hostname=host)
|
||||
req = f"GET {path} HTTP/1.1\r\nHost: {host}\r\nUser-Agent: Mozilla/5.0\r\nConnection: close\r\n\r\n"
|
||||
ssock.sendall(req.encode('utf-8'))
|
||||
resp = ssock.recv(4096).decode('utf-8', errors='replace')
|
||||
ssock.close()
|
||||
|
||||
status_line = resp.splitlines()[0] if resp else "No response"
|
||||
loc = [l for l in resp.splitlines() if 'location:' in l.lower()]
|
||||
loc_str = loc[0][:75] + "..." if loc else ""
|
||||
print(f" ✓ {host:25} -> {status_line:15} {loc_str}")
|
||||
except Exception as e:
|
||||
print(f" ✗ {host:25} -> ERROR: {e}")
|
||||
|
||||
print(f"\n=== Removed Endpoints via NPM VIP ({npm_vip}:443) ===")
|
||||
for host in removed_hosts:
|
||||
path = '/admin/' if 'pihole' in host else '/'
|
||||
try:
|
||||
sock = socket.create_connection((npm_vip, 443), timeout=5)
|
||||
ssock = ctx.wrap_socket(sock, server_hostname=host)
|
||||
req = f"GET {path} HTTP/1.1\r\nHost: {host}\r\nUser-Agent: Mozilla/5.0\r\nConnection: close\r\n\r\n"
|
||||
ssock.sendall(req.encode('utf-8'))
|
||||
resp = ssock.recv(4096).decode('utf-8', errors='replace')
|
||||
ssock.close()
|
||||
|
||||
status_line = resp.splitlines()[0] if resp else "No response"
|
||||
print(f" - {host:25} -> {status_line:15} (Default host/unrouted)")
|
||||
except Exception as e:
|
||||
print(f" - {host:25} -> {e}")
|
||||
Reference in New Issue
Block a user