Security: Remove hardcoded credentials, enforcing env vars
This commit is contained in:
46
sync.py
46
sync.py
@@ -3,17 +3,24 @@ import os
|
||||
import time
|
||||
import sys
|
||||
|
||||
# --- KONFIGURATION (Via Environment Variables) ---
|
||||
# Falls keine ENV-Vars gesetzt sind, werden die alten Hardcoded-Werte als Fallback genutzt.
|
||||
NETBOX_URL = os.getenv("NETBOX_URL", "http://172.30.242.99")
|
||||
TOKEN = os.getenv("NETBOX_TOKEN", "0b740520aeef964cfd2ca34b82a472a271d51649")
|
||||
def log(msg):
|
||||
"""Ungepufferte Ausgabe für Docker Logs"""
|
||||
print(msg, flush=True)
|
||||
|
||||
# --- KONFIGURATION ---
|
||||
# Pflichtfelder - Abbruch wenn nicht gesetzt
|
||||
NETBOX_URL = os.getenv("NETBOX_URL")
|
||||
TOKEN = os.getenv("NETBOX_TOKEN")
|
||||
|
||||
if not NETBOX_URL or not TOKEN:
|
||||
log("FATAL ERROR: Environment variables NETBOX_URL and NETBOX_TOKEN are required.")
|
||||
log("Please provide them via -e flag or .env file.")
|
||||
sys.exit(1)
|
||||
|
||||
# Optionale Konfiguration mit Defaults
|
||||
ZONE_NAME = os.getenv("ZONE_NAME", "klenzel.net")
|
||||
REVERSE_ZONE_NAME = os.getenv("REVERSE_ZONE_NAME", "172.in-addr.arpa")
|
||||
|
||||
# Interval in Sekunden
|
||||
REFRESH_INTERVAL = int(os.getenv("REFRESH_INTERVAL", "600"))
|
||||
|
||||
OUTPUT_FILE_FWD = os.getenv("OUTPUT_FILE_FWD", "/zones/db.klenzel.net")
|
||||
OUTPUT_FILE_REV = os.getenv("OUTPUT_FILE_REV", "/zones/db.reverse.arpa")
|
||||
DEFAULT_TTL = os.getenv("DEFAULT_TTL", "3600")
|
||||
@@ -21,18 +28,13 @@ DEFAULT_TTL = os.getenv("DEFAULT_TTL", "3600")
|
||||
# Fallback Konfiguration (wenn KEIN NS in NetBox gefunden wird)
|
||||
FALLBACK_NS_HOSTNAME = os.getenv("FALLBACK_NS_HOSTNAME", "fks-01-cl-cdns")
|
||||
FALLBACK_NS_IP = os.getenv("FALLBACK_NS_IP", "172.25.16.152")
|
||||
# ---------------------
|
||||
|
||||
HEADERS = {'Authorization': f'Token {TOKEN}', 'Accept': 'application/json'}
|
||||
|
||||
def log(msg):
|
||||
"""Ungepufferte Ausgabe für Docker Logs"""
|
||||
print(msg, flush=True)
|
||||
|
||||
def fetch_ipam_data():
|
||||
"""
|
||||
Holt alle aktiven IPs mit DNS-Namen aus NetBox.
|
||||
Wirft eine Exception, wenn NetBox nicht erreichbar ist (kein try/except hier!).
|
||||
Wirft eine Exception, wenn NetBox nicht erreichbar ist.
|
||||
"""
|
||||
url = f"{NETBOX_URL}/api/ipam/ip-addresses/?status=active&dns_name__n=&limit=0"
|
||||
log(f"Abruf IPAM: {url}")
|
||||
@@ -114,7 +116,6 @@ def get_ns_config(plugin_records, all_records):
|
||||
def generate_zone_file_fwd(ipam_data, plugin_records):
|
||||
"""Erstellt die Forward-Zone"""
|
||||
|
||||
# Daten aufbereiten
|
||||
ipam_records = []
|
||||
for ip in ipam_data:
|
||||
dns_name = ip.get('dns_name', '')
|
||||
@@ -133,7 +134,6 @@ def generate_zone_file_fwd(ipam_data, plugin_records):
|
||||
|
||||
all_records = plugin_records + ipam_records
|
||||
|
||||
# Header-Logik
|
||||
primary_ns, extra_headers = get_ns_config(plugin_records, all_records)
|
||||
|
||||
serial = int(time.time())
|
||||
@@ -152,7 +152,6 @@ def generate_zone_file_fwd(ipam_data, plugin_records):
|
||||
header.extend(extra_headers)
|
||||
header.append("")
|
||||
|
||||
# Schreiben
|
||||
with open(OUTPUT_FILE_FWD, "w") as f:
|
||||
f.write("\n".join(header))
|
||||
f.write("\n; --- Records ---\n")
|
||||
@@ -207,11 +206,10 @@ def generate_zone_file_rev(ipam_data, plugin_records):
|
||||
log(f"SUCCESS: Reverse Zone geschrieben ({len(ptr_records)} Records).")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Kurzer Check ob Zielordner existiert
|
||||
if not os.path.exists(os.path.dirname(OUTPUT_FILE_FWD)):
|
||||
log(f"FATAL: Verzeichnis {os.path.dirname(OUTPUT_FILE_FWD)} fehlt!")
|
||||
time.sleep(30)
|
||||
exit(1)
|
||||
time.sleep(5)
|
||||
sys.exit(1)
|
||||
|
||||
log(f"--- CoreDNS Sync startet ---")
|
||||
log(f"NetBox URL: {NETBOX_URL}")
|
||||
@@ -221,22 +219,14 @@ if __name__ == "__main__":
|
||||
log(f"\n--- Sync Start: {time.ctime()} ---")
|
||||
|
||||
try:
|
||||
# Schritt 1: Daten holen (wirft Exception bei Fehler)
|
||||
# Wir holen BEIDE Datensätze, bevor wir irgendetwas schreiben.
|
||||
# Wenn einer fehlschlägt, bricht der ganze Block ab.
|
||||
ipam_data = fetch_ipam_data()
|
||||
plugin_records = fetch_plugin_records()
|
||||
|
||||
# Schritt 2: Zonen schreiben
|
||||
# Wird nur erreicht, wenn fetch_ipam_data UND fetch_plugin_records erfolgreich waren
|
||||
generate_zone_file_fwd(ipam_data, plugin_records)
|
||||
generate_zone_file_rev(ipam_data, plugin_records)
|
||||
|
||||
except Exception as e:
|
||||
# Sicherheits-Logik: Bei JEDEM Fehler (Netzwerk, HTTP 500, Parse-Error)
|
||||
# fangen wir hier ab und schreiben KEINE Dateien.
|
||||
# Die alten Dateien bleiben erhalten -> CoreDNS liefert weiter die alten Daten (kein NXDOMAIN).
|
||||
log(f"CRITICAL ERROR: Sync abgebrochen! Behalte alte Zone-Files. Grund: {e}")
|
||||
|
||||
log(f"Schlafe {REFRESH_INTERVAL} Sekunden...")
|
||||
time.sleep(REFRESH_INTERVAL)
|
||||
time.sleep(REFRESH_INTERVAL)
|
||||
|
||||
Reference in New Issue
Block a user