join_unix_ad.local 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. # =========================
  4. # Konfiguration (ANPASSEN!)
  5. # =========================
  6. DOMAIN="DOMAIN.local"
  7. REALM="DOMAIN.LOCAL" # i.d.R. DOMAIN in GROSS
  8. AD_DNS_IP="192.168.178.3" # Synology AD/DNS IP
  9. DC_HOST="nas.DOMAIN.local" # optional für Tests
  10. ADMIN_USER="Administrator@DOMAIN.LOCAL"
  11. # Optional: Test-User (nur für getent/id Test nach Join)
  12. TEST_USER="TESTUSER"
  13. # Optional: Computer OU (leer lassen wenn nicht benötigt)
  14. COMPUTER_OU=""
  15. # Verhalten
  16. FORCE_NO_MDNS=true # hosts: files dns (empfohlen bei .local)
  17. DISABLE_AVAHI=true # avahi-daemon stoppen/deaktivieren
  18. SET_KRB5_RDNS_FALSE=true # rdns = false setzen (sehr empfehlenswert)
  19. # =========================
  20. # Helper
  21. # =========================
  22. require_root() {
  23. if [[ "${EUID}" -ne 0 ]]; then
  24. echo "Bitte als root ausführen: sudo $0"
  25. exit 1
  26. fi
  27. }
  28. backup_file() {
  29. local f="$1"
  30. if [[ -f "$f" ]]; then
  31. cp -a "$f" "${f}.bak.$(date +%Y%m%d%H%M%S)"
  32. fi
  33. }
  34. have_cmd() { command -v "$1" >/dev/null 2>&1; }
  35. fail() {
  36. echo "FEHLER: $*" >&2
  37. exit 1
  38. }
  39. info() { echo "==> $*"; }
  40. # =========================
  41. # Install packages (Debian/Ubuntu)
  42. # =========================
  43. install_packages() {
  44. info "Installiere benötigte Pakete..."
  45. export DEBIAN_FRONTEND=noninteractive
  46. apt-get update -y
  47. apt-get install -y \
  48. realmd sssd sssd-tools libnss-sss libpam-sss adcli \
  49. krb5-user packagekit samba-common-bin oddjob oddjob-mkhomedir \
  50. dnsutils network-manager
  51. }
  52. # =========================
  53. # Disable Avahi/mDNS
  54. # =========================
  55. disable_mdns() {
  56. if [[ "${DISABLE_AVAHI}" == "true" ]] && systemctl list-unit-files | grep -q '^avahi-daemon\.service'; then
  57. info "Stoppe/Deaktiviere avahi-daemon (mDNS/.local)..."
  58. systemctl stop avahi-daemon || true
  59. systemctl disable avahi-daemon || true
  60. fi
  61. if [[ "${FORCE_NO_MDNS}" == "true" ]]; then
  62. info "Erzwinge hosts: files dns (mdns raus) in /etc/nsswitch.conf..."
  63. backup_file /etc/nsswitch.conf
  64. if grep -q '^hosts:' /etc/nsswitch.conf; then
  65. # setze hosts-Zeile hart auf "files dns"
  66. sed -i -E 's/^hosts:.*/hosts: files dns/' /etc/nsswitch.conf
  67. else
  68. echo 'hosts: files dns' >> /etc/nsswitch.conf
  69. fi
  70. else
  71. info "Setze nur dns vor mdns in /etc/nsswitch.conf..."
  72. backup_file /etc/nsswitch.conf
  73. # Best-effort: files dns mdns4_minimal
  74. if grep -q '^hosts:' /etc/nsswitch.conf; then
  75. sed -i -E 's/^hosts:.*/hosts: files dns mdns4_minimal/' /etc/nsswitch.conf
  76. else
  77. echo 'hosts: files dns mdns4_minimal' >> /etc/nsswitch.conf
  78. fi
  79. fi
  80. }
  81. # =========================
  82. # Set DNS persistently
  83. # =========================
  84. set_dns_persistent() {
  85. info "Setze DNS persistent auf ${AD_DNS_IP}..."
  86. # 1) NetworkManager: DNS fest in Verbindung setzen
  87. if systemctl is-active --quiet NetworkManager && have_cmd nmcli; then
  88. info "NetworkManager aktiv -> setze DNS via nmcli (persistent)"
  89. # aktive Verbindung ermitteln
  90. local con
  91. con="$(nmcli -t -f NAME,DEVICE con show --active | head -n1 | cut -d: -f1 || true)"
  92. if [[ -n "${con}" ]]; then
  93. nmcli con mod "${con}" ipv4.ignore-auto-dns yes
  94. nmcli con mod "${con}" ipv4.dns "${AD_DNS_IP}"
  95. nmcli con mod "${con}" ipv4.dns-search "${DOMAIN}"
  96. nmcli con up "${con}" >/dev/null
  97. return 0
  98. fi
  99. fi
  100. # 2) systemd-resolved: DNS auf Interface setzen (nicht immer persistent, aber oft)
  101. if systemctl is-active --quiet systemd-resolved && have_cmd resolvectl; then
  102. info "systemd-resolved aktiv -> setze DNS via resolvectl"
  103. local iface
  104. iface="$(ip -o route show default | awk '{print $5}' | head -n1)"
  105. [[ -n "${iface}" ]] || fail "Konnte Default-Interface nicht ermitteln."
  106. resolvectl dns "${iface}" "${AD_DNS_IP}"
  107. resolvectl domain "${iface}" "~${DOMAIN}"
  108. return 0
  109. fi
  110. # 3) Fallback: /etc/resolv.conf (kann überschrieben werden, aber besser als nichts)
  111. info "Fallback -> schreibe /etc/resolv.conf (kann überschrieben werden)"
  112. backup_file /etc/resolv.conf
  113. cat >/etc/resolv.conf <<EOF
  114. search ${DOMAIN}
  115. nameserver ${AD_DNS_IP}
  116. EOF
  117. }
  118. # =========================
  119. # Kerberos: rdns=false
  120. # =========================
  121. set_krb5_options() {
  122. if [[ "${SET_KRB5_RDNS_FALSE}" != "true" ]]; then
  123. return 0
  124. fi
  125. info "Setze Kerberos rdns=false in /etc/krb5.conf..."
  126. backup_file /etc/krb5.conf
  127. # Wenn libdefaults existiert, rdns setzen/ersetzen, sonst block hinzufügen
  128. if grep -q '^\s*\[libdefaults\]' /etc/krb5.conf; then
  129. if grep -q '^\s*rdns\s*=' /etc/krb5.conf; then
  130. sed -i -E 's/^\s*rdns\s*=.*/ rdns = false/' /etc/krb5.conf
  131. else
  132. # rdns nach libdefaults einfügen
  133. awk '
  134. BEGIN{done=0}
  135. /^\s*\[libdefaults\]\s*$/{
  136. print
  137. if(!done){print " rdns = false"; done=1}
  138. next
  139. }
  140. {print}
  141. ' /etc/krb5.conf > /tmp/krb5.conf.new && mv /tmp/krb5.conf.new /etc/krb5.conf
  142. fi
  143. else
  144. cat >>/etc/krb5.conf <<EOF
  145. [libdefaults]
  146. rdns = false
  147. EOF
  148. fi
  149. }
  150. # =========================
  151. # Preflight checks
  152. # =========================
  153. preflight() {
  154. info "Prüfe Zeit (Kerberos ist zeitkritisch)..."
  155. timedatectl status | sed -n '1,12p' || true
  156. info "Prüfe DNS-Auflösung (_ldap SRV)..."
  157. dig +short _ldap._tcp."${DOMAIN}" SRV | head -n5 || true
  158. info "Prüfe DC Hostname (optional)..."
  159. dig +short "${DC_HOST}" A || true
  160. info "Realm discovery..."
  161. realm discover "${DOMAIN}" || true
  162. info "Kerberos Test (kinit) mit ${ADMIN_USER}..."
  163. # kinit braucht Passwort -> interaktiv
  164. # Wichtig: kinit muss funktionieren, sonst Join sinnlos
  165. if ! kinit "${ADMIN_USER}"; then
  166. fail "kinit fehlgeschlagen. Prüfe DNS/Zeit/Realm. (Ticket kommt nicht.)"
  167. fi
  168. info "klist (Ticket vorhanden?)"
  169. klist || true
  170. }
  171. # =========================
  172. # Join domain
  173. # =========================
  174. join_domain() {
  175. info "Domain-Join: ${DOMAIN} (Realm: ${REALM})..."
  176. # leave nur best-effort
  177. realm leave "${DOMAIN}" >/dev/null 2>&1 || true
  178. if [[ -n "${COMPUTER_OU}" ]]; then
  179. realm join "${DOMAIN}" -U "${ADMIN_USER}" --computer-ou="${COMPUTER_OU}" --verbose
  180. else
  181. realm join "${DOMAIN}" -U "${ADMIN_USER}" --verbose
  182. fi
  183. info "Aktiviere mkhomedir..."
  184. pam-auth-update --enable mkhomedir || true
  185. info "Starte SSSD neu..."
  186. systemctl restart sssd || true
  187. info "realm list:"
  188. realm list || true
  189. info "Test Benutzerauflösung:"
  190. if [[ -n "${TEST_USER}" ]]; then
  191. getent passwd "${TEST_USER}@${DOMAIN}" || true
  192. id "${TEST_USER}@${DOMAIN}" || true
  193. fi
  194. }
  195. # =========================
  196. # Main
  197. # =========================
  198. require_root
  199. install_packages
  200. disable_mdns
  201. set_dns_persistent
  202. set_krb5_options
  203. preflight
  204. join_domain
  205. info "FERTIG ✅"
  206. echo "Login-Format: user@${DOMAIN}"
  207. echo "Tipp: Teste Login: su - ${TEST_USER}@${DOMAIN}"