v0.5.0: Add RBAC auth, LLM router, audit logging, output sanitization
- New: auth.py – Role-based access (operator/approver/viewer) - New: llm_router.py – Configurable primary/fallback provider chain - New: audit_log.py + audit_query.py – DSGVO-compliant audit trail - New: sanitize_output() – masks secrets in bot responses - Updated: bot.py – Integrated auth guards, router, audit logging - Updated: ollama_client.py – Router-compatible interface - Updated: CLOWNFISCHSERVER.md – Documentation updated - Updated: README.md – Documentation updated
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# 🐠 CLOWNFISCHSERVER – HomeIP Auto-Update
|
||||
# Purpose: Auto-update firewall rule for dynamic home IP (myfritz.net)
|
||||
# Runs: Every 5 minutes (via cron)
|
||||
# Author: Mehlzoerwer-Claude
|
||||
# License: GPL-3.0
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# --- Configuration ---
|
||||
INSTALL_DIR="/opt/clownfischserver"
|
||||
ENV_FILE="$INSTALL_DIR/config/.env"
|
||||
STATE_FILE="/var/lib/clownfischserver-homeip-state"
|
||||
LOG_FILE="/var/log/clownfischserver-homeip-updater.log"
|
||||
SSH_PORT=22
|
||||
|
||||
# --- Helpers ---
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# --- Load .env ---
|
||||
load_env() {
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
log "ERROR: .env not found at $ENV_FILE"
|
||||
exit 1
|
||||
fi
|
||||
# Load and trim CRLF/LF
|
||||
MYFRITZ_DOMAIN=$(grep "^CLOWNFISCHSERVER_HOME_IP_DOMAIN=" "$ENV_FILE" | cut -d= -f2 | tr -d '\r\n')
|
||||
if [ -z "$MYFRITZ_DOMAIN" ]; then
|
||||
log "ERROR: CLOWNFISCHSERVER_HOME_IP_DOMAIN not set in .env"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Detect Firewall ---
|
||||
detect_firewall() {
|
||||
if systemctl is-active --quiet ufw; then
|
||||
echo "ufw"
|
||||
elif systemctl is-active --quiet firewalld; then
|
||||
echo "firewalld"
|
||||
elif command -v iptables &>/dev/null; then
|
||||
echo "iptables"
|
||||
else
|
||||
log "ERROR: No firewall detected (ufw/firewalld/iptables)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Resolve DNS with fallbacks ---
|
||||
resolve_ip() {
|
||||
local domain="$1"
|
||||
|
||||
# Try dig first
|
||||
if command -v dig &>/dev/null; then
|
||||
IP=$(dig +short "$domain" A | grep -oE '^[0-9.]+$' | head -1)
|
||||
[ -n "$IP" ] && echo "$IP" && return 0
|
||||
fi
|
||||
|
||||
# Try nslookup
|
||||
if command -v nslookup &>/dev/null; then
|
||||
IP=$(nslookup "$domain" 2>/dev/null | grep "Address:" | tail -1 | awk '{print $2}' | grep -oE '^[0-9.]+$')
|
||||
[ -n "$IP" ] && echo "$IP" && return 0
|
||||
fi
|
||||
|
||||
# Try getent
|
||||
if command -v getent &>/dev/null; then
|
||||
IP=$(getent hosts "$domain" | awk '{print $1}' | grep -oE '^[0-9.]+$' | head -1)
|
||||
[ -n "$IP" ] && echo "$IP" && return 0
|
||||
fi
|
||||
|
||||
log "ERROR: Could not resolve $domain"
|
||||
return 1
|
||||
}
|
||||
|
||||
# --- Load previous state ---
|
||||
load_state() {
|
||||
if [ -f "$STATE_FILE" ]; then
|
||||
PREVIOUS_IP=$(cat "$STATE_FILE" | grep "^IP=" | cut -d= -f2)
|
||||
echo "$PREVIOUS_IP"
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Save state ---
|
||||
save_state() {
|
||||
local ip="$1"
|
||||
echo "IP=$ip" > "$STATE_FILE"
|
||||
chmod 600 "$STATE_FILE"
|
||||
}
|
||||
|
||||
# --- UFW Functions ---
|
||||
ufw_add_rule() {
|
||||
local ip="$1"
|
||||
ufw allow from "$ip" to any port "$SSH_PORT" comment "clownfisch-homeip" >/dev/null 2>&1
|
||||
log "UFW: Added rule for $ip:$SSH_PORT"
|
||||
}
|
||||
|
||||
ufw_remove_rule() {
|
||||
local ip="$1"
|
||||
echo "y" | ufw delete allow from "$ip" to any port "$SSH_PORT" >/dev/null 2>&1
|
||||
log "UFW: Deleted rule for $ip"
|
||||
}
|
||||
|
||||
# --- Firewalld Functions ---
|
||||
firewalld_add_rule() {
|
||||
local ip="$1"
|
||||
firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='$ip' port protocol='tcp' port='$SSH_PORT' accept" >/dev/null 2>&1
|
||||
firewall-cmd --reload >/dev/null 2>&1
|
||||
log "firewalld: Added rule for $ip:$SSH_PORT"
|
||||
}
|
||||
|
||||
firewalld_remove_rule() {
|
||||
local ip="$1"
|
||||
firewall-cmd --permanent --remove-rich-rule="rule family='ipv4' source address='$ip' port protocol='tcp' port='$SSH_PORT' accept" >/dev/null 2>&1
|
||||
firewall-cmd --reload >/dev/null 2>&1
|
||||
log "firewalld: Deleted rule for $ip"
|
||||
}
|
||||
|
||||
# --- iptables Functions ---
|
||||
iptables_add_rule() {
|
||||
local ip="$1"
|
||||
iptables -I INPUT -s "$ip" -p tcp --dport "$SSH_PORT" -j ACCEPT
|
||||
log "iptables: Added rule for $ip:$SSH_PORT"
|
||||
}
|
||||
|
||||
iptables_remove_rule() {
|
||||
local ip="$1"
|
||||
iptables -D INPUT -s "$ip" -p tcp --dport "$SSH_PORT" -j ACCEPT 2>/dev/null || true
|
||||
log "iptables: Deleted rule for $ip"
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
main() {
|
||||
log "=== HomeIP Auto-Update started ==="
|
||||
|
||||
load_env
|
||||
FIREWALL=$(detect_firewall)
|
||||
NEW_IP=$(resolve_ip "$MYFRITZ_DOMAIN") || exit 1
|
||||
PREVIOUS_IP=$(load_state)
|
||||
|
||||
if [ "$NEW_IP" = "$PREVIOUS_IP" ]; then
|
||||
log "No change: $NEW_IP (same as previous)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "IP change detected: $PREVIOUS_IP → $NEW_IP (firewall: $FIREWALL)"
|
||||
|
||||
# Remove old rule
|
||||
if [ -n "$PREVIOUS_IP" ]; then
|
||||
case "$FIREWALL" in
|
||||
ufw) ufw_remove_rule "$PREVIOUS_IP" ;;
|
||||
firewalld) firewalld_remove_rule "$PREVIOUS_IP" ;;
|
||||
iptables) iptables_remove_rule "$PREVIOUS_IP" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Add new rule
|
||||
case "$FIREWALL" in
|
||||
ufw) ufw_add_rule "$NEW_IP" ;;
|
||||
firewalld) firewalld_add_rule "$NEW_IP" ;;
|
||||
iptables) iptables_add_rule "$NEW_IP" ;;
|
||||
esac
|
||||
|
||||
# Save state
|
||||
save_state "$NEW_IP"
|
||||
|
||||
log "=== HomeIP Auto-Update completed successfully ==="
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user