|
|
@@ -0,0 +1,240 @@
|
|
|
+#!/usr/bin/env bash
|
|
|
+set -euo pipefail
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Konfiguration (ANPASSEN!)
|
|
|
+# =========================
|
|
|
+DOMAIN="DOMAIN.local"
|
|
|
+REALM="DOMAIN.LOCAL" # i.d.R. DOMAIN in GROSS
|
|
|
+AD_DNS_IP="192.168.178.3" # Synology AD/DNS IP
|
|
|
+DC_HOST="nas.DOMAIN.local" # optional für Tests
|
|
|
+ADMIN_USER="Administrator@DOMAIN.LOCAL"
|
|
|
+# Optional: Test-User (nur für getent/id Test nach Join)
|
|
|
+TEST_USER="TESTUSER"
|
|
|
+
|
|
|
+# Optional: Computer OU (leer lassen wenn nicht benötigt)
|
|
|
+COMPUTER_OU=""
|
|
|
+
|
|
|
+# Verhalten
|
|
|
+FORCE_NO_MDNS=true # hosts: files dns (empfohlen bei .local)
|
|
|
+DISABLE_AVAHI=true # avahi-daemon stoppen/deaktivieren
|
|
|
+SET_KRB5_RDNS_FALSE=true # rdns = false setzen (sehr empfehlenswert)
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Helper
|
|
|
+# =========================
|
|
|
+require_root() {
|
|
|
+ if [[ "${EUID}" -ne 0 ]]; then
|
|
|
+ echo "Bitte als root ausführen: sudo $0"
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+backup_file() {
|
|
|
+ local f="$1"
|
|
|
+ if [[ -f "$f" ]]; then
|
|
|
+ cp -a "$f" "${f}.bak.$(date +%Y%m%d%H%M%S)"
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+have_cmd() { command -v "$1" >/dev/null 2>&1; }
|
|
|
+
|
|
|
+fail() {
|
|
|
+ echo "FEHLER: $*" >&2
|
|
|
+ exit 1
|
|
|
+}
|
|
|
+
|
|
|
+info() { echo "==> $*"; }
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Install packages (Debian/Ubuntu)
|
|
|
+# =========================
|
|
|
+install_packages() {
|
|
|
+ info "Installiere benötigte Pakete..."
|
|
|
+ export DEBIAN_FRONTEND=noninteractive
|
|
|
+ apt-get update -y
|
|
|
+ apt-get install -y \
|
|
|
+ realmd sssd sssd-tools libnss-sss libpam-sss adcli \
|
|
|
+ krb5-user packagekit samba-common-bin oddjob oddjob-mkhomedir \
|
|
|
+ dnsutils network-manager
|
|
|
+}
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Disable Avahi/mDNS
|
|
|
+# =========================
|
|
|
+disable_mdns() {
|
|
|
+ if [[ "${DISABLE_AVAHI}" == "true" ]] && systemctl list-unit-files | grep -q '^avahi-daemon\.service'; then
|
|
|
+ info "Stoppe/Deaktiviere avahi-daemon (mDNS/.local)..."
|
|
|
+ systemctl stop avahi-daemon || true
|
|
|
+ systemctl disable avahi-daemon || true
|
|
|
+ fi
|
|
|
+
|
|
|
+ if [[ "${FORCE_NO_MDNS}" == "true" ]]; then
|
|
|
+ info "Erzwinge hosts: files dns (mdns raus) in /etc/nsswitch.conf..."
|
|
|
+ backup_file /etc/nsswitch.conf
|
|
|
+ if grep -q '^hosts:' /etc/nsswitch.conf; then
|
|
|
+ # setze hosts-Zeile hart auf "files dns"
|
|
|
+ sed -i -E 's/^hosts:.*/hosts: files dns/' /etc/nsswitch.conf
|
|
|
+ else
|
|
|
+ echo 'hosts: files dns' >> /etc/nsswitch.conf
|
|
|
+ fi
|
|
|
+ else
|
|
|
+ info "Setze nur dns vor mdns in /etc/nsswitch.conf..."
|
|
|
+ backup_file /etc/nsswitch.conf
|
|
|
+ # Best-effort: files dns mdns4_minimal
|
|
|
+ if grep -q '^hosts:' /etc/nsswitch.conf; then
|
|
|
+ sed -i -E 's/^hosts:.*/hosts: files dns mdns4_minimal/' /etc/nsswitch.conf
|
|
|
+ else
|
|
|
+ echo 'hosts: files dns mdns4_minimal' >> /etc/nsswitch.conf
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Set DNS persistently
|
|
|
+# =========================
|
|
|
+set_dns_persistent() {
|
|
|
+ info "Setze DNS persistent auf ${AD_DNS_IP}..."
|
|
|
+
|
|
|
+ # 1) NetworkManager: DNS fest in Verbindung setzen
|
|
|
+ if systemctl is-active --quiet NetworkManager && have_cmd nmcli; then
|
|
|
+ info "NetworkManager aktiv -> setze DNS via nmcli (persistent)"
|
|
|
+ # aktive Verbindung ermitteln
|
|
|
+ local con
|
|
|
+ con="$(nmcli -t -f NAME,DEVICE con show --active | head -n1 | cut -d: -f1 || true)"
|
|
|
+ if [[ -n "${con}" ]]; then
|
|
|
+ nmcli con mod "${con}" ipv4.ignore-auto-dns yes
|
|
|
+ nmcli con mod "${con}" ipv4.dns "${AD_DNS_IP}"
|
|
|
+ nmcli con mod "${con}" ipv4.dns-search "${DOMAIN}"
|
|
|
+ nmcli con up "${con}" >/dev/null
|
|
|
+ return 0
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+
|
|
|
+ # 2) systemd-resolved: DNS auf Interface setzen (nicht immer persistent, aber oft)
|
|
|
+ if systemctl is-active --quiet systemd-resolved && have_cmd resolvectl; then
|
|
|
+ info "systemd-resolved aktiv -> setze DNS via resolvectl"
|
|
|
+ local iface
|
|
|
+ iface="$(ip -o route show default | awk '{print $5}' | head -n1)"
|
|
|
+ [[ -n "${iface}" ]] || fail "Konnte Default-Interface nicht ermitteln."
|
|
|
+ resolvectl dns "${iface}" "${AD_DNS_IP}"
|
|
|
+ resolvectl domain "${iface}" "~${DOMAIN}"
|
|
|
+ return 0
|
|
|
+ fi
|
|
|
+
|
|
|
+ # 3) Fallback: /etc/resolv.conf (kann überschrieben werden, aber besser als nichts)
|
|
|
+ info "Fallback -> schreibe /etc/resolv.conf (kann überschrieben werden)"
|
|
|
+ backup_file /etc/resolv.conf
|
|
|
+ cat >/etc/resolv.conf <<EOF
|
|
|
+search ${DOMAIN}
|
|
|
+nameserver ${AD_DNS_IP}
|
|
|
+EOF
|
|
|
+}
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Kerberos: rdns=false
|
|
|
+# =========================
|
|
|
+set_krb5_options() {
|
|
|
+ if [[ "${SET_KRB5_RDNS_FALSE}" != "true" ]]; then
|
|
|
+ return 0
|
|
|
+ fi
|
|
|
+
|
|
|
+ info "Setze Kerberos rdns=false in /etc/krb5.conf..."
|
|
|
+ backup_file /etc/krb5.conf
|
|
|
+
|
|
|
+ # Wenn libdefaults existiert, rdns setzen/ersetzen, sonst block hinzufügen
|
|
|
+ if grep -q '^\s*\[libdefaults\]' /etc/krb5.conf; then
|
|
|
+ if grep -q '^\s*rdns\s*=' /etc/krb5.conf; then
|
|
|
+ sed -i -E 's/^\s*rdns\s*=.*/ rdns = false/' /etc/krb5.conf
|
|
|
+ else
|
|
|
+ # rdns nach libdefaults einfügen
|
|
|
+ awk '
|
|
|
+ BEGIN{done=0}
|
|
|
+ /^\s*\[libdefaults\]\s*$/{
|
|
|
+ print
|
|
|
+ if(!done){print " rdns = false"; done=1}
|
|
|
+ next
|
|
|
+ }
|
|
|
+ {print}
|
|
|
+ ' /etc/krb5.conf > /tmp/krb5.conf.new && mv /tmp/krb5.conf.new /etc/krb5.conf
|
|
|
+ fi
|
|
|
+ else
|
|
|
+ cat >>/etc/krb5.conf <<EOF
|
|
|
+
|
|
|
+[libdefaults]
|
|
|
+ rdns = false
|
|
|
+EOF
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Preflight checks
|
|
|
+# =========================
|
|
|
+preflight() {
|
|
|
+ info "Prüfe Zeit (Kerberos ist zeitkritisch)..."
|
|
|
+ timedatectl status | sed -n '1,12p' || true
|
|
|
+
|
|
|
+ info "Prüfe DNS-Auflösung (_ldap SRV)..."
|
|
|
+ dig +short _ldap._tcp."${DOMAIN}" SRV | head -n5 || true
|
|
|
+
|
|
|
+ info "Prüfe DC Hostname (optional)..."
|
|
|
+ dig +short "${DC_HOST}" A || true
|
|
|
+
|
|
|
+ info "Realm discovery..."
|
|
|
+ realm discover "${DOMAIN}" || true
|
|
|
+
|
|
|
+ info "Kerberos Test (kinit) mit ${ADMIN_USER}..."
|
|
|
+ # kinit braucht Passwort -> interaktiv
|
|
|
+ # Wichtig: kinit muss funktionieren, sonst Join sinnlos
|
|
|
+ if ! kinit "${ADMIN_USER}"; then
|
|
|
+ fail "kinit fehlgeschlagen. Prüfe DNS/Zeit/Realm. (Ticket kommt nicht.)"
|
|
|
+ fi
|
|
|
+
|
|
|
+ info "klist (Ticket vorhanden?)"
|
|
|
+ klist || true
|
|
|
+}
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Join domain
|
|
|
+# =========================
|
|
|
+join_domain() {
|
|
|
+ info "Domain-Join: ${DOMAIN} (Realm: ${REALM})..."
|
|
|
+ # leave nur best-effort
|
|
|
+ realm leave "${DOMAIN}" >/dev/null 2>&1 || true
|
|
|
+
|
|
|
+ if [[ -n "${COMPUTER_OU}" ]]; then
|
|
|
+ realm join "${DOMAIN}" -U "${ADMIN_USER}" --computer-ou="${COMPUTER_OU}" --verbose
|
|
|
+ else
|
|
|
+ realm join "${DOMAIN}" -U "${ADMIN_USER}" --verbose
|
|
|
+ fi
|
|
|
+
|
|
|
+ info "Aktiviere mkhomedir..."
|
|
|
+ pam-auth-update --enable mkhomedir || true
|
|
|
+
|
|
|
+ info "Starte SSSD neu..."
|
|
|
+ systemctl restart sssd || true
|
|
|
+
|
|
|
+ info "realm list:"
|
|
|
+ realm list || true
|
|
|
+
|
|
|
+ info "Test Benutzerauflösung:"
|
|
|
+ if [[ -n "${TEST_USER}" ]]; then
|
|
|
+ getent passwd "${TEST_USER}@${DOMAIN}" || true
|
|
|
+ id "${TEST_USER}@${DOMAIN}" || true
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+# =========================
|
|
|
+# Main
|
|
|
+# =========================
|
|
|
+require_root
|
|
|
+install_packages
|
|
|
+disable_mdns
|
|
|
+set_dns_persistent
|
|
|
+set_krb5_options
|
|
|
+preflight
|
|
|
+join_domain
|
|
|
+
|
|
|
+info "FERTIG ✅"
|
|
|
+echo "Login-Format: user@${DOMAIN}"
|
|
|
+echo "Tipp: Teste Login: su - ${TEST_USER}@${DOMAIN}"
|