1198.book Seite 1 Donnerstag, 5. Februar 2009 3:02 15
Oliver Liebel, John Martin Ungar
OpenLDAP 2.4 Das Praxisbuch
1198.book Seite 2 Donnerstag, 5. Februar 2009 3:02 15
Liebe Leserin, lieber Leser, LDAP und die freie Implementierung OpenLDAP gehören zum Alltag fast aller Administratoren. Um den Verzeichnisdienst zu verstehen und OpenLDAP effektiv einzusetzen, es richtig zu konfigurieren und alle Elemente und Funktionen professionell nutzen zu können, ist einiges an Wissen nötig. Dieses Buch erklärt beides. In einer kurzen Einführung erfahren Sie zunächst, was Sie über LDAP und seine Historie wissen sollten. Danach wird der praktische Einsatz von OpenLDAP gezeigt, ausführlich und gespickt mit den Real-Life-Erfahrungen der Autoren. Oliver Liebel und John Martin Ungar haben nicht nur diese Erfahrung, Sie schaffen es auch, sie in einer verständlichen Sprache zu vermitteln. Für alle Administratoren bietet dieses Buch einen unschlagbaren Nutzwert. Es wurde mit großer Sorgfalt geschrieben, lektoriert und produziert. Sollte dennoch etwas nicht so funktionieren, wie Sie es erwarten, dann scheuen Sie sich nicht, sich mit mir in Verbindung zu setzen. Ihre Anregungen und Fragen sind jederzeit willkommen. Viel Vergnügen beim Lesen wünscht Ihnen
Jan Watermann Lektorat Galileo Computing
[email protected] www.galileocomputing.de Galileo Press · Rheinwerkallee 4 · 53227 Bonn
1198.book Seite 3 Donnerstag, 5. Februar 2009 3:02 15
Auf einen Blick 1
Vorab: Was man wissen sollte ...........................................
17
2
OpenLDAP installieren und betreiben ................................
49
3
OpenLDAP im Einsatz .........................................................
115
4
OpenLDAP und Applikationen ...........................................
375
A
Paketlisten ..........................................................................
521
B
Kompilationsoptionen ........................................................
529
C
RFCs, Drafts und LDAPv3-Core-Spezifikationen ................
533
D
Manpages nach Sektionen und Glossar .............................
545
1198.book Seite 4 Donnerstag, 5. Februar 2009 3:02 15
Der Name Galileo Press geht auf den italienischen Mathematiker und Philosophen Galileo Galilei (1564–1642) zurück. Er gilt als Gründungsfigur der neuzeitlichen Wissenschaft und wurde berühmt als Verfechter des modernen, heliozentrischen Weltbilds. Legendär ist sein Ausspruch Eppur se muove (Und sie bewegt sich doch). Das Emblem von Galileo Press ist der Jupiter, umkreist von den vier Galileischen Monden. Galilei entdeckte die nach ihm benannten Monde 1610. Gerne stehen wir Ihnen mit Rat und Tat zur Seite:
[email protected] bei Fragen und Anmerkungen zum Inhalt des Buches
[email protected] für versandkostenfreie Bestellungen und Reklamationen
[email protected] für Rezensions- und Schulungsexemplare Lektorat Jan Watermann Korrektorat Manfred von Sommer, München Typografie und Layout Vera Brauner Einbandgestaltung Barbara Thoben, Köln Herstellung Lissy Hamann Satz III-satz, Husby Druck und Bindung Bercker Graphischer Betrieb, Kevelaer Dieses Buch wurde gesetzt aus der Linotype Syntax Serif (9,25/13,25 pt) in FrameMaker. Gedruckt wurde es auf chlorfrei gebleichtem Offsetpapier.
Bibliografische Information der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar. ISBN
978-3-8362-1198-7
© Galileo Press, Bonn 2009 1. Auflage 2009
Das vorliegende Werk ist in all seinen Teilen urheberrechtlich geschützt. Alle Rechte vorbehalten, insbesondere das Recht der Übersetzung, des Vortrags, der Reproduktion, der Vervielfältigung auf fotomechanischem oder anderen Wegen und der Speicherung in elektronischen Medien. Ungeachtet der Sorgfalt, die auf die Erstellung von Text, Abbildungen und Programmen verwendet wurde, können weder Verlag noch Autor, Herausgeber oder Übersetzer für mögliche Fehler und deren Folgen eine juristische Verantwortung oder irgendeine Haftung übernehmen. Die in diesem Werk wiedergegebenen Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. können auch ohne besondere Kennzeichnung Marken sein und als solche den gesetzlichen Bestimmungen unterliegen.
1198.book Seite 5 Donnerstag, 5. Februar 2009 3:02 15
Inhalt Vorwort ....................................................................................................... 11 »Wer die Praxis übt, ohne sich vorher mit der Theorie beschäftigt zu haben, gleicht einem Steuermann, der sein Schiff ohne Kompass und Steuer besteigt und nun nicht weiß, wohin er fährt.« Leonardo da Vinci (1452–1519) 17
1
Vorab: Was man wissen sollte ............................................... 17 1.1
1.2 1.3 1.4 1.5 1.6 1.7
1.8
Eine kurze Geschichte des Internets ........................................... 1.1.1 Vom Bikini zum ARPAnet ............................................ 1.1.2 Pakete und Ströme ..................................................... Die Schweiz und die Wende ...................................................... Währenddessen … auf der anderen Seite der Stadt .................... X.500 und der OSI-Stack ........................................................... Struktur eines Verzeichnisdienstes ............................................. Objekte, Klassen, Attribute ........................................................ Nicht nach Schema F: die OpenLDAP-Schemas .......................... 1.7.1 core, cosine, inetOrgPerson, samba und einiges mehr ............................................................... 1.7.2 Die wichtigsten Schemas und ihre Funktion ................ 1.7.3 Eindeutige Identifikation mit OIDs .............................. 1.7.4 Erbschaftsangelegenheiten: die Welt der Objektklassen ............................................................. Kleine Baumschule – grundsätzliche Überlegungen zum Treedesign ......................................................................... 1.8.1 Den Directory Information Tree gestalten ................... 1.8.2 Sinnvolle Strukturen abbilden ..................................... 1.8.3 Anwendungsnähe .......................................................
17 17 18 20 22 23 24 31 35 36 39 40 41 45 46 47 48
Es gibt nur zwei Arten von Daten: gesicherte und unwichtige. 49
2
OpenLDAP installieren und betreiben ................................... 49 2.1
2.2
OpenLDAP-Basics ...................................................................... 2.1.1 Installation der Pakete ................................................ 2.1.2 Die Konfigurationsdateien .......................................... 2.1.3 Statische Betrachtungen: OpenLDAP-Konfiguration per slapd.conf ............................................................. 2.1.4 ldap.conf (Client) ........................................................ 2.1.5 /etc/ldap.conf (pam_ldap/nss_ldap) ............................ Irgendwie binär – die wichtigsten Binaries und Bibliotheken ...... 2.2.1 slapd ........................................................................... 2.2.2 slurpd (ACHTUNG: nur bis OpenLDAP 2.3!) ................ 2.2.3 libldap*(.so*) ...............................................................
49 49 52 54 63 65 67 67 68 69
5
1198.book Seite 6 Donnerstag, 5. Februar 2009 3:02 15
Inhalt
2.3
2.4
2.2.4 libnss-ldap(.so*) .......................................................... 2.2.5 pam_ldap(.so*) ............................................................ 2.2.6 »Gentlemen, start your engines …« ............................. Fingerübungen – OpenLDAP-Tools auf der Konsole ................... 2.3.1 Die ldap*-Tools ........................................................... 2.3.2 … und wann mit slap* ? .............................................. Get it on(line) – OpenLDAP-Administration zur Laufzeit ............ 2.4.1 OpenLDAP Reloaded – ‘database config’ und die Online-Konfiguration .................................................. 2.4.2 slapd – Online-Administration ................................... 2.4.3 Backup und Restore der Online-Konfiguration, Debugging ..................................................................
69 70 70 71 76 93 98 99 108 112
Nachdem wir die wichtigsten Grundlagen kennengelernt haben, schauen wir uns OpenLDAP nun im praktischen Einsatz an. 115
3
OpenLDAP im Einsatz ............................................................ 115 3.1
3.2
6
Völlig überlagert – Overlays in OpenLDAP ................................. 116 3.1.1 Gruppentherapie – dynamische Gruppen mit Overlay dynlist ............................................................ 119 3.1.2 Smile, you’re on Radar! – Auditing mit Overlay accesslog ........................................................ 124 3.1.3 Beziehungskrise – Sicherung der referentiellen Integrität mit Overlay refint ........................................ 128 3.1.4 Members Only – Gruppenzuordnung mit Overlay »memberOf« ............................................................... 130 3.1.5 Hochdynamisch – Dynamic Directory Services mit Overlay »dds« ....................................................... 136 3.1.6 ... und noch ein paar Overlays im Überblick ................ 141 3.1.7 And the Rest? ............................................................. 143 Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann. ...................................................................... 143 3.2.1 Warum man LDAP-Datenbanken replizieren sollte....... 143 3.2.2 Lastverteilung/Partitionierung ..................................... 151 3.2.3 Gesprengte Ketten – serverseitige Verfolgung (chasing) von Referrals mit Overlay chain .................... 159 3.2.4 The Time Machine – Zeit synchronisieren mit NTPD .... 165 3.2.5 Vorbereitungen und Vorbetrachtungen zur Replikation ................................................................. 172 3.2.6 Synchronization without Frustration = Sync Replication ......................................................... 176 3.2.7 syncrepl – Setup ........................................................ 185 3.2.8 Beispielhafte Lösungsansätze mit syncrepl ................... 193
1198.book Seite 7 Donnerstag, 5. Februar 2009 3:02 15
Inhalt
3.2.9
3.3 3.4
3.5
3.6
3.7
Delta Force – Replikation in Perfektion mit delta-syncrepl ............................................................. 3.2.10 Replikation der Online-Konfiguration – Provider/Consumer ..................................................... 3.2.11 Bäumchen, wechsle dich: Standby-/ Multi-Master-Replikation ............................................ 3.2.12 Double trouble? N-Way/Multi-Master-Replikation ..... 3.2.13 Traumhafte Nachtruhe dank Schläfer – Hot-Failover mit Standby-Master und Heartbeat .......... Feind hört mit: Verschlüsselte Übertragung ............................... OpenLDAP mit SSL und TLS ...................................................... 3.4.1 Familienbande - SSL und TLS ...................................... 3.4.2 636 – die alte Hausnummer ........................................ 3.4.3 Cyrus-SASL und seine SASLMechs – eine bunte Truppe ...................................................... 3.4.4 Ja siiiisscher dat: – TLS-Konfiguration mit SASLMech EXTERNAL ................................................. 3.4.5 Eine Frage der Zertifizierung – X.509-Zertifikate per Skript .................................................................... 3.4.6 Port 636, die Zweite ................................................... 3.4.7 Handmade – X.509-Zertifikate in Handarbeit ............. Replikation und Chaining auf Nummer Sicher ............................ 3.5.1 syncrepl mit TLS .......................................................... 3.5.2 syncrepl mit TLS und SASLMech EXTERNAL ................ 3.5.3 syncrepl mit SSL .......................................................... 3.5.4 Chaining mit TLS und SSL ............................................ 3.5.5 ... und dann war da ja noch die Sache mit den Zertifikaten im Failover-Fall ......................................... Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP ................................... 3.6.1 Nicht nur in Malibu Beach: PAM ................................. 3.6.2 PAM, NSS und LDAP .................................................. 3.6.3 pam_ldap .................................................................... 3.6.4 (lib)nss_ldap ................................................................ 3.6.5 nscd ............................................................................ 3.6.6 Authentifikation am System mit aktiviertem TLS .......... 3.6.7 Debugging .................................................................. Nur mit Clubkarte – Zugriffsregelung durch ACLs ....................... 3.7.1 Wer ist hier der Boss? – ACL-Reihenfolge .................... 3.7.2 <Was> (access to) .......................................................
196 202 213 216 220 232 241 241 242 243 246 248 260 263 268 269 273 275 275 277 279 279 285 286 286 288 289 290 291 293 296
7
1198.book Seite 8 Donnerstag, 5. Februar 2009 3:02 15
Inhalt
3.8
3.9
3.7.3 <Wer> (by) ................................................................. 3.7.4 <Wie> – und mit welchen Rechten? .......................... 3.7.5 Und was es sonst noch gibt ... ..................................... Larry und die schläfrigen Katzen ................................................ 3.8.1 Die »Was«-Frage ......................................................... 3.8.2 Kommen wir zum »Wie« ............................................. 3.8.3 Und nun zum »Warum« .............................................. 3.8.4 Ein Blick aufs Messgerät: Performance-Check............... 3.8.5 Feintuning .................................................................. 3.8.6 Ab auf den Index ........................................................ 3.8.7 Built for Speed – Zahlen und Fakten ............................ 3.8.8 Die Sache mit dem Backup ... ..................................... 3.8.9 Und zum Schluss ein bisschen Replikation ... schon wieder? ............................................................. Selbst ist der Admin – das eigendefinierte Schema ..................... 3.9.1 Attribute ..................................................................... 3.9.2 Attribut-Syntax und Matching Rules ........................... 3.9.3 Objektklassen ............................................................. 3.9.4 Geht nicht – gibt’s nicht ... .......................................... 3.9.5 OID-Makros ............................................................... 3.9.6 Rein Schematisch – Replikation der Schemas...............
302 312 319 321 323 325 328 333 337 348 351 353 354 355 357 358 363 365 368 369
Bug for bug, feature for feature, we will implement the SMB(CIFS) protocol. Jeremy Allison, SambaXP 2006 375
4
OpenLDAP und Applikationen ............................................... 375 4.1
4.2 4.3
8
Die Meister der Domäne: OpenLDAP und Samba ..................... 4.1.1 Die wunderbare Welt der MS-Protokolle .................... 4.1.2 Samba 3 mit OpenLDAP einsetzen .............................. 4.1.3 Grundlegendes Setup: ldapmaster als PDC .................. 4.1.4 Tools zur User-Verwaltung .......................................... 4.1.5 Redundantes Setup: ldapslave als BDC ........................ 4.1.6 The new Dance – Samba 4 und OpenLDAP................ 4.1.7 Setup eines Standalone Samba 4 DC mit OpenLDAP-Backend ................................................... 4.1.8 Staffelflug: Zwei Samba 4-DCs mit OpenLDAP in Multi-Master-Replikation ........................................ Für die Furchtlosen: OpenLDAP und Kerberos ........................... Setup von Kerberos V5 .............................................................. 4.3.1 Was diese Frau so alles treibt: Schon wieder PAM … ... 4.3.2 SASL, die Zweite: GSSAPI ............................................
375 375 379 380 384 395 400 402 409 412 417 423 425
1198.book Seite 9 Donnerstag, 5. Februar 2009 3:02 15
Inhalt
4.3.3
4.4
4.5
4.6
4.7
4.8
Bullet-Proof: OpenLDAP-Replikation per syncrepl, TLS und Kerberos ....................................................... 4.3.4 Der Hund im Baum – MIT-Kerberos-Datenbank im LDAP ..................................................................... 4.3.5 Kurz und gut: XP-Client an kerberisierter Samba-Domäne .......................................................... Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail ....................................................................................... 4.4.1 Setup der Postfix-Dateien main.cf/ldap-aliases.cf ........ 4.4.2 Adress-Umsetzung per LDAP ...................................... 4.4.3 Gruppentherapie für Postboten ................................... 4.4.4 Der unsichtbare Dritte: Postfix, TLS und saslauthd ....... 4.4.5 Setup der Mailclients für LDAP und TLS ...................... Cyrus-IMAP ............................................................................... 4.5.1 Setup .......................................................................... 4.5.2 Clients ........................................................................ 4.5.3 Geklonter Briefkasten – replizierte Cyrus-IMAP-Mailboxen ............................................... Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP ............................................. 4.6.1 Apache und OpenLDAP .............................................. 4.6.2 Squid – Zugriffe auf den Proxy über OpenLDAP kontrollieren ............................................................... Auf den Schirm! – Grafische Frontends zur OpenLDAPAdministration ........................................................................... 4.7.1 Kein kalter Kaffee – JXplorer ....................................... 4.7.2 Indianerland – Apache Directory Studio .................... 4.7.3 … und noch ein paar LDAP-Browser/-Tools ................ Ein kurzes Wort zu LDAP in eigenen Applikationen ...................
429 433 443 446 447 451 453 454 467 472 473 477 478 481 481 497 509 509 513 516 518
519
Anhang ...................................................................................... 519 A B C
Paketlisten ........................................................................................... Kompilationsoptionen .......................................................................... RFCs, Drafts und LDAPv3-Core-Spezifikationen .................................................... C.1 RFCs .......................................................................................... C.1.1 LDAP .......................................................................... C.1.2 SASL ........................................................................... C.1.3 TLS ............................................................................. C.1.4 KERBEROS ..................................................................
521 529 533 533 533 538 538 540
9
1198.book Seite 10 Donnerstag, 5. Februar 2009 3:02 15
Inhalt
C.2 C.3
LDAP-Drafts (Auszüge) .............................................................. 541 LDAPv3 Core – Specifications .................................................... 542
545
D
Manpages nach Sektionen und Glossar ................................. 545 D.1 D.2 D.3 D.4 D.5 D.6 D.7 D.8 D.9 D.10 D.11 D.12
OpenLDAP ................................................................................ PAM/NSS .................................................................................. OpenSSL .................................................................................... SASL .......................................................................................... Samba ....................................................................................... Heartbeat .................................................................................. MIT-Kerberos ............................................................................ Postfix ....................................................................................... Cyrus-Imap ................................................................................ Apache ...................................................................................... Squid ......................................................................................... Glossar ......................................................................................
545 547 548 548 549 550 550 551 553 553 554 554
Index ........................................................................................................... 557
10
1198.book Seite 11 Donnerstag, 5. Februar 2009 3:02 15
Vorwort Okay, ich könnte an dieser Stelle ellenlang über die technischen Details und Neuerungen der aktuellen OpenLDAP-Version lamentieren, die für mich natürlich allesamt Gründe waren, warum wir zu Wiederholungstätern wurden, oder, im moralischen Imperativ weitaus treffender ausgedrückt: werden mussten. Warum wir nach »nur« knapp drei Jahren eine Neuauflage unseres OpenLDAP-Buches herausbringen. Und das, obwohl sich die Minor-Number gerade mal um einen kleinen Zähler nach oben bewegt hat. Aber: Hinter der kleinen Nummer ».4« stecken ziemlich große und kernige Neuerungen. Nur würde mir – und vor allem Ihnen – ein stures, ausführliches Herunterbeten dieser neuen Features, Parameter und technischen Details an dieser Stelle herzlich wenig bringen. Sie als Leser würden dann wahrscheinlich nur diese ganz spezielle Müdigkeit verspüren, die vorrangig uns Männer beim Lesen trockener Gebrauchsinformationen ohne den gleichzeitigen Einsatz von zugehörigen Werkzeugen nur allzu oft überfällt. Deswegen fasse ich das Warum an dieser Stelle in drei Punkten zusammen: Punkt 1: Geht das? Ja – jetzt geht’s. Denn OpenLDAP 2.4 bringt neben jeder Menge anderer, wichtiger Innovationen eine der wichtigsten Neuerungen überhaupt mit: die brandneue Standby-/MultiMaster-Replikation. Failsafe-Mechanismus und Grundvoraussetzung für einen redundanten, jederzeit unterbrechungsfreien und ausfallsicheren Betrieb. Außerdem ein wichtiges Kernstück für das in den Startlöchern stehende Samba 4Release, ohne das ein Setup von redundanten Domain-Controllern auf OpenLDAP-Basis überhaupt nicht realisierbar wäre. Aus unserer langjährigen Erfahrung im Administrations-, Consulting- und Trainingsumfeld wissen wir, dass nahezu alle Admins – egal, ob es sich um mittelständische Firmen aller Größenordnungen, Banken, Internet-Provider, Hochschulen und immer öfter auch staatliche Institutionen handelt – schon lange auf dieses Feature warten. Denn hierdurch kann – erstmalig in der Geschichte von OpenLDAP – Hochverfügbarkeit auf Applikationsebene implementiert und sichergestellt werden. Diese neue und beileibe nicht triviale Konfiguration, die logischerweise eine extensive Konfiguration (und Replikation) der nun weitaus leistungsfähigeren Online-Konfiguration beinhaltet, nimmt einen großen Teil dieser überarbeiteten und deutlich erweiterten Neuauflage in Anspruch; so, wie auch die Overlays, die in den letzten drei Jahren mächtig interessanten Zuwachs bekommen haben.
11
1198.book Seite 12 Donnerstag, 5. Februar 2009 3:02 15
Vorwort
Auch Applikationen wie Samba, Kerberos, Squid und Postfix sind erwachsener geworden, und mit ihrem Reifungsprozess haben sich natürlich auch die Verfahren zur Anbindung an OpenLDAP als Single Point of Administration zum Teil komplett geändert. Mir ging es nicht darum, ein »funktionierendes« Buch mit ein paar kleinen Patches »mal eben« schnell auf den neuesten Stand zu bringen. OpenLDAP hat in den letzten Jahren einige interessante neue Kunststücke gelernt, so wie auch wir uns tiefer in seine ganz spezielle und für Neulinge oft nicht leicht verständliche Art der Kommunikation eingearbeitet haben. Unsere Kernprämisse war und ist, dieses Buch genauso schlüssig und praxisorientiert wie seine Vorgänger zu gestalten. Eine komplette Überarbeitung war daher unumgänglich. Die Kenner der Vorgängerversion werden natürlich einige Kapitel, die zum grundlegenden Verständnis von OpenLDAP notwendig sind, wiedererkennen, so wie zum Beispiel die einleitenden Kapitel über die Entstehung von LDAP, Kommandozeilentools, Binaries und Schemas sowie die Grundlagen der Verschlüsselung, in denen auch wir das Rad nicht komplett neu erfinden können. Aber auch diese Kapitel haben wir so sorgfältig wie möglich überarbeitet, verbessert, neu strukturiert und von Fehlern bereinigt, die uns von engagierten Lesern mitgeteilt wurden. An dieser Stelle noch einmal herzlichen Dank dafür! Punkt 2: Build for Speed Ein weiteres Warum ist für mich die Rolle, die OpenLDAP mittlerweile in der Hierarchie der Verzeichnisdienste spielt. Schon lange muss sich das OpenSource-Flaggschiff im Verzeichnisdienst-Bereich nicht mehr hinter proprietären Verzeichnisdiensten wie zum Beispiel Microsofts ADS (Active Directory) oder Novells eDirectory verstecken – im Gegenteil. Die Zuwachsrate an Neuinstallationen oder Umstellungen von einem anderen Verzeichnisdienst auf OpenLDAP war nie so hoch wie jetzt. Und noch eine andere Sache ist für seine Konkurrenz, kommerzielle wie Open Source, längst in unerreichbare Höhen gerückt: die Performance, mit der OpenLDAP arbeitet. Ausführliche Benchmarks und Tests (von denen wir uns im Datenbank-Kapitel eingehend überzeugen werden) haben mehrfach klar unter Beweis gestellt, dass OpenLDAP im direkten Vergleich mit ADS, Novells eDirectory oder Redhats Fedora DS mehr als viermal so performant arbeitet und damit weltweit die Nase klar vorne hat. Anfang 2008 veröffentlichte Oracle ein Whitepaper, in dem Larry Ellisons Truppe stolz ihre Benchmarking-Ergebnisse für eine OID-Datenbank (Oracle Internet Directory) mit zwei Milliarden Einträgen auf einem System mit HighEnd-Hardware präsentierte. Oracle wähnte sich als Platzhirsch – getragen von der
12
1198.book Seite 13 Donnerstag, 5. Februar 2009 3:02 15
Vorwort
Euphorie, Novells damals etwa zwei Jahre alten »offiziellen« Benchmark-Rekord, bezogen auf etwa eine Milliarde Einträge im eDirectory, gebrochen zu haben. All das klang mit Sicherheit durchaus Ehrfurcht gebietend, aber die Jungs des OpenLDAP-Teams brachte das keineswegs um ihren Schlaf. Sie fragten sich nur, was denn eigentlich Larrys Truppe so dermaßen aus dem Häuschen brachte. Denn die »LDAP Guys«, wie sich unsere OpenLDAP-Jungs auch gerne nennen, hatten längst ohne großen Presserummel und sonstiges Trara einen Benchmark über fünf Milliarden Entries durchgeführt, und das mit deutlich besseren Latenzzeiten von weniger als einer Millisekunde pro Eintrag. Zum Vergleich: Alle anderen lagen im Bereich von mehreren Millisekunden pro Entry … Einer Performance, die die eben genannten, kommerziellen Anbieter dazu brachte, mit offenen Mündern zu stieren, ihre schamesroten Häupter abzuwenden und kleinlaut auf ein anderes Thema zu wechseln. Von den Jungs aus Redmond brauchen wir erst gar nicht zu reden, denn ihr ADS stellt das traurige Schlusslicht dar. Vielleicht wäre die Niederlage für sie alle etwas weniger schmerzhaft gewesen, wenn das OpenLDAP-Team mit adäquater Hardware gearbeitet hätte. Aber auch diesem Punkt wurden die Kommerzkönige enttäuscht, denn die LDAP Guys hatten die besseren Ergebnisse auf deutlich schlechterer und älterer Hardware erzielt. Und um das Ganze noch zu toppen: Die Benchmarks wurden mit einem OpenLDAP der Version 2.3 erzielt. Denn Version 2.4 legt performance-technisch noch ein paar Briketts mehr auf. Das einzige, was sich Howard Chu und der Rest seines OpenLDAP-Teams bezogen auf ihre Konkurrenten – gefragt hatten, war: »Was hält euch eigentlich so lange auf?« Allerdings sollte sich Larry Ellison nicht allzu schlecht fühlen, denn schließlich kann Oracle dank der Übernahme von Sleepycat (und damit der Berkeley DB) – eine Sache immer noch voller Stolz verkünden: Das der schnellste und skalierbarste Verzeichnisdienst der Welt »Powered by Oracle Technology« ist. Nur ist es nicht Oracles Internet Directory. Er war es in der Vergangenheit nicht, und ist es bis heute nicht. Nur einer trägt den Titel des weltweit schnellsten DS zu recht: OpenLDAP. Dabei gerät leider viel zu oft in Vergessenheit, das OpenLDAP-Server bereits seit vielen Jahren ihre Zuverlässigkeit in allen möglichen und unmöglichen Hardware-Umgebungen und -Einsatzbedingungen unter Beweis stellen. Howard Chu und seine Truppe haben – wieder einmal – ganze Arbeit geleistet und ein qualitativ nahezu perfektes Produkt noch weiter verbessert.
13
1198.book Seite 14 Donnerstag, 5. Februar 2009 3:02 15
Vorwort
Mein Dank gilt an dieser Stelle daher allen Mitgliedern des OpenLDAP-Teams, ihrem unermüdlichen Einsatz und ihrer Stringenz. Punkt 3: Freeze! In jeder OpenLDAP-Evolutionsstufe rufen die Mitglieder des Core-Teams – mal mehr, mal weniger offiziell – einen Feature-Freeze aus, ab dem sich primär nicht mehr um die Implementierung neuer Features gekümmert wird, sondern hauptsächlich um die sorgfältige Pflege und das Bugfixing des OpenLDAP- Daemons und seiner zahlreichen und umfangreich konfigurierbaren Helferlein – und das ist mit Release 2.4.11 geschehen. Eine frühere Veröffentlichung des Buches, um die ersten mit der »2.4« an der Ziellinie zu sein, wäre zwar nett gewesen, hätte uns aber nicht wirklich weiter gebracht. Durch den aktuellen Entwicklungsstand konnten wir uns auf konkrete Features beziehen, die im Detail noch gepflegt und gegebenenfalls optimiert und dokumentiert werden, und werkeln nicht an einer inoffiziellen Beta herum. Auch wenn eine OpenLDAP-Beta immer noch um Längen stabiler ist als die meisten, als »stable« gekennzeichneten Programme. Das bringt mich direkt zum nächsten Kernpunkt – der OpenLDAP-Dokumentation. Auch hier hat sich in den letzten Jahren einiges getan, im Verhältnis zum Entwicklungsstand ist jedoch vieles beim Alten geblieben. Gut, weil die Entwickler ihre Arbeit auf OpenLDAP selbst fokussieren, schlecht für die Anwender, weil Teile der Dokumentation dabei nach wie vor oft auf der Strecke bleiben. Aber: eine reine OpenLDAP-Dokumentation kann und muss nicht sämtliche Feinheiten der Anbindung an andere, zentrale Netzwerkservices erschlagen; ebenso, wie sie kaum alle praxisrelevanten Setup-Szenarien erfassen kann. Und hier setzen wir – wie beim letzten Mal – an. Vielen Interessierten wird durch eine – in anderen Publikationen zum Thema leider immer noch oft verbreitete – Philosophie »Wer wissen will, wie xyz funktioniert, sollte einen Blick in den Sourcecode der Datei ab.c werfen …« ein Einstieg in das Thema wenig schmackhaft gemacht, denn schließlich ist nicht jeder Admin zwangsläufig ein leidenschaftlicher C-Programmierer; zudem wird der Verbreitung dieses interessanten, leistungsfähigen und stabilen Produkts damit wenig Vorschub geleistet. Auch ein Blick in die Manpage eines Programms oder einer Konfigurationsdatei ist zwar oft hilfreich (und sollte auch stets als Erstes konsultiert werden), bringt aber in vielen Fällen – gerade wenn es um die Interaktion von OpenLDAP mit anderen Applikationen geht – oft nicht das erwünschte Resultat. RTFM hilft zwar nach wie vor meistens, aber eben nicht immer …
14
1198.book Seite 15 Donnerstag, 5. Februar 2009 3:02 15
Vorwort
Wir haben versucht, auch mit dieser Neuauflage einen einfachen Einstieg in OpenLDAP zu ermöglichen; und gleichfalls die Umsetzung komplexer und vor allem praxisorientierter Setup-Szenarien, sowie die Anbindungen an unverzichtbare Dienste möglichst transparent zu erläutern. Das Buch, das Sie nun in den Händen halten, dreht sich – wie sein Vorgänger – in erster Linie um den praxisorientierten Teil von OpenLDAP: die Installation und Konfiguration von OpenLDAP als zentralem Verzeichnisdienst in der IT-Landschaft eines Unternehmens. Angefangen beim grundlegenden Setup, den benötigten Paketen, über das Handling der Kommandozeilentools, die Einrichtung einer verschlüsselten Kommunikation zwischen Client und Server, dem Setup von praxistauglichen, hochverfügbaren und verschlüsselten Replikationsszenarien, bis hin zum Einsatz von OpenLDAP als zentraler Datenbank, die von Clients und Services wie Samba, Apache, Postfix, Cyrus-IMAP und Squid genutzt wird – und damit den administrativen Aufwand, im Gegensatz zur sonst üblichen dezentralen und multiplen Speicherung und Pflege von Benutzerdaten, deutlich herabsetzt. Das Ganze gehen wir wie üblich Schritt für Schritt anhand von praktischen Beispielen durch, und zwar exakt mit den von der Verlagsseite herunterladbaren Konfigurationsdateien (http://www.galileocomputing.de/1801), die auch auf unseren Testsystemen ihre Funktionalität unter Beweis gestellt haben. Aber schließlich sind auch wir nur Menschen und daher – eben so wie wir alle – sicherlich nicht perfekt. Sollten sich also Fehler in bestimmte Konfigurationen eingeschlichen haben, oder falls wir ein Detail übersehen haben sollten: Geben Sie uns ein kurzes Feedback, damit wir reagieren und eine fehlerbereinigte Version des entsprechenden Kontextes über die Website unseres Verlages zur Verfügung stellen können. Wie beim letzten Mal haben wir versucht, eine möglichst komplette Liste aller »Stolpersteine« und Debugging-Checkpunkte zu jedem Abschnitt und Themenbereich zusammenzustellen, und ich hoffe, dass wir auch dieses Mal den größten Teil der möglichen Fehlerquellen im praxisorientierten Anwendungsfall erschlagen konnten. Natürlich werden auch die theoretischen Grundlagen zum Verständnis der jeweiligen Thematiken an den relevanten Stellen erläutert. Nach dem positiven Feedback zur ersten Ausgabe, das mir gezeigt hat, das wir auf dem richtigen Weg sind, bestand ein weiterer wichtiger Aspekt natürlich wiederum darin, die teilweise staubtrockenen, theoretischen LDAP-Bereiche nicht ganz so trocken zu vermitteln. Ich hoffe, es ist auch dieses Mal gelungen. Apropos Theorie: Die dem OpenLDAP-Projekt zugrunde liegenden RFCs (hinsichtlich der verwendeten Standards und theoretischen Grundlagen des Projekts) sind fester Bestandteil eines jeden OpenLDAP-Softwarepakets und liegen den (von der Web-
15
1198.book Seite 16 Donnerstag, 5. Februar 2009 3:02 15
Vorwort
site des Verlages) herunterladbaren Beispieldateien bei. So sind alle BackgroundInformation bei Bedarf immer sofort greifbar. Die Anforderungs- und Themenliste, die diesem Buch zugrunde liegt, entstammt wiederum primär den Fragen, Themen und Problematiken, die uns im Rahmen von Consulting-Aufträgen, Praxis-Workshops und Schulungen von OpenLDAPAdministratoren genannt wurden. Gekoppelt an das Feedback der Leser in den letzten Jahren, hat all dies zusammen den aktuellen wie bewährten Kurs zwangsläufig vorgegeben. Daher soll auch dieses Buch vor allem eines sein: ein praxisorientierter Leitfaden für den Einsatz von OpenLDAP im Netzwerk, und zwar auf der Basis praxiserprobter Szenarien. Ein Leitfaden, der dem Administrator beim Setup des Systems und vor allem auch der Lösung real anfallender Problematiken helfen kann. Ziel war es, den hilfreichen Leitfaden rund um das Thema OpenLDAP, den wir mit der letzten Ausgabe erfolgreich auf den Weg gebracht haben, mit diesem Buch zu aktualisieren, zu optimieren und abzurunden. Ich hoffe, dass wir die Aufgabe auch dieses Mal so gut wie möglich gelöst haben. Oliver Liebel
16
1198.book Seite 17 Donnerstag, 5. Februar 2009 3:02 15
»Wer die Praxis übt, ohne sich vorher mit der Theorie beschäftigt zu haben, gleicht einem Steuermann, der sein Schiff ohne Kompass und Steuer besteigt und nun nicht weiß, wohin er fährt.« Leonardo da Vinci (1452–1519)
1
Vorab: Was man wissen sollte
1.1
Eine kurze Geschichte des Internets
1.1.1
Vom Bikini zum ARPAnet
Der Name Castle Bravo könnte in uns durchaus Gedanken an tapfere, amerikanische Zelluloid-Helden wecken. Aber weder John Wayne noch seine HollywoodKomparsen haben etwas mit dem Namen zu tun – jedoch der Forschungsdrang ihrer Landsleute: Castle Bravo war der Codename der schwersten atomaren Testexplosion der USA. Die Bombe mit einer Sprengkraft von 15 Megatonnen wurde am 28. Februar 1954 über dem Bikini-Atoll gezündet und brachte – neben einer Reihe neuer Erkenntnisse der Art, wie sie Militärs und deren Wissenschaftler für sinnvoll halten – einen kompletten Ausfall jeglicher Kommunikation der beteiligten Schiffe und Truppen mit sich. Die Menschheit war einen großen Schritt weiter gelangt, sie war nun doch in der Lage, einen elektromagnetischen Pulsar (kurz: EMP) auszulösen. Weil aber zur Menschheit auch »die bösen Jungs« im Kalten Krieg gehörten und die mit russischer Unverfrorenheit auch über atomare Waffen verfügten, stellten der EMP und der mit ihm verbundene Kommunikationszusammenbruch ein mächtig großes Problem dar: (»Mr. President, mit einem Wort: Wir verlieren unsere Zweitschlagsfähigkeit.«), das dringend gelöst werden musste. Was niemand ahnte: Die Forschungen, die man nun begann, waren die Geburtsstunde des Internets. So geht jedenfalls die Legende, die auch nicht völlig frei erfunden sein dürfte, denn: Am Beginn der Arbeit über die Paketverwaltung von Datenströmen standen einige Memos der Rand Corporation, seinerzeit DER militärische Think Tank der USA. Nur am Rande: Die UdSSR zündete am 30. Oktober 1961 eine 60-MegatonnenBombe in 4000 Metern Höhe. Über die Folgen ist nichts bekannt, aber es dürfte das Ende aller elektrischen Geräte im Umkreis von 100–200 km gewesen sein. Wo rohe Kräfte sinnlos walten …
17
1198.book Seite 18 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
1.1.2
Pakete und Ströme
J. C. Licklider legte den Grundstein des Internets in den späten 50er-Jahren mit seinen Überlegungen zu Time-Sharing-Systemen. Er leitete damals eine Forschungsgruppe beim US-Rüstungslieferanten Bolt, Beranek and Newman (BBN). Computerhersteller und die meisten Vertreter des Informatik-Establishments waren der Ansicht, dass Time-Sharing eine ineffiziente Verwendung von Computerressourcen darstelle und nicht weiter verfolgt werden solle. Lickliders Argument war, umgekehrt, dass Rechner für eine Echtzeit-Interaktion für »kooperatives Denken mit einem Menschen« zu schnell und zu kostspielig seien, weshalb sie ihre Zeit zwischen vielen Nutzern aufteilen müssten. Entscheidend an diesem Ansatz war aber die »paketweise« Auffassung von Datenverarbeitungsprozessen, entgegen der damals üblichen Auffassung von Datenströmen. Die konsequente Verfolgung dieses Ansatzes erlaubte es ihm, eine Neudefinition des Computers als Rechenmaschine hin zum Computer als Kommunikationsgerät vorzunehmen. Bei diesem Entwicklungsstand seiner Konzepte wechselte er 1962 zur Advanced Research Projects Agency (ARPA) des US-Verteidigungsministeriums. Die ARPA-Forschungsabteilung unter Licklider schrieb die verschiedenen Bestandteile des neuen Netzes aus. Das Stanford Research Institute (SRI) erhielt den Auftrag, die Spezifikationen für das neue Netz zu schreiben. Im Dezember 1968 legte das SRI den Bericht A Study of Computer Network Design Parameters vor. Zur selben Zeit arbeiteten Doug Engelbart und seine Gruppe am SRI bereits an computergestützten Techniken zur Förderung menschlicher Interaktion. Daher wurde entschieden, dass das SRI der geeignete Ort sei, ein Network Information Center (NIC) für das ARPAnet einzurichten. Die ARPA-Ausschreibung für ein Network Measurement Center ging an die University of California in Los Angeles (UCLA), wo Leonard Kleinrock arbeitete, der seine Doktorarbeit über Warteschlangentheorie geschrieben hatte. Den Zuschlag für die Entwicklung der Paketvermittlungstechnologien, genauer eines Interface Message Processor (IMP), erhielt BBN. Dort arbeitete unter anderem Robert E. Kahn, der vom MIT gekommen war und auf den ein Großteil der Architektur des Internets zurückgeht. Die IMPs, Vorläufer der heutigen Router, hatten die Aufgabe, die niedrigste Verbindungsschicht zwischen den über Telefonleitungen vernetzten Rechnern (Hosts) herzustellen. Die ersten IMPs wurden im Mai 1969 ausgeliefert. Der Startschuss zum Internet fiel im Herbst 1969, als die ersten vier Großrechner der UCLA, des SRI, der University of California in Santa Barbara (UCSB) und der University of Utah miteinander verbunden wurden.
18
1198.book Seite 19 Donnerstag, 5. Februar 2009 3:02 15
Eine kurze Geschichte des Internets
Zwei Jahre später bestand das Netz aus 14 Knoten und wuchs um einen pro Monat. Nach Fertigstellung des NCP und Implementierung für die verschiedenen Architekturen entstanden jetzt die höheren Dienste Telnet und FTP (File Transfer Protocol), Ray Tomlinson von BBN modifizierte ein E-Mail-Server-Programm für das ARPANET und erfand die »user@host«-Konvention. Larry Roberts schrieb hierfür einen Mail-Client. Und der führte gleich zum Start des E-Commerce im nagelneuen Internet. Denn, so war zu hören, es wurde über diesen neuen Kommunikationsweg ein schwunghafter Handel mit Marihuana zwischen den Studenten in Berkeley, CA, und denen vom MIT betrieben. Wer Teile des älteren Unix-Quellcodes mitsamt den Kommentaren gesehen hat, ist sofort bereit, diese Geschichte zu glauben. Und wenn sie falsch sein sollte, so ist sie jedoch gut erfunden … Die Telekommunikationsunternehmen waren am Konzept der »paketweisen« Datenübertragung schon damals durchaus interessiert, allerdings mehr unter den Gesichtspunkten Fehlertoleranz und Netzauslastung. Letztlich boten sie aber doch wieder nur einen kanalbasierten Übertragungsweg an: Die Spezifikationen dieses Dienstes wurden im Rahmen der Internationalen TelekommunikationsUnion (ITU) verhandelt und 1976 unter der Bezeichnung X.25 standardisiert. Die Bundespost bot ihn unter dem Namen Datex-P an. So wurde einem rhizomatischen Netz, das aus militärischem Kalkül heraus von einzelnen Knoten ausgehend dezentral wuchert, eine zentral geplante und verwaltete hierarchische, baumförmige Struktur gegenübergestellt. Die Zeit schien reif, das Werk der Öffentlichkeit zu präsentieren, was 1972 auf der International Conference on Computer Communications in Washington stattfand. Im Keller des Konferenzhotels wurden ein Paketvermittlungsrechner und ein Terminal Interface Processor (TIP) installiert, der anders als ein IMP den Input von mehreren Hosts oder Terminals verarbeiten konnte. Angeschlossen waren 40 Maschinen in den ganzen USA. Aber natürlich war das Hardwarekonzept noch immer nicht wirklich befriedigend. Am ärgsten schien die Möglichkeit, ein System mit konkurrierenden Übertragungsstandards auf unterster Ebene zu generieren. Bob Metcalfe umriss deshalb in seiner Doktorarbeit an der HarvardUniversität das Konzept für ein Local Area Network (LAN) mit multiplen Zugangskanälen, das er Ethernet nannte. Am Xerox PARC entwickelte er das Konzept weiter, bevor er später 3COM gründete. ARPANET, SATNET und das Radionetz hatten verschiedene Schnittstellen, Paketgrößen, Kennzeichnungen und Übertragungsraten, was es schwierig machte, sie untereinander zu verbinden. Robert Kahn, der von BBN an die DARPA (eine Unterabteilung des amerikanischen Department of Defense, wurde später in ARPA umbenannt) ging, und Vint Cerf, der an der Stanford-Universität unterrich-
19
1.1
1198.book Seite 20 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
tete, begannen, ein Protokoll zu entwickeln, um verschiedene Netze miteinander zu verbinden. Im Herbst 1973 stellten sie auf einem Treffen der International Network Working Group in England den ersten Entwurf zum Transmission Control Protocol (TCP) vor. Im Jahr darauf wurde TCP zeitgleich an der Stanford-Universität, bei BBN und dem University College London (Peter Kirstein) implementiert. Damit war der Grundstein für das moderne Internet gelegt. Und es ging zügig weiter. Anfang 1975 verfügte das ARPANET über 61 Knoten. Die erste Mailingliste wurde eingerichtet. Zusammen mit den RFCs werden Mailinglisten zum wichtigsten Mittel der offenen Kooperation der technischen Gemeinschaft. In der beliebtesten Liste dieser Zeit diskutierte man jedoch über Science-Fiction. TCP/IP wurde zum De-facto-Standard, doch die Anerkennung als offizieller Standard blieb ihm verwehrt. Ein Irrweg in der Netzwerkentwicklung begann, als die International Organization for Standardization (ISO) ab 1982 ein Referenzmodell (OSI-Modell) für einen eigenen, verbindungsorientierten Internetzwerkstandard namens Open Systems Interconnection (OSI) entwickelte. Im Gegensatz zum horizontalen Prozess der Internet-Community beruht das Standardisierungsverfahren der ISO auf einem vertikalen, mehrschichtigen Prozess aus Vorschlägen, Ausarbeitungen und Abstimmungen, der zwischen den nationalen Standardisierungsorganisationen, den Arbeitsgruppen und schließlich dem Plenum der ISO hin und her geht. Dabei sollen alle Interessen berücksichtigt werden. Sie wissen schon – eine Kommission wie die Hartz- oder Warren-Kommission. Andererseits führten diese Bemühungen zum X.500-Protokoll, die Grundlage dessen, wovon wir hier reden. Mehr davon im nächsten Abschnitt.
1.2
Die Schweiz und die Wende
Zunächst geschah etwas wirklich Entscheidendes: 1981 begann Bill Joy an der Universität von Kalifornien in Berkeley mit einem Forschungsauftrag der DARPA damit, die TCP/IP-Protokolle in die dort gepflegte freie Version des Betriebssystems Unix zu integrieren. Sie wurden im August 1983 in der BSD (Berkeley Systems Distribution)-Unix-Version 4.2 veröffentlicht. Die Betriebssysteme von Computer und Netz waren verschmolzen. Nicht zuletzt deshalb begannen viele Computerunternehmen, wie zum Beispiel das von Joy mitgegründete Sun Microsystems, BSD zur Basis ihrer Workstations zu machen. Die freie Software BSD 4.2 verbreitete sich rasch. Tausende von Entwicklern in der ganzen Welt übernahmen es und schufen so die Grundlage für das heutige globale Internet.
20
1198.book Seite 21 Donnerstag, 5. Februar 2009 3:02 15
Die Schweiz und die Wende
Zu dieser Zeit beschloss die ARPA, das bestehende Internet aufzuspalten in das so genannte ARPAnet als Grundlage eines Wissenschaftsnetzes und das MILnet für rein militärische Belange. Von den damals 113 Host-Rechnern blieb dem ARPAnet nur ein kleiner Rest von 45 Rechnern übrig. Das Militär hat eben immer und überall Vorrang – möglicherweise, weil es bewaffnet ist. Dennoch waren an den 45 verbliebenen Internet-Hosts sehr viel mehr Client-Rechner angeschlossen als bei den Uniformträgern, und das nun entmilitarisierte Netz wuchs rasant. 1988 kam mit dem Internet Relay Chat (IRC) eine weitere – und äußerst direkte – Online-Kommunikationsform hinzu, so dass man es nun schon zu tun hatte mit: Telnet, FTP, E-Mail, USEnet und IRC. Die Dinge begannen, unübersichtlich zu werden. Anfang der 90er-Jahre entstanden drei verschiedene Konzepte, um dem anwachsenden Datenberg Herr zu werden. Zwei davon sind mittlerweile nur noch den Älteren unter uns bekannt, das dritte war so erfolgreich, dass aus einigen Hunderttausend Rechnern in nur 15 Jahren einige Hundert Millionen wurden. Aber der Reihe nach: Zunächst entstand eine der ersten Suchmaschinen: Archie, abgeleitet von dem Wort archives für Archive. Archie war in der Lage, bekannte FTPServer zu durchsuchen und Indizes anzulegen. Dennoch war dieser Dienst nicht zu vergleichen mit den komfortablen Robots des 21. Jahrhunderts. Der Suchstring durfte aus einem Wort und maximal acht Zeichen bestehen, so dass man schon sehr genau wissen musste, wonach man suchte, oder bereit sein sollte, eine Menge Zeit zu investieren. Der zweite Versuch, der inflationären Unübersichtlichkeit Herr zu werden, hieß GOPHER (engl. Erdhörnchen) und ist ein Informationsdienst, der mit Hilfe eines Gopher-Clients oder eines Webbrowsers abgerufen werden kann. Für die Wahl des Namens gibt es zwei Theorien: Gopher = engl. Beutelratte, das Maskottchen des Bundesstaates und der Universität von Minnesota, oder »Go for it«. Die Überlegung, die zu Gopher führte, war die umständliche Handhabung des File-Transfer-Protokolls, bei dem man sich einloggen und über Konsolenbefehle in Verzeichnisse wechseln musste, um die gewünschte Datei zu finden und herunterladen zu können. Zudem wollte man ein einfach zu administrierendes Informationssystem schaffen, das wenige Ressourcen benötigt. Wie später beim WWW basiert GOPHER auf Angeboten von GOPHER-Servern, die mit geeigneten Clients abgefragt werden können. Heute ist GOPHER ein fast vergessenes Relikt, obwohl es Versuche gab, ein elitäres, nichtkommerzielles Nebenweb zu bauen. Wen’s interessiert: Alle Webbrowser von Netscape und Mozilla sind immer noch GOPHERfähig.
21
1.2
1198.book Seite 22 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
Für die Verwalter und Entscheider des jungen Internets war das Handling einer weiter und weiter anschwellenden Datenflut ein neues und schwer zu lösendes Problem. Für Experimentalphysiker, die an Teilchenbeschleunigern arbeiten, war dies seit jeher das tägliche Brot. So ist es nicht verwunderlich, dass ein Physiker am CERN in Genf eine Methode entwickelte, Verknüpfungen zwischen großen Datenmengen zu erzeugen, um so zu einem handhabbaren Umgang zu gelangen. Wie sich zeigte, war diese Methode auch – und zwar bestens – geeignet, die Angebote des schneller und schneller wachsenden Internets zu strukturieren. So gerieten das Hypertext Transfer Protocol (HTTP) und die Hypertext Markup Language (HTML) in den Fokus der Aufmerksamkeit. Beides wurde 1991 in das Internet implementiert und ist seither in aller Munde als das World Wide Web (WWW). Und für diesen unbestreitbaren Verdienst erhielt der englische Wissenschaftler Sir Timothy Berners-Lee den wohlverdienten Ritterschlag. Er steht bis heute dem W3C-Konsortium vor, einer gemeinnützigen Organisation, die die Standardisierung und Weiterentwicklung des WWW koordiniert. Der Rest der Geschichte ist bekannt …
1.3
Währenddessen … auf der anderen Seite der Stadt
DAP, DSP, DISP und die Anwendungen Verzeichnisdienste existieren, seitdem es Bibliotheken gibt. Allerdings machte sowohl die stürmische Entwicklung des Internets als auch die zunehmende Vernetzung von Firmenrechnern eine neues, netzwerkzentriertes Modellierung von Verzeichnisstrukturen notwendig. X.500 wurde 1988 von der CCITT spezifiziert als »eine Menge offener Systeme, die gemeinsam eine Datenbank halten, in der Informationen über Objekte der realen Welt abgelegt sind«. Die CCITT spezifiziert im Wesentlichen drei Protokolle: 왘 DAP (Directory Access Protocol): dient dem Zugriff auf die Informationen 왘 DSP (Directory Service Protocol): für die Kommunikation der Server untereinander 왘 DISP (Directory Information Shadowing Protocol) Allerdings setzt X.500 auf einem vollständigen ISO/OSI-Stack auf, was einen durchschlagenden Erfolg unmöglich machte, denn im OSI-Modell nimmt der Abstraktionsgrad der Funktionen von Schicht 1 zu Schicht 7 deutlich zu. Die
22
1198.book Seite 23 Donnerstag, 5. Februar 2009 3:02 15
X.500 und der OSI-Stack
Daten werden von einer Schicht zur nächsten weitergereicht, das heißt, die Kommunikation erfolgt in vertikaler Richtung. Auf der Senderseite läuft die Kommunikation von oben nach unten und auf der Empfängerseite von unten nach oben. Logisch gesehen erfolgt die Kommunikation zwischen Sender und Empfänger jedoch horizontal in jeder Schicht.
1.4
X.500 und der OSI-Stack
Die nach dem OSI-Referenzmodell entwickelten Netzprotokolle haben mit der TCP/IP-Protokollfamilie gemeinsam, dass es sich um hierarchische Modelle handelt. Es gibt aber entscheidende konzeptionelle Unterschiede: OSI legt die Dienste genau fest, die jede Schicht für die nächsthöhere zu erbringen hat. TCP/ IP hat kein derartig strenges Schichtenkonzept wie OSI. Weder sind die Funktionen der Schichten genau festgelegt noch die Dienste. Es ist erlaubt, dass eine untere Schicht unter Umgehung zwischenliegender Schichten direkt von einer höheren Schicht benutzt wird – z.B. benutzt SSH direkt und ohne die TCP-Schicht IP als Transportprotokoll. TCP/IP ist damit erheblich effizienter als die OSI-Protokolle, allerdings sind die Protokolle zahlreicher, weil die OSI-Standards eine wesentlich größere Bandbreite an Möglichkeiten bieten. Letztlich konnte sich das OSI-Modell auf breiter Ebene nicht durchsetzen und nur zwei OSI-konforme Protokolle sind noch in Gebrauch: X.400 als Alternativentwurf zu Internet Mail und der X.500-Standard, der einen Verzeichnisdienst beschreibt. Ursprünglich war dieser Verzeichnisdienst als das »Telefonbuch« der X.400-Maildienste angelegt, es gab sogar Überlegungen, mit seiner Hilfe das junge Internet zu sortieren und zu akzeptableren Navigationsmöglichkeiten zu gelangen, als sie mit Archie, Gopher und Prospero geboten wurden. Die Entwicklung des Webs und des Domain Name Space machten diese Anstrengungen obsolet. Insgesamt wuchs mit den OSI-konformen Anwendungen auf der einen und dem rapiden Anschwellen der Bedeutung des TCP/IP-basierten Internets auf der anderen Seite das Risiko, zu Inkompatibilitäten und konkurrierenden Standards zu gelangen. Das hätte jedermanns Arbeit in vernetzten Rechnerumgebungen unerträglich erschwert. Glücklicherweise entwickelte die University of Michigan 1993 das Konzept von LDAP (Lightweight Directory Access Protocol). Die Crux war dabei, dass LDAP TCP/IP als Übertragungsprotokoll einsetzte und damit einen umfassenden Einsatz von Verzeichnisdiensten im Intra- und Internet ermöglichte. Allerdings funktionierten die ersten Versionen in der Hauptsache als Proxy-Dienste für reguläre X.500-DAP-Server.
23
1.4
1198.book Seite 24 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
Das wurde allerdings bald geändert. Da man ja schon einen Dienst hatte, und da DAP-Server nach wie vor selten waren und sind, entschied man sich im OpenLDAP-Team, die Angelegenheit mit eigenen Backends zu betreiben.
1.5
Struktur eines Verzeichnisdienstes
OpenLDAP funktioniert im »klassischen« X.500-Sinn als Verzeichnisdienst, und auch wenn seine Funktionalität im Vergleich zum Original kräftig beschnitten werden musste, so kann man doch fast den gesamten Funktionsvorrat eines DAPDienstes aus den vorhandenen Möglichkeiten erzeugen. Zeit, sich die Arbeitsweise von Verzeichnisdiensten näher anzusehen. Die Technik im Überblick Im Internet und in unternehmensinternen Intranets werden Verzeichnisse in der Regel dazu verwandt, um Benutzer- und Objektdaten zentral zu sammeln und Applikationen zur Verfügung zu stellen. Diesen Datensammlungen liegt meist eine Datenbank zugrunde, die diese Daten aufnimmt. Um mit diesem Dienst in Kontakt zu treten, werden so genannte Netzwerkprotokolle verwendet, um Daten aus dem Verzeichnis abzufragen oder zu aktualisieren. In den meisten Fällen kommt dabei ein so genanntes Directory Access Protocol zum Einsatz, Standardimplementierungen dieses Protokolls sind DAP aus der X.500-Architektur sowie LDAP, einer leichtgewichtigen (lightweight) Form von DAP (Directory Access Protocol). Ein Verzeichnisdienst (engl. Directory Service oder DS) ist somit eine im Netzwerk verteilte, hierarchische Datenbank, die auf dem Client-ServerPrinzip basiert. In dieser Datenbank können beliebige Informationen gespeichert werden. Die Einträge in der Datenbank können verglichen, gesucht, erstellt, modifiziert, repliziert und gelöscht werden. Welche Arten von Verzeichnisdiensten gibt es? Es gibt verschiedene Verzeichnisdienste, die sich strukturell unterscheiden. Zum einen gibt es das auf X.500 basierende Lightweight Directory Access Protocol (LDAP). Hiervon sind einige Abwandlungen entstanden, deren Aufbau auf LDAP basiert, aber proprietär umgesetzt worden ist; hier sind vor allem Novells eDirectory und Active Directory (ADS) von Microsoft zu nennen, wobei sich das Letztere von etlichen Standards bereits weit entfernt hat. Aber wen wundert’s? Weiterhin gibt es noch den hinlänglich bekannten Domain Name Service (DNS) und den Network Information Service (NIS) – auch Yellow Pages genannt – von Sun. Beide Systeme haben ihren eigenen, spezifischen Aufbau. Ein typischer
24
1198.book Seite 25 Donnerstag, 5. Februar 2009 3:02 15
Struktur eines Verzeichnisdienstes
DNS-Baum ähnelt einem LDAP-Baum aufgrund seiner nahen Verwandtschaft sehr stark im Aufbau; NIS ist im Kern nichts anderes als ein Verfahren, die lokalen Passwortdateien durch Kopieren über das Netz auf allen beteiligten Servern synchron zu halten. Zu erwähnen sind auch noch das Siemens-Verzeichnis Dir.X und das LDAP-ähnliche Domino Directory, das oft in der Bankenwelt anzutreffen ist. Was unterscheidet Verzeichnisdienste von relationalen Datenbanksystemen? Es gibt mehrere grundlegende Unterschiede zwischen relationalen Datenbanken (oder auch RDBMS: Relationale Datenbank-Management-Systeme) und Verzeichnisdiensten. Verzeichnisdienste sind darauf optimiert, dass deutlich häufiger gelesen als geschrieben wird. Im Gegensatz dazu sind Datenbanken meist schreib-/leseoptimiert: Für ein Telefonbuch wird der Eintrag nur einmal erstellt, aber viele Male nachgeschlagen. Datenbanken laufen meist auf einem einzelnen Server, dagegen sind Verzeichnisdienste in der Regel immer über mehrere Server verteilt. Das heißt, Teile der Verzeichnisstruktur können auf unterschiedlichen Servern liegen (Partitionierung), ebenso sind komplette Kopien des Verzeichnisses auf mehreren Servern möglich (Replikation). In großen Verzeichnisstrukturen finden sich oft Mischformen der beiden gerade erläuterten Konzepte. Ein exzellentes Beispiel hierfür ist der DNS, in dem es die Root-Server gibt, die alle die gleiche Information zur Verfügung stellen, aber auch untergeordnete Server, die nur für bestimmte Bereiche zuständig sind, wie zum Beispiel die Nameserver der Telekom. Verzeichnisdienste sind in der Regel objektorientiert, das heißt, sie bestehen aus einzelnen Objekten, Funktionen zu diesen Objekten gibt es nicht. Verzeichnisdienste unterstützen in der Regel selbst keine Transaktionen (darum kümmert sich üblicherweise die ihnen unterliegende Datenbank), jedoch steht eine protokollseitige Implementierung von Transaktionskontrollen für OpenLDAP 2.5 auf der To-do-Liste, siehe hierzu auch http://tools.ietf.org/html/ draft-zeilenga-ldap-txn-13. Relationen existieren innerhalb eines DS ebenso wenig wie eine aufwändige (Programmier-)Sprache, wie z.B. SQL bei relationalen Datenbanken. Es ist also von der Anwendung abhängig, ob ein Verzeichnisdienst oder ein Datenbanksystem zum Einsatz kommt. In vielen Foren taucht oft die grundsätzliche Frage auf: Warum nicht LDAP zusammen mit einem RDBMS betreiben? Zur Beantwortung dieser Frage sind jedoch noch einige LDAP-Vorkenntnisse erforderlich, z.B. was Objektklassen, Attribute und einiges mehr angeht. Daher werden wir auf diese Frage in einem späteren Abschnitt eingehen, wenn wir über die Standard-Datenbank unseres
25
1.5
1198.book Seite 26 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
LDAP, die Oracle Berkeley DB, sprechen: Abschnitt 3.8, »Larry und die schläfrigen Katzen«. Aufbau eines Verzeichnisdienstes Das Klassenmerkmal von Verzeichnisdiensten ist ihre Baumstruktur. Hier ein kleines Beispiel für den hierarchischen Aufbau:
rootDSE c=de
o=Firma1
ou=forschung
cn=user1
Abbildung 1.1
c=at
o=Firma2
o=Firma3
ou=verkauf
cn=user2
cn=user3
Beispielhafte Baumstruktur
Den höchsten (unsichtbaren) Einstiegspunkt eines jeden Verzeichnisbaumes oder auch DIT (Directory Information Tree) bildet immer der rootDSE (DSE = Directory Service Entry). Der rootDSE enthält »unsichtbare« Informationen über den LDAP-Server selbst und seine Kapabilitäten (Fähigkeiten) in Form von sogenannten operationellen Attributen (operational Attributes). Mehr zu diesen speziellen Attributen erfahren wir im Abschnitt 2.3, »Fingerübungen«. Vom rootDSE ausgehend verzweigt der Baum auf niedrigere Hierarchie-Ebenen. Die höchste »greifbare« Ebene eines jeden DIT bildet üblicherweise die so genannte Basis-DN oder auch BaseDN (DN = Distinguished Name), die aus mindestens einer, oft jedoch auch zwei oder mehreren Komponenten bestehen kann. Im vorgenannten Beispiel existieren 3 BaseDNs, die zugleich eine TLD (TopLevel-Domain)-Komponente enthalten (hier: c=de und c=at, wobei c für country steht): firma1.de, firma2.de und firma3.at
26
1198.book Seite 27 Donnerstag, 5. Februar 2009 3:02 15
Struktur eines Verzeichnisdienstes
Die Kurzform der Schreibweise erinnert an einen DNS-artigen Domainnamen, und das aus gutem Grund, denn die Vorfahren von DNS und LDAP haben, wie wir wissen, die gleichen Wurzeln. In der LDAP-Welt werden die DNs eines Objektes jedoch immer voll ausgeschrieben, und zwar in der Form: Attribut1=Attributwert(von Attribut1),Attribut2=Attributwert(von Attribut2),usw.
Bezogen auf unser Beispiel also: o=firma1,c=de Hinweis: Unser LDAP akzeptiert zwar in der Regel Leerzeichen vor und nach den Kommas eines DN (und entfernt sie normalerweise auch beim Import eines Datensatzes), sie sollten jedoch in der Regel vermieden werden.
Die Organisation (o = organization) Firma1 beherbergt in diesem Beispiel wiederum untergeordnete organisationelle Einheiten, sogennante ou’s, oder auch organizationalUnits, die wiederum in der Regel Container für weitere Objekte bilden (üblicherweise User oder Drucker einer bestimmten Abteilung, shares, weitere ou’s oder sonstige Objekte). Bezogen auf das kleinste, greifbare bzw. nicht weiter zerlegbare Objekt innerhalb eines Trees (üblicherweise ein User-Objekt wie »user1« in unserem Beispiel), stellt sich ein komplett ausgeschriebener DN wie folgt dar: uid=user1,ou=verkauf,o=firma1,c=de
Wie wir unschwer erkennen können, wird der DN eines Objektes immer ausgehend vom Objekt selbst (z.B. dem User: uid=user1) hin zur BaseDN gelesen und geschrieben. Dieser DN schlüsselt sich wie folgt auf: Das Userobjekt mit der uid (userID) user1 liegt in der organizationalUnit (ou) verkauf, welche der BaseDN o=firma1,c=de untergeordnet ist. Diese an den äußersten Enden des Baumes gelagerten Objekte werden auch oft als Blatt- oder Leaf-Objekte bezeichnet. Vereinfacht kann man auch sagen, dass der DN eines Objekts immer vom Blatt zur Wurzel (rootDSE) gelesen und geschrieben wird. Wir wissen also nun, dass jedes Objekt innerhalb eines Trees durch seinen vollständigen DN definiert wird. Der DN ist in der LDAP-Terminologie damit am ehesten mit einem indizierten Datenbankfeld einer relationalen Datenbank vergleichbar, das nur genau einmal pro Datenbank vorkommen und keine Dubletten haben darf. Die DNs aller Objekte innerhalb des DIT erzeugen eine hierarchische, baumartige Struktur. Teile von DNs werden als Relative Distinguished Names (RDNs)
27
1.5
1198.book Seite 28 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
bezeichnet. So lässt sich der DN: ou=verkauf,o=firma1,c=de durch Hinzufügen des RDN uid=user1 zum vollen DN des Users konstruieren. Exkurs: Das Kind braucht einen »erlesenen« Namen Very »distinguished«, for sure. Aber welche Attribute existieren denn nun, aus denen wir einen erlesenen oder – in unserem Fall zutreffender – einen absolut kenntlichen und eindeutigen DN bilden können? Einfache Frage – viele Antworten. Denn hier gilt: Viele Wege führen nach Rom und viele (aber nicht alle) DNs zum gewünschten Ziel. Schauen wir uns ein paar Standard-Attribute zur Bildung eines DNs an: Für die oberste Hierarchie-Ebene sind mehrere Varianten denkbar, in der Regel läuft es jedoch auf einige wenige hinaus. c=
kann als Landeskürzel wie z.B. de, com, at usw., üblicherweise in Kombination mit o=
verwendet werden, also z.B.: o=brainstorm,c=de um z.B. eine LDAP-Struktur entsprechend einer bereits existierenden InternetDomäne aufzubauen. Denkbar sind auch einfache Varianten, bei denen nur die Organisation angegeben wird: o=brainstorm. dc (domainComponent) ist ein echter Allrounder; mit ihm lassen sich auch verschachtelte Domänen-Strukturen allgemeingültig und relativ einfach abbilden, z.B.: dc=dortmund,dc=germany,dc=brainstorm,dc=de
Für Objekte unterhalb der Top Level Domain bzw. BaseDN werden üblicherweise mehrere ou’s (organizationalUnits) verwendet; eine ou beinhaltet, wie wir bereits wissen, als typisches Container-Objekt weitere untergeordnete Objekte, in der Regel User. ou=verkauf,dc=local,dc=site
Unterhalb der TLD oder BaseDN – sowie in jeder ou und denen ggf. untergeordneten ou’s – sind Gruppenobjekte einsetzbar. Sie beinhalten keine weiteren Verzweigungen auf andere, untergeordnete Objekte, sondern »nur« Attribute, in denen ihre Mitglieder gelistet sind. Die Gruppenobjekte werden typischerweise per cn (commonName) angesprochen: cn=superuser,dc=local,dc=site
28
1198.book Seite 29 Donnerstag, 5. Februar 2009 3:02 15
Struktur eines Verzeichnisdienstes
Das »Schlusslicht« der DN-Kette (das am tiefsten verzweigte Objekt im Baum) bildet üblicherweise – falls es keine Gruppe ist – das Userobjekt. uid=ckent,ou=verkauf,o=firma1,c=de
So weit, so gut. Oder nicht? Könnten wir denn nicht auch einen cn als RDN angeben? Klar, insofern er gewissen Regeln folgt, die in der Regel aber eher den Regeln eines uid-Attributes entsprechen, und das am besten ohne Regelverstöße. Regeln klar? Im Ernst: cn ist – bis auf wenige Ausnahmen – für den DN von Userobjekten nur die dritte bis letzte Wahl. Warum das so ist, klären wir gleich in Abschnitt 1.6, im Exkurs: »uid? or not uid?« Fassen wir zusammen: Wir wissen nun also, wie ein Baum aufgebaut ist, dass der Baum selbst aus Objekten besteht, diese wiederum über eindeutige DNs beschrieben werden – und wir wissen nun auch, wie sich diese DNs üblicherweise zusammensetzen. Na prima. Und was ist ein Objekt? Gute Frage, und die Antwort ist schnell gegeben: Innerhalb eines LDAP-Trees ist alles ein Objekt! Allerdings dauert, wie wir uns denken können, die dahinter liegende Erklärung ein klein wenig länger. Bleiben wir bei einem einfachen Beispiel: Einer »normalen« Datenbank. Jede Datenbank besteht, wie wir wissen, aus einzelnen Datenbankfeldern, deren Eigenschaften wir in den meisten Fällen selbst definieren können. So können wir Integer-, Real-, Boolean-, Text- oder sonstige Felder in die Datenbank einpflegen und anschließend mit Werten befüllen. Meistens werden wir ein bestimmtes Feld indizieren, wie z.B. eine Produktnummer oder ein Name, damit keinesfalls Dubletten eines Datensatzes entstehen können, und die referentielle Integrität der Datenbank gewährleistet bleibt. Wir wissen schon, dass diese Indizierung in der LDAP-Welt durch den DN geschieht, der pro Objekt immer eindeutig sein muss. Kommen wir nun zurück zu den Datenbankfeldern. Die LDAP-Datenbank kann von ihrem Aufbau ähnlich betrachtet werden wie eine »normale« Datenbank. Nur werden hier nicht nur einzelne Datenbankfelder (Attribute) betrachtet, sondern meist deren Zusammenfassung, die sogenannten Objektklassen. Jede Objektklasse beinhaltet eine bestimmte Untermenge an Attributen (Datenbankfeldern) mit spezifischen Eigenschaften. Wollen wir also erreichen, dass ein Objekt bestimmte Eigenschaften innehaben soll, müssen wir das Objekt mit bestimmten Objektklassen ausstatten, die wiederum bestimmte Attribute besitzen. Klingt kompliziert? Ist es nicht. Betrachten wir einfach folgendes Beispiel: Wir möchten innerhalb unseres DIT ein Userobjekt anlegen, das folgende Eigen-
29
1.5
1198.book Seite 30 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
schaften haben soll: Das User-Objekt soll sich am Linux-System anmelden können und es soll zugleich zusätzliche Informationen über den User wie z.B. seine Mailadresse und Telefonnummer beinhalten. In der wunderbaren Welt unseres LDAP eine leicht lösbare Aufgabe. Wir benötigen einfach die entsprechenden Objektklassen: posixAccount liefert alle Attribute, die ein Linux-User zur Anmeldung am System benötigt, wie z.B. homeDirectory, loginShell, uid, uidNumber, und die Objektklasse inetOrgPerson liefert alles, was wir an zusätzlichen »Internet«-mäßigen Attributen wie mail, telephoneNumber usw. benötigen. Sehr schön. Aber woher wissen wir, welche Objektklassen es überhaupt gibt und welche Attribute sie enthalten? Kein Problem, auch das klären wir sofort. Zunächst müssen wir uns aber noch einmal verinnerlichen, dass die Leistungsfähigkeit unserer LDAP-Datenbank durch die Objektklassen und Attribute, die uns zur Verfügung stehen, klar definiert wird. Beim Start des OpenLDAP-Daemons werden mit Hilfe von sogenannten Schema-Dateien üblicherweise die zur Verfügung stehenden Datenbankfelder, also alle Attribute und Objektklassen, geladen. Diese Schema-Dateien beinhalten im Klartext alle Attribut- und ObjektklassenDefinitionen. So enthält eine Attribut-Definition nicht nur den Namen (NAME) des Attributs, sondern auch seinen OID (Object-Identifier), seinen Attributsyntax (SYNTAX, also welcher Regel das Datenbankfeld gehorchen muss: z.B. Integer-Syntax oder nur Boolean-Werte zulässig), welche Vergleichsregeln (EQUALITY) auf das Attribut angewendet werden dürfen (z.B. Groß-Kleinschreibung ignorieren) und ob es eindeutig sein muss (SINGLE-VALUE) oder mehrfach vorkommen kann (MULTI-VALUE, Default). Objektklassen fassen die zuvor definierten einzelnen Attribute zu Gruppen zusammen, wobei in der Regel eine Teilmenge dieser Attribute Pflichtwerte sind, ein anderer Teil optionale Attribute, die keinen Wert besitzen müssen, aber können. Wenn wir also bestimmte Objektklassen zu bestimmten Zwecken benötigen, z.B. um ein Objekt mit bestimmten Fähigkeiten (Attributen) auszustatten, müssen wir sicherstellen, das die entsprechenden Schemadateien und mit ihnen die entsprechenden Objektkassen und Attribute geladen wurden, damit sie uns auch zur Verfügung stehen. Fassen wir zusammen: Die Objektklassen und Attribute sind also das eigentliche Rückgrat unserer LDAP-Datenbank, denn sie stellen die Datenbank-Felder bereit, die uns zur Verfügung stehen, um Objekte entsprechend unseren Wünschen zu
30
1198.book Seite 31 Donnerstag, 5. Februar 2009 3:02 15
Objekte, Klassen, Attribute
beschreiben. Okay, bei Gehaltsschecks wird die Geschichte vielleicht etwas dünn. Datenstrukturen oder Objekte, die innerhalb eines Directorys abgelegt bzw. erzeugt werden, heißen Einträge (Entries) und beschreiben ein Objekt, wie z. B. eine Person. Ein solcher Eintrag wird deshalb auch als Objekt bezeichnet. War doch ganz einfach, oder nicht ?
1.6
Objekte, Klassen, Attribute
Jedes Objekt hat ein oder mehrere Attribute, abhängig von den gewählten Objektklassen, so viel wissen wir schon. Welche Attribute das Objekt letztlich wirklich besitzt, wird in der zugeordneten Objektklasse durch die Pflicht-Attribute definiert. Jedes Attribut hat eine OID, einen menschenlesbaren Alias zu dieser OID, eine bestimmte Attributsyntax und die zugehörigen Vergleichsregeln sowie einen oder mehrere Attributwerte. Objektklassen, Attribute und ihre Syntax besitzen immer einen weltweit eindeutigen Object IDentifier (OID). Diese sind vom X.500-Modell übernommen worden. Nehmen wir als Beispiel das Attribut telephoneNumber aus dem cosine.schema: Es besitzt – wer hätte es gedacht: die Objektsyntax telephoneNumber, die alle Zeichen von 0 bis 9, Bindestriche und Leerzeichen erlaubt. Der Attributwert könnte also z.B. 0800-12-34567-89 sein. Hätte das Attribut telephoneNumber nicht die (übliche) Syntax telephoneNumber, sondern etwa die Syntax Integer, wären keine Leerzeichen oder Bindestriche zulässig. Bei Verwendung des telephoneNumberSyntax werden jedoch die Attributwerte 0800-12, 0800 12 und 080012 identisch interpretiert und bei einer Suchanfrage nach 080012 auch zurückgegeben. Mit der Attributsyntax bzw. den Matching Rules lässt sich auch explizit steuern, ob nach Groß-/Kleinschreibung bei Attributwerten unterscheiden wird. Achtung: Bei einigen Attributen wie z.B. cn, ou, o, c … ist Groß-/Kleinschreibung caseinsensitiv, d.h., es ist egal, ob cn=clark kent oder cn=Clark Kent geschrieben wird. Die so genannten Matching Rules bestimmen darüber, wie nach einem Objekt innerhalb des Trees gesucht wird: z.B. nach dem kompletten String, einem Teilstring, ob Groß-Kleinschreibung interpretiert wird, usw. Fassen wir kurz zusammen: Attribut: Eigenschaft eines Objekts, das durch den Attributtyp festgelegt ist. Attributsyntax: Beschreibung des Attributtyps und dessen Eigenschaften. MatchingRules: Die Art, wie die Attributwerte eines Attributs verglichen werden. Bei einigen Attributen kann auch ein Teilvergleich der Werte festgelegt werden.
31
1.6
1198.book Seite 32 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
Objektklasse: Die in einer Objektklasse zusammengefassten Attribute beschreiben ein Konstrukt, das zur Abbildung von Objekten der Wirklichkeit dienen kann, indem durch sie Pflicht-Attribute und optionale Attribute des Eintrags definiert werden. Unterschieden wird hierbei zwischen Objektklassen vom Typ ABSTRACT, STRUCTURAL und AUXILIARY. Kurze Anmerkung: Die Objektklassen und ihre Bedeutungen werden wir im nächsten Abschnitt 1.7, »Nicht nach Schema F«, ausführlich behandeln; und später, im Abschnitt 3.9, »Selbst ist der Admin«, sogar eigene Objektklassen und Attribute entwerfen. Die einzelnen Objektklassen entstehen durch Vererbung und Erweiterung, und entstammen alle der gemeinsamen, abstrakten Basisklasse top.
Nehmen wir ein ganz einfaches Beispiel für ein Objekt, das in allen folgenden Beispielen die BaseDN für unseren Tree darstellen wird. Wir verwenden statt eines country (c)- oder locality (l)-Bezeichners eine so genannte domainComponent, oder kurz dc. Das dc-Attribut wird von der Objektklasse dcObject zur Verfügung gestellt, die sich im core.schema findet. Als nächstes brauchen wir noch einen Bezeichner für unsere Organisation, hierfür bietet sich die Objektklasse organization an, die das Attribut o zur Verfügung stellt. Werfen wir nun einen Blick auf den Aufbau dieses Objekts: dn: dc=local,dc=site objectClass: dcObject objectClass: organization dc: local o: Brainstorm
# definiert den eindeutigen DN # stellt das Attribut ‘dc’ bereit # stellt das Attribut ‘o’ bereit
Sieht aus, als hätten wir alles, was wir brauchen, um zumindest schon einmal die BaseDN unseres Trees abzubilden. Weiter im Text. Schauen wir uns nun ein einfaches Userobjekt an, wie es in unserem Baum vorkommen soll. Dabei müssen wir natürlich berücksichtigen, dass die ou, in der sich der User befindet, bereits existieren muss, bevor wir das Userobjekt anlegen würden, andernfalls wären eine Fehlermeldung das Einzige, was wir ernten. Wir bleiben bei der Festlegung, dass unser Userobjekt sowohl Linux-Attribute zur Anmeldung am System besitzen soll als auch zusätzliche »Internet-Attribute« wie Mailadresse und Telefonnummer. dn: uid=ckent,ou=verkauf,dc=local,dc=site objectClass: posixAccount objectClass: inetOrgPerson cn: Clark Kent uid: ckent uidNumber: 1001 gidNumber: 100 homeDirectory: /home/ckent sn: Kent
32
1198.book Seite 33 Donnerstag, 5. Februar 2009 3:02 15
Objekte, Klassen, Attribute
description: Superman loginShell: /bin/bash mailAddress: [email protected] postalCode: 555-krypton
Und dazu nun einige Erläuterungen: Der fett gedruckte Teil der vorgenannten Beispiele zeigt Attribute, die in jedem Fall einen Attributwert enthalten müssen, d.h., es handelt sich um so genannte »MUST«-Attribute. Der Teil in Normaldruck ist optional. Hier kann also etwas stehen, muss aber nicht. Es handelt sich um so genannte »MAY«-Attribute. Die Objektklassen bestimmen darüber, welche Attribute MUST, also Pflichtfelder, und welche vom Typ MAY, also optional sind. Sie sagen uns weiterhin, welche Art von User hier beschrieben wird. So definiert die Objektklasse posixAccount mit ihren Attributen einen klassischen Linux/Unix-Benutzer, während die Objektklasse inetOrgPerson unseren User mit »Internet-Attributen« ausstattet, so wie z.B. der Mail-Adresse, Telefonnummer usw. Schauen wir uns kurz einige der Attribute an: uid: ckent uidNumber: 1001 gidNumber: 100 homeDirectory: /home/ckent loginShell: /bin/bash
In diesen Einträgen finden sich die Standard-Eckdaten eines jeden Unix-Benutzers wieder: uid (der Account/Login-Name), uidNumber (die dem Account zugehörige UserID-Nummer), gidNumber (Gruppen-ID-Nummer), das Heimatverzeichnis und natürlich auch die loginShell, die festgelegt, ob der User überhaupt eine Shell erhält, mit der er auf der Konsole der Maschine arbeiten darf. Gleichfalls wird damit festgelegt, mit welcher Shell dies geschieht. Falls eine LoginMöglichkeit nicht gewünscht wird, kann man z.B. loginShell: /bin/false wählen. Im Prinzip findet sich hier also alles wieder, was bei einer files-basierten Anmeldung eines Users normalerweise über die Dateien /etc/passwd und /etc/ shadow erschlagen würde. Apropos User ...
33
1.6
1198.book Seite 34 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
Exkurs: uid? or not uid? Noch ein kleiner Tipp zum DN bzw. RDN eines Userobjekts: Üblicherweise sollten wir bei Userobjekten immer dem Attribut uid gegenüber cn (commonName) als RDN den Vorzug geben. Der Grund hierfür ist schnell erläutert. Die uid entspricht dem UnixAccount-Namen, der in der Regel aufgrund der für ihn geltenden Bestimmungen klein geschrieben wird, dazu an einem Stück, und keine Umlaute, Sonder- und/oder Leerzeichen beinhaltet. Somit ist das uid –Attribut unter dem Gesichtspunkt der Eindeutigkeit in jedem Fall die bessere Entscheidung für einen RDN – denn: Das Attribut commonName (cn) ist von dem im OpenLDAP-Daemon »hartverdrahteten« Attribut ‚name’ (OID 2.5.4.41, Directorystring in UTF8-Syntax) abgeleitet und entspricht üblicherweise dem vollen Namen des Benutzers (Vor- und Nachname); kann also Leerzeichen und länderspezifisch gesehen jede Menge Umlaute beinhalten, die uns das LDAP-Leben unnötig erschweren (dazu gleich mehr). Und vor allem ist cn ebenfalls nicht erste Wahl, wenn es um Eindeutigkeit geht – und das ist bezogen auf den gesamten DN eines (User-) Objektes schließlich immer oberste Prämisse. Und noch etwas anderes, das exakt mit dem Punkt »Umlaute« einhergeht, ist bei der Verwendung von cn im DN so gut wie unvermeidlich: die Base64-Kodierung des kompletten DNs. Nehmen wir an, unser Kollege Reneé-Marc-Migûel Müllerhübschenhöfchenhausenß (etwaige, aber eher unwahrscheinliche Ähnlichkeiten mit lebenden oder toten Individuen seien uns an dieser Stelle bitte verziehen) besteht darauf, seinen vollen Namen (cn, commonName) inklusive aller Umlaute im DN zu tragen. Wir sagen »Na prima, du Komiker.«, machen ein dummes Gesicht und tun ihm den »Gefallen«. Und nach dem ersten Blick auf die Kommandozeile, die ihm seinen frisch importieren Datensatz zeigt, ist er an der Reihe ein dummes Gesicht zu machen, denn sein DN sieht nach der »Optimierung« in etwa so aus wie das Geschreibsel eines Schimpansen, der gerade auf der Tastatur seine Morgengymnastik absolviert hat (String abgekürzt): #....\C3\A9 M\C3\BCllerh\C3\BCbschenh\C3\B6fchenhausen\C3\9F.... dn::...dWlkPVJlbmXDqSBN...undsoweiterundsofort...x1c2VyL1Ps LG91PTQ5NTUsb3U9Y3VzdCxvPUdBRA==
Das Problem ist, dass Strings mit Umlauten, Sonder- und/oder Leerzeichen beim Import automatisch Base64-codiert werden, und damit auf der Kommandozeile ohne weiteres nicht mehr lesbar sind. Daher die ganz einfache Regel: no cn für User im dn, und alles wird gutgehen. P.S: Daher sollten wir auch bei Objekten, die kein uid-Attribut besitzen und »ihren« DN nur per cn bilden können (wie z.B. posixGroup), den Namen mit Bedacht wählen. Denn: Tut es wirklich weh, den Gruppennamen »cn=DomainAdmins« statt »cn=Domänen Admins« zu verwenden? Nicht wirklich.
Noch ein paar Beispiele zu diversen Objektklassen und dem, was sie an Attributen zur Verfügung stellen: objectClass: posixAccount
34
1198.book Seite 35 Donnerstag, 5. Februar 2009 3:02 15
Nicht nach Schema F: die OpenLDAP-Schemas
Das Objekt hat die Attribute eines Unix-Users: objectClass: inetOrgPerson
Das Objekt besitzt Attribute wie Nachname, Telefonnummer und Mail-Adresse. objectClass: shadowAccount
Das Objekt authentifiziert sich mit einem Shadow-Passwort. objectClass: sambaSAMAccount
Dem Objekt sind die Attribute eines Samba-Users zugeordnet. Fazit Die durch einen Distinguished Name eindeutig adressierten Entitäten eines Verzeichnisdienstes nennt man Objekte. Objekte gehören einer oder mehreren Objektklassen an.
Die Zugehörigkeit zu einer Objektklasse stattet das Objekt mit Attributen dieser Klasse aus. Die Attribute eines Objekts sind seine Eigenschaften, wie z. B. Name, Anschrift, Telefonnummer. Die Objektklassen bestimmen darüber, welche ihrer Attribute Werte besitzen müssen und welche optional sind.
Bevor wir unseren LDAP-Server starten und mit den Kommandozeilentools beharken, müssen wir zum grundlegenden Verständnis auf jeden Fall noch einen Blick hinter die Kulissen der Schemadateien werfen. Denn sie bilden die Basis für alle Objekte und Attribute, – und damit das Kernstück der »Datenbank« – die uns unser LDAP zur Verfügung stellt. Und vor allem sind sie eines nicht: nach Schema F …
1.7
Nicht nach Schema F: die OpenLDAP-Schemas
Unter einem Schema versteht man im Rahmen der KI-Forschung die Modellierung von Domänen der realen Welt mit dem Ziel eines strukturierten und fundierten Aufbaus von Wissensbasen, damit rechnergestützt maximales Wissen generiert werden kann. Und dieser Satz erklärt auch, warum theoretische Informatiker auf dem Arbeitsmarkt so schwer zu vermitteln sind. Dennoch: Der Satz ist richtig. Nehmen wir an, wir betrachten die Personalabteilung des Saftladens, der uns ständig viel zu
35
1.7
1198.book Seite 36 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
wenig Geld überweist, als eine Domäne der realen Welt, die es abzubilden gilt. Formulieren wir diese Abbildung – wir können ja nicht anders – aus dem Blickwinkel des Systemadministrators, und … hoppla: Die Geordnete Welt der Personalabteilung teilt sich wie das Rote Meer in technische Ressourcen und Humanressourcen. Die wiederum bestehen jeweils aus Objekten mit Eigenschaften. Das kommt uns bekannt vor? Absolut richtig. Denn der Directory Information Tree – kurz DIT – ist genau so strukturiert. Denken wir uns nun die Objekte und ihre Eigenschaften auf einen Zweck hin organisiert, gelangen wir zu einem Schema. Damit kommen wir nun dem Ziel eines strukturierten und fundierten Aufbaus von Wissensbasen so nahe wie möglich. Genauso funktionieren die OpenLDAP-Schemas. Es gibt einen Zweck, und das Schema stellt die notwendigen Ressourcen zur Verfügung. Lautet der Zweck z.B. »Anmeldung an ein Unix-System«, so ist das Mittel dazu das NISSchema, das die erforderlichen Objektklassen wie z.B. posixAccount und seine Attribute bereitstellt.
1.7.1
core, cosine, inetOrgPerson, samba und einiges mehr
Die Schemadateien liegen im Unterordner /schema/ des eigentlichen LDAPArbeits-Ordners, typischerweise bei den meisten Distributionen unter /etc/ (open)ldap/*. Werfen wir nun einen kurzen Blick in das nis.schema, um den Aufbau besser zu verstehen: Das folgende Listing zeigt uns einen Teil des NIS-Schemas (Achtung, einige Zeilen sind hier umbrochen): # Attribute Type Definitions attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber' DESC 'An integer uniquely identifying a user in an \ administrative domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber' DESC 'An integer uniquely identifying a group in an \ administrative domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) ...<schnipp>... attributetype ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory' DESC 'The absolute path to the home directory' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
36
1198.book Seite 37 Donnerstag, 5. Februar 2009 3:02 15
Nicht nach Schema F: die OpenLDAP-Schemas
attributetype ( 1.3.6.1.1.1.1.4 NAME 'loginShell' DESC 'The path to the login shell' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) # Object Class Definitions objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY DESC 'Abstraction of an account with POSIX attributes' MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) )
Wir sehen hier eine eindeutige Unterteilung in Attribute und Objekte. Ebenfalls erkennen wir, dass die Attribute vor den Objektklassen definiert werden. Warum? Ganz einfach: Die Objektlassen werden aus einer Ansammlung der zuvor definierten Attribute gebildet. Also definitiv kein Henne-Ei-Problem. Wir erkennen Attribute wie loginShell und homeDirectory und z.B. die Objektklasse posixAccount, also alles Details, die auf die Informationen hinweisen, die wir im Allgemeinen für Unix/Linux-User-Accounts benötigen. (Diese Informationen bzw. »Datenbankfelder« liegen bei einer »normalen«, filebasierten Authentifizierung wie bereits erwähnt in den Dateien /etc/passwd und /etc/shadow.) Zurück zu den Objekten: Jedes Attribut und jede Objektklasse hat einen eindeutigen Namensbezeichner, »NAME«. Das ist nichts anderes als der menschenlesbare und von System interpretierte Alias der OID des Attributs oder der Objektklasse. Im Listing oben können wir so z.B. die bereits erwähnten Bezeichner uidNumber, gidNumber usw. ausmachen. Betrachten wir nun die Objektklasse mit dem Namensbezeichner posixAccount: Dort erkennen wir, dass einige Attribute aufgelistet sind, aus denen sich diese Objektklasse per Definition zusammensetzt. Dort fällt sofort die bereits erwähnte Unterteilung der Attribute auf, und zwar in »MUST« und »MAY«. Und das bedeutet, wie wir bereits wissen, die Unterteilung in Pflichtattribute (»MUST«) und optionale Attribute (»MAY«). MUST-Attribute müssen immer gesetzt werden, MAY-Attribute können gesetzt werden, müssen aber nicht. In einer gewissen Weise kann man sich auch den Bezug zwischen Objekten und Attributen wie in einer objektorientierten Programmiersprache vorstellen. In einer Hochprogrammiersprache könnte ein Objekt wie z.B. window die Eigenschaften (Attribute) color, width und height haben, von denen einige in jedem Fall Werte besitzen müssen, andere nicht. Die übliche Syntax hierbei wäre immer:
37
1.7
1198.book Seite 38 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
Objekt.Eigenschaft
wobei ein Objekt fast immer mehrere Eigenschaften (Attribute) besitzen kann: window.color window.width window.height
Ein Fenster müsste z.B. in jedem Fall die Eigenschaften Höhe und Breite besitzen; die Farbe ist dabei lediglich eine optionale Komponente, die für die Funktion des Fensters nebensächlich ist. Und um nun wieder Bezug zum schlauen Satz am Anfang dieses Abschnitts zu nehmen: Die Schemadateien enthalten also die notwendige Struktur, damit wir rechnergestützt maximales Wissen generieren können. Zusammenfassend können wir also sagen: 왘 Ein LDAP-Schema beschreibt die Liste möglicher Typen von Einträgen (die man als Objektklassen bezeichnet) zusammen mit den mit ihnen verknüpften Attributen: 왘 Die Attribute werden vor den Objektklassen definiert. 왘 Eine Objektklasse kann MUST- und MAY-Attribute besitzen. 왘 Schemadefinitionen werden in Dateien abgelegt, die üblicherweise nach dem Muster Schemaname.schema benannt werden. 왘 Jeder LDAP-Dienst greift auf (mindestens) eine oder mehrere Schemadefinitionen zurück. In ihnen sind die erforderlichen Standard-Objektklassen und ihre zugehörigen Attribute beschrieben. 왘 Es stehen immer nur die Schemas zur Verfügung, die beim Start des LDAP-Servers per Include-Statement in seine statische Konfiguration (slapd.conf) eingebunden sind. Bei der Laufzeitkonfiguration ab Version 2.4 können Schemas – und damit Objektklassen und die ihnen zugehörigen Attribute – z.B. im laufenden Betrieb hinzugefügt und somit auch repliziert werden. Der Beispieleintrag der Schema-Sektion in unserer slapd.conf könnte also z.B. so aussehen: include include include include
38
/etc/openldap/schema/core.schema /etc/openldap/schema/cosine.schema /etc/openldap/schema/inetorgperson.schema /etc/openldap/schema/nis.schema
1198.book Seite 39 Donnerstag, 5. Februar 2009 3:02 15
Nicht nach Schema F: die OpenLDAP-Schemas
1.7.2
Die wichtigsten Schemas und ihre Funktion
Schema
Funktion
core.schema
Standard X.501 (93) enthält Standardattribute, die grundsätzlich eingebunden werden müssen.
cosine.schema
LDAPv3-Schema, das vom X.500 COSINE-Schema abgeleitet ist. Es enthält wichtige Standardattribute der Version 3.
inetorgperson.schema
Enthält einige nützliche Attribute für den Aufbau eines organisationsorientierten Dienstes. Abhängig von core.schema und cosine.schema.
nis.schema
Attributdefinition, um LDAP als Network Information Service (NIS) zu nutzen – Standard für Linux/Unix-User.
openldap.schema
Einige wenige Zusatzattribute vom OpenLDAP-Projekt. Benötigt core, cosine und inetorgperson.
samba(3).schema
Enthält die entsprechenden Objektklassen, um Userobjekte mit Samba-spezifischen Attributen auszustatten und via LDAP zu verwalten
misc.schema
Enthält einige Entwürfe für zusätzliche Mail-Attribute. Der Kommentar aus dieser Datei: Not recommended for production use! Use with extreme caution! sollte ausreichend sein.
dyngroup.schema
Wird in Verbindung mit dem Overlay dynlist zur Erzeugung von dynamischen Gruppen-Objekten benötigt.
ppolicy.schema
Schema für die Bereitstellung von Passwort-Richtlinien. Leider noch kein Standard, und die gleichzeitige Verwendung von PAM ist nicht möglich.
Tabelle 1.1 Schemas und Ihre Funktion
Wir sehen also: alles recht nützliche Schemas, bis auf misc. Daher: misc – du musst leider draußen bleiben … Eine wichtige Anmerkung in Bezug auf Schemas und OpenLDAP in der Protokollversion 3: Seit der Version 3 ist von der Clientseite das so genannte SchemaDiscovery möglich. Dadurch ist der Client imstande zu prüfen, welche Objektklassen und Attribute der LDAP-Server anhand der eingebundenen Schemas zur Verfügung stellt und welche Syntax, Matching Rules und Controls er kennt. Mehr zu diesen Begriffen in den folgenden Abschnitten. Beispiele zum Schema-Discovery finden wir im Abschnitt 2.3, »Fingerübungen«. Die globalen Versionsspezifikationen von LDAPv3 finden sich im Anhang. Noch ein Wort zu den Standard-Schemas im LDIF-Format (core.ldif, cosine.ldif usw.), die sich üblicherweise ebenfalls im OpenLDAP-Konfigurations-Unterordner ../schema/ befinden: Hierbei handelt es sich um Schemas, die bereits im
39
1.7
1198.book Seite 40 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
LDAP Data Interchange Format (abgekürzt: LDIF) zur direkten Verwendung innerhalb der Online-Konfiguration vorkonfiguriert sind. Mehr zu dem Thema in den folgenden Kapiteln.
1.7.3
Eindeutige Identifikation mit OIDs
Jede Objektklasse und jedes Attribut ist eindeutig durch einen numerischen OID (Object IDentifier, siehe unser Listing aus dem nis.schema aus Abschnitt 1.7.1, »core, cosine, inetOrgPerson, samba und einiges mehr«) gekennzeichnet. Die OIDs sind in den Standard-Schemas fest zugeordnet und sollten auf gar keinen Fall verändert werden. Wir können uns das am ehesten vorstellen wie die fest vergebenen MAC-Adressen auf Netzwerkkarten oder eindeutige IP-Adressen im Internet. Wir können allerdings für unsere Firma/Uni/etc. eine eigene OID beantragen und mit Hilfe dieser Kern-OID durch Erweiterung des Adressraums unser eigenes Schema erzeugen oder kollisionsfrei Attribute zu bestehenden Schemas hinzufügen. Die OIDs sind in einer Weise dargestellt, wie man sie seit Ludwig Wittgensteins »Tractatus logico-mathematicus« kennt: Punkt.Unterpunkt.Unterunterpunkt.etc.pp
Das Ganze wird entsprechend durch Zahlenketten dargestellt, wobei der führende Teil der Kette, der ja immer gleich bleibt, durch einen zugeordneten Namen ersetzt werden kann. Ein Beispiel: 1.1 OID der Firma 1.1.2 LDAP-Elemente 1.1.2.1 Attribut-Typen 1.1.2.1.1 meineAttribute 1.1.2.2 Objektklassen 1.1.2.2.1 meineObjektklassen
Nehmen wir an, die IANA hätte uns den ID-Block 56.8.78.77 zugewiesen. Dann hätten wir eine Menge Zahlen zu tippen bei jeder Schemadefinition. Stattdessen lässt sich 56.8.78.77 durch eine Zuweisung wie meineOID ersetzen. Man gelangt dann zu so etwas wie: MeineOID.1 MeineOID.1.1 MeineOID.1.2
Auf diese Weise wird es möglich, für eigene Anwendungen spezialisierte Schemas zu erzeugen. Ein Beispiel, das nahe liegt, wäre etwa ein sip.schema, das Internet-Telefonie an einen Verzeichnisdienst koppelt, insbesondere Attribute, die
40
1198.book Seite 41 Donnerstag, 5. Februar 2009 3:02 15
Nicht nach Schema F: die OpenLDAP-Schemas
bisher nicht zur Verfügung standen, sagen wir: videoPhone (boolean: yes/no) oder transferSpeed (numeric). Möglich ist es auch, vorhandene Schemas um firmenspezifische Attribute zu erweitern oder etwas in der Art von personal.schema auf die Bedürfnisse der Personalabteilung hin zu konstruieren. Aber Achtung! Bei all der Konstruiererei sollte man immer im Hinterkopf behalten, dass man nicht an den Standard-Schemas herumbiegen sollte, denn dadurch verscherzt man sich gegebenenfalls die Kompatibilität mit anderen OpenLDAP-Verzeichnissen, die unmodifizierte Standard-Schemas verwenden. Zudem lassen die vorhandenen Standard-Schemas in der Regel kaum Wünsche offen.
Eine intelligente Alternative zur Modifikation von Standard-Schemas bietet – wie bereits erwähnt- ein eigendefiniertes Schema. Wir werden diese Thematik der eigendefinierten Objektklassen, Attribute und Schemas im Abschnitt 3.9, »Selbst ist der Admin – das selbstdefinierte Schema«, noch eingehend beleuchten. Fassen wir also noch einmal kurz zusammen: 왘 OID (Object Identifier) bezeichnen eindeutig die definierten Attribute und Objektklassen eines Schemas. 왘 Mit einer eigenen Root-OID lassen sich Ableitungen für eigene Attribute oder Objektklassen erzeugen. 왘 So lassen sich vorhandenen Schemas Attribute hinzufügen oder komplett neue Schemadefinitionen erzeugen. 왘 Beim Ändern von »Standard-Schemas« muss immer die Kompatibilität zu anderen Verzeichnissen im Hinterkopf behalten werden.
1.7.4
Erbschaftsangelegenheiten: die Welt der Objektklassen
Damit’s hier was zu erben gibt, muss niemand sterben. Und den Rechtsanwalt brauchen wir auch nicht. Hier geht es eher um die ewige Frage der Klassenzugehörigkeit. Klassenzugehörigkeit? Genau. Von Objektklassen ist die Rede. Wir haben von Objekten gehört als den »finalen« Elementen des Directory Information Trees (DIT). Wir wissen mittlerweile, dass diese Objekte Eigenschaften haben, die Attribute genannt werden. Eine dieser Eigenschaften ist immer der (Distinguished-) Name des Objekts. Und wir können zwischen zwingend obligatorischen MUSTAttributen und den wahlweise mit Inhalt gefüllten (fakultativen) MAY-Attributen unterscheiden. Woher aber kommen all diese Attribute? Nein, die bringt weder der Storch noch der Osterbeagle. Sie werden üblicherweise vererbt.
41
1.7
1198.book Seite 42 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
Zunächst: Es gibt derzeit drei mögliche Typen von Objektklassen. Sie werden ABSTRACT, STRUCTURAL und AUXILIARY genannt. Betrachten wir der Reihe nach diese Objektklassentypen, dann wird die Vererbungsdefinition transparenter. ABSTRACT: Die Objektklasse des Typs ABSTRACT stellt im eigentlichen Sinne keine Objekte und Attribute zur Verfügung, sie dient nur dazu, dass andere Objektklassen von ihr abgleitet werden (wie eine Art Vorlage bzw. Template, siehe auch hier wieder die Analogie zur objektorientierten Programmierung). Sie ist also nicht »fassbar«, wenn man es so ausdrücken will, daher passt die Bezeichnung ABSTRACT auch recht gut. Sie dient dazu, um die von ihr abgeleiteten »echten« Objektklassen mit bestimmten Eigenschaften auszustatten. Das perfekte Beispiel für eine ABSTRACT-Objektklasse ist top. top wäre in diesem Sinne wohl am ehesten als »Mutter aller Objektklassen« zu bezeichnen. Ein weiteres Beispiel wäre alias. Ein entsprechender Eintrag in einem Datensatz für die Objektklasse top würde so aussehen: objectClass: top
STRUCTURAL: Eine als STRUCTURAL definierte Objektklasse kann man sich am ehesten als Objektklasse vorstellen, welche die tatsächlich im DIT verwendeten »echten« Objekte beschreibt. Ein praktisches Beispiel dafür ist die Objektklasse person, mit der sich eine »echte« Person im DIT darstellen lässt. Gemäß X.501-Definition muss jeder DIT-Eintrag zumindest von einer »echten« Objektklasse des Typs STRUCTURAL abgeleitet sein. Ein Objekt im DIT – z.B. ein Userobjekt –, das mit Hilfe einer bestimmten, strukturellen Klasse gebildet wurde, konnte in älteren OpenLDAP-Versionen NICHT im Nachhinein einer anderen strukturellen Objektklasse zugewiesen werden. So konnte zum Beispiel ein User-Objekt, das über die Objektklasse organizationalPerson gebildet wurde, nicht nachträglich der – vererbungstechnisch (s.u.) korrekten – Objektklasse inetOrgPerson zugeordnet werden, die alle Attribute von organizationalPerson enthält. Als Vorgehensweise in diesem Fall blieb nur Löschung und Neuanlage des Objekts mit der gewünschten Klassenzuordnung. Seit Version 2.4 können wir diese »Einschränkung« mit Hilfe spezieller Mechanismen (manage-Privilegien, ldap extended Operations), die wir in späteren Kapiteln noch ausführlich erörtern werden, umgehen. Inwiefern das sinnvoll, notwendig oder gar unumgänglich ist, hängt natürlich immer vom jeweiligen Szenario ab. Hierzu wie gesagt später mehr.
42
1198.book Seite 43 Donnerstag, 5. Februar 2009 3:02 15
Nicht nach Schema F: die OpenLDAP-Schemas
AUXILIARY: (engl. zusätzlich) Mit dieser Objektklasse können einer bestehenden Objektklasse neue Eigenschaften (Attribute) hinzugefügt werden. Diese müssen jedoch bereits bekannt sein (Reihenfolge der Schema-Includes, dazu gleich mehr). AUXILIARY kann nicht »stand-alone« verwendet werden, es setzt zwingend eine übergeordnete, strukturelle Objektklasse voraus. Ein Beispiel für eine AUXILIARY-Objektklasse wäre posixAccount aus dem nis.schema. Und wie sieht das Ganze nun tatsächlich aus? Betrachten wir hierzu einfach drei typische strukturelle Objektklassen unseres DITs, die hierarchisch von top und schließlich voneinander abgeleitet sind: Die Vererbung geht exakt in dieser Reihenfolge vonstatten: objectClass: top ### ABSTRACT, nur zur Vererbung objectClass: person ### STRUCTURAL, abgeleitet von top objectclass: organizationalPerson ### STRUCTURAL, abgeleitet von person objectclass: inetOrgPerson ### STRUCTURAL, abgeleitet von organizationalPerson
Die Objektklasse top, Typ ABSTRACT, steht wie bereits erläutert an der Spitze unserer Hierarchie. In den Schemadefinitionen (core.schema und inetorgperson.schema) findet sich die Vererbung/Ableitung jeweils in der Zeile SUP STRUCTURAL der jeweiligen Objektklasse. Betrachten wir hierzu die Objektklasse »person«: Ein #> grep 2.5.6.6 core.schema –A 4
führt Folgendes zutage: objectclass ( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
Deuten wir die dritte Zeile: Der Eintrag SUP top STRUCTURAL besagt, dass die Objektklasse person von der übergeordneten (engl. SUPerior), abstrakten Objektklasse top abgeleitet wurde und somit automatisch ihre Attribute erbt. Es besagt weiterhin, dass person eine strukturelle Objektklasse (STRUCTURAL) darstellt, also eine eigenständige, »echte« Objektklasse mit den dazugehörigen MUST-/
43
1.7
1198.book Seite 44 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
MAY-Attributen abbildet, die auch »stand-alone« eingesetzt werden kann und eine eigenständige Objekthierarchie abbildet. Nun zur Objektklasse organizationalPerson: Ein #> grep organizationalPerson core.schema -A 3
führt nun Folgendes zutage: objectclass ( 2.5.6.7 NAME 'organizationalPerson' DESC 'RFC2256: an organizational person' SUP person STRUCTURAL
Zeile 3 zeigt uns wiederum eindeutig, dass die Objektklasse organizationalPerson von der Objektklasse person abgeleitet wurde und damit indirekt auch von top. In diesem Fall handelt es sich auch um eine »echte« Objektklasse des Typs STRUCTURAL. Die strukturelle Objektklasse inetOrgPerson wiederum ist abgeleitet von organizationalPerson. Hinweis: Die Objektklasse inetOrgPerson ist nicht mit der gleich lautenden Schemadatei zu verwechseln, der sie entstammt! Sie stellt übrigens eine der meistgenutzten Objektklassen überhaupt dar. Um die Thematik zu verdeutlichen, schauen wir uns den Kommentar im Header des Samba(3).schemas an: ## Prerequisite schemas - uid (cosine.schema) ## - displayName (inetorgperson.schema) ## - gidNumber (nis.schema)
Die Objektklasse sambaSamAccount (aus dem samba(3).schema, Typ AUXILIARY) leitet sich direkt von top ab und erweitert top um bestimmte Attribute, die jedoch zum Teil aus anderen Kern-Schemas unseres LDAP stammen, in diesem Fall cosine, inetorgperson und nis. Wie dem Kommentar unschwer zu entnehmen ist, ist es eine zwingende Vorgabe, dass die entsprechenden Schemas mit den erforderlichen Attributen unserem LDAP-Server auf jeden Fall bereits vor der Einbindung des samba(3).schema bekannt sein müssen. Wir erkennen: Die korrekte Lade-Reihenfolge der Schema-Dateien ist für unseren OpenLDAP zwangsläufig von immenser Wichtigkeit. Beim Start des LDAPDaemons mit falsch angeordneten Schemas dürfte höchstwahrscheinlich die folgende oder eine ähnliche Fehlermeldung auf der Konsole auftauchen: AttributeType not found:
44
1198.book Seite 45 Donnerstag, 5. Februar 2009 3:02 15
Kleine Baumschule – grundsätzliche Überlegungen zum Treedesign
Recht gut kann man das Einlesen der Objekte und Attribute aus den Schemas auch verfolgen, wenn man sich die Meldungen unseres OpenLDAP-Daemons in einem detaillierten Debug-Level ansieht, dazu später mehr. Einen weitaus tieferen und ausführlicheren Blick in die Eingeweide der Schemas, Objektklassen und Attribute werden wir im Abschnitt 3.9, »Selbst ist der Admin – das eigendefinierte Schema« vornehmen. Und, wie der Titel bereits vermuten lässt, ein selbstgebautes Schema in unseren LDAP-Server importieren.
So weit der Teil, der das grundlegende Verständnis der »Datenbankfelder« unseres LDAP-Servers – seiner Objektklassen, Attribute und Schemas – behandelt. Bevor wir zum körperlich aktiveren Teil schreiten, dem Setup unseres LDAP-Servers, werfen wir noch einen Blick auf das, was jeder Admin vor der Einrichtung des eigentlichen Trees tun sollte: Er sollte sich Gedanken, darüber machen, wie er sein virtuelles Bonsai-Bäumchen so designen kann, das es auch später, wenn das Ding auf die Größe eines Mammutbaumes angewachsen ist, noch übersichtlich und pflegeleicht bleibt.
1.8
Kleine Baumschule – grundsätzliche Überlegungen zum Treedesign
Wir waren in der Schöpfung tätig, Abteilung Büsche und Bäume. Unsere letzte Entwicklung war 200 Meter hoch, knallrot und stank fürchterlich. Da hat ER uns gefeuert … Time Bandits, GB 1981 Wir sehen, die Gestaltung von Bäumen ist bisweilen nicht ohne Risiko. Und auch bei der Konzeptionierung eines Directory Information Trees lauert der eine oder andere Fallstrick. Betrachten wir die Dinge der Reihe nach: Wir haben bereits gesehen, wie in einem LDAP-basierten Verzeichnisdienst Namen von Objekten gebildet werden, wie z.B.: cn=ldapadmin,dc=local,dc=site uid=ckent,ou=verkauf,dc=local,dc=site
Auf diese Weise folgt eine Beschreibung vom Blatt über seinen Zweig und Ast zu Stamm und Wurzel des DITs. Klingt einfach, ist es auch. Der Teufel steckt aber, wie üblich, im Detail. Zuerst einmal: Size matters. Ein kleines Unternehmen mit einem kleinen Gesamtbaum kommt längst nicht so schnell in Schwierigkeiten wie ein multinationaler Konzern. Das liegt schon allein daran, dass kleine Unternehmen in der Regel
45
1.8
1198.book Seite 46 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
nicht so schnell in die Lage kommen, ihren DIT länderübergreifend aufzuteilen, denn bei einigen Hundert Objekten im Bäumchen ist derlei in der Regel einfach nicht notwendig. Wenn man dagegen beispielsweise Infrastrukturen von großen, international agierenden Telekom-Carriern betrachtet, die locker auf Objektzahlen im zwei- bis dreistelligen Millionenbereich kommen, wird das Dilemma schnell klar. Ein solcher DIT ist als Monolith weder handhabbar noch überschaubar und muss schon aus Gründen der Datensicherheit und Performance in nationale und gegebenenfalls kommunale Teilbäume zerlegt (partitioniert) werden, die so separat repliziert werden können und sollten. Zum anderen haben wir bei großen DITs (und einer dort schon logistisch bedingten, nicht flachen »Old-School«-Hierarchie) üblicherweise immer gleichartige Unterabteilungen im Baum: lokales Management, Sekretariat, Produktion, Entwicklung, Verkauf usw. an jedem Standort. All diese Blätter müssen konsistente, widerspruchsfreie Pfade aufweisen und auch separat replizierbar sein. Dann gibt es noch die Fragen der Sicherheit und der Zugriffssteuerung. Das erfordert ein überlegtes Treedesign, denn im Nachhinein lässt sich das krumme Bäumchen in der Regel nur schwer wieder geradebiegen. Also schauen wir uns im Folgenden ein paar der möglichen Ansätze an. Und so blöd es auch klingen mag: Mit Papier, Bleistift und einer Skizze anzufangen, ist auch im Zeitalter von Kernfusions-Experimenten, Marssonden und Quad-Core-Prozessoren der erste Schritt zum richtigen Ansatz.
1.8.1
Den Directory Information Tree gestalten
Hier existieren zwei unterschiedlichen Grundauffassungen, die beide ihre Berechtigung haben. Bei einem weitgehend monolithischen Datenraum, wie z.B. dem einer großen Universität, können wir die primäre Struktur direkt abbilden. Dabei entsteht ein Baum wie der folgende:
TU Dortmund
Physik
Mathematik
Informatik
Biotechnologie
Abbildung 1.2 Monolithische DIT-Struktur für einen einzelnen Standort
Damit gelangen wir zu Einträgen wie:
46
1198.book Seite 47 Donnerstag, 5. Februar 2009 3:02 15
Kleine Baumschule – grundsätzliche Überlegungen zum Treedesign
cn=ldapadmin,dc=tu-dortmund,dc=de uid=profmeier,ou=physik,dc=tu-dortmund,dc=de uid=profmueller,ou=mathematik,dc=tu-dortmund,dc=de
Kurz : Alle Abteilungen bzw. Fachbereiche, die organisatorisch direkt unterhalb der BaseDN dc=tu-dortmund,dc=de angesiedelt sind, haben ihre eigenen organizationalUnit’s, und könnten so einfach bei Bedarf ausgegliedert und autark von den jeweiligen Fachbereichen betrieben werden. Das gleiche Konzept könnte für ein multinationales Unternehmen dann in etwa so aussehen:
Tyrell Corporation
Los Angeles
Berlin
Paris
Tokio
Abbildung 1.3 Partitionierte DIT-Struktur für mehrere Standorte
und der DN eines Mitarbeiter-Objekts könnte sich so darstellen: uid=rdeckard,ou=bladerunner,l=losAngeles,o=tyrell,c=com
1.8.2
Sinnvolle Strukturen abbilden
Sinn soll’s natürlich immer machen – und prinzipiell macht es immer den meisten Sinn, gleichartige Objekte in eigenen Units zusammenzufassen. Auf den konkreten Einsatzfall bezogen, bedeutet das in der Regel z.B. User- und Maschinenkonten in separaten ou’s zu verwalten. Das hat keine LDAP-technische Notwendigkeit, hilft uns aber, organisatorische Klarheit in den DIT zu bringen und die Übersicht zu behalten:
TU Dortmund Physik
Dozenten
Computer
Laborgeräte
Abbildung 1.4 Gruppierung von jeweils identischen Objekten
47
1.8
1198.book Seite 48 Donnerstag, 5. Februar 2009 3:02 15
1
Vorab: Was man wissen sollte
Das führt uns zu folgenden Adressierungen: uid=profmeier,ou=dozenten,ou=physik,dc=tu-dortmund,dc=de uid=workstation1$,ou=computer,ou=physik,dc=tu-dortmund,dc=de cn=fusionsreaktor,ou=Geraete,ou=physik,dc=tu-dortmund,dc=de
1.8.3
Anwendungsnähe
Wir sollten unseren DIT immer so einteilen, dass seine Sub-Kontexte bzw. Teilbäume immer nah bei den Anwendungen sind, die auf sie zugreifen. Wenn wir z.B. einen Online-Shop betreiben und unsere Kunden via LDAP authentifizieren und verwalten wollen, sollte der Subtree (engl. Unterbaum, Teilbaum) »ou=webuser« üblicherweise in derselben Lokalität betrieben werden, in der auch unsere Webanwendung läuft. Das bringt kurze Latenzzeiten, macht die User glücklich und das Debugging im Fehlerfall deutlich einfacher. Daher gilt: Wir sollten in jedem Fall ein Treedesign vermeiden, bei denen Querys quer durchs Intranet und womöglich noch durch mehrere Adressräume geroutet werden müssen. So viel zu unserem kleinen Exkurs über die Baumschule. Im nächsten Kapitel geht’s dann nun auch endlich in die Praxis, und wir beharken unseren LDAP-Server – nach seiner Installation und dem Setup- kräftig mit den KommandozeilenTools. Und etwas später dann, im Abschnitt 3.2, »Replikation – oder: Frag dich nie, ob ein Server ausfällt. Frag dich immer nur, wann.«, werden wir uns genau anschauen, wie wir die Konzepte von Teilbäumen und Replikationen in der Praxis umsetzen können. Let’s rock …
48
1198.book Seite 49 Donnerstag, 5. Februar 2009 3:02 15
Es gibt nur zwei Arten von Daten: gesicherte und unwichtige.
2
OpenLDAP installieren und betreiben
2.1
OpenLDAP-Basics
So war das mit dem Internet, den Protokollen, Objekten und Designfragen. Sehr nützlich, aber bisher eben rein theoretisch. Und da der Anleser kaum Raum für weitschweifende Interpretationen lässt, legen wir nun auch los mit der Installation unseres OpenLDAP-Servers und seiner Komponenten, um unsere Objektdaten so stabil und optimal gesichert wie irgend möglich unterzubringen.
2.1.1
Installation der Pakete
Wie bereits im Vorwort erläutert, geht es uns auch in dieser Neuauflage vor allem darum, einem Administrator die Verfahren und das Know-how an die Hand zu geben, um ein praxistaugliches OpenLDAP-System mit allen relevanten Komponenten perfekt aufsetzen zu können. Unser OpenLDAP-Server soll nach erfolgtem Setup genau das tun, wofür er gedacht ist: er läuft stabil und (dank Replikation und Verschlüsselung) noch dazu in jeder Beziehung sicher, minimiert als zentrale Datenbank den administrativen Aufwand und wirkt sich so einfach positiv auf die seelische Ausgeglichenheit und Nachtruhe das Admins aus. Ein weiterer wichtiger Schwerpunkt unserer folgenden Betrachtungen liegt ebenfalls wiederum in der Auflistung typischer Fehler, die bei der Konfiguration des Systems gemacht werden können, ihren Ursachen – und, am allerwichtigsten: wie man diese Stolpersteine beseitigt. Denn die Fehlersuche und -Analyse ist immer das, was richtig in die Zeit – und damit logischerweise auch direkt ins Geld – geht. Daher findet sich in der Regel am Ende eines jeden größeren Abschnitts eine Zusammenstellung von Checkpunkten, um mögliche Fehlerquellen schnell und effizient aufdecken zu können. Wir beziehen uns bei den Paket- und Konfigurationsangaben primär auf die beiden in Deutschland am weitesten verbreiteten Linux-Distributionen, Debian (von uns in der Version 5 »Lenny« verwendet, die die schon etwas betagte »Etch« bald ablösen wird) und OpenSUSE 11.0, im Folgenden üblicherweise auch oft nur als »SUSE« oder »OSS 11« bezeichnet. Debian dient zudem als Basis für etli-
49
1198.book Seite 50 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
che andere Distributionen (Knoppix, Ubuntu, um nur zwei zu nennen), so dass sich die hier vorgestellten Verfahrensweisen relativ einfach portieren lassen können. Als Basis unserer Betrachtungen beziehen wir uns primär auf OpenLDAP in der – kurz vor Fertigstellung des Buches aktuellsten – Version 2.4.12, dessen distributionsspezifische Pakete für OpenSUSE 11.0 als RPMs in diversen Repositories vorliegen, wie etwa hier: http://download.opensuse.org/repositories/network:/ ldap:/OpenLDAP:/RE24/openSUSE_11.0 Debian verwendet out of the box die nicht mehr ganz aktuelle 2.4.11, jedoch dürfte ein Upgrade nicht mehr allzu lange auf sich warten lassen. Aber allein im Hinblick auf die aktuellsten Bugfixes (und die GnuTLS-Problematik, dazu später mehr) sollten Debian-User ernsthaft darüber nachdenken, die aktuellste Version gegebenenfalls vorab manuell zu installieren. Eine wichtige Änderung für OpenLDAP 2.4.12 hat sich vor allem hinsichtlich der verwendbaren Datenbanken ergeben, denn dieses OpenLDAP-Release erwartet nun erstmalig nach vielen Jahren eine neuere Version der Oracle Berkeley DB (oder kurz BDB), und zwar minimal Version 4.4 statt der vormals noch zulässigen 4.2.52. Detaillierte Infos und einiges mehr zu diesem Thema im Abschnitt 3.8 über die BDB: »Larry und die schläfrigen Katzen«. Da die Kernfunktionalitäten, abgesehen von Bugfixes und der gerade erwähnten Thematik, jedoch weitestgehend identisch für OpenLDAP 2.4.11 und 2.4.12 sind, stellt dies für alle nachfolgenden Betrachtungen kein größeres Problem dar. An den vakanten Stellen werden wir auf die gegebenenfalls vorliegenden Unterschiede explizit hinweisen. Eine kurze Vorab-Übersicht der von OpenLDAP 2.4.12 minimal benötigten Software findet sich unter: http://www.openldap.org/doc/admin24/appendix-recommended-versions.html. Auf die wichtigsten Unterschiede zu den Vorgängerversionen < 2.4.11 werden wir an den jeweils erforderlichen Stellen natürlich auch hinweisen. Dabei sollte allerdings jedem Leser klar sein, dass wir kaum jede noch so kleine Besonderheit aller möglichen Vorgängerversionen »erschlagen« können; ebenso wenig alle Abweichungen zu anderen Distributionen. Hier hilft wie üblich wirklich nur ein Studium der versionsbezogenen Manpages der jeweiligen, distributionsspezifischen Komponenten. Wir weisen auch darauf hin, dass wir für alle folgenden Konfigurationen keines der distributionsspezifischen Konfigurationstools wie z.B. OpenSUSE’s YaST verwenden, sondern uns stets auf ein »manuelles« Setup beziehen. Relevant für unsere weiteren Betrachtungen sind hierbei in der Regel die PaketVersionsstände, die zum Zeitpunkt der Erstellung/Fertigstellung dieses Buches dem aktuellen Patchlevel der jeweiligen Distributionspakete entsprechen. Eine komplette, kapitelweise zusammengefasste Auflistung der jeweils verwendeten Pakete findet sich in Anhang A.
50
1198.book Seite 51 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP-Basics
Die wichtigsten Kompilationsoptionen und -parameter der wichtigsten Pakete werden, insofern erforderlich, an der jeweiligen Stelle oder ebenfalls in Anhang (B) angeführt, so dass die jeweiligen Pakete auch jederzeit von Hand mit der relevanten Funktionalität erstellt werden können. Die Sicherstellung der Interoperabilität zwischen den einzelnen Paketen und ihren Features ist bei einem Setup From the Scratch erfahrungsgemäß leider meist etwas diffiziler als bei der Verwendung einer Distribution. Ebenfalls in Anhang (D) findet sich eine Übersicht der wichtigsten Manpages, jeweils nach Kategorien unterteilt (z.B. Server, Client, Backends, Overlay, Samba, Heartbeat, PAM usw.). Apropos Manpages Wenn wir im Folgenden auf manpages verweisen, tun wir dies üblicherweise in den Formen: man (<Manpage-Sektion>) oder ( <Manpage-Sektion>) Bezogen auf den Daemon unseres OpenLDAP-Servers (slapd) würden wir also z.B. auf slapd(8) verweisen, was der ausgeschriebenen Form man 8 slapd entspricht. Infos zu den Manpages selbst, ihren Sektionen und vielem anderen mehr finden sich in man man. Mann, mann … Doch genug der Vorrede und frisch ans Werk. Für eine Basisinstallation benötigen wir die in Anhang A, Sektion »Basic-Setup« gelisteten Pakete. Haben wir bereits ein bestehendes System, hilft bei SUSE ein schnelles: #> rpm –qa | grep
oder #> zypper search
bzw. bei Debian: #> aptitude search | grep ^i
um herauszufinden, welche Pakete bereits installiert sind und welche noch nachinstalliert werden müssen. Das verwendete #> steht hier und in allen folgenden Beispielen für den Kommandoprompt der Shell.
51
2.1
1198.book Seite 52 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
2.1.2
Die Konfigurationsdateien
Nach der Installation der distributionsspezifischen Pakete sehen wir uns kurz die Ablageorte der wichtigsten OpenLDAP-Dateien an. Konfigurations-, Schema- und Datenbankdateien (SUSE) /etc/sysconfig/ldap
SUSE-spez. Konfigurationsdatei für YaST/SuSEconfig, wird im Folgenden nicht behandelt
/etc/sysconfig/openldap SUSE-spez. Konfigurationsdatei für YaST/SuSEconfig, wird im Folgenden nicht behandelt /etc/openldap/slapd.conf OpenLDAP-Server-Konfigurationsdatei /etc/openldap/slapd.d/* OpenLDAP-Server-Konfigurationsordner, ab OpenLDAP 2.3 /etc/openldap/ldap.conf Systemweite Einstellungen für LDAP-Clients. Einstellungen werden gegebenenfalls durch die Dateien ~/.ldaprc bzw. ldaprc im Applikationsordner überschrieben, sofern vorhanden. /etc/ldap.conf
LDAP-Konfigurationsdatei für die PADL-Module pam_ ldap und libnss-ldap
/etc/openldap/schema/* Schemadateien /var/lib/ldap/*
Datenbankdateien
Konfigurations-, Schema- und Datenbankdateien (Debian) /etc/ldap/slapd.conf
OpenLDAP-Server-Konfigurationsdatei
/etc/ldap/slapd.d/*
OpenLDAP-Server-Konfigurationordner, ab OpenLDAP 2.3
/etc/ldap/ldap.conf
Systemweite Einstellungen für LDAP-Clients. Einstellungen werden gegebenenfalls durch die Dateien ~/.ldaprc bzw. ldaprc im Applikationsordner überschrieben, sofern vorhanden.
/etc/libnss-ldap.conf
Konfigurationsdatei für libnss-ldap
/etc/pam_ldap.conf
Konfigurationsdatei für pam_ldap
/etc/ldap/schema/*
Schemadateien
52
1198.book Seite 53 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP-Basics
/etc/default/slapd
Debian-spez. Konfigurationsdatei für ldap, wird im Folgenden nicht behandelt
/var/lib/ldap/*
Datenbankdateien
/usr/lib/ldap/*
Standard-Modulpfad, bei Debian benötigt
Bei einer Kompilation des OpenLDAP-Pakets ohne besondere PREFIX-Angabe für das Installationsverzeichnis liegen die OpenLDAP-relevanten Dateien üblicherweise unter: /usr/local/ An dieser Stelle noch ein kurzer Praxistipp: Zum schnellen Auffinden von Dateien eignet sich hervorragend das Tool locate bzw. slocate. Allerdings ist ein regelmäßiges Update der vom Programm verwendeten Indexdatenbank per updatedb nötig (z.B. per Cronjob).
Werfen wir zuerst einen Blick in die Konfigurationsdatei unseres LDAP-Servers, die slapd.conf. Das ist – in der statischen Form – der zentrale Ort, an dem sich alle Einstellungen des LDAP-Servers finden. Dort können auch Verweise auf externe Konfigurationsdateien per Include-Statement eingeleitet werden. Dieses IncludeStatement erlaubt es, wie wir bereits wissen, auf ausgelagerte Konfigurationsdirektiven zu verweisen, die beim Serverstart automatisch mit eingebunden werden. Der Einsatz ist hauptsächlich im Bereich der Einbindung von Schemadateien bekannt, es bieten sich aber auch andere Einsatzmöglichkeiten an – überall dort, wo Teile der Konfiguration eventuell zu groß und zu unübersichtlich werden könnten. Beispiele dafür wären: include /etc/openldap/acl.conf # Access Control Lists include /etc/openldap/hdb.conf # Database-Optionen include /etc/openldap/replicas.conf # Replikationsdirektiven
So könnte man ausufernde Zugriffsrechte übersichtlicher organisieren, Datenbankoptionen angeben oder umfangreiche Replikations- und PartitionierungsDirektiven separat verwalten. Ein Teil der slapd.conf -Einträge wird bei Debian bereits interaktiv direkt nach der Installation der OpenLDAP-Pakete gesetzt, gemäß der typischen Debian-Philosophie: Was installiert ist, wird auch benutzt. Die Einträge können aber natürlich auch im Nachhinein wieder geändert werden – was sich im Fall Debian leider auch als notwendig erweist, denn einige der möglichen Settings sind leider nicht ganz optimal gewählt. Dazu aber gleich mehr.
53
2.1
1198.book Seite 54 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
2.1.3
Statische Betrachtungen: OpenLDAP-Konfiguration per slapd.conf
Die slapd.conf in ihrer »statischen« Form kann von allen OpenLDAP-Versionen verwendet werden. In Versionen vor 2.3 ist dies die einzige Option, seit OpenLDAP Version 2.3 bietet uns slapd zusätzlich die Option seiner Konfiguration zur Laufzeit. Dazu mehr in Abschnitt 2.4, »Get it on(line) – OpenLDAP-Administration zur Laufzeit«. Die slapd.conf(5) ist üblicherweise in drei Sektionen unterteilt: globale, Backend- und Database-spezifische Direktiven, wobei Backends und zugehörige Databases mehrfach konfiguriert werden können. Schematisch stellt sich dies folgendermaßen dar: < Globale Konfigurationsdirektiven > ------------------------------------backend < Backend–Typ > # Konfigurationsdirektiven für alle Backends eines Typs ------------------------------------database < Database–Typ > # database-spezifische Direktiven
Die Direktiven an sich bilden dabei eine strenge Hierarchie: Globale Direktiven können durch Backend- oder Database-Direktiven überschrieben werden (z.B. ACLs), Backend-Direktiven können durch Database-Direktiven überschrieben werden. Sofern keine Überschreibung stattfindet, besitzen global spezifizierte Direktiven auch in den Backend- und Database-Sektionen Gültigkeit. In etlichen Dokumentationen wird der Begriff Backend oft nicht eindeutig definiert, bzw. wird unter dem Begriff Backend von der eigentlichen Datenbank gesprochen, die den DIT beinhaltet, wie z.B. der Oracle Berkeley DB. Dem ist NICHT so. Das Backend selbst (z.B. hdb/bdb) stellt eine Art Modifikator für die unterliegende Datenbank dar, und über die Backend-Direktive (backend ) werden Regeln für alle nachfolgenden Datenbanken des gleichen Backend-Typs spezifiziert, sofern diese Direktiven nicht innerhalb der Datenbanksektion (database ) anders spezifiziert werden. Backends werden dabei grob in drei Typenklassen unterteilt, und zwar: 왘 Backend-Typen, die Daten direkt abspeichern, wie z.B. bdb oder hdb: 왘 bdb – Backend für die Oracle Berkeley Database; wird im Folgenden noch eingehend besprochen. 왘 hdb – benutzt die gleiche Codebasis wie bdb, verwendet aber eine effektivere, speicherinterne Struktur. Ermöglicht u.a. Subtree-Renaming. Wird im Folgenden noch eingehend besprochen.
54
1198.book Seite 55 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP-Basics
왘 ldbm – (discontinued) besitzt keine Transaktionsfähigkeit, wird daher in Version 2.4 nicht mehr eingesetzt. 왘 ldif – Datenspeicherung im LDIF-Klartetxt-Format. Wird für die LDAPLaufzeit-Konfiguration (slapd.d/ / database config) verwendet. Sollte nicht für größere und/oder komplexe LDAP-Kontexte verwendet werden. Wird im Rahmen der slapd-Online-Konfiguration noch eingehend besprochen. 왘 sql – (experimental) SQL-RDBMS als Datenbank-Backend für LDAP. Ermöglicht Zugriff auf SQL-Datenbestände über LDAP. Stellt weder von der Konfigurierbarkeit noch von der Performance her einen gleichwertigen oder brauchbaren Ersatz für die Berkeley DB dar. Zudem ist das Backend immer noch experimentell. 왘 ndb – (experimental) MySQL-NDB-Cluster-Backend. Spricht direkt mit der MySQL Cluster Storage Engine, unter Umgehung des SQL-Layers (in Abstimmung mit den MySQL-Entwicklern). Daher performanter als das MySQL-Backend und aufgrund des Clusterings ausfallsicherer. Eine beliebige Anzahl von slapds mit back-ndb kann mit dem gleichen MySQL-Cluster verbunden sein. Nicht so performant wie ein Standalone-slapd-hdbGespann, soll jedoch besser skalieren. Leider erst kurz vor Fertigstellung des Buches in OpenLDAP Version 2.4.12 hinzugekommen, zudem noch experimentell, so dass wir dieses Backend nicht mehr behandeln konnten. 왘 Backends, die Daten (wie ein Proxy) zwischenspeichern, z.B. ldap, meta, relay 왘 ldap – agiert als Proxy für einen entfernten LDAP-Server, wird im Folgenden noch angesprochen. 왘 meta – wie ldap, agiert jedoch als Proxy für mehrere LDAP-Server, Erweiterung zu back-ldap. Zitat der Entwickler: »These features, although useful in many scenarios, may result in excessive overhead for some applications, so its use should be carefully considered.« 왘 relay – (experimental) ermöglicht das Mapping/Rewriting eines echten Naming Context (wie z.B. local.site in unseren Beispielen) auf einen virtuellen NC. Benötigt das Overlay rwm. 왘 Backends, die Daten zur Laufzeit generieren, z.B. monitor, dnssrv, perl/shell 왘 monitor – liefert einfache Überwachungsinformationen. Siehe hierzu auch slapd-monitor(5). 왘 dnssrv – (experimental) gibt Referrals entsprechend der DNS-SRV-Einträge zurück 왘 shell/perl – Ausführung von hinterlegten Shell- oder Perl-Skripten
55
2.1
1198.book Seite 56 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Eine gute Übersicht hierzu liefert auch slapd.backends(5). Wichtig dabei ist, dass die Direktiven, die für einen bestimmten Backend-Typ getroffen werden, für alle folgenden Backends dieses Typs Gültigkeit besitzen. Einige der Backends und/oder Overlays erfordern die Einbindung als Modul (Default bei Debian). Dies geschieht mit den Direktiven modulepath und moduleload .la, die allerdings nur dann wirksam sind, wenn openldap mit --enable-modules sowie den entsprechenden --enable-=mod bzw. --enable-overlays=mod kompiliert wurde. Die Sektion innerhalb einer Debian- slapd.conf könnte z.B. wie folgt aussehen, um das bdb- und hdb-Backend sowie die Overlays refint und memberof bereitzustellen: modulepath moduleload moduleload moduleload
/usr/lib/ldap/ back_bdb.la back_hdb.la memberof.la refint.la
Hier ein Beispiel für eine einfache Backend-Direktive, welche für alle BDB-Databases Gültigkeit besitzt, insofern sie nicht dort explizit mit einem anderen Wert gesetzt wird: backend sizelimit
hdb unlimited
Würde die sizelimit-Direktive innerhalb der Database-Sektion getroffen, wäre sie nur für diese eine Datenbank wirksam. Die Konfigurationsdirektiven innerhalb der database-Sektion beziehen sich immer nur auf die eine innerhalb ihrer Sektion spezifizierte Datenbank, wie z.B.: directory
/var/lib/ldap
So viel Information vorab zum Gültigkeitsbereich von Direktiven und zu einigen Backend-Typen. Im Folgenden sehen wir uns einige der elementarsten slapd.conf-Direktiven genauer an. Die Sektionen, zu denen die Direktiven gehören, sind im Folgenden jeweils in Klammern direkt hinter den Direktiven aufgeführt. Die slapd.conf wird auch von etlichen slap*-Befehlen ausgelesen, da diese direkt mit der Datenbank kommunizieren. Noch etwas zur Syntax selbst: Zeilen, die mit einer Raute # beginnen, werden grundsätzlich als Kommentar interpretiert. Ist die Raute eingerückt (nicht am Zeilenanfang), wird die Zeile NICHT als Kommentar interpretiert! Zeilen, die mit einem Leerzeichen beginnen oder eingerückt sind, werden vom slapd immer als Folgezeile der zuvor verwendeten Direktive (!) interpretiert.
56
1198.book Seite 57 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP-Basics
An dieser Stelle noch ein kurzer Hinweis zum verwendeten Editor: Wir haben in unserer langjährigen Praxis die besten Erfahrungen mit dem vi(m) gemacht. Er ist auf fast jedem System vorhanden und bietet hilfreiche Features, die sich vor allem beim Bearbeiten von LDIF-Dateien (noch einmal zur Erinnerung: LDIF=LDAP Data Interchange Format, in den folgenden Kapiteln oft auch einfach nur als LDIF oder ldif bezeichnet) bezahlt machen. Dazu mehr in Abschnitt 2.3, »Fingerübungen – OpenLDAP-Tools auf der Konsole«. Noch ein kurzer Tipp: Um den vi(m) zu einer farbig abgesetzten Darstellung zu bewegen, in seiner Konfigurationsdatei – meist /etc/vimrc – einfach den Parameter »syntax on« aktivieren. Nun zu den Direktiven der slapd.conf, die wir für ein minimales Setup benötigen: Die include-Direktive (global) dient meistens der Integration von Konfigurations- oder Schemadateien. Letztere stellen bestimmte Objektklassen und Attribute zur Verfügung. Alles Grundsätzliche über Schemas, Objektklassen und Attribute haben wir bereits in den vorangegangen Kapiteln erfahren. Bei der Einbindung der Schemas sind zudem folgende Punkte von absoluter Wichtigkeit: 왘 Die Reihenfolge, in der die Schemas eingebunden werden (Vererbung!) 왘 Bei Replikation eine identische Reihenfolge der Include-Statements für die Schemadateien auf Master- und Slave-Server 왘 Bei Replikation unbedingt identische Versionen(!) der Schemas auf Masterund Slave-Server. Seit V 2.4 ist mit Hilfe der Online-Konfiguration auch die Replikation der Schemas selbst möglich, was eine deutliche administrative Vereinfachung darstellt. include
/etc/ldap/schema/core.schema
Die access-Direktiven (Global-, Backend- und Database-spezifisch) dienen der Zugriffsregelung auf den DIT (Directory Information Tree). Geregelt wird der Zugriff über ACLs (Access Control Lists). Sie bestimmen, wer (welches Objekt, z.B. User/Gruppe) wie (z.B. lesend/schreibend/authentifizierend) auf was (welche Objekte) im Verzeichnis zugreifen darf. Eine Auswertung des anfragenden DN (DN = Distinguished Name) kann auch über reguläre Ausdrücke erfolgen. Standardmäßig darf zunächst nur der rootdn (dazu gleich mehr) schreibend zugreifen, alle anderen lesend. ACLs werden wir in Abschnitt 3.7, »Nur mit Clubkarte – Zugriffsregelung durch ACLs« eingehend behandeln. Wichtig hierbei: Wenn aus Gründen der Übersichtlichkeit die Zeilen umbrochen werden, immer die Einrückung beachten → Leerzeichen am Anfang = Folgezeile der vorhergehenden Direktive!
57
2.1
1198.book Seite 58 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
access to attrs=userPassword by self write by * auth access to * by * read
Die defaultsearchbase -Direktive (global) kümmert sich um Clientanfragen, bei denen keine BaseDN übermittelt wurde, und stellt sie auf die hier angegebene Suchbasis ein. Korrespondierende Einstellung wäre die BASE-Direktive in der ldap.conf-Client-Konfiguration. defaultsearchbase dc=local,dc=site
Die ServerID- Direktive (Global) setzt eine 4-stellige Integer-Zahl, die einen Wert von 0–4095 annehmen kann. Die ServerID wird in Verbindung mit Standby-/ Multi-Master-Replikation benötigt, um jeden Server durch eine ID replikationstechnisch eindeutig zu kennzeichnen. Ergänzend zu jeder ID kann (bzw. muß in bestimmten Fällen, dazu später mehr) eine LDAP-URL angegeben werden, die ergänzend auf den jeweiligen Server zeigt. Korrespondierende Direktive: mirromode ServerID
1
ldap://ldapmaster.local.site
Die backend-Direktive (Backend) leitet Direktiven für Database-Backends eines bestimmten Typs ein (siehe oben). Hierüber können Direktiven für alle nachfolgenden Backends des gleichen Typs (z.B. hdb oder bdb) gesetzt werden. Für ein einfaches Standard-Setup ist diese Direktive nicht zwingend erforderlich. backend hdb
Die database-Direktive (Database) definiert die Schnittstelle zur eigentlichen Datenbank unseres LDAP-Servers und fungiert gleichzeitig als Modifikator für alle Requests an genau diese unterliegende Datenbank. Über diese Schnittstelle werden die Daten in entsprechend aufbereiteter Form in der eigentlichen Datenbank abgelegt. So unterstützt das hdb-Backend z.B. im Gegensatz zum bdbBackend Subtree-Renaming. Die Einstellung korrespondiert mit der BackendDirektive (Backend) und kann bei einmal gesetzter database-Direktive nicht einfach geändert werden. Soll z.B. die database von bdb auf hdb umgestellt werden, weil plötzlich Subtree-Renaming gefordert ist, muss der Tree gesichert, die Datenbank gelöscht und der Baum komplett neu eingelesen werden. Als Datenbank selbst kommt üblicherweise eine Oracle Berkeley Database, (i.F. auch Berkeley DB oder einfach nur bdb bzw. BDB genannt) zum Einsatz. Die BDB bringt neben ihrer Performance eine weitere, unabdingbare Eigenschaft für ihren
58
1198.book Seite 59 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP-Basics
Einsatz als LDAP-Datenspeicher mit: Transaktionskontrolle. Die Datenbank überwacht dabei permanent, ob jede Transaktion, z.B. die von einem User angeforderte Änderung eines Objekts, auch vollständig durchgeführt wurde. Falls eine Änderung inkonsistent ist bzw. nicht vollständig durchgeführt wurde, etwa durch fehlerhafte Daten, bleibt der letzte funktionierende Zustand der Datenbank erhalten. Das Thema Berkeley DB werden wir im Abschnitt 3.8, »Larry und die schläfrigen Katzen«, noch sehr ausführlich erörtern. database hdb
Die cachesize-Direktive (Database) legt die Größe eines Objekt-bezogenen Cache fest, der vom jeweiligen Backend im Speicher des slapd-Hosts verwaltet wird (bei Debian nicht gesetzt, Defaultwert: 1000). Dieser Wert sagt unserem slapd, wie viele Objekte des DIT er im Cache für einen schnellen Zugriff vorhalten soll. Die cachesize-Direktive darf nicht mit der set_cachesize-Direktive der BDB/ Oracle Berkeley DB verwechselt werden, denn letztere regelt die Cachegröße der unterliegenden Datenbank. Mehr zu dieser Direktive im Abschnitt 3.8 über die Oracle Berkeley DB, »Larry und die schläfrigen Katzen.« cachesize
10000
Die suffix-Direktive (Database) dient der Definition unserer BaseDN. Die BaseDN (DN = Distinguished Name) beschreibt unsere Top Level Domain (TLD) oder auch Basis, den »höchsten« sichtbaren Punkt unseres DIT (Directory Information Tree), von dem aus auf alle anderen Bereiche verzweigt wird. Die Direktive ist unabdingbar mit der jeweiligen Datenbank verknüpft. Das Suffix besteht üblicherweise aus mindestens einer oder mehr Komponenten. Varianten wären z.B. o=firma1 oder o=firma2,c=de, wobei o für organization und c für country steht. In unserem Fall wählen wir jedoch dc (dc = domain component) und die TLD bzw. BaseDN local.site. Umgesetzt auf unseren Suffix sieht das wie folgt aus: suffix "dc=local,dc=site"
Pro LDAP-Server wird im Regelfall nur ein Suffix – und damit auch nur eine Datenbank – angegeben. Wer mehr Suffixe auf einer Maschine bedienen möchte, dem seien an dieser Stelle drei Alternativen genannt. 1. Die erste Variante ist bei der Leistungsfähigkeit moderner Hardware im Allgemeinen recht problemlos umzusetzen: Mehrere LDAP-Server für verschiedene Suffixe – und damit natürlich auch verschiedene DITs – laufen getrennt auf virtuellen Maschinen, die sich auf einem Host befinden. Tools gibt es genug, hier seien nur Xen, VMware oder Virtualbox genannt. 2. Die zweite Variante wäre, die slapd.conf für die Verwendung mehrerer Suffixe und getrennter Datenbanken (z.B. /var/lib/ldap1/*, /var/lib/ldap2/*) zu kon-
59
2.1
1198.book Seite 60 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
figurieren (siehe Beispieldaten zu diesem Abschnitt: http://www.galileocomputing.de/1801). 3. Die dritte Variante wäre die Verwendung einer zweiten slapd.conf für den zweiten Suffix, die explizit über eine weitere Instanz unseres slapd aufgerufen werden würde. Allerdings muss für diese Instanz ein anderer Port gewählt werden, da der Standard-Port 389 durch die erste slapd-Instanz auf der gleichen Maschine bereits belegt ist. Die Syntax könnte so aussehen: #> slapd -f slapd-2.conf -h ldap://ldapmaster.local.site:9000
Allerdings würde ein Ausfall des physikalischen Servers in allen Konfigurationsbeispielen alle dort konfigurierten LDAP-Server ins Nirwana aller Bits jagen. Hardware-Redundanz bringt hier zwar eine gewisse Nachtruhe, eine bessere und sicherere Lösung für den Produktionseinsatz ist ein »echter« Server pro Suffix, der zudem hardwareredundant ausgelegt ist und dessen Kontext zumindest einmal komplett auf eine zweite Maschine repliziert wird (Full Replica). Diese Konfiguration und andere Replikationsszenarien werden wir später eingehend behandeln. Die checkpoint-Direktive (Database) legt die Frequenz fest, in welchen Intervallen Wiederherstellungs-/Prüfpunkte im Transaktionslog der unterliegenden Datenbank gesetzt werden (Größe in KB/abgelaufene Zeit). Mehr dazu im Abschnitt 3.8 über die Oracle Berkeley DB, »Larry und die schläfrigen Katzen«. checkpoint
1024
5
Die rootdn-Direktive (Database) legt den DN des LDAP-Administrators »hartverdrahtet« in unserer LDAP-Serverkonfiguration fest. Hierbei wird kein bestehender System-Account unserer Linux-Plattform verwendet (was aufgrund der geforderten DN-Syntax ohnehin nicht möglich wäre), sondern ein in der slapd-Konfiguration statisch fest verankerter Account, der stets den vollen Zugriff auf unseren DIT hat. Unser rootdn darf also standardmäßig jederzeit alle administrativen Tätigkeiten an unserem LDAP-Server durchführen. Das komplette rootdn-Statement muss sich immer auf den tatsächlich verwendeten Suffix (in unserem Fall dc=local,dc=site) beziehen und sieht für unser Verzeichnis daher wie folgt aus: rootdn
"cn=ldapadmin,dc=local,dc=site"
Kurze Anmerkung zur Debian-slapd.conf: Das rootdn-Statement ist standardmäßig nicht in der Debian-slapd.conf aktiviert. Zudem verwendet Debian unnötigerweise ACLs für den rootdn (roodn:rw, alle anderen:r), die aufgrund der DefaultPolicy überhaupt nicht gesetzt sein müssten. Der zweite Teil des ebenfalls dort vorhandenen Kommentars »rootdn directive … This is needed for syncrepl« (syncrepl = Sync Replication, mehr hierzu ab Abschnitt 3.2, »Replikation«) kann nur
60
1198.book Seite 61 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP-Basics
von jemandem stammen, der das Konzept missverstanden hat. Leider symptomatisch: Weil die Debian-slapd.conf in ihrer distributionsspezifischen Konzeption insgesamt etwas neben der Spur liegt (Standalone-Anweisung für ein slurpdreplogfile, obwohl slurpd in Version 2.4 überhaupt nicht mehr Bestandteil von OpenLDAP ist, eine aktivierte backend-Direktive, die nicht benötigt wird und bei der Konvertierung in das Online-Format Probleme bereitet, u.v.m.), beziehen wir uns im Folgenden primär auf eine relativ »standardisierte« slapd.conf, wie sie z.B. SUSE verwendet. Wollen wir hoffen, dass die Debian-slapd.conf bis zur Lenny-Final noch etwas Überarbeitung erhält. Die rootpw-Direktive (Database) dient, wie die Namensähnlichkeit schon erahnen lässt, der Definition des Passworts für den zuvor beschriebenen rootdn. Zur Erzeugung des Passworts stehen mehrere kryptographische Methoden zur Verfügung, die unkomplizierteste ist sicherlich, dort ein Klartext-Passwort einzutragen, was allerdings sicherheitstechnisch indiskutabel ist. Eine probate und auch praxistaugliche Lösung bietet das Programm /usr/sbin/slappasswd (man 8(C) slappasswd), da es Passwörter mit verschiedenen Verschlüsselungsverfahren generiert, unter anderem CRYPT, MD5, SHA und SSHA. Mit der Option -h kann die bevorzugte Methode ausgewählt werden, z.B. #> slappasswd –h {MD5}
Die Standardmethode (ohne Angabe von -h) ist {SSHA}. Nachdem wir eine Sicherheitskopie der slapd.conf erstellt haben, können wir das Ergebnis von slappasswd entweder per #> slappasswd >> slapd.conf
an die Datei anfügen, oder wir lassen uns das verschlüsselte Passwort auf der Kommandozeile mit #> slappasswd –s
ausgeben und fügen es manuell in die slapd.conf ein. Als Klartextpasswort wählen wir für unsere Testzwecke linux. Danach modifizieren wir den rootpw-Eintrag entsprechend, so dass unterhalb des rootdn-Eintrags folgende Direktive zu finden ist (der verschlüsselte Passwortwert weicht natürlich ab): rootpw
{SSHA}tq7ChHArQ1PnKXX/gEQefNctmSlIJyQP
Die Angabe des verwendeten Verschlüsselungsverfahrens (Standardmethode in unserem Fall: SSHA) bleibt dabei erhalten. (Das rootpw-Statement ist standardmäßig nicht in der Debian-slapd.conf enthalten.) In der Direktive argsfile (global) werden die eingestellten Startparameter des slapd abgelegt und können so überprüft werden.
61
2.1
1198.book Seite 62 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
argsfile
/var/run/slapd.args
Über die Direktive loglevel (global) wird das Logverhalten des slapd gesteuert, was vor allem für Debug-Zwecke unabdingbar ist. Der Daemon kann natürlich auch auf der Kommandozeile beim manuellen Start per slapd –d in den entsprechenden Log-Level versetzt werden, bei dem der Prozess im Vordergrund läuft und alle Meldungen direkt auf der aktiven Konsole ausgibt. Der direkt per –d übergebene Loglevel hat in dieser Situation logischerweise Präzedenz vor dem in der slapd.conf gesetzten. Grundsätzlich loggt unser slapd über syslogd in die Datei /var/log/messages. Alternativ kann über die logfile-Direktive die Ausgabe in eine andere Datei geleitet werden. Mögliche Integer-Werte zur Steuerung des Log-Levels sind: -1 0 1 2 4 8 16 32 64 128 256 512 1024 2048 16384 32768
(any) enable all debug values below (except 0) no debugging (0x1 trace) trace function calls (0x2 packets) debug packet handling (0x4 args) heavy trace debugging (function args) (0x8 conns) connection management (0x10 BER) print out packets sent and received (0x20 filter) search filter processing (0x40 config) configuration file processing (0x80 ACL) access control list processing (0x100 stats) stats log connections/operations/results (0x200 stats2) stats log entries sent (0x400 shell) print communication with shell backends (0x800 parse) entry parsing (0x4000 sync) LDAP Sync-Replication (0x8000 none) only messages that get logged whatever log level is
Alle vorgenannten Werte sind miteinander kombinierbar, d.h., eine numerische Verknüpfung von 32 + 128 = 160 würde alle Suchfilter und alle ACL-Zugriffe loggen. Der loglevel Default-Wert beträgt 256. loglevel
256
Weitere Beispiele für mögliche Schreibweisen: loglevel
acl trace oder loglevel
0x1 0x80
Die optionale overlay-Anweisung (Global, Backend, Database) leitet immer die Aktivierung eines bestimmten Overlays ein. Typischerweise finden sich im Anschluss an diese Direktive Overlay-spezifische Anweisungen, die meist in der Form - <wert> aufgebaut sind, z.B.:
62
1198.book Seite 63 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP-Basics
overlay syncprov syncprov-sessionlog 100
Die Direktive sizelimit (Global, Backend, Database) regelt über einen IntegerWert die maximale Anzahl der gefundenen Objekte, die einem angegebenen Suchmuster entsprechen. Standardmäßig ist der Wert 500 eingestellt. Um eine unlimitierte Anzahl einzustellen, kann der Attributwert unlimited verwendet werden. sizelimit
unlimited
Die Direktive password-hash (Global) stellt den zu verwendenden PasswortAlgorithmus bei Passwort-Änderungen ein. Mögliche Werte sind {SSHA}, {SHA}, {SMD5}, {MD5}, {CRYPT}, und{CLEARTEXT}. Wenn nicht explizit anders gesetzt, wird als Standard {SSHA} verwendet; der Wert sollte in der Praxis auch so belassen werden. Eine komplette Übersicht aller möglichen Konfigurationsdirektiven liefert uns man 5 slapd.conf; die meisten von ihnen behandeln wir in den folgenden Kapiteln. Tipp: Die Konfigurationssysntax der slapd.conf kann vorab über die Binary slaptest geprüft werden.
2.1.4
ldap.conf (Client)
Die ldap.conf-Client-Datei (Debian: /etc/ldap/ldap.conf, SUSE: /etc/openldap/ ldap.conf) dient zur Konfiguration von systemweiten Client- Einstellungen, die auf der libldap*.so* -Bibliothek basieren. Eine zusätzliche Konfigurationsdatei kann über die Systemvariable LDAPCONF definiert werden, z.B. indem die Variable in die systemweit gültige Login-Konfigurationsdatei /etc/profile integriert und exportiert wird. Hier ein Beispiel für das temporäre Setzen der Variablen auf der Kommandozeile: #> LDAPCONF = /etc/myldap/ldapclient.conf #> export LDAPCONF
Vereinfacht und im Zusammenhang mit unseren in Abschnitt 2.4, »Get it on(line)«, angewendeten LDAP-Client-Tools ausgedrückt, nehmen uns die hier getroffenen Einstellungen die Arbeit ab, bestimmte Parameter auf der Kommandozeile nicht mehr mit übergeben zu müssen, wie z.B. die Suchbasis und unseren eigentlichen LDAP-Server. Hierzu sind die beiden folgenden Einträge in die LDAP-Client-Datei vorzunehmen bzw. anzupassen:
63
2.1
1198.book Seite 64 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
BASE dc=local,dc=site URI ldap://ldapmaster.local.site
»BASE« definiert die Searchbase (Suchbasis) des Clients, d.h. den Punkt im DIT, ab dem der Client suchen darf. Die Searchbase kann auch auf einen tiefer im DIT liegenden Punkt verweisen, z.B. eine ou, so dass alle Suchoperationen auf diesen Teilbereich des DIT beschränkt werden – vorausgesetzt natürlich, es existiert innerhalb dieses Teilbereichs kein Referral (dazu mehr im Abschnitt über Replikation und Partitionierung). Existiert der BASE-Eintrag nicht, muss die Suchbasis auf der Clientseite per (-b) explizit mit angegeben werden. Die andere, bereits bekannte Alternative stellt das Setzen der defaultsearchbase-Direktive mit einer entsprechenden BaseDN in der slapd.conf dar. »URI« gibt dem Client an, an welchen Host er über das LDAP-Protokoll seine Anfrage richten soll. Wen’s interessiert: URL (Universal Resource Locator) ist eine spezielle Untergruppierung von URIs (Universal Resource Identifiers). URIs definieren im weitesten Sinne eine Adresse oder einen Ort, auf den zugegriffen werden kann. URLs definieren vereinfacht ausgedrückt den Zugriff auf einen bestimmten Inhalt mittels eines bestimmten Zugriffsmechanismus (z.B. mit Hilfe eines Protokolls wie http oder ldap). Optional kann auch noch der Port angegeben werden: URI ldap://ldapmaster.local.site:389
Mehrere Einträge (z.B. als redundante Fallback-Lösung) sind ebenfalls möglich: URI ldap://ldapmaster.local.site ldap://ldapslave.local.site Dabei ist zu beachten: Wollen wir z.B. die Direktive BINDDN nutzen, um uns das »lästige« Eintippen unseres User-DNs bei der Anwendung der ldap*-Tools (in Abschnitt 2.3.1, »Die ldap*-Tools«) ebenfalls zu ersparen, bringt uns ein Eintrag in der ldap.conf (Client) rein gar nichts. Warum? Ganz einfach: In dieser Datei werden globale (systemweite), LDAP-spezifische Client-Settings definiert. Da wir hier mit userbezogenen Daten arbeiten, hilft uns der entsprechende BINDDN-Eintrag nur dann, wenn wir ihn in der Datei .ldaprc in unserem jeweiligen User-Ordner platzieren: BINDDN
cn=ldapadmin,dc=local,dc=site
Ein komplettes Listing der weiteren Konfigurationsoptionen liefert man 5 ldap.conf. Weitere, an dieser Stelle noch nicht erläuterte Direktiven werden z.T. in den folgenden Kapiteln nach Bedarf erläutert.
64
1198.book Seite 65 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP-Basics
2.1.5
/etc/ldap.conf (pam_ldap/nss_ldap)
Hier geht es um die Konfigurationsdatei(en), die für die LDAP-Authentifikation am eigentlichen Linux-System von entscheidender Bedeutung ist/sind. Da sowohl Debian als auch SUSE die Bibliotheken libnss_ldap.so* und pam_ldap.so* üblicherweise benutzen, ist diese Konfigurationsdatei unabdingbar. pam_ldap (PAM = Plugable Authentication Modules) ist dabei für die authentifizierungsrelevanten Belange zuständig, libnss_ldap (NSS = Name Service Switch) kümmert sich vereinfacht ausgedrückt darum, wo welche userbezogenen Informationen (und auch andere Services) zu finden sind. Bei SUSE wird die Konfiguration beider Bibliotheken (libnss_ldap.so*, pam_ ldap.so*) über die zentrale Datei /etc/ldap.conf geregelt, was schon eine starke Vereinfachung ist, aber die Übersichtlichkeit nicht unbedingt erhöht; bei Debian existieren zwei Dateien, die für die jeweilige Bibliothek zuständig sind: /etc/ libnss-ldap.conf und /etc/pam_ldap.conf. Beide sind jedoch in Teilen identisch. In einigen Produktivumgebungen stießen wir auf selbstkreierte Varianten, in denen alle drei Files per Links in einer zusammengefasst wurden. Von dieser Vorgehensweise ist in jedem Fall abzuraten, um Überlappungen gegebenenfalls korrespondierender Settings zu vermeiden. Wir werden auf die Funktionalität dieser Dateien und der beteiligten Bibliotheken später in diesem Abschnitt und im Abschnitt 3.6, »Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP« weiter eingehen. An dieser Stelle widmen wir uns vorerst nur den momentan für uns relevanten Konfigurationsparametern. In allen vorgenannten Dateien sollten sich fürs Erste zumindest folgende Einträge finden lassen bzw. gesetzt werden, falls nicht vorhanden: Kleiner Praxistipp hierzu: Die aktiven Einträge in den Dateien lassen sich am schnellsten kontrollieren mit: #> egrep -v "(#|^$)" /etc/ldap.conf
Unter Debian setzen wir im vorgenannten Befehl anstelle von ldap.conf natürlich libnss-ldap.conf bzw. pam_ldap.conf. Hier ein Listing der in der Regel minimal erforderlichen Parameter in den Dateien /etc/ldap.conf (SUSE) bzw. /etc/libnss-ldap.conf und /pam_ldap.conf (Debian), bezogen auf unsere Settings: base dc=local,dc=site host ldapmaster.local.site # alternativ zu host: »uri ldap://ldapmaster.local.site” ldap_version 3
65
2.1
1198.book Seite 66 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
bind_policy soft pam_password exop nss_schema nis nss_map_attribute uniqueMember member pam_filter objectclass=posixAccount nss_base_passwd dc=local,dc=site nss_base_shadow dc=local,dc=site nss_base_group dc=local,dc=site
Ein paar kurze Erläuterungen zu den o.a. Direktiven Wichtig beim Parameter host ist, dass die Namensauflösung auf jeden Fall auch ohne laufenden LDAP funktioniert, alternativ zu host kann auch eine LDAP-URI auf einen Host oder einen Unix-Socket angegeben werden. ldap_version 3 legt den Einsatz der Protokollversion 3 fest, bind_policy soft erzwingt bei Fehlern auf der Serverseite eine sofortige Rückmeldung an den Client. pam_password exop erzwingt die in RFC 3062 spezifizierte »password modify extended operation«, bei der nur noch das neue Passwort an den Server übermittelt wird. pam_ filter definiert mit posixAccount das Filterkriterium, über das für eine Anmeldung gültige Accounts ausgesiebt werden; hierdurch wird die Objektklasse posixAccount vorausgesetzt und die uid – also der Loginname – übergeben. nss_ schema nis erzwingt die Verwendung des nis-Schemas für den Name Service Switch anstelle der ewigen Baustelle des rfc2307bis.schema, das zudem in bestimmten Konfigurationen in Verbindung mit dem samba(3).schema Probleme bereiten kann. Die nss_base*-Anweisungen legen die Searchbases für die jeweiligen maps (passwd, group, shadow) fest, die das Format einer typischen LDAPURL haben können: nss_base_<map> . nss_map_attribute legt fest, welche posix-Attribute bei Gruppen gemappt werden; hier wird das in der Praxis eher selten verwendeten uniqueMember (groupOfUniqueNames) auf member ( groupOfNames ) gemappt. Und noch ein Wort zu ldap_version: LDAP Version 3 wird nicht vollständig unterstützt, solange sich keine lauffähige OpenSSL-Version auf dem System befindet. Ein komplettes Listing aller Konfigurationsoptionen liefern pam_ldap(5) und nss_ldap(5). Zusätzlich zu den pam/nss-Settings in den vorgenannten Dateien müssen wir die Datei /etc/nsswitch.conf kontrollieren. Dort sollten folgende Einträge vorhanden sein:
66
1198.book Seite 67 Donnerstag, 5. Februar 2009 3:02 15
Irgendwie binär – die wichtigsten Binaries und Bibliotheken
passwd: files ldap group: files ldap shadow: files ldap
Die Einträge besagen, in welcher Reihenfolge die Systemdatenbanken beim Authentifizierungsvorgang abgearbeitet werden. Siehe hierzu auch man 5 nsswitch.conf. Der Parameter files wertet – falls die LDAP-Datenbank nicht erreichbar sein sollte – die lokalen Passwortdatenbanken /etc/passwd und /etc/ shadow aus. Daher sollte der Parameter ldap niemals allein verwendet werden, sondern immer nur in Verbindung mit einer Fallback-Lösung wie z.B. files, da sonst sogar unser guter alter Root vor verschlossener Haustür im Regen stehen könnte. Ups … Aber genug von solchen Horrorgeschichten. Wir werden die Authentifizierung am System per LDAP noch genauer unter die Lupe nehmen. Dazu aber ebenfalls später mehr im Abschnitt 3.6, »Hör mal, wer da hämmert …«. Dort ist auch beschrieben, welche PAM-spezifischen Konfigurationsdateien noch angepasst werden müssen, damit die Anmeldung des LDAP-Users auch am System selbst funktioniert. Für unsere gleich in Abschnitt 2.3 folgenden Fingerübungen rings um unser Bonsai-Bäumchen benötigen wir diese Settings jedoch noch nicht.
2.2
Irgendwie binär – die wichtigsten Binaries und Bibliotheken
»Bist du ein Bit?« »Ja!« »Kannst Du auch noch was anderes sagen?« »Nein!« Tron, USA 1982 Nachdem wir nun einen Blick auf die Konfigurationsdateien geworfen haben und zumindest grundlegend wissen, wo der Schraubenschlüssel anzusetzen ist, betrachten wir nun in einer kurzen Übersicht die wichtigsten Binaries und Bibliotheken, die mehr oder weniger direkt zu unserem LDAP-Server gehören.
2.2.1
slapd
Involvierte Konfigurationsdateien/-verzeichnisse: slapd.conf oder slapd.d/
67
2.2
1198.book Seite 68 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Beginnen wir mit dem Server-Daemon selbst, dem slapd. Der slapd ist üblicherweise an folgenden Ablageorten zu finden: 왘 /usr/lib/openldap/
(SUSE)
왘 /usr/sbin/
(Debian)
왘 /usr/local/libexec/
(Standalone)
Der slapd wird – wie bereits erläutert – in den meisten Distributionen in der Regel über Startskripte automatisch bei Systemstart in den jeweils gewünschten Run-Levels gestartet. Bei einer Standalone-Installation muss die Einbindung per Startskript gegebenenfalls manuell vorgenommen werden. Über ein Startskript oder die Kommandozeile lassen sich unserem LDAP-Daemon bequem Startparameter mit auf den Weg geben, wie z.B. bestimmte Debug-Level (-d), Aktivierung bestimmter Protokolle und Ports (-h), die Verwendung eines bestimmten Users (-u) und einer Gruppe (-g), mit deren Rechten der Daemon läuft, eine explizite Angabe der Konfigurationsdatei (-f), Versions(-V)-info und einiges andere mehr. Ein Überblick über mögliche Startparameter liefert uns man 8 slapd. Ein manueller Aufruf unseres slapd mit typischen Optionen könnte z.B. so aussehen: #>
/usr/lib/openldap/slapd –f /etc/openldap/slapd.conf \ –h ldap:/// -u ldap –g ldap –d 4
Die Pfadangabe zur Binary und Konfigurationsdatei sowie verwendete User und Gruppe sind bezogen auf SUSE. Bei Debian würde ein adäquater Startaufruf wie folgt aussehen: #> /usr/sbin/slapd -f /etc/ldap/slapd.conf –h ldap:/// -g openldap -u openldap –d 4
2.2.2
\
slurpd (ACHTUNG: nur bis OpenLDAP 2.3!)
Involvierte Konfigurationsdateien: slapd.conf, ldap.conf (Client) Der separate Replikationsdaemon slurpd war bis Version 2.3 unter dem gleichen Verzeichnis wie der slapd zu finden. Seine Standardkonfigurationsdatei ist ebenfalls die slapd.conf. Achtung: Der slurpd verhält sich dem slapd gegenüber wie ein Client. Daher liest er auch die systemweite Client-Konfigurationsdatei ldap.conf (libldap) aus, z.B. für TLS-Settings. Einen Überblick über die möglichen Parameter in OpenLDAP-Versionen bis 2.3 liefert man 8 slurpd. Wichtiger Hinweis: Der veraltete und fehleranfällige Replikationsdaemon slurpd ist nicht mehr Bestandteil der Version 2.4. Ein eindeutiges Statement der Entwickler zu den Gründen findet sich unter: http://www.openldap.org/doc/
68
1198.book Seite 69 Donnerstag, 5. Februar 2009 3:02 15
Irgendwie binär – die wichtigsten Binaries und Bibliotheken
admin24/replication.html#Replacing%20Slurpd. Weiterführende Erläuterungen hierzu geben wir in Abschnitt 3.2.5, »Vorbereitungen und Vorbetrachtungen zur Replikation«.
2.2.3
libldap*(.so*)
Involvierte Konfigurationsdateien: ldap.conf (Client), ldaprc, .ldaprc libldap*.so* sind die Laufzeitbibliotheken, die von LDAP-Servern und -Clients genutzt werden, daher sind sie gegebenenfalls auch auf Systemen anzutreffen, auf denen selbst kein LDAP-Server läuft. Die Bibliotheken finden sich unter: 왘 /usr/lib/
(Debian)
왘 /lib/
(SUSE)
왘 /usr/local/lib/
(Standalone)
libldap-Clients werten die Dateien /etc/(open)ldap/ldap.conf (Client, systemweit), ldaprc (im Applikationsordner) und ~/.ldaprc (userspezifisch) aus, und zwar in dieser Reihenfolge. Über die Variablen LDAPCONF und LDAPRC können optional zusätzliche Konfigurationsdateien angegeben werden, LDAPCONF zeigt dabei auf eine zusätzliche Client-Konfigurationsdatei, LDAPRC sollte auf eine Datei im CWD (Current Working Directory) oder Home-Verzeichnis des gewünschten Users zeigen. Detaillierte Informationen zu dieser Bibliothek werden über man 3 ldap (LDAP API) bereitgestellt, allerdings müssen dazu – falls OpenLDAP nicht aus den Sourcen installiert wurde – unter Debian und SUSE folgende Pakete installiert sein: libldap2-dev (Debian) und openldap2-devel (SUSE).
2.2.4
libnss-ldap(.so*)
Involvierte Konfigurationsdateien: /etc/ldap.conf (SUSE und Standalone), /etc/ libnss-ldap.conf (Debian), /etc/nsswitch.conf Ablageort: /lib/libnss_ldap.so (OSS11 und Debian) Über die libnss-ldap-Bibliothek (www.padl.com) können userbezogene Informationen per NSS (Name Service Switch) direkt aus dem LDAP bezogen werden. Sie stellt uns damit über den LDAP die userbezogenen Account-Informationen – wie User, Gruppe, IDs und mehr – zur Verfügung, die »normalerweise« entweder per /etc/passwd|shadow oder per NIS bereitgestellt werden würden.
69
2.2
1198.book Seite 70 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
2.2.5
pam_ldap(.so*)
Involvierte Konfigurationsdateien: /etc/ldap.conf (SUSE und Standalone), /etc/ pam_ldap.conf (Debian) Ablageort: /lib/security/pam_ldap.so (OSS11 und Debian) Die pam_ldap-Bibliothek (www.padl.com) ermöglicht es, dass sich nicht nur die systeminternen Benutzerkonten (/etc/passwd|shadow) zur Authentifizierung heranziehen lassen, sondern eine Authentifizierung zusätzlich durch die im DIT eines LDAP-Verzeichnisses hinterlegten Userobjekte erfolgen kann. Voraussetzung ist natürlich, dass diese Userobjekte die entsprechenden Objektklassen und Attribute vorweisen können; in der Regel sucht pam_ldap nach der Objektklasse posixAccount für diese Vorgehensweise (konfigurierbar über /etc/ldap.conf bzw. /etc/pam_ldap.conf). Unter anderem bietet pam_ldap die Möglichkeit, seine Kommunikation zum Server per SSL/TLS (auch über SASL) zu verschlüsseln. Auf die Funktionalität der beiden letztgenannten Bibliotheken und auf alles andere, was mit der Authentifizierung am System mittels PAM, NSS und LDAP zu tun hat, gehen wir später im Abschnitt 3.6, »Hör mal, wer da hämmert«, detailliert ein. Jetzt ist es aber an der Zeit, die Maschine anzuwerfen …
2.2.6
»Gentlemen, start your engines …«
Nach den ganzen Vorbetrachtungen und Vorbereitungen sollte unser LDAP-Server nun bereit für den ersten Start sein. Die permanente Einbindung des LDAPDienstes erfolgt bei SUSE über die chkconfig/insserv-Befehle bzw. bei Debian über das update-rc.d-Skript. Die Kommandos zum Re-/Starten und Stoppen des Dienstes sehen wie folgt aus: #> /etc/init.d/slapd #> /etc/init.d/ldap #> /usr/local/libexec/slapd
#(Debian) #(SUSE) #(StandAlone)
Ein hilfreiches Tool, mit dem wir testen können, ob unser slapd läuft, ist natürlich wieder der Befehl ps. #> ps aux | grep slapd | grep –v grep
Ebenfalls hilfreich an dieser Stelle – und auch im späteren Verlauf – ist das Tool nmap, das uns schnell zeigt, ob der Standard-LDAP-Port 389 bereits geöffnet ist. #> nmap localhost
So – neue Tasse Kaffee holen und Finger aufwärmen, denn jetzt geht’s endlich rund …
70
1198.book Seite 71 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
2.3
Fingerübungen – OpenLDAP-Tools auf der Konsole
Die Technik entwickelt sich vom Primitiven über das Komplizierte zum Einfachen. Antoine de Saint-Exupéry In Zeiten grafischer Oberflächen, die von ihren Farben, 3D-Darstellungsmöglichkeiten und -Effekten her ohne Probleme jede Bildschirm-Statistenrolle im StarWars- oder Star-Trek-Filmuniversum übernehmen können, scheinen Kommandozeilen-Befehle archaisch und überholt. Als Leser dieses Buches werden Sie mit der Kommandozeile bereits mehr oder weniger vertraut sein. Auf jeden Fall aber gut zu wissen, dass die LDAP-(Remote-) Administration auf der Kommandozeile eine unkomplizierte und schnelle Angelegenheit ist. Zudem lässt sich die Leistungsfähigkeit der im Folgenden vorgestellten Tools in Verbindung mit kleinen Shellskripten hervorragend aufbohren – wobei im Rahmen von Upgrades unseres slapd bzw. seiner Tools natürlich stets darauf geachtet werden muss, ob sich keine relevanten Befehls-Optionen geändert haben. Grundsätzlich gilt, dass jeder Administrator die wichtigsten LDAP-Kommandozeilen-Tools und ihre gängigsten Optionen aus dem Effeff beherrschen sollte. In Verbindung mit Perl-, Python- oder PHP-LDAP-Bibliotheken ist eine zusätzliche Interaktionsmöglichkeit vorhanden. An dieser Stelle noch ein kleiner Praxistipp: Wir alle kennen das bash-history-»Problem«: Wir arbeiten auf mehreren Konsolen bzw. Remote-Sitzungen mit der gleichen Identität, und die einzige Befehls-History, die gespeichert wird, ist die der letzten Session, die wir beenden. Mit einigen kleinen Ergänzungen lässt sich das Manko schnell beheben, und wir haben alle verwendeten Befehle von allen Sessions in der History. Dazu editieren wir einfach die .bashrc des jeweiligen User-Accounts oder setzen die Parameter in der globalen bash-Steuerungsdatei, bei SUSE z.B. /etc/bash.bashrc: shopt -s histappend PROMPT_COMMAND="history -a"
Durch die shell-option shopt -s histappend ist die Shell in der Lage, neue Befehle an die History-Datei anzuhängen. PROMPT_COMMAND="history -a" sorgt dafür, dass die Shell vor der Ausgabe des nächsten Prompts die History-Daten sofort wegsichert. In dieser Konstellation kann es manchmal hilfreich sein, die History-Länge – je nach gesetztem Defaultwert (HISTSIZE=1000 bei SUSE und nur 500 bei Debian) – etwas aufzubohren.
Und nun zu unseren Tools im Einzelnen. Damit wir etwas Leben in unseren DIT bekommen, müssen wir unsere im Moment noch leere LDAP-Datenbank mit einer Basisdatei vom Typ LDIF (Lightweight Database Interchange Format, defi-
71
2.3
1198.book Seite 72 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
niert in der RFC 2849, »The LDAP Data Interchange Format (LDIF) – Technical Specification«) befüllen. Die nachfolgend auszugsweise gelistete Datei (struktur.ldif) erstellt die elementaren Einträge in der LDAP-Datenbank, zunächst unsere BaseDN sowie ein Abbild unseres LDAP-Admin-Objekts als organisatorische Rolle; dazu gleich mehr. Anschließend werden alle weiteren Objekte wie organizationalUnits, Gruppen und User-Objekte erzeugt. Wie in der LDIF-Spezifikation gefordert, müssen die Objekte durch eine Leerzeile voneinander abgegrenzt sein, die Kommentare sind nur hier im auszugsweisen Listing zum besseren Verständnis eingefügt und fehlen in der Beispieldatei: dn: dc=local,dc=site # 1.Eintrag: der DN (Distinguished Name) unsere Basis, liest # sich: local.site objectClass: dcObject # Objektklasse dcObject aus core.schema, stellt das Attribut # dc (MUST) zur Verfügung objectClass: Organization # Objektklasse Organization aus core.schema, stellt # das Attribut o (MUST) zur Verfügung dc: local # Attribut dc (domainComponent) und Attributwert (local) o: Brainstorm # Attribut o (organization)und Attributwert (Brainstorm) # LEERZEILE ZUR TRENNUNG DER OBJEKTE dn: cn=ldapadmin,dc=local,dc=site # 2.Eintrag: ldapadmin.local.site (cn=commonName) objectClass: organizationalRole # Objektklasse organizationalRole aus core.schema, stellt # das Attribut cn (MUST) zur Verfügung cn: ldapadmin # Attribut cn und Attributwert (ldapadmin)
Die Kommentarzeilen (#) dienen nur der Lesbarkeit. Im Klartext sieht der Anfang unserer LDIF-Datei struktur.ldif also so aus: dn: dc=local,dc=site objectClass: dcObject objectClass: Organization dc: local o: Brainstorm dn: cn=ldapadmin,dc=local,dc=site objectClass: organizationalRole cn: ldapadmin # ...u.s.w., hier folgen die anderen Objekte...
72
1198.book Seite 73 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
Damit unser rootdn im DIT als »echtes« LDAP-Objekt über seinen DN greifbar ist und als solches auch ausgewertet/behandelt werden kann, bilden wir ihn bei der Befüllung unseres DIT zusätzlich als Objekt ab. Hierzu verwenden wir eine so genannte »organizationalRole«, also einfach ausgedrückt: eine Rolle. Dies kann man vielleicht am ehesten mit Film oder Theater vergleichen: Es gibt Haupt- und Nebenrollen. Und das DIT-Pendant zu unserem hartverdrahteten rootdn spielt aufgrund seines DNs die ultimative Hauptrolle, er darf einfach alles, ohne ihn geht überhaupt gar nichts. Eben so wie Käpt´n Kirk auf der Enterprise. Weiter im Text: Das Passwort der Userobjekte in der LDIF-Datei wurde per slappasswd in der gleichen Vorgehensweise generiert wie für den rootpw-Eintrag in unserer slapd.conf. Das Passwort ist für alle User-Accounts das Gleiche, nämlich – wie üblich und stets hochinnovativ: »linux«. Kurze Anmerkung: Die OpenLDAP-Kommandozeilentools wie ldapadd oder ldapmodify unterstützen seit Version 2.4 auch die Möglichkeit, innerhalb einer LDIF-Datei per Include-Statement auf eine oder mehrere externe LDIF-Dateien zu verweisen: include: file:///root/admin2.ldif
Ein weiteres, sehr interessantes Feature besteht darin, Informationen aus einer Datei direkt als Eingabe für ein Attribut zu verwenden: description:< file:///root/kents_description.txt
Wobei statt »file:///« auch URI-Schemas wie ftp oder http unterstützt werden. Weitere ausführliche Informationen und Beispiele liefert man 5 ldif. Bereits an dieser Stelle lässt sich der Aufbau einer typischen LDAP-Objektdefinition unschwer erkennen: Zuerst der Distinguished Name (DN), der immer genau ein (1) Objekt innerhalb des DIT eindeutig (!) beschreibt. Dann folgen die benötigten Objektklassen (objectClass), die die erforderlichen bzw. gewünschten Attribute (hier dc, o, cn) zur Verfügung stellen. Zwischen zwei Objekten muss mindestens eine Leerzeile vorhanden sein, damit OpenLDAP beim Import oder bei Änderungen klar zwischen den Objekten unterscheiden kann. Das manuelle Anlegen von LDIF-Dateien per Editor gestaltet sich für den Anfänger meist etwas hakelig. Aber auch erfahrenere Admins können ein Lied davon singen, dass sich hier und dort bisweilen der Fehlerteufel einschleicht, die unser slapd jedoch meistens relativ aussagekräftig anmeckert. Und wenn nicht: Es gibt Gott sei Dank noch jede Menge Debug-Modes. Beim Import von LDIF-Dateien in die LDAP-Datenbank treten die meisten Fehler aus folgenden Gründen auf:
73
2.3
1198.book Seite 74 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
왘 suffix, rootdn, rootpw nicht oder falsch gesetzt (nur Erstbefüllung) 왘 Objektklassen/Attribute, die in der LDIF-Datei zwar angegeben sind, aber durch fehlende/ungeeignete Schemas nicht zur Verfügung stehen 왘 Vererbungsfehler durch Verwendung mehrerer Objektklassen vom Typ STRUCTURAL, die nicht voneinander abgeleitet sind 왘 Von Objektklassen geforderte MUST-Attribute sind in der LDIF-Datei nicht vorhanden oder syntaktisch falsch. 왘 Unterschiedliche Objekte wurden nicht durch eine Leerzeile getrennt. 왘 Zeilen beginnen mit einem Leerzeichen oder Tab. 왘 Es wurde kein UTF-8/ASCII-Zeichensatz verwendet (siehe unsere Anmerkung zum »Editor Ihrer Wahl« der nächsten Seite). 왘 Die LDIF-Datei enthält unzulässige Sonderzeichen, die den Datensatz beim Einlesen in die Datenbank unbrauchbar machen. Die ersten sechs Punkte lassen sich anhand unserer bereits erworbenen Kenntnisse relativ schnell überprüfen. Eine ergänzende Anmerkung zum vorletzten Punkt: Der ASCII- und UTF-8-Zeichensatz sind, was die ersten 128 Zeichen betrifft, identisch. Zeichen aus anderen Zeichensätzen, die nicht in UTF-8 enthalten sind (z.B. Zeichen aus ISO8859), müssen konvertiert werden. Dafür kann man das Tool iconv verwenden. Aus unserer Erfahrung möchten wir zu diesem Punkt noch kurz Folgendes anmerken: Am besten auf die Verwendung von Sonderzeichen und Umlauten ganz verzichten. Das gibt im Betrieb am wenigsten Probleme. Alternativ lässt sich der vi(m) allerdings auch dazu bringen, UTF-8 zu verwenden (siehe weiter unten). Der letzte Punkt lässt sich ebenfalls recht einfach kontrollieren. Wir öffnen den vi mit der LDIF-Datei im Kommandomodus und geben das Kommando set list hinter dem Doppelpunkt ein. Dadurch werden Zeilenumbrüche, Tabs und einige andere Steuerzeichen angezeigt. Wie bereits in unserem Exkurs »uid? or not uid?« in Abschnitt 1.6, »Objekte, Klassen, Attribute«, über die Verwendung von Sonderzeichen in Verbindung mit LDAP-Daten erwähnt: Per Definition reagiert unser LDAP-Server auf Leerzeichen oder sonstige Sonderzeichen/Umlaute in den Attributwerten oder DNs beim Import von LDIF-Dateien mit sofortiger Base64-Codierung des Attributwertes/ DNs, was sich im importierten Datensatz typischerweise immer an dem doppelten Doppelpunkt »::« zwischen Attributbezeichner und Attributwert erkennen lässt. Typisches Beispiel hierfür ist der Attributwert für userPassword. Durch die Base64-Codierung ist der Attributwert auf der Kommandozeile in der Regel nicht mehr im Klartext lesbar, was uns bei Passwörtern mit Sicherheit nicht stört – im
74
1198.book Seite 75 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
Gegenteil. Bei anderen Attributwerten oder gar dem DN sieht die Sache jedoch schon anders aus. Kleiner Praxistipp: Die oftmals erwähnte Phrase »Bearbeiten Sie die LDIF-Datei mit einem Editor Ihrer Wahl …« können wir aus unseren Erfahrungen keineswegs empfehlen, sondern raten an dieser Stelle nochmals zur Verwendung des vi(m) bzw. eines Editors, mit dem Sie »überflüssige« (Steuer-) Zeichen erkennen und entfernen können. Mitterweile beherrscht sogar der Editor des Midnight Commanders (z.B. mcedit 4.6.2) per Default diese Einstellung.
Bezüglich UTF-8 können wir im Kommandomodus des vi(m) (:) mit set encoding? den aktuell eingestellten Wert anzeigen lassen und diesen bei Bedarf mit set encoding=utf-8 umstellen. Eine sehr ausführliche Dokumentation hierzu findet sich unter http://www.vim.org/htmldoc/mbyte.html#UTF-8.
Damit kommen wir nun zum eigentlich wichtigsten Teil, was das Handling der Daten auf unserem LDAP-Server angeht. Grundsätzlich stehen uns folgende ldap*-Kommandozeilentools zur Verfügung: 왘 ldapsearch
– Suchen/Exportieren von Objekten
왘 ldapadd
– Hinzufügen von Objekten (entspricht ldapmodify –a)
왘 ldapmodify
– Ändern vorhandener Objekte (auch DN-Modifizierung und extended Operations möglich)
왘 ldapdelete
– Löschen vorhandener Objekte
왘 ldappasswd
– Passwort für ein (User-)Objekt setzen
왘 ldapexop
– Extended Operations (ManageDIT, ManageDSAIT, DDSObjekte per relax auffrischen)
왘 ldapcompare – Prüfe, ob der Datensatz existiert, Rückgabewert: Boolean 왘 ldapwhoami
– meine aktuelle LDAP-Identität
왘 ldapmodrdn
– Modifizieren des »relativen dn« (rdn)
Das Tool ldapadd ist dabei tatsächlich nur ein Softlink auf ldapmodify. Wird ldapadd aufgerufen, arbeitet tatsächlich ldapmodify intern mit der Option -a (add). Die extended Operations (ldapexop) können üblicherweise ebenfalls direkt per ldapmodify -e aufgerufen werden. Zu jedem der genannten Befehle (Ausnahme: ldapexop) existiert natürlich eine umfangreiche Manpage, aber darauf wollen wir uns nicht ausruhen. Übung macht schließlich den (LDAP-)Meister.
75
2.3
1198.book Seite 76 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Alle vorgenannten ldap*-Kommandos liegen üblicherweise im Suchpfad. Wenn nicht, geben wir den absoluten Pfad zum Kommando an – z.B. /usr/bin/ldapadd – oder erweitern die PATH-Systemvariable.
2.3.1
Die ldap*-Tools
Hinter den Kulissen – das LDAP-Funktionsmodell Zum Verständnis, wie eine typische LDAP-Sitzung abläuft, werfen wir vorab noch einen kurzen Blick auf das Funktionsmodell des LDAP-Protokolls, damit klar wird, was bei einer Client-Anfrage an den DIT, z.B. durch eines der vorgenannten Kommandozeilentools, so eigentlich passiert. Das LDAP-Protokoll ist sitzungsorientiert (wie z.B. auch SMTP). Das bedeutet: Bevor überhaupt Daten ausgetauscht werden können, muss eine so genannte Session (Sitzung) initialisiert werden. Das erfolgt in drei Schritten: Binding: Die Anmeldung des Clients am Server (mit oder ohne Authentifizierung, gegebenenfalls verschlüsselt); dann erfolgt eine Prüfung der vom LDAP-Client unterstützten Features, wie z.B. die Protokollversion. Message-Exchange: Der eigentliche Austausch von Nachrichten (Clientseite: Request, Serverseite: Response). Zulässige Messages sind hierbei: bind, unbind, search, add, modify, modrdn, delete, extend, compare, abandon. Unbind steht für eine normale Beendigung der Verbindung. Eine ausführliche Beschreibung des Sitzungsvorgangs mit etlichen Querverweisen findet sich unter http://www.openldap.org/software/man.cgi?query=ldap bzw. man 3 ldap. Und nun zu den Kommandozeilen-Tools und zur Erstbefüllung unserer LDAPDatenbank. ldapadd Vor unserer Erstbefüllung noch einmal schnell geprüft, ob die für die Objekte benötigten Schemas core, cosine, inetOrgPerson und nis per include in die slapd.conf eingebunden sind und, falls dem noch nicht so ist, ob der slapd anschließend neu gestartet wurde, um die Änderungen zu übernehmen. Zum Import der Daten per ldapadd muss unser LDAP-Server natürlich laufen (check per ps oder nmap). Wir setzen nun folgendes ldapadd-Kommando (hier ohne Pfadangaben) ab, mit dem wir die LDIF-Datei in den DIT importieren:
76
1198.book Seite 77 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
#> ldapadd –x –W –D cn=ldapadmin,dc=local,dc=site \ –f struktur.ldif
Eine kurze Erläuterung zu den Parametern: -x: einfache, unverschlüsselte Authentifizierung (simple bind), -W: anschließende Passworteingabe erforderlich, -D: den binddn (die Identität) angeben, mit der wir uns am LDAP-Server anmelden (»binden«) wollen, denn davon hängen auch direkt die Rechte ab, mit denen wir auf unseren DIT zugreifen dürfen. Erforderlich ist immer die Angabe des vollständigen Distinguished Name (DN); in diesem Fall verwenden wir natürlich den DN (rootdn) unseres ldapadmin (cn=ldapadmin,dc=local,dc=site), damit wir schreibend auf den DIT zugreifen dürfen. Der Parameter -f (file) gibt schließlich die zu verwendende LDIF-Datei an. Grundsätzlich gilt: Falls eine Komponente des DN (z.B. der cn des Objekts) Leerzeichen enthält, sollte der komplette DN in Anführungszeichen gesetzt werden. Kleiner Tipp: Einige der Kommandozeilen-Optionen lassen sich zusammenfassen, bezogen auf das letzte Beispiel z.B. »-xWD«. Wer sich das Tippen des DNs ersparen will, kann – wie bereits erwähnt – über die Datei .ldaprc in seinem jeweiligen Home-Ordner den BINDDN direkt mit angeben (siehe hierzu auch ldap.conf(5)). Der obige Befehl würde, bezogen auf unseren ldapadmin-DN, dann folgendermaßen lauten: #> ldapadd –xW –f struktur.ldif
Nachdem wir den Befehl abgeschickt haben, folgt die Passwortabfrage für das rootdn-Passwort: Enter LDAP Password:
Wenn nach der Passworteingabe die Rückmeldung adding adding adding adding
new new new new
entry entry entry entry
"dc=local,dc=site" "dn=ldapadmin,dc=local,dc=site" "ou=verkauf,dc=local,dc=site" "ou=marketing,dc=local,dc=site"
... und so weiter und so fort.
wie hier dargestellt aussieht, haben wir erfolgreich unsere erste kleine Verzeichnisstruktur befüllt. Falls Fehlermeldungen auftauchen, zurück zum Start, nicht über Los gehen und auf jeden Fall noch einmal alle vorgenannten Punkte überprüfen. Gerade für Einsteiger kann es oft hilfreich sein, sich die Struktur des Trees und der darin enthaltenen Objekte nach der Initialbefüllung zunächst einmal grafisch zu visualisieren, denn die Struktur eines Trees ist auf der Kommandozeile immer etwas abstrakt. Kleiner Tipp: Zu dieser frühen Phase sollten wir über ein grafisches Tool nur anonym auf den DIT zugreifen, denn mit den entsprechenden
77
2.3
1198.book Seite 78 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Rechten ausgestattet, ist ein ganzer Subtree mal eben mit einem Klick verschoben oder gelöscht. Grafisch stellt sich unser DIT (hier eine Ansicht im JXplorer; mehr zu diesem Tool in Abschnitt 4.7, »Auf den Schirm!«) im Moment etwa so dar:
Abbildung 2.1
Grafische Darstellung unseres aktuellen DIT im JXplorer
Die muntere, kleine Objekt-Runde unseres Bäumchens sollte uns nun genug Spielraum geben, um das ldapsearch-Tool schon langsam auf Betriebstemperatur zu bringen. Los geht’s … ldapsearch, zum Ersten Als Erstes prüfen wir, ob wir die gerade eingefügten Daten in unserem DIT auch lesen können. Der Defaultwert "(objectClass=*)" liefert dabei alle im DIT befindlichen Objekte zurück: #> ldapsearch –x "(objectClass=*)"
Alternativ tut es auch ein einfaches ldapsearch -x. In jedem Fall sollte folgende Ausgabe erscheinen: # extended LDIF # # LDAPv3 # base (default) with scope subtree # filter: (objectclass=*) # requesting: ALL # # local.site dn: dc=local,dc=site
78
1198.book Seite 79 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
objectClass: dcObject objectClass: organization dc: local o: Brainstorm # ldapadmin, local.site dn: cn=ldapadmin,dc=local,dc=site objectClass: organizationalRole cn: ldapadmin # ... und hier folgen alle anderen Objekte
Falls z.B. folgender Fehler auftritt: result: 32 No such object
lässt sich durch eine einfache Variation des ldapsearch-Befehls leicht feststellen, ob die Einstellungen in der ldap.conf (Client-Datei) betreff BASE (-b) und URI/ Host (-h) fehlerhaft sind oder nicht gesetzt wurden. #> ldapsearch -x objectClass=* -h ldapmaster -b \ dc=local,dc=site
An dieser Stelle können wir gegebenenfalls noch einmal prüfen, ob der in der URI eingetragene Hostname über die /etc/hosts aufgelöst werden kann. Eine »bereinigte« Version der ldapsearch-Ausgabe ohne Kommentare kann durch den ergänzenden Parameter -LLL erzielt werden. #> ldapsearch -x –LLL
Die »saubere« Ausgabe sollte nun so aussehen: dn: dc=local,dc=site objectClass: dcObject objectClass: organization dc: local o: Brainstorm # ... und hier folgen alle anderen Objekte
Bereits hier wird deutlich, dass sich mit ldapsearch hervorragend Datensätze aus dem DIT in direkt verwertbarer (LDIF-)Form extrahieren lassen. Modifikationen an Objekten werden so auch fernab von grafischen Frontends zu einer leichten Übung. Das zahlt sich vor allem dann aus, wenn dem Admin z.B. gerade »nur« eine RemoteKonsolensitzung über SSH zur Verfügung steht. Der Datensatz wird gefiltert, d.h. nur mit den benötigten Attributen ausgelesen (wie das geht, sehen wir gleich), modifiziert und anschließend per ldapmodify wieder in den DIT eingelesen. Achtung: ldapmodify-Operationen sind seit OpenLDAP Version 2.4 nur noch mit einem bestimmten LDIF-Syntax zulässig. Mehr zu diesem Thema im nächsten Abschnitt über ldapmodify.
79
2.3
1198.book Seite 80 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Als Suchmuster für die im obigen Beispiel verwendete Objektklasse (objectClass) lassen sich alle in unserem DIT existierenden Objektklassen nutzen, z.B. posixAccount, person, sambaSamAccount usw., ebenso natürlich alle zugehörigen Attribute: #>
ldapsearch -x -LLL objectClass=posixAccount mail
listet alle vorhandenen Objekte vom Typ posixAccount (also alle Userobjekte) auf, und von diesen Objekten (außer dem DN) nur das gewünschte Attribut, also mail: dn: uid=hcallahan,ou=verkauf,dc=local,dc=site mail: [email protected] dn: uid=eripley,ou=forschung,dc=local,dc=site mail: [email protected] ...
Praxistipp: Wenn wir einen umfangreichen DIT durchsuchen, kann die Anzahl der gefundenen Objekte je nach Suchkriterium leicht die Marke von 500 übersteigen. Das ist, wie wir bereits aus dem Kapitel Installation wissen, der Standardwert für die Obergrenze bei ldapsearch-Querys. Wir erinnern uns: Dieser Wert kann über den Parameter sizelimit in der slapd.conf geändert werden. Beispiele: sizelimit <positiver integer wert> oder sizelimit unlimited
ldapmodify Was ist faul im Staate Dänemark? Nichts, mein süßer Prinz, nur das LDIF-Format für Änderungen an Objekten hat sich im Gegensatz zu allen OpenLDAP-Vorgängerversionen seit Version 2.4 entscheidend geändert. War es bis zur Version 2.3 einschließlich möglich, einfach ein komplettes Objekt per ldapsearch auszulesen, nur das gewünschte Attribut zu ändern und den ganzen Datensatz (entsprechende ACLs vorausgesetzt) wieder einzulesen, tut sich bei so einem Versuch in Version 2.4 gar nichts mehr. Die einzige, aber durchaus aussagekräftige Rückmeldung, die wir bekommen, lautet: ldapmodify: modify operation type is missing at line 2, entry ...
und so weiter und so fort. Was ist passiert? Ein Blick in die manpage von ldapmodify sagt uns alles, was wir wissen müssen. Und das entspricht dem, was uns auch die Fehlermeldung mitgeteilt hat. ldapmodify erwartet explizit, was mit welchem Attribut gemacht werden soll. Aufwändig? Vielleicht. Gut für die Performance? In jedem Fall. Denn ist es wirklich sinnvoll, ein Objekt mit vielen Attributen, von denen einige vielleicht sogar eine beträchtliche Datenmenge besitzen können (z.B. Bilddaten), komplett neu einzulesen, auch wenn nur eines geändert wurde? Nicht in diesem Raum-Zeit-Kontinuum, vor allem angesichts der ständig
80
1198.book Seite 81 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
steigenden Datenmengen. Auch wenn OpenLDAP der weltweit schnellste DS ist – unnötige Modifikationen bremsen auch ihn aus. Daher lag der Schritt nahe, Modifikationsoperationen lediglich auf die zu ändernden Attribute zu beschränken. Schauen wir uns an, wie das im Detail nun vor sich geht. Die direkteste Variante wäre ein interaktives ldapmodify auf der Kommandozeile – ohne LDIF-Datei, versteht sich. Allerdings ist diese Methode nicht ganz einfach, vor allen Dingen, da bei einer Fehleingabe alles erneut am Prompt eingeben werden muss. Dass es dennoch geht, möchten wir wenigstens an einem kleinen Beispiel zeigen, denn wie in jedem Bereich gilt auch hier: Übung macht den Meister. Nach Eingabe unseres Authentifikations-DNs (cn=ldapadmin,dc=…) und des Passwortes erfolgt die Eingabe zeilenweise; jede Zeile wird per Enter beendet, womit man in die nächste Zeile wechselt. Als Erstes wird der vollständige DN angegeben, denn das System muss ja wissen, welches Objekt modifiziert werden soll. Anschließend folgen mit changetype die Art der Modifikation, gefolgt von dem zu ändernden Attribut, und schließlich dem zugehörigen Attributwert. Voilà! #> ldapmodify -xWD cn=ldapadmin,dc=local,dc=site Enter LDAP Password:
dn: uid=ckent,ou=verkauf,dc=local,dc=site changetype: modify replace: description description: Superman, who else
Nach Eingabe der letzten Zeile setzen wir noch ein CR (Carriage Return oder besser bekannt als »Enter«) ab, dann beenden wir den interaktiven ldapmodifyBefehl mit [Ctrl] + [D] bzw. [Strg] + [D]. Nun sollte folgende Rückmeldung erscheinen: modifying entry "uid=ckent,ou=verkauf,dc=local,dc=site"
… und alles hat geklappt. War doch ganz einfach, oder? Okay, die Variante per LDIF-Datei ist zugegebenermaßen doch ein klein wenig komfortabler. Das LDIF (kent1.ldif) selbst sieht genauso aus wie unsere eben getätigte Eingabe auf der Kommandozeile, also: dn: uid=ckent,ou=verkauf,dc=local,dc=site changetype: modify replace: description description: Superman, who else
Das Einlesen erfolgt in bekannter Weise: #> ldapmodify -xWD cn=ldapadmin,dc=local,dc=site –f kent1.ldif
81
2.3
1198.book Seite 82 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Im nächsten Beispiel erstellen wir zur Übung folgende Datei (kent2.ldif) und lesen sie anschließend ebenfalls per ldapmodify in den DIT ein: dn: cn=ldapadmin,dc=local,dc=site changetype: modify add: title title: Admin
Der letzte Eintrag (title) wurde in diesem Fall ergänzt (zum Objekt hinzu»addiert«). Das title-Attribut (MAY) wird von der Objektklasse organizationalPerson aus dem core.schema (von der die von unserem Userobjekt verwendete Objektklasse inetOrgPerson abgeleitet ist) zur Verfügung gestellt. Nun lesen wir den modifizierten Datensatz per ldapmodify wieder in den DIT ein: #>ldapmodify -xWD cn=ldapadmin,dc=local,dc=site -f kent2.ldif modifying entry "uid=ckent,ou=verkauf,dc=local,dc=site"
Des Weiteren bietet uns ldapmodify dank der in RFC 4525 »LDAP Modify-Increment Extension« spezifizierten Operation z.B. auch die Möglichkeit, »numerische« Werte inkrementell zu erhöhen. Hier eine LDIF, die die uidNumber unseres Kumpels Clark vom aktuellen Wert ausgehend um 1000 Zähler nach oben setzen würde, also auf den Wert 1901. dn: uid=ckent,ou=verkauf,dc=local,dc=site changetype: modify increment: uidNumber uidNumber: 1000
ldapdelete Zum Löschen vorhandener DIT-Einträge existiert in der Analogie das ldapdeleteKommando (vergleiche z.B. auch useradd/userdel/usermod-Kommandos). Im nächsten Beispiel wollen wir unseren Kollegen Clark Kent löschen. Nachdem wir seinen Datensatz zuvor mit unserem administrativen DN (cn=ldapadmin,dc=…) per ldapsearch komplett – also mit allen Attributen inklusive Passwort – gesichert haben, #> ldapsearch –xWD cn=ldapadmin,dc=local,dc=site \ uid=ckent –LLL > ckent.ldif
legen wir los: #> ldapdelete –xWD cn=ldapadmin,dc=local,dc=site \ uid=ckent,ou=verkauf,dc=local,dc=site
82
1198.book Seite 83 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
Es erfolgt keine Ausgabe, wenn alles ohne Fehler abgelaufen ist. Hinter der Identität, mit der wir den simple bind durchführen, wird der vollständige (!) DN des zu löschenden Objekts angegeben. Ein anschließendes ldapsearch bringt uns nun Gewissheit: Unser Superman ist – vorerst – futsch. Nun lesen wir ihn per ldapadd und der zuvor erstellten Datei ckent.ldif in der bekannten Vorgehensweise wieder ein. Noch ein kleiner Tipp vorab: Es gibt tatsächlich auch Objekte, die sich – egal, ob wir nun LDAP-Admin sind oder nicht – hartnäckiger als eine pandimensionale, arkturianische Grippe der Löschung per ldapdelete widersetzen. Aber auch denen kommen wir bei, keine Panik. Einen speziellen Vertreter dieser resistenten Gattung schauen wir uns im Abschnitt über Partitionierung an. Andererseits ist höchste Vorsicht geboten, und zwar vor dem niedlichen, kleinen Schalter –r: Denn wenn wir ldapdelete mit -r (=rekursiv, wir ahnten es) auf einen Subtree anwenden, ist jener komplett futsch, und zwar mitsamt aller Subordinates, also allen untergeordneten Einträgen. Der folgende Befehl würde den kompletten Subtree ou=forschung unseres kleinen Bäumchens kappen, mitsamt Sub-Unit ou=xeno: #> ldapdelete –xWD cn=ldapadmin,dc=local,dc=site \ ou=forschung,dc=local,dc=site -r
Also noch mal: VORSICHT mit ldapdelete -r!
ldapsearch, zum Zweiten – OID´s und operational Attributes Noch einmal zurück zu ldapsearch, dem (fast) wichtigsten LDAP-Kommandozeilentool. Über die explizite Angabe von Attributen – oder deren OIDs – können wir ebenfalls sehr gezielt im DIT suchen. Hierzu schauen wir uns einige Beispiele an: #> ldapsearch -x uid=ckent mail
Diese Zeile liefert uns neben dem DN von Clark Kent nur das Attribut mail und dessen Attributwert zurück. #> ldapsearch -x uid=ckent 0.9.2342.19200300.100.1.3
Dieser Befehl liefert uns ebenfalls das Attribut mail (anhand seiner OID aus dem cosine.schema) zurück. Der Vollständigkeit halber: Die betagte 0.9.2342.*-OID entstammt dem Directory Pilot Project für X.500 Attribute, von denen die meisten Attribute ursprünglich in RFC 1274 spezifiziert wurden (aktueller Stand: RFC 4524) und dem cosine.schema entstammen. Mehr zu OIDs von Attributen und Objektklassen im Abschnitt 3.9, »Selbst ist der Admin – das eigendefinierte Schema«.
83
2.3
1198.book Seite 84 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Abgesehen davon, dass kaum anzunehmen ist, das sich irgend jemand auf dieser Erdkugel die OID eines Attributs besser merken könnte als den menschenlesbaren Alias selbiger, müssen wir bei dieser Art der Suche einen Punkt stets im Hinterkopf behalten: Suchen wir nämlich über die OID, kann es zu ungewünschten Nebeneffekten kommen – wenn z.B. das Attribut A eines Objekts abgefragt wird, das über Vererbung eines Superior (übergeordneten) Attributs B entstand, und A selbst nicht gesetzt ist, bekämen wir als Ergebnis, dass bei der OID-Abfrage des Attributs A statt der korrekten Ausgabe (eben gar nichts) der eigentlich nicht zugehörige Wert von Attribut B angezeigt wird. Daher sollte bei der Suche immer der eindeutige, namentliche Attributbezeichner verwendet werden. Hinzu kommt, dass diese Suche auch schneller ist, da Attribute über die Datenbank indexiert werden können. OIDs werden nicht indexiert, daher muss jedes Mal der komplette DIT durchsucht werden, und die Performance geht logischerweise in die Knie. Eine weitere, interessante und hilfreiche Option von ldapsearch ist das kleine, aber feine »+«. Darüber werden die so genannten »operational Attributes« angezeigt. Diese normalerweise »unsichtbaren« Attribute führt jedes Objekt unseres DITs mit sich. Sie enthalten – neben einer intern verwendeten, eindeutigen entryUUID und der dem Objekt zugrunde liegenden, strukturellen Objektklasse – sehr wichtige Informationen, wie z.B. den DN des Users, der das Objekt angelegt (creatorsName) bzw. zuletzt modifiziert hat (modifiersName). Hinzu kommen unabdingbare Informationen wie z.B. der createTimestamp und der modifyTimestamp des Datensatzes, wobei Letzterer – neben der entryCSN – für eine korrekte Replikation des Datensatzes unerlässlich ist. #> ldapsearch –x uid=ckent –LLL +
Ausgabe: dn: uid=ckent,ou=verkauf,dc=local,dc=site structuralObjectClass: inetOrgPerson entryUUID: 7637f55e-36db-102d-8896-771018049ad4 creatorsName: cn=ldapadmin,dc=local,dc=site createTimestamp: 20081025122323Z entryCSN: 20081025210930.472801Z#000000#000#000000 modifiersName: cn=ldapadmin,dc=local,dc=site modifyTimestamp: 20081025210930Z entryDN: uid=ckent,ou=verkauf,dc=local,dc=site subschemaSubentry: cn=Subschema hasSubordinates: FALSE
Eine gezielte Ausgabe einzelner operational Attributes ist natürlich auch möglich: #> ldapsearch -x uid=ckent modifiersName modifyTimestamp -LLL
84
1198.book Seite 85 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
ldapsearch zum Dritten – Suchfilter Die Verwendung von Suchfiltern ermöglicht es uns, selektiv Einträge aus dem DIT zu lesen. Anstatt an dieser Stelle die komplette Litanei aller möglichen ldapsearch-Optionen und -Filter herunterzubeten, werden wir die jeweils relevanten Optionen in diesem und den folgenden Kapiteln anhand der entsprechenden Beispiele demonstrieren und erläutern. Beschränken wir uns also zunächst auf die ldapsearch-Basics, von denen wir ja bereits einige kennengelernt haben. Unterhalb unserer BaseDN dc=local,dc=site stehen uns die 5 Organizational Units (ou) verkauf, forschung (mit Sub- Unit ou=xeno), security und marketing sowie die den Units untergeordneten User als Test-Objekte zur Verfügung. ldapsearch bietet uns nun etliche Möglichkeiten, die Suche selektiv auf bestimmte Bereiche und Objekte unseres DIT einzuschränken. Kommen wir als Erstes zur Einschränkung des Bereiches, in dem überhaupt gesucht werden soll. Hierfür steht die Kommandozeilenoption –s <scope> zur Verfügung. <scope> (engl. = Bereich) spezifiziert die Suchtiefe innerhalb des DIT und kann dabei die Werte base, one oder sub annehmen. Die Bedeutung des scopes ist schnell erklärt: 왘 base: Nur innerhalb der BaseDN suchen (bei uns: local.site), nicht unterhalb. 왘 one: Es wird nur eine (one) Ebene unterhalb der jeweils angegebenen Searchbase (-b) gesucht. 왘 sub: (Standard-Scope) Suche im kompletten DIT. Wenn nichts angegeben wird, gilt immer sub. Mit der Kommandozeilenoption -b (siehe oben) kann die Searchbase angegeben werden, d.h. der Punkt im DIT, ab dem die Suche starten soll. Das kann die BaseDN, aber auch jeder andere untergeordnete Punkt innerhalb des DIT, z.B. eine ou. Wenn nichts angegeben wird, sucht ldapsearch nach einer korrespondierenden Einstellung für die Searchbase in der Client-Konfigurationsdatei ldap.conf. Ist dort nichts definiert und ebenfalls in der slapd.conf kein Eintrag für die defaultsearchbase vorhanden, startet ldapsearch mit einer undefinierten Searchbase und liefert üblicherweise kein Suchergebnis zurück. Demonstrieren wir nun einige Suchbeispiele anhand unseres DIT: #> ldapsearch -x -LLL cn="Ellen Ripley*" -s base
Das liefert gar nichts zurück, weil die gute, alte und vor allem geklonte Ellen Ripley zwar dreimal im DIT vorhanden ist, aber sicher nicht in unserer BaseDN, sondern nur unterhalb der ou forschung, der ou xeno unterhalb der ou forschung sowie der ou marketing. Eine Anmerkung hierzu: Im Normalfall ist es weder
85
2.3
1198.book Seite 86 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
günstig noch empfehlenswert, ein und dasselbe User-Objekt mehrmals an verschiedenen Stellen des DIT zu erstellen. Wir haben in diesem Fall das Userobjekt uid=eripley mehrfach angelegt (natürlich mit unterschiedlichen uidNumber und cn’s), um die Funktionalität der Suchfilter und Scopes in diesem frühen Stadium zu demonstrieren. Im Normalfall würde ein User-Objekt als member einem oder mehreren Gruppenobjekten statisch oder dynamisch zugeordnet werden. Dieses Verfahren werden wir im Folgenden noch genau erläutern. Der folgende Suchbefehl #> ldapsearch -x -b ou=forschung,dc=local,dc=site \ cn="Ellen Ripley*" -s one description
liefert uns genau einen gefundenen Eintrag zurück, und zwar den aus der ou forschung, die wir per Option -b als Searchbase angegeben haben. Die »unter«-Unit xeno wird aufgrund des gesetzten scopes (-s one) ignoriert. #> ldapsearch -x -b ou=forschung,dc=local,dc=site \ cn="Ellen Ripley*" -s sub description
Diese Eingabe liefert uns hingegen zwei Einträge für cn=Ellen Ripley (1 und 2), einmal den aus der Unit-Forschung sowie den aus der Sub-Unit xeno. Die Option -s sub ist in diesem Fall optional, da -s Default immer sub ist, wenn nichts explizit angegeben wird. Weitere Filtertypen: 왘 ~= annähernd gleich
approx(imate)
왘 <= kleiner gleich
(less) eq(ual)
왘 >= größer gleich
(greater) eq(ual)
Anmerkung: Der Filter ~= funktioniert allerdings nur, wenn die Kompilationsoption --enable-phonetic gesetzt wurde (üblicherweise Default) #> ldapsearch -x -b ou=forschung,dc=local,dc=site \ cn~="Repeley" description
und <= bzw. >= nur bei Attributen, die eine ORDERING-MatchingRule besitzen, wie z.B. das Attribut dnQualifier aus dem core.schema. ldapsearch, zum Vierten – Filterverknüpfungen Testen wir nun einige Verknüpfungen von Suchfiltern. Wenn im LDAP-Kontext von Verknüpfungen gesprochen wird, sind logische Verknüpfungen im Sinne von UND/ODER/NICHT gemeint. Die Filterverknüpfungen bauen sich wie folgt auf:
86
1198.book Seite 87 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
왘 ( & (filter 1) (filter 2) … (filter n))
→ UND-Verknüpfung
왘 ( | (filter 1) (filter 2) … (filter n))
→ ODER-Verknüpfung
왘 ( !
→ Filter-Negierung
(filter) )
Der letzte Punkt, die Filternegierung, kann sich immer nur auf einen Filter beziehen. Dazu nun einige Beispiele aus unserem DIT (einige der Befehlszeilen sind umbrochen): #> ldapsearch -x "(|(sn=Kiu)(sn=Ripley))" -LLL dn
Findet alle User-Objekte im DIT, deren sn-Attribut (surname, Nachname) den Wert Kiu ODER (|) Ripley hat. #> ldapsearch -x "(&(uid=*)(description=*Forschung*))" -LLL dn
Findet alle User-Objekte, die das Attribut uid gesetzt haben UND (&) in deren Beschreibungsattribut der String Forschung auftaucht. #> ldapsearch -x "(|(uid=ckent)(&(sn=*i*) \ (description=*Forschung)))" -LLL dn
Findet alle User-Objekte, deren uid entweder ckent ist ODER deren sn-Attribut ein »i« enthält UND deren description-Attribut am Ende des Strings das Wort »Forschung« enthält (ckent, eripley, skiu). #> ldapsearch -x "(|(uid=ckent)(&(sn=*i*) \ (description=*Forschung)(!(sn=Ripley))))" -LLL dn
Liefert fast das gleiche Ergebnis wie der vorherige Suchfilter, allerdings wird hierbei noch der Datensatz mit dem sn-Attributwert »Ripley« per »!« (NICHT) ausgeschlossen. Eine etwas andere Reihenfolge für das Filterkonstrukt ist hier ebenfalls möglich, um den gleichen Effekt zu erzielen. Wichtig ist dabei schlussendlich immer die korrekte Klammersetzung, damit die logischen Verknüpfungen korrekt greifen: #> ldapsearch -x "(|(uid=ckent)(&(!(sn=Ripley))(sn=*i*) (description=*Forschung)))" -LLL dn
\
Anhand der Beispiele lässt sich gut erkennen, wie wir mit relativ geringem Aufwand die Suche durch effiziente Verknüpfungen von Filtern einschränken können. Weitere Einschränkungen durch Spezifikation der Searchbase (-b) können natürlich im Zusammenspiel ebenfalls verwendet werden. Am wichtigsten ist – wie soeben erwähnt – immer die korrekte Klammersetzung, um die richtigen Verknüpfungen zu erzielen. Dazu an dieser Stelle noch einige abstrakte Beispiele, ohne Bezug auf unseren DIT:
87
2.3
1198.book Seite 88 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
(&(mail=*)(uid=*t)(sn=k*))
# Attribut mail vorhanden UND uid endet mit »t« UND sn beginnt mit »k«. (|(cn=x*)(cn=y*)(cn=z*))
# cn beginnt mit x ODER y ODER z. (&(!(cn=c*))(!(sn=k*)))
# cn beginnt NICHT mit »c« UND sn beginnt NICHT mit »k«. Ein ähnliches Vorgehen zur Präselektion von Objektdaten lässt sich mit LDAPURLs erreichen, die wir im späteren Verlauf noch ansprechen werden. ldapsearch, zum Fünften – Schema-Checking, Extensions und anderes Als vorerst letztes ldapsearch-Beispiel wollen wir noch kurz die nützliche Eigenschaft demonstrieren, per ldapsearch über Schema-Discovery (ab LDAP Protokollversion 3) die geladenen Objektklassen, Attribute, Matching Rules und die verwendete LDAP-Syntax unseres DIT zu listen. Wir verwenden dazu ldapsearch mit folgenden Optionen: #> ldapsearch -x -b cn=subschema -s base <suchbegriff> # oder "+"
Für <suchbegriff> können wir an dieser Stelle Folgendes einsetzen: objectClasses, attributeTypes, matchingRules und ldapSyntaxes. Setzen wir alternativ "+", haut uns unser slapd alle oben genannten Informationen um die Ohren, und noch mehr. Unterhalb der Base cn=subschema (der Name kann optional über die schemadn-Direktive in der slapd.conf geändert werden, worauf in der Praxis jedoch üblicherweise nicht zurückgegriffen wird) finden sich üblicherweise die in RFC 4512 definierten Subschema Subentries. Subschema (Sub)entries werden –vereinfacht ausgedrückt- dazu verwendet, um grundlegende Informationen über die zur Verfügung stehenden Schemas zu verwalten. Im Detail: Welche der oben genannten objectClasses, attributeTypes, matchingRules und ldapSyntaxes stehen uns konkret zur Verfügung? Nehmen wir an, wir brauchen schnell eine Information über die MUST-Attribute der Objektklasse posixAccount, so liefert uns z.B. der Befehl #> ldapsearch -x -b cn=subschema -s base \ objectClasses | grep –i posixaccount -A3
blitzschnell einen Überblick: objectClasses: ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) )
88
1198.book Seite 89 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
Okay, seien wir mal ehrlich: Ein grep –i posixaccount nis.schema –A5 hätte uns das gleiche Ergebnis genauso schnell gebracht. Aber irgendwie weiß man ja vielleicht doch nicht immer so genau, in welchem Schema sich das gesuchte Objekt gerade versteckt, oder …? Weiter im Text: #> ldapsearch –x -b "" -s base +
liefert uns neben anderen Informationen über verfügbare LDAP-Extensions, -Controls und -Features auch die unterstützten Authentifizierungsmechanismen (*SASL*) sowie die LDAP-Protokollversion. Hier einige Auszüge: supportedControl: 2.16.840.1.113730.3.4.18 supportedControl: 2.16.840.1.113730.3.4.2 supportedControl: 1.3.6.1.4.1.4203.1.10.1 supportedControl: 1.2.840.113556.1.4.319 supportedControl: 1.2.826.0.1.3344810.2.3 supportedControl: 1.3.6.1.1.13.2 supportedControl: 1.3.6.1.1.13.1 supportedControl: 1.3.6.1.1.12 supportedExtension: 1.3.6.1.4.1.1466.20037 supportedExtension: 1.3.6.1.4.1.4203.1.11.1 supportedExtension: 1.3.6.1.4.1.4203.1.11.3 supportedExtension: 1.3.6.1.1.8 supportedFeatures: 1.3.6.1.1.14 supportedFeatures: 1.3.6.1.4.1.4203.1.5.1 supportedFeatures: 1.3.6.1.4.1.4203.1.5.2 supportedFeatures: 1.3.6.1.4.1.4203.1.5.3 supportedFeatures: 1.3.6.1.4.1.4203.1.5.4 supportedFeatures: 1.3.6.1.4.1.4203.1.5.5 supportedLDAPVersion: 3 supportedSASLMechanisms: CRAM-MD5 supportedSASLMechanisms: DIGEST-MD5 supportedSASLMechanisms: GSSAPI supportedSASLMechanisms: EXTERNAL
# # # # # # # # # # # # # # # # # #
Proxied Authorization ManageDSAIT [RFC3296] Subentries [RFC3672] Paged Results Matched Values Control Post read Control Pre read Control Assertion Control Nur bei aktiviertem TLS Modify Password ldapwhoami Cancel operation Incremental modify Operational Attributes ObjectClass Attribute-Def.Lists Boolean True/False Filters Language Tag Options Laguage Range Options
# nur bei aktiviertem TLS [RFC2830,s.o.]
Weitere Infos hierzu finden sich in den RFCs 4512 und 4521. Ein interessantes Feature sei an dieser Stelle in Verbindung mit ldapsearch ebenfalls noch genannt – der so genannte extensible Search. Typischerweise wird in der Attributdefinition eines Attributes festgelegt, wie nach dem Attribut gesucht werden kann, so z.B., ob Groß-Kleinschreibung beachtet werden soll oder nicht. Typischerweise gilt bei bestimmten Attributen wie cn oder uid die Matching Rule caseIgnoreMatch, also wird Groß- und Kleinschreibung ignoriert. Über den extensible Search #> ldapsearch -x uid:caseExactMatch:=CKent
wird explizit die im Suchstring angegebene Matching Rule impliziert, d.h., es wird in diesem Fall nach Groß- und Kleinschreibung unterschieden.
89
2.3
1198.book Seite 90 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Als letztes, aber nicht unwichtigstes ldapsearch-Beispiel wollen wir uns noch anschauen, wie wir mit ldapsearch den eigentlichen Naming Context, also den Suffix unseres DIT auslesen können. An dieser Stelle muss natürlich unweigerlich die Frage kommen: Wieso das denn? Ganz einfach: Wissen wir denn wirklich immer, wie der NC (Naming Context) des Servers aussieht, auf den wir zugreifen? Nö. Und in diesem Fall können wir uns – natürlich vorausgesetzt, wir kennen wenigstens den Server bzw. seine IP – das Attribut namingContexts auslesen, das alle NCs beinhaltet, die der LDAP-Server bedient: #> ldapseach –x –h –b ““ –s base namingContexts
ldappasswd Das ldappasswd-Kommando dient dazu, die Passwörter bereits bestehender UserObjekte zur Laufzeit im DIT zu ändern. Der Unterschied zum bereits verwendeten slappasswd besteht vereinfacht ausgedrückt darin, dass ldappasswd den Passworteintrag über das LDAP-Protokoll direkt im aktiven DIT ändert; slappasswd hingegen liefert »offline« einen codierten Passworteintrag, der per Cut & Paste oder über append (>>) in einer LDIF-Datei oder – wie bereits demonstriert – in unserer slapd.conf Verwendung finden kann. Nehmen wir ein konkretes Beispiel, in dem wir das Passwort von Clark Kent ändern (Zeile umbrochen): #> ldappasswd -xWD cn=ldapadmin,dc=local,dc=site –S \ uid=ckent,ou=verkauf,dc=local,dc=site
Die Passwortabfrage erfolgt dabei drei Mal: das neue Passwort für Clark Kent, die Bestätigung des neuen Passworts für Clark Kent und zu guter Letzt das Passwort für unseren ldapadmin, damit die Änderungen in den DIT geschrieben werden können. Der zu verwendende Verschlüsselungsalgorithmus wird über die Direktive password-hash in der slapd.conf(5) eingestellt. ldapcompare ldapcompare führt eine Vergleichsabfrage (engl. compare = Vergleich) durch und liefert – je nachdem, ob das gesuchte Objekt bzw. der korrekte Attributwert im DIT gefunden wurde – einen entsprechenden Boolean-Wert (TRUE/FALSE) zurück: #> ldapcompare -x "uid=ckent,ou=verkauf,dc=local,dc=site" sn:Kent TRUE
90
1198.book Seite 91 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
ldapwhoami Dieses Tool gibt die Identität an, mit der man am DIT angemeldet ist. Die Funktionalität ist mit dem Linux-»whoami« vergleichbar, bringt uns aber in diesem frühen Stadium unseres LDAP-Setups keinen nennenswerten Vorteil, da zurzeit auf jeden Fall noch ein simple bind per DN-Authentifizierung erfolgen muss: #> ldapwhoami -xWD "uid=ckent,ou=verkauf,dc=local,dc=site"
Es bestätigt uns nach Eingabe des Passworts für Clark Kent, dass Clark Kent Clark Kent ist. Gut zu wissen, zumindest bei partieller Amnesie. Interessanter wird’s später mit GSSAPI. Versprochen. ldapmodrdn Die Schlüsselbuchstaben bei diesem LDAP-Kommandozeilentool sind »rdn«, denn rdn steht in diesem Fall für »relative distinguished name«, und den Begriff kennen wir schon aus den ersten Abschnitten. Nehmen wir z.B. den DN unseres User-Objekts Susie Kiu. Der komplette DN liest sich wie folgt: uid=skiu,ou=forschung,dc=local,dc=site. Der RDN (Relative Distinguished Name) der guten Susie lautet dabei: uid=skiu. Und genau diesen Eintrag können wir nun per ldapmodrdn modifizieren. Im folgenden Beispiel benennen wir unsere Susie um, und zwar ändern wir ihre uid von skiu auf skiu1: #> ldapmodrdn –xWD cn=ldapadmin,dc=local,dc=site \ uid=skiu,ou=forschung,dc=local,dc=site uid=skiu1
Eine weitere Variante ist die Angabe einer Datei (mod_skiu.ldif), in der der »alte«, komplette DN und der neue RDN angegeben sind, z.B.: uid=skiu,ou=forschung,dc=local,dc=site uid=skiu1
Mit ihr können wir das Objekt ebenfalls modifizieren: #> ldapmodrdn -xWD cn=ldapadmin,dc=local,dc=site -r -f mod_skiu.ldif
\
Der Parameter -r kümmert sich dabei um die Löschung des alten RDNs. ldapmodify, zum Zweiten - modrdn Wollen wir unsere gute Susie nun komplett in eine andere ou verschieben, ist dazu ein anderes Vorgehen nötig. Und zwar benötigen wir dazu den bereits bekannten ldapmodify-Befehl, allerdings mit einer etwas abgewandelten LDIFDatei.
91
2.3
1198.book Seite 92 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Würden wir einfach den Datensatz unseres User-Objekts uid=skiu per ldapsearch extrahieren, den DN bearbeiten und per ldapmodify wieder einfügen, bekämen wir eine Fehlermeldung, weil das User-Objekt an dem neuen Ort noch gar nicht existiert und daher nicht modifiziert werden kann. Nun kann man natürlich einwenden, dass man das User-Objekt an die neue Stelle im DIT kopieren und das alte Objekt löschen kann. Völlig richtig. Allerdings sind das schon vier Arbeitsschritte (Extrahieren, Modifizieren, Importieren, Löschen). Und da wir ergonomisch arbeiten, machen wir es etwas anders: Wir erzeugen die folgende kleine LDIF-Datei (skiu_modrdn.ldif): dn: uid=skiu,ou=forschung,dc=local,dc=site changetype: modrdn newrdn: uid=skiu deleteoldrdn: 1 newSuperior: ou=verkauf,dc=local,dc=site
und führen nun den ldapmodify-Befehl in bekannter Weise aus: #> ldapmodify -xWD cn=ldapadmin,dc=local,dc=site -f skiu.ldif
Das Ergebnis bzw. die Rückmeldung sollte nach Eingabe unseres ldapadmin-Passworts folgendermaßen aussehen: modifying rdn of entry uid=skiu,ou=forschung,dc=local,dc=site"
Natürlich stellen wir uns nun die Frage, woher die speziellen Anweisungen und Parameter dieser LDIF-Datei stammen. Dazu müssen wir leider einen Blick in die etwas trockene technische Spezifikation der LDIF-Dateien werfen, die in RFC 2849 »The LDAP Data Interchange Format (LDIF)« definiert ist. An dieser Stelle daher nur ein kurzes Listing der wichtigsten Parameter, die nicht nur in Verbindung für Modifikationen des RDN nutzbar sind, sondern auch für andere Einträge in der LDIF-Datei per ldapmodify genutzt werden können, z.B. auch zum Ergänzen (add) oder Löschen (delete) von Attributen. Mögliche Werte für 왘 changetype: [ add | delete | modify | modrdn/moddn ] 왘 bei changetype modify: Verwendung von add:, replace: und delete: möglich. 왘 deleteoldrdn: 0 oder 1 (0 = alten Eintrag behalten,1 = alten Eintrag löschen) 왘 newsuperior: der neue DN-Eintrag des Objekts (nur in Verbindung mit modrdn) 왘 newrdn: der neue rdn-Eintrag des Objekts (nur in Verbindung mit modrdn)
92
1198.book Seite 93 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
Eine komplette Erläuterung aller Varianten mit Beispielen würde den Rahmen dieses Abschnitts sprengen, daher verweisen wir an dieser Stelle noch einmal auf die im Anhang aufgeführte RFC 2849, in der auch aussagekräftige Beispiele aufgeführt sind. New Kid on the Block – Extended Operations mit ldapexop ldapexop wurde in Version 2.4 eingeführt, um direkt so genannte »extended Operations« auf Objekte innerhalb des DIT anwenden zu können. Extendend Operations benötigen wir z.B., um dynamische Objekte im Tree zu behandeln; wie das geht, zeigen wir im Overlay-Abschnitt 3.1.5, »Hochdynamisch«. Eine andere Anwendung wäre das Handling von manageDSAit-Controls, das wir z.B. in Verbindung mit referrals (Verweisen) benötigen; dieses Control schauen wir uns im Abschnitt über Chaining genauer an. Leider existiert zum Zeitpunkt der Erstellung des Buchs noch keine nennenswerte Manpage zu diesem Tool (Ausnahme ldap_extended_operation(3), die nur die internen Routinen beschreibt); wollen wir hoffen, dass sich dies bald ändert. Eine weitere und sehr machtvolle Einsatzmöglichkeit bieten die extended Operations in Verbindung mit dem Access-Level »manage« und dem Control manageDIT. Dazu später mehr im Abschnitt über ACLs »Nur mit Clubkarte«. Grundsätzlich ist es auch möglich, alle extended Operations per ldapmodify (-e) anzustoßen. Beispiele hierzu werden wir uns später anschauen.
2.3.2
… und wann mit slap* ?
slapcat und slapadd Eine gute Frage. Denn einige Befehle wirken auf den ersten Blick zumindest verwandt, so wie z.B. ldappasswd und slappasswd, oder slapadd und ldapadd. Aber: Die slap*-Tools arbeiten völlig anders als Ihre ldap*-Online-Brüder. Rekapitulieren wir: Alle Aktionen wie z.B. Lesen oder Schreiben erfolgen mit den ldap*Tools von einem beliebigen LDAP-Client, der über das LDAP-Protokoll(!) auf den Server zugreift. Daher ist auch für alle ldap*-Befehle ein aktiver slapd zwingende Vorgabe. Dagegen gilt jedoch bei der Verwendung fast aller slap*-Tools: Der slapd sollte NICHT laufen, um die Integrität der unterliegenden Datenbank nicht zu gefährden. Die Ursache liegt darin begründet, dass die slap*-Tools direkt auf die LDAPDatenbankdateien der Berkeley DB (den Ablage-Ort gibt die Direktive directory in unserer slapd.conf vor) zugreifen. Aus diesem Grund können die slap*-Befehle auch nicht via LDAP-Protokoll über das Netz,
93
2.3
1198.book Seite 94 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
sondern immer nur direkt auf der Maschine abgesetzt werden, auf der sich auch der eigentliche LDAP-Server mitsamt den Datenbankdateien befindet. Daher auch oft der Begriff »Offline-Tools« im Zusammenhang mit slap*-Kommandos. Prinzipiell lässt sich sagen, dass Tools wie slapcat oder slapadd aus Gründen der Daten-Konsistenz immer im Offline-Modus benutzt werden sollten, allerdings mit einer Ausnahme, zu der wir gleich kommen. Die Daseinsberechtigung dieser beiden Tools besteht primär in zwei Verwendungen: Backup und Klonen. Beim Backup könnte eine zuvor per slapcat ausgelesene Datenbank, die durch Fehler unbrauchbar geworden ist, über slapadd jederzeit wiederhergestellt werden. Eine andere Einsatz-Variante wäre das »Klonen« einer vorhandenen LDAPDatenbank zur Erzeugung eines identischen Datenbestandes auf einer anderen Maschine zwecks Replikation (siehe hierzu auch das Abschnitt 3.2, »Replikation«). Dabei würde auf dem nicht laufenden LDAP-Master-Server ein kompletter Datenbank-Dump des aktuellen DITs per slapcat erstellt, der wiederum in die leere Datenbank des ebenfalls nicht aktiven LDAP-Slave-Servers per slapadd eingelesen würde. ACHTUNG: Eine Vermischung der Befehle – z.B. Auslesen der Datenbank per slapcat und anschließendes Einlesen dieser Datensätze in eine leere Datenbank mit ldapadd – sollte vermieden werden. Die per slapcat ausgelesenen Datensätze werden in der Reihenfolge ausgelesen, wie sie physikalisch in der Datenbank liegen, und nicht hierarchisch, wie z.B. ldapsearch es macht. slapadd prüft auch nicht die Existenz erforderlicher Superior-Einträge (z.B. TLD: local.site), bevor es einen gegebenenfalls untergeordneten Datensatz in die Datenbank schreibt.
Daher sollten slapcat und slapadd immer nur zusammen in dieser Konstellation als Offline-Werkzeuge zum Auslesen und Befüllen einer nicht laufenden LDAP-Datenbank verwendet werden. (Wegen ihrer etwas »groben« Vorgehensweise laufen sie auch manchmal unter der Bezeichnung »Brute-Force-Directory-Commands«). Und noch ein wichtiger Punkt zum Thema »Rohe Gewalt«: slapadd eignet sich auch nicht dazu, einzelne Datensätze inkrementell dem DIT hinzuzufügen, so wie ldapadd es vermag, sondern immer »nur« für das volle Programm, wie eine Initialbefüllung einer Datenbank. Bei slapadd gilt also immer: Alles oder nichts.
Eine einfache, aber effektive und automatisierte Sicherung der LDAP-Datenbank per cron könnte so aussehen: Stop des slapd, Test auf laufende Instanzen des Daemons, wenn keine vorhanden, Dump der Datenbank per slapcat. killall slapd; [ “$(ps aux | grep slapd | grep –v grep)” ] slapcat > dbdump_$(date +%F).ldif
94
&& \
1198.book Seite 95 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
Dann Neustart des Daemons. Bei mehreren Datenbanken kann per slapcat –n die gewünschte Datenbank angegeben werden. Die Rücksicherung erfolgt ebenfalls bei gestopptem slapd und vorab gelöschten Datenbank-Dateien (Ausnahme: die Datei DB_CONFIG) unterhalb des BDB-Arbeitsordners (z.B. /var/ lib/ldap/*.* in unserer Konfiguration) per: #> slapadd –l dbdump_.ldif
Anschließend müssen gegebenenfalls noch der korrekte Eigentümer und die Gruppe für die frisch generierten DB-Dateien gesetzt werden. Wenn wir uns die LDIF-Datei unseres per slapcat erstellten Backups anschauen, erkennen wir auch sehr schnell, wo der gravierende Unterschied zwischen dem Auslesen eines laufenden LDAP-Servers per ldapsearch und dem Dump der dbDateien per slapcat liegt: slapcat liest zu jedem Objekt nicht nur die Standard-Attribute, sondern auch die bereits bekannten operational Attributes aus. Das ist vor allem dann unverzichtbar, wenn die zurückzusichernde Datenbank Teil einer Replikation ist. Nur so ist sichergestellt, dass alle beteiligten Server aufgrund der Timestamps wissen, wie aktuell welcher Datensatz nach dem Restore wirklich ist. An dieser Stelle müsste eigentlich spätestens irgend jemand einwerfen, dass man doch auch per ldapsearch alle Attribute, also auch die operational Attributes auslesen kann. Klar, das funktioniert, und sogar so gut, dass wir tatsächlich ALLE Attribute auf dem Radar haben: #> ldapsearch -xWD cn=ldapadmin,dc=local,dc=site
"*" "+"
Aber – und jetzt kommt der entscheidende Part: Unser slapd läuft, rennt, arbeitet – kurzum: er ist aktiv, und somit kann rein theoretisch in der Zeitspanne auf ihn schreibend(!) zugegriffen werden, während wir gerade die DB auslesen. Folge: mögliche Inkonsistenzen. Also: Normalerweise Finger weg von dieser Nummer, und Backups immer schön artig offline per slapcat erstellen, dann gibt’s in keinem Fall Ärger mit unerwünschten Modifikationen beim Auslesen. Die einzige Alternative, um slapcat auf einem laufenden System einzusetzen, wäre bei gleichzeitiger Verwendung der Online-Konfiguration gegeben. Mit ihrer Hilfe (und dem Boolean-Attribut olcReadOnly können wir unseren eigentlichen Datenbank-Kontext (dc=local,dc=site) temporär in den Read-Only-Status versetzen. Wie das funktioniert, schauen wir uns im nächsten Abschnitt 2.4.2, »slapd – Online-Administration«, genauer an.
95
2.3
1198.book Seite 96 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Noch eine grundsätzliche Anmerkung, die prinzipiell für alle Backups gilt: Backup regelmäßig durchführen: gut. Backup regelmäßig durchführen und in nicht allzu großen Intervallen zusätzlich prüfen, ob ein Restore mit den frisch gezogenen Backup-Daten auch wirklich funktioniert: optimal.
Eine weitere, aber nicht wirklich unproblematische Backup-Variante wäre die Verwendung von db_hotbackup, einem Tool der bdb-Utils, doch dazu später mehr im Abschnitt 3.8 über die Berkeley DB, »Larry und die schläfrigen Katzen«. Noch ein Wort zur slapadd-Performance: Gerade bei der Initialbefüllung von sehr großen Datenbeständen per slapadd spielen neben der Cache-Auslegung, zu der wir später kommen (siehe oben), zwei Faktoren eine große Rolle. Zum einen kann über die slapd.conf der Parameter tool-threads gesetzt werden, wobei der Integer-Wert der Anzahl der verwendbaren CPUs entspricht. Bei zwei CPUs kann also tool-threads 2 gesetzt werden, was die Performance schon deutlich verbessern sollte. Zum anderen kann slapadd auch mit dem Schalter -q (quick) gestartet werden, wobei allerdings einige Integritätsprüfungen auf der Strecke bleiben. Die gesteigerte Performance kann so schnell in einer inkonsistenten Datenbank resultieren. slapindex Das slapindex-Kommando dient der manuellen Offline-(Re-)Indizierung der Datenbank bzw. einzelner Attribute, z.B. wenn der slapd-Konfiguration ein neues index-Statement hinzugefügt wurde. Beim Import eines Datensatzes per ldapadd werden die in den Datenbankoptionen der slapd.conf bzw. in slapd.d/ gesetzten Indizes automatisch aktualisiert. Beim direkten Import von Daten per slapadd ist nur noch in den Versionen vor 2.3 eine manuelle Reorganisation per slapindex nötig. Die aktuelle Version von slapadd erledigt dies beim Import der Datensätze automatisch. Was wir beachten müssen: Alle generierten IndexDateien werden mit der Identität des Users angelegt, der das slapindex-Kommando ausführt. Arbeiten wir in der Online-Konfiguration unseres slapd, ist slapindex zum Däumchendrehen verdonnert, denn die Indexe werden dann zur Laufzeit on the fly generiert. Auch dazu gleich mehr im Abschnitt 2.4 über die OpenLDAP-Laufzeitkonfiguration und später im Abschnitt 3.8 über die Berkeley DB, »Larry und die schläfrigen Katzen«. Sonstige slap*-Tools: 왘 slapacl: Vorabtests von ACLs – dazu mehr im Abschnitt über ACLs.
96
1198.book Seite 97 Donnerstag, 5. Februar 2009 3:02 15
Fingerübungen – OpenLDAP-Tools auf der Konsole
왘 slaptest: Syntaktischer Check der slapd.conf. Kleiner Tipp: slaptest kann ebenfalls zur Konvertierung der statischen in eine Online-Konfiguration verwendet werden. Syntax (hier ohne Pfadangaben): slaptest -f slapd.conf -F slapd.d/
왘 slapdn: Konformitätsüberprüfung von DNs anhand der eingebundenen Schemas 왘 slapauth: Hierüber kann die Umsetzung von DNs bei der Authentifikation mit Hilfe der authz-policy und authz-regexp-Direktiven in der slapd.conf vorab getestet werden. … edit on the fly – mit ldapvi Und da wir immer noch bei Kommandozeilentools sind, hier noch ein Hinweis auf ein hilfreiches Tool, welches das Management der Objekte per Kommandozeile für den einen oder anderen noch etwas übersichtlicher gestalten mag: ldapvi. Auf der Debian-Seite existiert ldapvi als Bestandteil der Distribution, bei OpenSUSE finden sich ebenfalls entsprechende Pakete in den Repositories. Und wie der Name schon erahnen lässt, ist der gute alte vi(m) involviert. Für SUSE und andere Distributionen, in denen das Tool nicht enthalten ist, kann auf die Sourcen zurückgegriffen werden, der von David Lichteblau (http:// www.lichteblau.com/src.html#ldapvi) bereitgestellt wird. ldapvi lässt sich – sofern die Client-Datei ldap.conf konfiguriert ist – ohne Parameter aufrufen und zeigt dann alle im DIT vorhandenen Objekte. Diese lassen sich dann wie mit einem gewöhnlichen vi direkt bearbeiten. Die Änderungen werden beim Speichern (:w) nach entsprechender Autorisierung direkt in den DIT geschrieben. Eine Präselektion einzelner Objekte über Suchfilter ist wie bei ldapsearch möglich: #> ldapvi -D cn=ldapadmin,dc=local,dc=site uid=ckent
Ein ähnliches Verfahren verwenden übrigens auch die ldb*-Kommandozeilentools der neuen Samba 4-Suite. Alle weiteren Infos zu dem nützlichen Tool und zu seinen Kommandozeilenoptionen erhält man über die Manpage; ein umfangreiches Manual mit Beispielen befindet sich auf der oben genannten Website. ldap_scripts Ein weiteres »Tool« bzw. eine Tool-Sammlung für LDAP-Befehle bringen die so genannten ldap_scripts mit. Das Paket ist standardmäßig auf Debian Lenny enthalten, die Sourcen finden sich im Netz unter http://contribs.martymac.com/.
97
2.3
1198.book Seite 98 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Die ldapscripts verstehen sich dabei als ein Set von Shellskripten, mit denen man POSIX-Konten (User, Gruppen, Maschinen) in einem OpenLDAP-Verzeichnis verwalten kann. Sie können als Standalone-Werkzeuge angewendet oder z.B auch in die smb.conf eingebunden werden, um dort die entsprechenden Aktionen beim Anlegen/Löschen/Modifizieren von User-, Gruppen- und MaschinenObjekten zu triggern. Die Konfiguration der Skripte erfolgt durch Editieren der Datei ldapscripts.conf. Für die Anlage von Usern, Gruppen und Maschinen besteht zusätzlich die Möglichkeit, ldif-Templates zu verwenden. Ein kurzes Wort in eigener Sache zum Thema »LDAP-Skripte«, womit nicht nur diese Tools, sondern auch alle anderen gemeint sind, die »Arbeitserleichterungen« bei der täglichen Arbeit mit LDAP mit sich bringen sollen. Alles schön und gut, aber man sollte dabei nicht vergessen, dass jedes zusätzliche Tool oder Skript, das in die Kommunikationskette vor unseren slapd geschaltet wird, zusätzliche Probleme mit sich bringen kann. Nehmen wir ein simples Beispiel: In Version xyz einer beliebigen »LDAP-Script-Sammlung« modifiziert das script my_ldapmodify_xyz.sh (or whatever) einen oder mehrere hundert Datensätze mit einem Schlag. Tolle Sache. Was aber, wenn die statisch im Skript verbauten Parameter nicht mehr denen der eingesetzten slapd-(Minor-)-Version bzw. den korrespondierenden (lib)ldap-Tools entsprechen? Gibt’s nicht? Von wegen – alles schon da gewesen. In jeden Fall heißt es dann: Dumm gelaufen. Im günstigsten Fall passiert nix, im ungünstigsten all das, was wir weder wollen noch brauchen. Daher beim Einsatz aller Third-Party-Tools (davon nehmen wir auch sämtliche grafischen Klicki-Bunti-LDAP-Clients keineswegs aus) solche Sachen einfach mal im Hinterkopf behalten. Keep it simple.
2.4
Get it on(line) – OpenLDAP-Administration zur Laufzeit
Apropos: Bis zu diesem Punkt war ja alles noch recht simpel, deswegen schalten wir nun einen Gang höher und schauen mal, wie weit wir mit unserem angesammelten Wissen über die Kommandozeilentools aus den letzten Kapiteln kommen, wenn wir unseren slapd – auch fernab von grafischen Frontends – online konfigurieren und administrieren wollen. Hierzu switchen wir »mal eben« (genau die Schlüsselworte, die jeder Admin kennt und die typischerweise direkt nach dem Ausspruch durch den weisungsbefugten, aber IT-technisch völlig planlosen Vorgesetzen immer das gleiche, merkwürdige Kribbeln unter der Kopfhaut des Admins hervorrufen) auf die OnlineKonfiguration unseres slapd. Und um genau gegen dieses Gefühl gewappnet zu sein, nehmen wir das Prozedere jetzt ganz genau unter die Lupe.
98
1198.book Seite 99 Donnerstag, 5. Februar 2009 3:02 15
Get it on(line) – OpenLDAP-Administration zur Laufzeit
2.4.1
OpenLDAP Reloaded – ‘database config’ und die Online-Konfiguration
Seit Version OpenLDAP 2.3 gibt es eine grundlegende Veränderung gegenüber älteren Versionen: Die Möglichkeit der »Online«-Konfiguration zur Laufzeit. Bei Verwendung einer »statischen« slapd.conf ist bei jeder Änderung an der Datei bzw. Konfiguration ein restart/reload des slapd notwendig, damit der Daemon die Änderung übernehmen kann. Dieses Verhalten wurde komplett geändert, so dass seit Version 2.3 fast alle Änderungen an den Konfigurationsdirektiven ohne restart des slapd übernommen werden können. Aber nun die entscheidende Frage: Wie konnte das erreicht werden, wo die Datei slapd.conf(5) doch »statischer« Natur ist? Die Lösung liegt in der Verwendung einer eigenen Datenbank (database config), in der die konfigurationsspezifischen Einstellungen gespeichert werden. Die zugehörigen Daten werden im Ordner slapd.d/ unterhalb des distributionsspezifischen OpenLDAP-Konfigurations-Ordners (z.B. /etc/openldap bei SUSE) abgelegt. Als Backend wird das bereits vorgestellte ldif-Backend verwendet, daher liegen die Objektdaten auch in Form von klartextlesbaren LDIF-Dateien gemäß RFC 2849-Spezifikation vor, die auch alle operationellen Attribute wie z.B. Timestamps enthalten. Das Prinzip, das bei der Änderung von Parametern verwendet wird, entspricht dem in einer »regulären« LDAP-Datenbank. Hier wie dort können mit LDAP-Operationen wie z.B. ldapadd oder ldapmodify unter Verwendung von LDIF-Dateien Änderungen zur Laufzeit an der Konfiguration des slapd(8) vorgenommen werden, ohne den eigentlichen Prozess neu zu starten. Bei einer Modifikation wird der Timestamp des jeweiligen Objekts aktualisiert, was unseren slapd dazu veranlasst, die Konfiguration neu einzulesen und damit zu aktualisieren. Das Ganze funktioniert natürlich auch mit grafischen LDAP-Konfigurationstools. In OpenLDAP Version 2.4.x sind zum Teil umfangreiche und wichtige Änderungen und Neuerungen in die Online-Konfigurationsmöglichkeiten eingeflossen, die wir im Verlauf des Buches natürlich sehr genau unter die Lupe nehmen werden. Es gilt jedoch nach wie vor: Nicht alle Konfigurationsdirektiven der »alten«, statischen slapd.conf lassen sich ohne weiteres in die Online-Konfiguration übernehmen. Daher ist es möglich – und für bestimmte Konfigurationen durchaus praktisch-, das nach wie vor ein Mischbetrieb von statischer und dynamischer (Online-)Konfiguration möglich ist. Üblicherweise bietet es sich natürlich an, eine vorhandene und bereits so weit wie möglich konfigurierte slapd.conf in das Online-Format zu konvertieren, anstatt mit einem Basic-Setup »from the scratch« eine Initalbefüllung vorzuneh-
99
2.4
1198.book Seite 100 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
men und die umfangreichen Konfigurationsdirektiven anschließend manuell in die Online-Konfiguration einzupflegen. Letzteres würde sich höchstens für den gelangweilten Admin anbieten, der mal wieder absolut nichts mit seinem Jahresurlaub anzufangen weiß. Daher liegt es also nahe, die slapd.conf zunächst mit allen Parametern, Overlays, ACLs, Schemas etc. möglichst optimal auf die jeweiligen Anforderungen anzupassen, dann zu testen und schließlich in das OnlineFormat zu konvertieren. Hilfreiche Unterstützung hierbei wie auch bei allen verfügbaren Direktiven der Laufzeitkonfiguration, bietet slapd-config(5). Doch bevor es frisch ans Konvertieren geht, sind noch ein paar Stolpersteine aus dem Weg zu räumen: Der Online-Konfigurations-Ordner slapd.d/ existiert üblicherweise noch nicht, und muss vor der Konvertierung angelegt werden. Bei SUSE würde der komplette Pfad /etc/openldap/slapd.d/ lauten. Des Weiteren muß beachtet werden, dass dieser Ordner (mitsamt allen Unterordnern und Dateien) nach erfolgter Konvertierung für den User/die Gruppe schreib- bzw. lesbar sein muss, mit dessen/deren Rechten unser slapd läuft (bei SUSE z.B. User: ldap, Gruppe: ldap) sonst gibt es Probleme beim Zugriff auf die Daten der Online-Konfiguration bzw. ihrer permanenten Speicherung. Das läßt sich am einfachsten erreichen, indem der Konvertierungsvorgang direkt mit der Identität (User/Gruppe) durchgeführt wird, mit der unser slapd auch später arbeitet. Hierzu gleich mehr. Ein weiteres, unabdingbares Detail für den administrativen Zugriff auf die Online-Konfiguration ist natürlich der entsprechende DN. Admin-DN? Schon wieder? Wir haben doch schon einen. Richtig – aber »nur« für unser »Arbeits«Verzeichnis, das den Tree zu unserer BaseDN enthält, nämlich dc=local,dc=site. Der Konfigurations-Kontext ist jedoch ein ganz anderer: cn=config. Und um nun Zugriff auf diesen Kontext zu erlangen, brauchen wir einen neuen rootdn und das zugehörige Passwort. Am einfachsten lässt sich der Account durch eine kleine, zusätzliche Anpassung unserer slapd.conf vor der Konvertierung erreichen. Wir fügen oberhalb unseres »eigentlichen« Datenbank-Kontextes die drei folgenden Zeilen ein (die rootpwDirektive ist aus unserem »normalen« database hdb-Kontext übernommen, das Kennwort ist dementsprechend »linux«): database config rootdn cn=config rootpw {SSHA}iLwhoppdqOjJ+0HUroiScDJ3cpbOgo4u ###################### database hdb ...
100
1198.book Seite 101 Donnerstag, 5. Februar 2009 3:02 15
Get it on(line) – OpenLDAP-Administration zur Laufzeit
Nach der Konvertierung finden sich die Account-Daten (rootdn/rootpw) für den Zugriff auf die Konfigurationsdatenbank cn=config in folgender LDIF-Datei (relativer Pfad, die Backslashes maskieren nur die Sonderzeichen): slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif
und sehen etwa so aus: olcRootDN: cn=config olcRootPW:: e1NTSEF9aUx3aG9wcGRxT2pKKzBIVXJvaVNjREozY3BiT2dvNHU=
Um es noch einmal zu verdeutlichen: Der hier beschriebene olcRootDN dient ausschließlich der Verwaltung der neuen LDAP-Konfigurations-Datenbank unterhalb des Trees cn=config. Er ist nicht zu verwechseln mit dem gleichnamigen olcRootDN in der Datei ../slapd.d/cn=config/olcDatabase={1}hdb.ldif. Bei Letzterem handelt es sich um den konvertierten rootdn des Kontextes »dc=local, dc=site« und somit um den administrativen Account für die eigentliche Verzeichnis-Datenbank unseres DIT. Noch ein kleiner Tipp vor der Konvertierung: Wird die Template-Datei DB_CONFIG.example – in unserer Konfiguration z.B. unterhalb von /var/lib/ldap/ – in DB_CONFIG umbenannt und als Datenbank-Konfigurationsdatei für unsere Berkeley DB verwendet (siehe hierzu auch das Abschnitt 3.8, »Larry und die schläfrigen Katzen«, über die Berkeley DB), sollten alle eventuell vorhandenen Kommentare aus der Datei entfernt werden, da diese in etwas älteren OpenLDAP-Versionen sonst gegebenenfalls Probleme in der Online-Konfiguration bereiten könnten (»olcDbConfig: value #xyz provided more than once«).
Machen wir uns nun an die eigentliche Konvertierung: Die Konvertierungs-Funktionalität wird sowohl von unserem slapd-Daemon selbst, als auch von einigen anderen slap-Tools wie z.B. slaptest zur Verfügung gestellt. Wir stellen hier zunächst das Verfahren per slapd vor, die »Offline«-Konvertierungs-Variante per slaptest werden wir später im Abschnitt 3.2.10, »Replikation der Online-Konfiguration«, beleuchten. Zunächst sollte vor der Konvertierung der slapd.conf per slapd in jedem Fall sichergestellt sein, dass der slapd-Daemon gestoppt ist. Ein kurzer Test per #> ps aux | grep slapd | grep –v grep
sollte uns schnell Klarheit darüber verschaffen, ob noch eine Instanz des Daemons aktiv ist. Die für die Konvertierung benötigte Syntax (im nachfolgenden Beispiel ebenfalls bezogen auf SUSE-Pfade, Zeile ist umbrochen) sieht wie folgt aus:
101
2.4
1198.book Seite 102 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
#> /usr/lib/openldap/slapd –f /etc/openldap/slapd.conf –F /etc/openldap/slapd.d –u ldap –g ldap –d 1
\
Der Parameter -f gibt den absoluten Pfad zur Konfigurationsdatei an, welche als Vorlage für die Online-Konfiguration dienen soll, -F den Pfad zum neuen Konfigurationsordner, der, wie bereits erwähnt, zuvor erstellt und mit den entsprechenden Rechten/Eigentümern versehen werden sollte. Die Parameter -u und -g geben den User und die Gruppe an, mit deren Identität der slapd gestartet wird. Das stellt sicher, dass alle konvertierten Files unterhalb von slapd.d/ gleich mit den korrekten Rechten und Eigentümern erstellt werden. Wird der Konvertierungsvorgang nicht mit der Identität (User, Gruppe) durchgeführt, mit der unser slapd später auch laufen soll, müssen alle Dateien unterhalb von slapd.d/ nachträglich entsprechend per chown angepasst werden. Der Parameter -d legt den gewählten Debug-Level fest und sorgt neben einem detaillierten Output, der uns auf etwaige Fehler stupsen könnte dafür, dass unser slapd ausschließlich im Vordergrund arbeitet und wir ihn nach erfolgter Konvertierung einfach per [Strg] + [C] beenden können. Warum das sehr wichtig ist: Wird der Konvertierungsvorgang per slapd nicht im Vordergrund durchgeführt (und nach erfolgreicher Beendigung per [Strg] + [C] abgebrochen), läuft unser slapd nach erfolgter Konvertierung munter weiter und verwendet zunächst BEIDE Konfigurationen (online und statisch), da in seiner cn=config ein Verweis auf die (alte) slapd.conf existiert. Durch den konkurrierenden Zugriff auf identische Konfigurations-Settings in cn=config und slapd.conf würden anschließende, per Online-Konfiguration durchgeführte Änderungen daher nicht in jedem Fall greifen. Daher ist es ungemein wichtig, die folgenden Punkte zu beachten. 1. Nach der Konvertierung sicherstellen, dass keine Instanz unseres slapd mehr aktiv ist. 2. Unseren slapd nach erfolgreicher Konvertierung explizit nur unter Verwendung der Online-Konfiguration starten. Auf der Kommandozeile könnte das z.B. so aussehen (hier ohne Pfadangaben): #> slapd –F slapd.d/ -u ldap -g ldap
Bei SUSE lässt sich z.B. über die Datei /etc/sysconfig/openldap permanent festlegen, ob slapd mit statischer oder dynamischer Konfiguration arbeiten soll. Zuständig hierfür ist der Parameter: OPENLDAP_CONFIG_BACKEND="<wert>"
Als <Wert> kann files für die Verwendung der statischen Konfiguration gesetzt werden (Default) oder ldap für die Online-Konfiguration. Bei Debian
102
1198.book Seite 103 Donnerstag, 5. Februar 2009 3:02 15
Get it on(line) – OpenLDAP-Administration zur Laufzeit
kann dies über die Datei /etc/default/slapd und die darin enthaltene Option geschehen: SLAPD_CONF=<Path-to-slapd.d-Directory>
3. Nach erfolgreicher Konvertierung in das Online-Format und vor einem Neustart kann die alte slapd.conf umbenannt oder bewegt werden. Alternativ könnte die slapd.conf auch bestehen bleiben, allerdings sollten wir dann alle Direktiven, die nun über die Laufzeitkonfiguration erschlagen werden, auskommentieren. Ausnahmen wären z.B. Replikations-Direktiven für den slurpd (nur V2.3) oder Direktiven für Overlays, die nicht zur Laufzeit konfiguriert werden können. Um diese Komponenten in Verbindung mit der neuen slapd.d/-Datenbank zu nutzen, können ihre Direktiven in einer separaten Konfigurationsdatei untergebracht werden, welche in cn=config.ldif über das Attribut olcConfigFile definiert wird (default: slapd.conf). Anmerkung: Die Beschränkung auf eine statische Konfiguration per slapd.conf betrifft – wie eben erwähnt – unter anderem den bis zur Version 2.3 noch vorhandenen, alten Standalone-Replikationsdaemon slurpd. Das schmerzt uns allerdings herzlich wenig; warum, erfahren wir später im Abschnitt 3.2 über Replikation. 4. Eine weitere Alternative, um den Zugriff auf die statische Konfigurationsdatei zu unterbinden, wäre die komplette Löschung des Attributs olcConfigFile innerhalb der Online-Konfiguration. Diese Änderung können wir natürlich nur vornehmen, wenn wir administrativen Zugriff auf den Konfigurationskontext cn=config haben und keine Komponenten mehr verwenden, die eine statische Konfiguration benötigen. Zunächst ist es aber wichtig zu verstehen, wie und wo wir in den Eingeweiden der Online-Konfiguration unseres OpenLDAP herumschrauben können. Daher sollten wir uns vorab die Architektur der unterliegenden LDIF-Datenbank noch genauer anschauen. Falls nicht schon geschehen, starten wir hierfür unseren slapd explizit mit der Online-Konfiguration und der entsprechenden Identität, im folgenden Beispiel bezogen auf SUSE-Pfade und Eigentümer: #> /usr/lib/openldap/slapd –F /etc/openldap/slapd.d \ -u ldap –g ldap Tipp: Tauchen im Log nach dem Start bzw. Neustart des slapd im Debug-Mode folgende oder ähnliche Fehlermeldungen auf: could not stat file "/etc/openldap/slapd.d/cn=config/cn=schema.ldif": Permission denied
103
2.4
1198.book Seite 104 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
kann die Ursache darin liegen, dass nach einer bereits erfolgten Konvertierung in das Online-Konfigurations-Format die Dateien unterhalb von slapd.d/ z.B. root.root als Owner/Gruppe haben – sofern die Konvertierung als root durchgeführt wurde- und unser slapd nun mit einer anderen Identität läuft. In diesem Fall sollten Owner und Gruppe rekursiv für slapd.d/ auf den Owner und die Gruppe gesetzt werden, mit dessen/deren Rechten unser slapd üblicherweise läuft.
Die slapd.d/-Konfiguration wird – wie ein normaler Tree – in Form eines LDAPVerzeichnisbaumes gespeichert. Die verwendeten Objektklassen und Attribute (die allesamt üblicherweise mit olc* beginnen) werden dabei über ein vordefiniertes bzw. hartverdrahtetes (Online-Konfigurations-)Schema (cn=schema) unseres slapd zur Verfügung gestellt. Die Attributnamen setzen sich dabei in der Regel aus den »statischen« Konfigurationsdirektiven und dem Prefix-String olc (openldap configuration) zusammen, also z.B.: Alte slapd.conf-Direktive:
rootdn cn=ldapadmin,dc=local,dc=site
Neue slapd.d/-Direktive:
olcRootDN: cn=ldapadmin,dc=local,dc=site
Betrachten wir zunächst den schematischen Aufbau des Online-Konfigurationsverzeichnisses:
olcDatabase={-1}frontend Globale und Clientspezifische Settings olcDatabase={0}config Direktiven der OnlineKonfiguration
cn=config TLD der config-DB
cn=config.ldif Globale KonfigurationsOptionen
cn=schema Unit für Schemas
olcDatabase={n}hdb/bdb hdb/bdb-Konfiguration
cn={0}core.ldif LDAP-Core-Schema
cn=schema.ldif Objektklassen und Attribute der Online-Konfiguration
cn={1}cosine.ldif LDAP-Cosine-Schema
cn={2}inetOrgPerson.ldif LDAP-inetOrgPerson-Schema
Abbildung 2.2 Aufbau des DIT der OpenLDAP Laufzeit-Konfiguration
104
1198.book Seite 105 Donnerstag, 5. Februar 2009 3:02 15
Get it on(line) – OpenLDAP-Administration zur Laufzeit
Der slapd.d/-Konfigurations-Tree strukturiert sich wie folgt: An der Spitze des Trees befindet sich das Objekt cn=config. Die hier sichtbaren Daten liegen im Klartext in der Datei slapd.d/cn=config.ldif, in der globale slapd-Konfigurationsattribute abgelegt sind, z.B. pid-, args-,TLS-, authz-regexp-Direktiven, Loglevel, Threads, Pfad zu Konfigurations-Directory und -Files und Ähnliches. Achtung: Man sollte sich von der sichtbaren Klartextstruktur dieser DatenbankDatei(en) nicht in die Irre leiten lassen. Jede Datei unterhalb von slapd.d/ enthält zusätzlich alle erforderlichen operationellen Attribute (die wir aus dem Abschnitt 2.3, »Fingerübungen«, bereits kennen), die für die »online«- Funktionalität der Online-Konfiguration unabdingbar sind, allen voran natürlich der modifyTimestamp bzw. die entryCSN (dazu später mehr). Sie sorgen dafür, dass jede online durchgeführte Änderung sofort aktiv wird. Von einer direkten Manipulation der Dateien unterhalb von slapd.d/ per Editor ist in jedem Fall abzuraten. Da die Timestamps auf diesem Weg nicht aktualisiert werden, wäre in jedem Fall ein Neustart des slapd erforderlich, um die Änderungen zu übernehmen. Und damit wäre der größte Vorteil der Online-Konfiguration in den Wind geblasen.
Daher sollte das Ändern von Attributwerten in der Online-Konfiguration stets über ldap*-Befehle erfolgen, ob dies nun »manuell« per LDIF-Files und den entsprechenden Kommandozeilentools oder über ein grafisches Werkzeug geschieht, spielt keine Rolle. Hauptsache, die LDIFs unterhalb von slapd.d/. werden nicht manuell editiert. Die nächste fatale Konsequenz einer manuellen Manipulation der Online-Konfiguration –insbesondere im Hinblick auf eine Replikation selbiger– besteht darin, dass die Änderungen (logischerweise ebenfalls aufgrund des nicht aktualisierten Timestamps) nicht auf korrespondierende Slaves oder andere Master repliziert werden!
Die möglichen Child-Entries des Online-Konfigurations-Trees definieren sich dabei im Detail wie folgt: cn=Module (dynamisch geladenene Module): nur relevant, wenn ldap über --enable-modules kompiliert wurde. Hier können je nach vorhandenen Modul-
pfaden multiple Child-Entries auftauchen. cn=Schema (Schemadefinitionen): In cn=config/cn=schema liegt das »hartverdrahtete« Systemschema mit Objekten und Attributen der Laufzeitkonfiguration des slapd. Untergeordnete Einträge sind typischerweise die Standard-Schemas wie z.B. core, cosine und inetorgperson (cn={0}core, cn={1}cosine usw.), die zur Laufzeit modifiziert werden können. Der Name des Schema-Child-Eintrags leitet sich dabei immer vom Namen des im Include-Statement (slapd.conf) angegebenen Files ab. Der erste Schema-Child-Eintrag ist üblicherweise immer cn=core,cn=schema,cn=config. Die Zahlen in den geschweiften Klammern bestimmen die richtige Ladereihenfolge der Entries, üblicherweise beginnend bei {0}.
105
2.4
1198.book Seite 106 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Anmerkung: Die Online-Konfiguration verwendet die Zahlen im Prefix immer zur eindeutigen Bestimmung der Ladereihenfolge von Objekten/Direktiven. Wurden in Version 2.3 Objekte manuell zur Konfigurations-DB hinzugefügt, mussten diese Nummern eventuell noch manuell auf einen korrekten Wert angepasst werden. In Version 2.4 erfolgt diese Anpassung vollautomatisch. Apropos 2.4:
Seit Version 2.4 können Schema-Elemente wie Attribute und Objektklassen in der Online-Konfiguration nicht mehr nur addiert, sondern auch zur Laufzeit gelöscht oder modifiziert werden. Dies gilt allerdings nur für »normale« Schemas wie core oder nis, das »hartverdrahtete« Schema der Online-Konfiguration mit seinen spezifischen Objekten kann natürlich nicht modifiziert oder gelöscht werden (s.o.).
Des Weiteren liegen die Schemas core, cosine, inetorgperson, nis und openldap zusätzlich in einer LDIF-Variante im Schema-Unterordner unseres slapd, und können so jederzeit bei Bedarf direkt per ldapadd der Online-Konfiguration hinzugefügt werden. Bei einer Konvertierung werden die in der slapd.conf aktiven Schema-Dateien automatisch mitkonvertiert; wie wir weitere Schemas, die nicht im LDIF-Format vorliegen, zu einem späteren Zeitpunkt konvertieren und in die Online-Konfiguration integrieren können, schauen wir uns in Abschnitt 3.2.10, »Replikation der Online-Konfiguration«, an. olcBackend-Entries werden verwendet, um Settings für spezifische BackendTypen und somit alle Instanzen einer Datenbank des jeweils verwendeten Backend-Typs zu beschreiben (wird derzeit in der Online-Konfiguration nicht verwendet). olcDatabase-Entries legen in bekannter Weise die database-spezifischen Settings fest. Als Child-Entries können hier typischerweise z.B. olcOverlay-Objekte auftauchen, wie z.B. olcOverlay=syncprov. Mehr hierzu u.a. im Abschnitt 3.1 über Overlays, »Völlig überlagert ...«. In der Struktur der Online-Konfiguration sind zwei olcDatabase-Einträge immer fest verankert: die config-Database und die frontendDatabase. Frontend-spezifische Settings (wie z.B. ACLs) vererben sich typischerweise immer auf database-Einträge, sofern sie dort nicht explizit überschrieben bzw. anders gesetzt werden. Werfen wir nun wieder mit Hilfe eines grafischen Tools (hier mit dem JXplorer, den wir in Abschnitt 4.7, »Auf den Schirm!«, noch ausführlich vorstellen) einen Blick auf die Struktur des DIT unserer Online-Konfigurationsdatenbank. Als BaseDN muss hierzu cn=config gewählt werden, als rootdn ebenfalls cn=config mit dem von uns gesetzten, zugehörigen Passwort »linux«, das Ganze natürlich mit der IP bzw. dem Hostnamen unseres LDAP-Servers und Port 389. By the way: Ein anonymer Readonly-Zugriff auf die Online-Konfiguration kann natürlich, je nach verwendeten ACLs, ebenfalls möglich gemacht werden. Aber wie so oft im Leben sollte auch hier die Regel gelten: Was die bösen Buben nicht sehen, bringt
106
1198.book Seite 107 Donnerstag, 5. Februar 2009 3:02 15
Get it on(line) – OpenLDAP-Administration zur Laufzeit
sie auch nicht auf komische Ideen. Eine Exkursion über die Kommandozeile mit Hilfe von ldapsearch lässt sich einfach per #> ldapsearch –xWD cn=config –b cn=config
und anschließender Eingabe des eben genannten Passworts initiieren.
Abbildung 2.3 Login für die Online-Konfiguration per JXplorer (r/w)
Abbildung 2.4 Darstellung der cn=config-Datenbank im JXplorer
107
2.4
1198.book Seite 108 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Die config- und frontend-Database werden immer erzeugt, zudem werden sie vor der Erstellung jeder anderen Sektion angelegt. Die Attribute unterhalb von {0}config und ihre korrespondierenden Werte definieren, wer wie auf die eigentliche Laufzeit-Konfiguration zugreifen darf und welche Optionen für sie gesetzt sind. Wir richten unseren Blick auf das nächste Objekt im Konfigurations-Tree, und spätestens in exakt diesem Moment fragen wir uns, was zum Teufel auf einmal der Begriff {-1}frontend an dieser Stelle soll. Die ganze Zeit ging es schließlich um irgendwelche Backends und Datenbanken und nun – das Frontend? OpenLDAP-geschichtlich und -codetechnisch gesehen, definierte das Frontend genau genommen den Bereich des Programms, der sich direkt um die Interaktion mit den LDAP-Clients kümmert und auf der anderen Seite mit dem Backend bzw. der Database kommuniziert. Bezogen auf die Laufzeitkonfiguration unseres slapd entspricht das Frontend also eher der globalen Sektion der slapd.conf und beinhaltet damit Settings, die sich auf untergeordnete Datenbanken vererben, insofern die Settings dort nicht überschrieben werden. Und noch einmal zur Erinnerung, weil nach der globalen Sektion auch Backendspezifische Direktiven gesetzt werden könnten: Die olcBackend-Direktiven würden Optionen für alle nachfolgenden Datenbanken des gleichen Backend-Typs definieren, werden aber in der Online-Konfiguration (olc-Attribute olcBackend und olcBackendConfig) derzeit nicht benötigt. Sodele – genug der grauen Theorie, ab ans Eingemachte ...
2.4.2
slapd – Online-Administration
Fangen wir zunächst locker an, indem wir die aktuellen Konfigurationseinstellungen auslesen (je nach ACLs mit oder ohne Authentifikation): #> ldapsearch –xWD cn=config -b cn=config
Die Ausgabe sollte uns in etwa Folgendes liefern: # extended LDIF ... dn: cn=config objectClass: olcGlobal cn: config olcConfigFile: /etc/openldap/slapd.conf olcConfigDir: /etc/openldap/slapd.d
… und jede Menge weitere Daten. Kontaktaufnahme per Kommandozeile also geglückt. Falls nicht, den slapd in einem sehr detaillierten Debug-Mode aufrufen
108
1198.book Seite 109 Donnerstag, 5. Februar 2009 3:02 15
Get it on(line) – OpenLDAP-Administration zur Laufzeit
und einen erneuten Versuch starten. Klappt die Konvertierung, aber nicht der anschließende Start des slapd mit der Online-Konfiguration, sind die Ursachen meistens – wie bereits erwähnt – in den Berechtigungen und Eigentümern des Ordners slapd.d/ und den darunter liegenden Ordnern und Dateien zu suchen, die in diesem Fall nicht korrekt gesetzt sind. Nach entsprechender Überprüfung/ Korrektur den slapd restarten. Wenn dieser Versuch ebenfalls fehlschlägt, sollte die Konvertierung mit einer sorgfältig überarbeiteten slapd.conf noch einmal wiederholt werden. Zuvor natürlich nicht vergessen, die alten Dateien und Ordner unterhalb von slapd.d/ zu löschen und die Rechte der neu erstellten Dateien gegebenenfalls wieder entsprechend anzupassen. Um spezifische Subkontexte anzusprechen, benötigen wir im Filter eine etwas andere DN-Syntax, als wir bisher gewohnt waren. Der folgende Filter liefert uns z.B. nur den hdb-spezifischen Subkontext: #> ldapsearch -xWD cn=config
-b cn=config
olcDatabase={1}hdb
# {1}hdb, config dn: olcDatabase={1}hdb,cn=config objectClass: olcDatabaseConfig objectClass: olcHdbConfig olcDatabase: {1}hdb olcDbDirectory: /var/lib/ldap olcSuffix: dc=local,dc=site ...usw...
Jetzt werden wir etwas gewagter und führen die ersten tieferen Eingriffe in den Eingeweiden unserer slapd-Online-Konfiguration durch: Zunächst fügen wir den neuen Parameter olcSizeLimit, der die Anzahl der zurückgegebenen Objekte bei ldapsearch-Operationen limitiert, unserer Konfiguration hinzu. Hierzu verwenden wir das folgende bereits bekannte Format. Die Datei nennen wir sizelimit.ldif: dn: olcDatabase={1}hdb,cn=config changetype: modify add: olcSizeLimit olcSizeLimit: 2
Die Änderung fügen wir ein mit: #> ldapmodify -xWD cn=config -f sizelimit.ldif
Die Pfade zu den Dateien sind natürlich gegebenenfalls entsprechend zu ergänzen. Die Rückmeldung unseres slapd sollte so aussehen: modifying entry "olcDatabase={1}hdb,cn=config"
Danach kontrollieren wir, ob die Änderungsoperation gegriffen hat:
109
2.4
1198.book Seite 110 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
#> ldapsearch -x uid=* cn -LLL
Die Ausgabe nach der Passwortabfrage sollte wie folgt aussehen: dn: uid=ckent,ou=verkauf,dc=local,dc=site cn: Clark Kent dn: uid=hcallahan,ou=verkauf,dc=local,dc=site cn: Harry Callahan Size limit exceeded (4)
Et voilà, genau wie eingestellt, wurde die Suchoperation nach zwei gefundenen Einträgen abgebrochen. Unsere erste, echte Konfiguration der slapd-Parameter zur Laufzeit des Systems. Und, wie wir sehen können (sollten) – sie war erfolgreich, und vor allem sofort aktiv. Natürlich soll die Limitierung kein Dauerzustand sein, also stellen wir in der gleichen Art und Weise das olcSizeLimit wieder zurück auf unendlich (unlimited) oder löschen den olcSizeLimit Parameter komplett und stellen damit das Limit zurück auf den Defaultwert von 500. Und weil’s so schön ist, gleich noch ein paar Beispiele mit praktischem Nutzwert. Wir haben uns zwar noch nicht mit der unserem slapd unterliegenden Datenbank, der Oracle-Berkeley DB beschäftigt (das holen wir sehr detailliert im Abschnitt 3.8, »Larry und die schläfrigen Katzen«, nach), doch soll uns dies nicht daran hindern, vorab schon ein paar weitere interessante Features der OnlineKonfiguration zu testen. Das Thema, um das es sich beim folgenden Punkt dreht, hatten wir im letzten Abschnitt schon angesprochen, als es um das Backup der Datenbank per slapcat ging. Wir wissen: slapcat nur offline. Ausnahme: Datenbank im Readonly-Modus. Und genau den schalten wir nun mit diesem kleinen LDIF innerhalb der Online-Konfiguration an. Dabei unbedingt auf den richtigen Kontext achten (olcDatabase={1}hdb,cn=config): dn: olcDatabase={1}hdb,cn=config changetype: modify replace: olcReadOnly olcReadOnly: TRUE
Der Boolean Wert FALSE im olcReadOnly -Attribut schaltet die hdb unseres Kontextes dc=local,dc=site logischerweise wieder in den R/W-Modus. Versuchen wir im Readonly-Modus, ein Objekt aus unserem Kontext zu modifizieren, erhalten wir wie erwartet: ldap_modify: Server is unwilling to perform (53) additional info: operation restricted
Nun können wir in aller Ruhe auch online ein Backup von unserer Datenbank per slapcat erstellen, ohne gegen Paranoia über mögliche Inkonsistenzen ankämpfen zu müssen. Nachdem wir die hdb wieder in den R/W-Modus zurückgeschaltet haben, kommen wir zum nächsten Punkt, der ebenfalls die Datenbankdateien
110
1198.book Seite 111 Donnerstag, 5. Februar 2009 3:02 15
Get it on(line) – OpenLDAP-Administration zur Laufzeit
betrifft. Hierzu eine kleine Erläuterung vorab. In der Welt der Datenbanken bringt es immer einen Performance-Vorteil, wenn häufig benutzte bzw. gesuchte Attribute indexiert werden. Hierzu erstellt die Datenbank ein Indexfeld für das entsprechende Attribut; Suchvorgänge für dieses Attribut werden so deutlich beschleunigt. Bezogen auf unseren slapd würden wir in der statischen Konfiguration z.B. einen Indexeintrag in der Form index uid,cn eq
in der database-Sektion erstellen, der Suchvorgänge auf die genannten Attribute optimiert. Allerdings würden die zugehörigen Indexdateien unterhalb von /var/ lib/ldap/ erst nach einem Restart des slapd zur Verfügung stehen. Aber nicht mit uns, das können wir auch online. Also fix ein passendes LDIF erstellt: dn: olcDatabase={1}hdb,cn=config changetype: modify add: olcDbIndex olcDbIndex: cn,uid eq
und das LDIF per ldapadd in unsere Online-Konfiguration eingefügt. Und siehe da, was im Ordner /var/lib/ldap plötzlich auftaucht. -rw-------rw-------
1 ldap ldap 1 ldap ldap
8192 Oct 2 15:37 cn.bdb 8192 Oct 2 15:37 uid.bdb
Genauso ist es möglich, eine komplette neue Datenbank für einen neuen Suffix anzulegen. So würde das folgende LDIF einen komplett neuen NC (Naming Context) und die zugehörige Datenbank erzeugen. Der Ordner für die Datenbankdateien (/var/lib/ldap-test) muss natürlich existieren und die entsprechenden Rechte/Eigentümer haben: dn: olcDatabase=hdb,cn=config objectClass: olcDatabaseConfig objectClass: olcHdbConfig olcDatabase: hdb olcDbDirectory: /var/lib/ldap-test olcDbIndex: objectClass eq olcSuffix: o=test,dc=site olcRootDN: cn=ldapadmin,o=test,dc=site olcRootPW: {SSHA}iLwhoppdqOjJ+0HUroiScDJ3cpbOgo4u
Der neue Kontext steht uns sofort zur Verfügung und kann befüllt werden. Allerdings müssen wir beachten, dass wir die neue Datenbank nicht ohne weiteres wieder aus der Online-Konfiguration entfernen können, denn ldapdelete-Operationen für komplette Objekte innerhalb der Online-Konfiguration werden der-
111
2.4
1198.book Seite 112 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
zeit nicht unterstützt. Hier wären also Handarbeit und ein manueller Restart des slapd angesagt. Die Möglichkeiten der Online-Konfiguration gehen natürlich weit über die hier vorgestellten hinaus. Da es wenig Sinn ergibt, alle möglichen Direktiven »standalone« herunterzubeten, werden wir sie in den jeweiligen Abschnitten zu den entsprechenden Thematiken erläutern. Ein wichtiger Punkt jedoch vorab: Es ist technisch natürlich durchaus machbar, selbst sensible Parameter wie z.B. den DN des Admin-Accounts der Online-Konfiguration zu ändern. Ändert man ihn jedoch so, dass er nicht mehr zum Kontext cn=config selbst gehört, ist Sense, und die Online-Konfiguration muss händisch nachgearbeitet oder neu erstellt werden.
Wer es nicht erwarten kann: Eine Übersicht aller verfügbaren olc-KonfigurationsDirektiven liefert uns slapd-config(5), und die Objektklassen und Attribute der Online-Konfiguration lassen sich relativ komfortabel mit dem JXplorer oder Apache Directory Studio (beide siehe Abschnitt 4.7, »Auf den Schirm!«) über den Ordner cn=schema betrachten. Ein weiterer hochinteressanter Punkt: Bei Verwendung der Online-Konfigurationsvariante besteht die Möglichkeit, die gesamte slapd-Online-Konfiguration – mitsamt cn=config-Datenbank und aller beteiligten Schemas – komplett oder in Teilen zu replizieren. Ohne diese Möglichkeit wären zum Beispiel die in Version 2.4 neu eingeführten Standby-Master- und Multi-Master-Replikationsvarianten keinesfalls realisierbar. Wie das funktioniert, schauen wir uns ab Abschnitt 3.2.10, »Replikation der Online-Konfiguration«, genauer an.
2.4.3
Backup und Restore der Online-Konfiguration, Debugging
Zum Schluss dieses Abschnitts noch ein kleiner Praxistipp: Wie wir bereits wissen, können wir per slapcat ein Backup der »normalen« Datenbank unseres Kontextes dc=local,dc=site zur Laufzeit erstellen, indem wir die Datenbank des Kontextes in der Online-Konfiguration auf Readonly setzen. Das Ganze funktioniert theoretisch natürlich genauso für unsere Online-Konfiguration. Allerdings gibt es hierbei einen kleinen, aber vakanten Unterschied zum Online-Backup unserer »normalen« Kontext-Datenbank im Readonly-Modus, der den »Online-Vorteil« zunichte macht. Wir können zwar per dn: olcDatabase={0}config,cn=config changetype: modify
112
1198.book Seite 113 Donnerstag, 5. Februar 2009 3:02 15
Get it on(line) – OpenLDAP-Administration zur Laufzeit
replace: olcReadOnly olcReadOnly: TRUE
die gesamte Online-Konfiguration ebenfalls in einen Readonly-Modus versetzen und auch ein konsistentes Backup im laufenden Betrieb erstellen, aber um unsere Online-Konfiguration ist es bereits nach dem Setzen der Direktive geschehen, denn sie ist von nun an wirklich nur noch Readonly. So in Stein gemeißelt, dass auch für den allmächtigen rootdn nichts mehr geht. Hier würde nur manuelle Interaktion helfen, indem wir die olcReadOnly-Direktive in der LDIF-Datei (die Backslashes dienen nur der Maskierung von Sonderzeichen) slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif
manuell wieder auf FALSE setzen und unseren slapd restarten. Fazit: Es existiert nur eine Variante, um ein sauberes Backup der Online-Konfiguration zu ziehen: slapd stoppen und slapcat mit ein paar zusätzlichen Parametern auf die Reise schicken. Mit #> slapcat –n 0
> dump_config.ldif
(Pfadangaben sind gegebenenfalls zu ergänzen) können wir die komplette Online-Konfiguration unterhalb von slapd.d/ in einem Backup-LDIF sichern. Vor einem Restore muss der komplette Inhalt des slapd.d/-Ordners gelöscht werden. Das anschließend ausgeführte slapadd benötigt folgende Parameter (Pfadangaben sind gegebenenfalls zu ergänzen): #> slapadd -F slapd.d -n 0 -l dump_config.ldif
Nach dem Restore und vor dem Neustart des slapd nicht vergessen, die Rechte und Eigentümer der Dateien des slapd.d/-Ordners zu prüfen bzw. gegebenenfalls rekursiv anzupassen. Auch wenn wir die Konvertierungsprozeduren bereits mit Links erledigen können – dieses Restore-Verfahren ist noch ein wenig einfacher, zudem liefert es immer den zuletzt gesicherten Stand der Online-DB, wohingegen eine frisch konvertierte Konfiguration gegebenenfalls wieder angepasst werden müsste. Hier noch einmal einige der wichtigsten Checkpunkte bei etwaigen Fehlern für die Online-Konfiguration in der Übersicht: Vor der Konvertierung: 왘 Ordner slapd.d/ erstellt? 왘 slapd.conf mit allen erforderlichen Direktiven angepasst? 왘 Alle slapd-Instanzen beendet? 왘 Alle Pfadangaben des Konvertierungsbefehls korrekt?
113
2.4
1198.book Seite 114 Donnerstag, 5. Februar 2009 3:02 15
2
OpenLDAP installieren und betreiben
Nach der Konvertierung: 왘 slapd wieder beendet? 왘 Ordner slapd.d/ und alle darunter liegenden Dateien und Ordner für slapd les-/ schreibbar? 왘 slapd explizit nur mit der Online-Konfiguration wieder gestartet? Das war’s – fürs Erste – mit der Online-Konfiguration. Bei den folgenden Betrachtungen beziehen wir uns aus Gründen der Übersichtlichkeit und Verständlichkeit primär auf die statische Variante der slapd-Konfiguration, die bei Bedarf natürlich jederzeit über die vorgenannten Prozeduren in eine dynamische verwandelt werden kann. Das Thema der Online-Konfiguration werden wir mit allen Konsequenzen natürlich in den Replikations-Kapiteln vertiefen, wenn es um die Replikation der config-DB und der Schemas geht sowie um die brandneue Standby-/ Multi-Master-Replikation. Und immer daran denken: Die einfachste Variante zur Erzeugung einer komplexen und möglichst kompletten Online-Konfiguration besteht darin, alle erforderlichen und gewünschten Direktiven in die slapd.conf zu integrieren, alles zu testen und die slapd.conf anschließend mit der bereits bekannten Befehlssyntax zu konvertieren. Für unsere nun folgenden Betrachtungen löschen wir also die erstellte slapd.d/-Konfiguration wieder (rm –r slapd.d/*) und arbeiten mit der statischen slapd.conf-Variante weiter.
Bevor wir uns im Abschnitt 3.2, »Replikation«, intensiv mit elementaren Punkten wie der Partitionierung und Replikation auseinandersetzen, müssen wir zwangsläufig vorab auch einen Blick auf ein paar interessante Vertreter einer ganz speziellen Gattung werfen. Ohne sie wären aktuelle Replikations-Verfahren und viele andere nützliche Features, die ein OpenLDAP im aktuellen Produktiveinsatz benötigt, schlichtweg nicht realisierbar. Ein Familienzuwachs, den uns unser OpenLDAP seit der Generation 2.3 stolz und vor allem stable präsentieren kann – die Overlays.
114
1198.book Seite 115 Donnerstag, 5. Februar 2009 3:02 15
Nachdem wir die wichtigsten Grundlagen kennengelernt haben, schauen wir uns OpenLDAP nun im praktischen Einsatz an.
3
OpenLDAP im Einsatz
OpenLDAP im Einsatz – klingt ein bisschen nach staatlichen Schutzorganen oder Feuerwehr. Na ja, im weitesten Sinne soll unser LDAP ja auch Ordnung in das Chaos unübersichtlicher, heterogener Netzwerklandschaften bringen. Unser primäres Ziel wird dabei natürlich sein, möglichst viele Anwendungen zentral per OpenLDAP zu erschlagen: Useranmeldung, Authentifizierung für verschiedenste Netzwerk-Services wie Samba, Postfix, Apache und etliche andere. Aber bevor wir unseren LDAP mit allen möglichen Applikationen verquicken, müssen wir uns um die eigentliche Infrastruktur unseres Verzeichnisdienstes kümmern. Der erste Schritt hierzu besteht natürlich immer in einer möglichst sinnigen Gestaltung des eigentlichen Trees, aber das haben wir ja bereits in Abschnitt 1.8, »Kleine Baumschule«, erschlagen – zumindest, was mögliche, konzeptionelle Ansätze angeht. Was aber kommt als Nächstes? Was ist bzw. was muss eine der grundlegendsten Eigenschaften eines jeden Verzeichnisdienstes sein? Ja klar, Wohnung putzen, Bier holen und den Müll rausbringen ... Aber mal im Ernst: Was muss eine der unabdingbarsten Eigenschaften sein? Redundanz – was sonst. Dazu können und müssen wir natürlich wiederum konzeptionelle Überlegungen anstellen, die sich in erster Linie um die folgenden Punkte drehen sollten: 왘 Wie stelle ich die Integrität meines DIT sicher? 왘 Welche zusätzlichen Funktionalitäten benötige ich, und welche Overlays stellen sie bereit? 왘 Muss der Tree partitioniert werden? 왘 Brauche ich Multi-Master-Replikation, oder wäre eine RO-Slave-Replikation gemäß den X.500-Standards nicht besser und sicherer? 왘 Brauche ich Full-Replicas, oder ist es sinnvoll ggf. nur Teilbäume oder bestimmte Attribute zu replizieren? 왘 Müssen Teile der Konfiguration und/oder der Schemas on the fly auf korrespondierende Server repliziert werden?
115
1198.book Seite 116 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Wir sehen schon: Fragen über Fragen. Aber das ist unerlässlich, und die vorgenannten Punkte stellen auch nur einen groben Umriss der Spezifikation dar, über die wir uns im Vorfeld Gedanken machen müssen, wollen wir nicht später vor der fast unlösbaren Aufgabe stehen, einen krumm und schief designten Tree wieder in eine brauchbare Form zu bringen. Aber genau deswegen stehen wir hier, am Anfang dieses Kapitels, und werden danach – hoffentlich – all diese Punkte entspannt und planungssicher beantworten können.
3.1
Völlig überlagert – Overlays in OpenLDAP
Der ursprüngliche Begriff »Overlay« entstammt einer späten Periode der Computer-Steinzeit, die die Autoren (u.a. mit Turbo Pascal unter DOS) noch miterleben durften, und entsprang der damaligen Notwendigkeit, trotz sehr geringen Arbeitsspeichers größere Programme betreiben zu können. Das Konzept der Overlays gestaltet sich im Fall von OpenLDAP allerdings etwas anders, als das im Anleser beschriebene: Die in OpenLDAP zum Einsatz kommenden Overlays bieten, vereinfacht ausgedrückt, die Möglichkeit, das Verhalten der eingesetzten Datenbank zu modifizieren, ohne die Datenbank (in unserem Fall die Oracle Berkeley DB) oder das Datenbank-Backend selbst zu verändern. Die Overlays werden dabei – je nach Positionierung – z.B. dem eigentlichen Datenbank-Backend modular vorgeschaltet, nehmen die Anfragen entgegen, modifizieren sie und leiten sie erst dann über das Backend an die darunter liegende Datenbank weiter. Auf umgekehrtem Weg passiert das Gleiche in umgekehrter Reihenfolge: Die von der Datenbank an das Backend zurückgegebene Antwort wird ebenfalls vom Overlay modifiziert und an die anfragende Funktion zurückgegeben. Einige Overlays können ebenso gut in der globalen Sektion vorgeschaltet werden, spezifikationsbedingt beschränken sich ihre Funktionalitäten dann nicht auf ein bestimmtes Backend, sondern können global genutzt werden. Im Klartext bedeutet dies, dass das Overlay in einer globalen/Frontend-spezifischen Konfiguration ausgeführt wird, direkt nachdem der eingehende Request geparst und validiert wurde, aber noch bevor Datenbank- bzw. Backend-spezifische Settings aktiviert werden. Globale Overlays können dadurch unabhängig von der database operieren und in speziellen Fällen sogar die Selektion der database beeinflussen, z.B. durch ein Rewriting des anfragenden DNs. Ein typisches Beispiel für ein Overlay, das sowohl global als auch database-spezifisch gesetzt werden kann, ist chain, das wir in Abschnitt 3.2.3, »Gesprengte Ketten«, genau anschauen werden.
116
1198.book Seite 117 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Einer der wichtigsten Aspekte der Overlays: Overlays sind modular konzipiert, unabhängig davon, ob sie bei der Kompilation statisch eingebunden werden oder– wie bei Debian üblich – als Module zur Verfügung gestellt werden. Durch dieses modulare Konzept können wir das gesamte Verhalten unseres OpenLDAP Servers durch Hinzustöpseln oder Entfernen von Overlays fast nach Belieben modifizieren, ohne tiefgreifende Änderungen am System selbst vornehmen zu müssen. Das Overlay wird einfach als zusätzliche Komponente in die Konfiguration aufgenommen und ist nach dem Setzen seiner spezifischen Direktiven (und einem Restart bei statischer Konfiguration) funktionsbereit. Damit ist die Flexibilität der Overlays aber längst nicht erschöpft: Wir können mehrere Overlays miteinander kombinieren, sie sozusagen aufeinander »stapeln«, um auch komplexere Funktionalitäten abbilden zu können. Allerdings kann eine falsch gewählte Reihenfolge der Overlays auch zu unerwünschten Nebeneffekten führen. Hierzu später mehr. Schauen wir uns nun genauer an, wie wir mit einigen der zur Verfügung stehenden Overlays das Verhalten unseres LDAP modifizieren können. Einige der Overlays, wie syncprov, chain und accesslog, werden wir bereits in den nächsten Kapiteln über Partitionierung und Replikation im konkreten Einsatz erleben und ausführlich analysieren, weswegen wir sie hier nur kurz vorstellen. Die verfügbaren Overlays finden sich im Sourcecode unterhalb von /servers/slapd/overlays/. Um zu testen, welche Overlays die LDAP-Pakete der jeweiligen Distribution mitbringen – falls OpenLDAP nicht from the scratch kompiliert wurde –, können wir uns einfach per apropos eine Übersicht anzeigen lassen (oft hilft nach einer frisch durchgeführter Kompilierung und Installation auch ein freundliches mandb(8)): #> apropos slapo
Nachfolgend eine alphabetisch geordnete Übersicht über die verfügbaren Overlays in Version 2.4.12, etliche von ihnen werden wir in den folgenden Abschnitten eingehend behandeln; inoffizielle, veraltete und experimentelle Overlays lassen wir in der Regel außen vor. Der größte Teil der Overlays kann zusammen mit der Online-Konfiguration verwendet werden, Infos hierzu finden sich in der Regel in der Manpage des jeweiligen Overlays: accesslog
Auditing für DB-Zugriffe, wird für delta-syncrepl benötigt
auditlog
einfache Variante von accesslog, loggt Klartext in eine Datei
chain
automatische, serverseitige Verfolgung von Referrals
collect
neu in 2.4.12, trägt kollektive Attribute (RFC3671) zusammen
constraint
Attributwerte mit regulären Ausdrücken eingrenzen (inoffiziell)
dds
zeitlich limitierte Objekte erstellen (RFC2589)
117
3.1
1198.book Seite 118 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
dyngroup
dynlist Vorläufer mit eingeschränkter Funktionalität (veraltet)
dynlist
dynamische Gruppen über Filterkriterien spezifizieren
memberof
Reverse Group Membership
pcache
Proxy-caching für ldapsearch-Requests
ppolicy
Passwortrichtlinien (noch kein Standard, experimentell)
refint
Sicherstellung der referentiellen Integrität innerhalb des DIT
retcode
Erzeugung von Returncodes für Ereignisse (für Testzwecke)
rwm
Kontext-Rewriting (experimentell)
syncprov
stellt die LDAP Sync-Replikation zur Verfügung
translucent
konsolidierte Ansicht verschiedener Kontexte
unique
Sicherstellung der Einzigartigkeit von Attributen
valsort
zurückgegebene Werte sortieren
An dieser Stelle ein paar wichtige Punkte, die beim Einsatz von Overlays beachtet werden müssen: Erstens: Die Reihenfolge der Overlays. Overlays werden »gestapelt« abgearbeitet. Hierbei erfolgt die Abarbeitung der Overlays in umgekehrter Reihenfolge – das am weitesten unten (unterhalb aller sonstigen Einträge der database-Sektion) in der slapd.conf definierte Overlay wird zuerst abgearbeitet. So können z.B. Probleme auftreten, wenn ein Proxy-Cache (overlay pcache) zur Beschleunigung von Search-Requests in Verbindung mit Overlay rwm (zur Umschreibung von Suffixen) betrieben wird, und das Overlay rwm vor (also in der slapd.conf unterhalb von) Overlay pcache initiiert werden würde. In dem Fall würde im Proxy-Cache nach dem bereits umgeschriebenen DN gesucht, der in dieser Suffix-Form nicht vorliegt. Zweitens: Overlays können – je nach Overlay und Einsatzzweck – in einigen Fällen sowohl in der globalen als auch in der database-Sektion der Konfiguration eingebunden werden. Auskunft hierzu gibt die jeweilige Manpage des Overlays. Global definierte Overlays werden dabei vor den database-spezifischen Overlays aufgerufen. Drittens: Overlays sollten – sofern nicht in der globalen Sektion definiert – stets nach allen anderen Anweisungen der database-Sektion der slapd.conf aufgerufen werden. Aus Gründen der Übersichtlichkeit sollten beim Einsatz mehrerer Overlays diese immer durch Leerzeilen voneinander getrennt werden. Viertens: Overlay-Subdirektiven werden (im Gegensatz zu ACLs oder anderen slapd.conf-Subdirektiven) NICHT eingerückt, sondern beginnen nach der Initialisierungszeile des Overlays immer in der jeweils folgenden Zeile am Zeilenanfang.
118
1198.book Seite 119 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Typischerweise beginnt die Overlay-Subdirektive immer mit dem Namen des Overlays, also z.B.: -<Subdirektive> <Wert> Zum Einkompilieren aller verfügbaren Overlays muss der configure-Schalter --enable-overlays=yes verwendet werden, alternativ kann man auch selektiv vorgehen und per --enable- die gewünschten Overlays einzeln einbinden. Ergänzend zu den Manpages findet sich auch eine – leider nicht mehr ganz aktuelle – Auflistung der gängigsten Overlays mit einer Kurzbeschreibung in der LDAP-Faq-O-Matic unter: http://www.openldap.org/faq/data/cache/1169.html. Eine ausführlichere Übersicht bietet: http://www.openldap.org/doc/admin24/ overlays.html. Debian-User sollten bei allen folgenden Beispielen immer daran denken, die jeweiligen Overlay-Module entsprechend der nachfolgenden Abschnitte in die slapd.conf einzubinden, z.B.: modulepath moduleload moduleload # usw.
/usr/lib/ldap/ back_bdb.la back_hdb.la dynlist.la
Doch genug der Vorrede. Schauen wir uns die Jungs nun bei der Arbeit an, und überzeugen uns selbst von ihren Fähigkeiten ...
3.1.1
Gruppentherapie – dynamische Gruppen mit Overlay dynlist
Eine Gruppentherapie? Okay, jeder Unix- oder Linux-Admin, der irgendwann einmal gezwungen war, eine sendmail.cf manuell zu erstellen, hat im Anschluss daran vielleicht kurz mit diesem Gedanken gespielt. Oder damit, demjenigen körperliche Gewalt anzudrohen, der ihm das Ganze eingebrockt hat. Sei´s drum, in unserem Fall geht es um etwas anderes. Nämlich um ein Overlay, das uns jede Menge Arbeit abnehmen kann. Und wie? Ganz einfach: »Normale«, statische Gruppen, in denen Userobjekte zusammengefasst werden, benötigen üblicherweise die Interaktion des Admins oder eines berechtigten Users, der die Objekte eben jener Gruppe hinzufügt oder wieder herausnimmt. Overlay dynlist (slapo-dynlist(5)) nimmt uns diese Arbeit größtenteils ab, indem es Objekte aus dem DIT anhand bestimmter Filterkriterien zu dynamischen Gruppen zusammenfasst. Diese Filterkriterien können dabei zur Laufzeit modifiziert werden und erlauben so eine zusätzliche Flexibilität.
119
3.1
1198.book Seite 120 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Eine praktische Anwendung für den Einsatz dieser Funktionalität wäre z.B. eine dynamisch erstellte Administratoren- oder Superuser-Gruppe mit besonderen Rechten, die sich aus allen Mitarbeitern des DIT zusammensetzt, die im Attribut title den Wert admin gesetzt haben. Betrachten wir die Funktionalität am besten in der Praxis. Um das Overlay in der Standard-Variante zu betreiben, benötigen wir zunächst ein zusätzliches Schema, das die erforderlichen Objekte zur Verfügung stellt: include
//dyngroup.schema
Das Include-Statement für das dyngroup.schema binden wir hinter den bereits vorhandenen Schemas ein. Es beinhaltet die nachstehend verwendeten Objekte: die Objektklasse groupOfURLs und das Attribut memberURL, das aus dem Attribut labeledURI (core.schema) abgeleitet wurde. Das dyngroup.schema wurde ursprünglich von Netscape entwickelt und wird laut Kommentar im Schema selbst immer noch nicht für Produktivumgebungen empfohlen. In unseren Produktivumgebungen läuft dynlist seit Langem problemlos, daher verweisen wir nur auf den Kommentar und enthalten uns einer Bewertung. Nun setzen wir die folgenden Direktiven für das Overlay unterhalb der Datenbanksektion ein: overlay dynlist dynlist-attrset groupOfURLs memberURL
Über die Sub-Direktive dynlist-attrset können insgesamt drei Parameter spezifiziert werden, die wir uns nun anschauen. Der erste Parameter definiert die Objektklasse, unter der die gefundenen Objekte als Gruppe zusammengefasst werden. Das ist üblicherweise die vom dyngroup.schema bereitgestellte strukturelle Objektklasse groupOfURLs, kann aber theoretisch auch eine andere Objektklasse sein, die ein Attribut vom Typ labeledURI enthält, wie z.B. labeledURIObject aus dem core.schema, was jedoch aufgrund des Objektklassen-Typs (AUXILIARY) eher ungünstig ist. Eine brauchbare Alternative wäre die Objektklasse openLDAPou aus dem openldap.schema, die ebenfalls das Attribut labeledURI enthält und vom Typ STRUCTURAL ist, also problemlos auch standalone eingesetzt werden kann. Der zweite Parameter definiert die LDAP-URL; das angegebene Attribut muss als Attributwert eine LDAP-URL mit den typischen Parametern enthalten: Angabe des Hosts, der BaseDN und eines frei definierbaren Suchfilters. In unserem Beispiel verwenden wir das Attribut memberURL (abgeleitet von labeledURI), das ebenfalls dem dyngroup.schema entstammt. Über die memberURL werden –
120
1198.book Seite 121 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
anhand der in der LDAP-URL spezifizierten Kriterien – die Objekte dynamisch aus dem DIT kollektiert. Wird der dritte, optionale Parameter member gesetzt, werden die gefundenen Objekte nicht anhand des spezifizierten Rückgabe-Attributs (im unteren Beispiel: sn) gelistet, sondern mit ihrem kompletten DN, was zur Auswertung per ACL unerlässlich ist. Achtung: Bei der Auswertung von dynamischen Gruppen durch ACLs ist Vorsicht geboten. Wird member in der Konfiguration des Overlays als Rückgabe gewählt (kompletter DN), aber vergessen, das Rückgabeattribut (hier: sn) aus dem Suchfilter zu entfernen: memberURL: ldap:///dc=local,dc=site?sn?sub?(title=admin)
greift die ACL definitiv NICHT, obwohl die zurückgegebenen Objekte korrekt ausgelesen werden! Wie eine passende ACL zur Auswertung einer dynamischen Gruppe vom Typ groupOfURLs aussehen könnte, schauen wir uns im Abschnitt 3.7 über ACLs, »Nur mit Clubkarte«, an.
Nun erstellen wir folgende LDIF-Datei für eine dynamische Testgruppe, und importieren sie in unseren DIT, um die Funktionalität zu veranschaulichen: dn: cn=dyngroup,dc=local,dc=site objectClass: groupOfURLs cn: dyngroup memberURL: ldap:///dc=local,dc=site?sn?sub?(title=admin)
Die Definition der memberURL sorgt dafür, dass alle bestehenden oder neu erstellten Mitarbeiter im gesamten DIT, die im Attribut title den String-Wert »admin« vorweisen können, mit ihrem Attribut sn (Surname = Nachname) in der Gruppe cn=dyngroup zusammengefasst werden. Für diese Funktionalität muss das Overlay – wie in unserem Beispiel – zunächst ohne den Parameter member in der Subdirektive dynlist-attrset konfiguriert sein. Nachdem wir das Gruppenobjekt in den DIT eingefügt haben, verpassen wir den User-Objekten skiu, ckent und hcallahan den Attributwert »admin« im Attribut title. Anschließend suchen wir per ldapsearch nach unserem neuen Gruppenobjekt, und das Ergebnis sollte wie folgt aussehen: dn: cn=dyngroup,dc=local,dc=site objectClass: groupOfURLs objectClass: top cn: dyngroup memberURL: ldap:///dc=local,dc=site?sn?sub?(title=admin) sn: Kent sn: Callahan sn: Kiu
121
3.1
1198.book Seite 122 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Als Attributwerte für memberURL können alle Filterverknüpfungen gemäß RFC 2255 verwendet werden. Dieser URL-Filter würde zum Beispiel die Kollegin Susie Kiu außen vor lassen (Zeile wurde umbrochen): ldap:///dc=local,dc=site?sn?sub?(&(title=admin) (mail=*verkauf*))
Jetzt betrachten wir die üblicherweise verwendete dynlist-Konfiguration mit aktiviertem member-Parameter, die dafür sorgt, dass die zurückgegebenen Objekte mit ihrem kompletten DN ausgeliefert werden. Diese Variante ist deswegen in den üblichen Anwendungsfällen am sinnvollsten, weil sie perfekt über ACLs ausgewertet werden kann. Wie das funktioniert, schauen wir uns im Abschnitt 3.7 über ACLs, »Nur mit Clubkarte«, genauer an. Nachdem wir den member-Parameter in der dynlist-Subdirektive aktiviert (nicht vergessen, den slapd zu restarten) und das sn-Attribut als Rückgabewert aus dem Filter entfernt haben, prüfen wir das Ergebnis erneut: dn: cn=dyngroup,dc=local,dc=site objectClass: groupOfURLs objectClass: top cn: dyngroup memberURL: ldap:///dc=local,dc=site??sub?(title=admin) member: uid=ckent,ou=verkauf,dc=local,dc=site member: uid=hcallahan,ou=verkauf,dc=local,dc=site member: uid=skiu,ou=forschung,dc=local,dc=site
Die andere Variante wäre der Einsatz einer dynamischen Gruppe, die auf der bereits angesprochenen Objektklasse openLDAPou und dem Attribut labeledURI aus dem openldap.schema basiert. Hierzu muss natürlich das Standard-openldap.schema inkludiert werden. Das Overlay selbst muss natürlich ebenfalls auf die tatsächlich verwendeten Attribute und Objektklassen angepasst werden: overlay dynlist dynlist-attrset openLDAPou labeledURI member
Danach nicht vergessen, den slapd neu zu starten. Und hier die zugehörige Objektdefinition, in der aufgrund der geänderten Objektklasse ou statt cn verwendet werden muss: dn: ou=dyngroup1,dc=local,dc=site objectClass: openLDAPou ou: dyngroup1 labeledURI: ldap:///dc=local,dc=site??sub?(title=admin)
Ein sehr kleiner Nachteil aus dem letztgenannten Beispiel sollte nicht unerwähnt bleiben: Im Gegensatz zu den verwendeten Objekten aus dem openldap.schema
122
1198.book Seite 123 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
bietet das dyngroup.schema außer der Objektklasse groupOfURLs unter anderem noch die zusätzliche Objektlasse dgIdentityAux und das zusätzliche Attribut dgIdentity. Im Normalfall wird die URL-Expansion, also die Auswertung des Suchfilters, mit der Identität des aktuell angemeldeten LDAP-Users durchgeführt. Mit Hilfe der zusätzlichen Objekte ist es möglich, die Suche über eine explizit angegebene Identität durchführen zu lassen: dn: cn=dyngroup,dc=local,dc=site objectClass: groupOfURLs objectClass: dgIdentityAux cn: dyngroup memberURL: ldap:///dc=local,dc=site?sub?(title=admin) dgIdentity: cn=proxyuser,dc=local,dc=site
Tipp: Bei sehr großen DITs kann eventuell der zusätzliche Einsatz des pcacheOverlays in Erwägung gezogen werden, da das dynamische Parsen des Trees mit steigender Komplexität der Filterkriterien der dynamischen Gruppen etwas auf die Performance drücken kann. Auf der anderen Seite darf nicht vergessen werden, dass – wie bei jedem Proxy – die zurückgelieferten Daten, abhängig von der TTL (Time To Live = »Lebensdauer« der Daten), gegebenenfalls nicht dem aktuellsten Stand entsprechen. Weitere Infos zum Overlay pache liefern www.openldap.org/pub/kapurva/proxycaching.pdf (dort finden sich auch alle design- und implementierungsspezifischen Details) und slapo-pcache(5). Noch ein wichtiger Hinweis: Das dynlist-Overlay kann natürlich auch mehrfach aufgerufen werden. Die Direktiven müssen nur jedes Mal wieder mit overlay dynlist eingeleitet werden. Die Integration des Overlays in die Online-Konfiguration ist ebenfalls problemlos möglich. Mix it up ... Noch ein kurzes Wort zu Mischformen von statischen und dynamischen Gruppen: In der Praxis kann es durchaus – je nach Einsatzzweck – erforderlich sein, normale, statische Gruppen mit dynamischen Fähigkeiten auszustatten. Ein interessantes Beispiel wäre, eine Gruppe vom Typ posixGroup, die üblicherweise in Verbindung mit Samba zur einfachen Gruppierung von Benutzern benötigt wird, mit dynamischen Kapabilitäten auszustatten. Um das »mal eben« umzusetzen, benötigen wir allerdings noch tiefer greifende Vorkenntnisse im Bereich SchemaDesign, also werden wir diese Aufgabe auch konsequenterweise im Abschnitt 3.9 über selbstdefinierte Schemas angehen. Was wir mit unseren momentanen Kenntnissen schon problemlos erschlagen können, ist ein Hybrid aus groupOfNames, den wir einfach um eine labeledURI ergänzen. So können wir z.B. einen »statischen« Pool von Superadmins verwal-
123
3.1
1198.book Seite 124 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
ten und bei Bedarf mal eben ein paar Teilzeitadmins über die Filter-Kriterien der labeledURI hinzufügen. Zusammengebaut sieht unser Objekt dann etwa so aus: dn: cn=dyngroup2,dc=local,dc=site objectClass: top objectClass: labeledURIObject objectClass: groupOfNames cn: dyngroup2 labeledURI: ldap:///dc=local,dc=site??sub?(title=admin) member: cn=dummyuser,dc=local,dc=site
Der dummy-member-Eintrag wird von groupOfNames benötigt, die ein leeres member-Feld überhaupt nicht mag. Die korrespondierenden Settings in unserer slapd.conf wären: overlay dynlist dynlist-attrset groupOfNames labeledURI member
3.1.2
Smile, you’re on Radar! – Auditing mit Overlay accesslog
Overlay accesslog bietet die Möglichkeit, jegliche Zugriffe auf unseren DIT – egal ob read-, write- oder session-spezifische Vorgänge – in einer separaten Datenbank zu loggen. Klingt zunächst vielleicht nicht sonderlich spannend, ist es aber. Zwar kann man über eine separate Log-Facility und den entsprechenden Debug-Mode Ähnliches erzielen, dabei bleibt die Ausgabe an sich doch eine statische LogDatei, zum anderen wäre sie weitaus weniger detailliert. Das Gleiche gilt für die Verwendung des sehr einfach gehaltenen Overlays auditlog, das Zugriffe auf den Kontext unter Berücksichtigung des modifyTimestamps und des modify-DNs in eine Klartextdatei loggen kann. Details hierzu finden sich in slapo-auditlog(5). Overlay accesslog bietet uns hier weitaus mehr. Entsprechend konfiguriert, legt es die gewünschten Informationen innerhalb einer separaten DB in Form eines eigenständigen Trees ab. Der Vorteil liegt zum einen in der exakten Filterung der geloggten Daten, wie z.B. ausschließliches Logging aller write-Operationen (add, modify, delete) und/oder session-spezifischer Operationen (abandon, bind, unbind), zum anderen in der Art und Weise, wie die Daten im Tree abgelegt werden: in einer LDAP-Datenbank, die mit den üblichen LDAP-Tools eingesehen und ausgewertet werden kann. Das Overlay bringt einige neue – für diesen Einsatz notwendige – Objektklassen (wie z.B. auditAdd, auditBind) und Attribute (wie z.B. reqMod, reqStart, reqType) mit sich, die durch die Einbindung des Overlays beim Start des slapd automatisch geladen werden. Eine vollständige Auflistung aller spezifischen Attribute und Objektklassen findet sich in slapo-accesslog(5).
124
1198.book Seite 125 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Die Konfiguration erfolgt über die Database-spezifischen Direktiven in der slapd.conf. Wir definieren als Erstes oberhalb unseres Standard-Kontextes folgende database-Sektion für die Log-DB: # Kontext fuer die accesslog-DB database hdb suffix "cn=logs" rootdn "cn=logs" rootpw {SSHA}Wq7vcBfeULcQDCeHGYtvWaPeYFxnonG3 directory /var/lib/ldaplogs index reqStart,reqEnd,reqMod,reqResult eq ############################### # default-Kontext database hdb suffix "dc=local,dc=site" ... # Initialisierung des overlays accesslog overlay accesslog logdb cn=logs logops writes session logpurge 08:00 00:30
In der ersten database- Sektion definieren wir die Datenbank (cn=logs), in der die Access-Logs abgespeichert werden, in der gleichen Weise wie Objekte in unserem »regulären« DIT. ACHTUNG: Das Attribut dc (domainComponent) darf in diesem Anwendungsfall nicht zur Kontextdefinition verwendet werden! Die Log-DB benötigt in jedem Fall cn= als Suffix. Die Overlay-Direktive unterhalb unseres »normalen« Datenbank-Kontextes (unser eigentlicher DIT: dc=local,dc=site) aktiviert das Overlay accesslog. Danach wird in den Subdirektiven der Kontext der verwendeten Log-Datenbank (cn=logs) eingestellt und die Filter festgelegt: logops writes session. Mit writes werden die Aktionen add/modify/delete abgedeckt, mit session sämtliche An- und Abmeldevorgänge (bind/unbind), auch Abbrüche (abandon), was für auditingZwecke ebenfalls wichtig ist. Mit logpurge werden die Kriterien festgelegt, nach denen ältere Einträge aus den Logs gelöscht werden. Das Format ist [dd+]hh:mm[:ss], wobei Tage und Sekunden optional sind. Der von uns verwendete Beispieleintrag würde bewirken, dass das Overlay die Log-DB alle 30 Minuten auf Log-Einträge scannt, die älter als acht Stunden sind, und diese löscht. In Produktivumfeldern sind diese Werte natürlich noch auf das reale Umfeld und die Bedingungen anzupassen.
125
3.1
1198.book Seite 126 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Über die optionalen Direktiven logold und logoldattr können bestimmte Objektklassen und/oder Attribute angegeben werden, deren »alte« Werte nach einer Modifikation oder einem Löschvorgang in der log-DB gespeichert werden. Über den ebenfalls optionalen Boolean-Parameter logsuccess kann festgelegt werden, ob z.B. insgesamt nur erfolgreiche (TRUE) oder alle (FALSE, default) Operationen im log gespeichert werden. Nach einem Neustart und einigen Aktionen (Anmelden, User editieren) durchsuchen wir den neu erstellten Kontext cn=logs: #> ldapsearch -x -b cn=logs dn: reqStart=20080508131636.000000Z,cn=logs objectClass: auditBind reqStart: 20080508131636.000000Z reqEnd: 20080508131636.000001Z reqType: bind reqSession: 3 reqAuthzID: reqDN: cn=ldapadmin,dc=local,dc=site reqResult: 0 reqVersion: 3 reqMethod: SIMPLE # 20080508131644.000000Z, logs dn: reqStart=20080508131644.000000Z,cn=logs objectClass: auditModify reqStart: 20080508131644.000000Z reqEnd: 20080508131644.000001Z reqType: modify reqSession: 3 reqAuthzID: cn=ldapadmin,dc=local,dc=site reqControls: {0}{2.16.840.1.113730.3.4.2} reqDN: uid=ckent,ou=verkauf,dc=local,dc=site reqResult: 0 reqMod: description:= superman, who else reqMod: entryCSN:= 20080508131644.135242Z#000000#000#000000 reqMod: modifiersName:= cn=ldapadmin,dc=local,dc=site reqMod: modifyTimestamp:= 20080508131644Z
Wir sehen jede Menge nützlicher Informationen, und die können immer hilfreich, wertvoll und manchmal auch äußerst befriedigend sein. Letzteres zum Beispiel dann, wenn auf unsere Standardfrage: »Was haben Sie denn zuletzt gemacht?« die typische, seit Anbeginn aller Bits und Bytes ewig gleiche und stets Unschuld beteuernde Stimme aus unserem Hörer tönt: »Äh, überhaupt nichts.« Na klar … Smile – you’re on Radar, Buddy. Womit wir wieder bei der treffenden Einleitung dieses Abschnitts wären. Oder wie der BOfH1 schon vor langer Zeit weise sprach: You can run, but you can’t hide ... 1 Bastard Operator from Hell, http://de.wikipedia.org/wiki/Bastard_Operator_From_Hell, fiktive Internetlegende
126
1198.book Seite 127 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Jeder geloggte Eintrag erhält einen eindeutigen Timestamp als DN, und zwar mit reqStart den exakten Startzeitpunkt des Ereignisses. Grafisch betrachtet, stellt sich unsere Log-DB nach einigen Zugriffen in etwa so dar:
Abbildung 3.1
Einträge in cn=log (Overlay accesslog)
Das accesslog-Overlay lässt sich problemlos in die dynamische slapd.d/-Konfiguration eingliedern. Analog zu den von uns verwendeten Direktiven der slapd.conf würde sich das nach der Konvertierung grafisch wie folgt darstellen:
Abbildung 3.2
Integration von Overlay accesslog in cn=config
Noch eine prinzipielle Anmerkung: Wir haben in unserer Konfiguration mit einem separaten rootdn und Passwort schreibenden Zugriff auf die Log-DB ermöglicht. Ob das gewünscht ist, muss jeder Admin selbst entscheiden. Prinzipiell kann das hilfreich sein, z.B. um manuell verbogene Einträge zu entfernen; gestattet aber durch den schreibenden Zugriff natürlich auch die bewusste Manipulation der Log-Entries, darüber muss man sich im Klaren sein. State of the Art: accesslog + syncprov = Delta Syncrepl Das höchste Niveau der Replikationskunst. So kann man die Verquickung der beiden Overlays syncprov und accesslog durchaus bezeichnen, denn zusammen spielen sie in der ersten Liga der Replikation. Das Thema behandeln wir sehr ausführlich in Abschnitt 3.2.10, »Replikation der Online-Konfiguration«; vorab sei –
127
3.1
1198.book Seite 128 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
da wir gerade beim Overlay accesslog sind – nur so viel verraten: Bei einer »normalen« Replikation von Objekten, von einem Server zum anderen, wird immer das ganze Objekt mit allen Attributen repliziert. Mächtig viel Overhead. Das dachten sich auch die Entwickler, und warfen noch einmal einen genauen Blick auf das uns nun wohlbekannte Overlay accesslog und taten das Logische: sie verquickten beide, und heraus kam die optimale Replikations-Variante mit minimalem Overhead – delta-syncrepl. Es wird interessant. Versprochen.
3.1.3
Beziehungskrise – Sicherung der referentiellen Integrität mit Overlay refint
Wer meint, es gäbe Beziehungen ohne Krisen, liest dieses Buch wahrscheinlich gerade in den Räumlichkeiten eines buddhistischen Klosters in Tibet. Wir anderen wissen, dass es in Beziehungen hier und da Probleme gibt. Oder manche Partner vom Zigarettenholen nie wieder zurückkommen. So oder ähnlich könnte man die Problematik schildern, um die sich ein spezielles Overlay kümmert: refint. Das Overlay refint sorgt für die Sicherstellung der referentiellen Integrität innerhalb unseres DIT. Der Begriff referentielle Integrität sollte dem einen oder anderen aus der Welt der Datenbanken vielleicht geläufig sein. Und damit ist hier, in der Welt unseres OpenLDAP, etwas Ähnliches gemeint. Wir erinnern uns dunkel daran, dass wir seit etlichen Taktzyklen eine statische Gruppe vom Objektklassentyp groupOfNames mit dem DN cn=superuser, dc=local,dc=site in unserem Tree herumschwirren haben. Die Mitglieder dieser Gruppe werden mit ihrem vollständigen DN unter dem Attribut member geführt, so ähnlich wie in einer dynamischen Gruppe des Typs groupOfURLs, die wir ja bereits kennen. Dort kümmert sich jedoch die memberURL on the fly darum, die Mitglieder dynamisch zu kollektieren bzw. sie außen vor zu lassen; sein Gegenpart groupOfNames agiert hier jedoch naturgemäß weitaus statischer und erwartet (ohne Unterstützung durch weitere Overlays) zumindest unsere Interaktion beim Hinzufügen oder Entfernen von Mitgliedern. Um der Frage vorzugreifen, warum wir nicht gleich alle Gruppen dynamisch anlegen: Wir wissen, dass dynamische Gruppen ihre Mitglieder zur Laufzeit über Suchfilter aus dem DIT kollektieren. Allein aus diesem Grund schneiden sie gegenüber einer statischen Gruppe zwangsläufig performancetechnisch immer etwas schlechter ab, und zwar mit steigender Komplexität des Suchfilters. Daher haben vor allem in großen Bäumen statische Gruppen durchaus ihre Einsatzberechtigung. Nehmen wir nun an, der gute Harry Callahan verdrückt sich unabgemeldet aus unserem Tree, um undercover schwere Jungs hops zu nehmen. So weit, so gut.
128
1198.book Seite 129 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Allerdings zeigt uns ein Blick per ldapsearch mit dem Fokus auf die Gruppe cn=superuser, dass sein DN dort immer noch im member-Attribut gelistet wird, obwohl das eigentliche User-Objekt längst nicht mehr vorhanden ist. Exakt um diese Problematik (und ähnliche gelagerte Fälle, die nicht nur Gruppenzugehörigkeiten betreffen) kümmert sich Overlay refint. Es überwacht alle im DIT durchgeführten modrdn/moddn- und delete –Operationen, und durchsucht den Tree nach weiteren Vorkommen des modifizierten/gelöschten DNs, um sie ebenfalls anzupassen bzw. zu entfernen. Bleiben wir beim Beispiel unserer statischen Gruppe superuser vom Typ groupOfNames und dem nun abwesenden Mr. Callahan. Um dieses Problem bei seinem nächsten Undercover-Einsatz automatisiert zu lösen, integrieren wir lediglich die beiden folgenden Statements in die Datenbanksektion unserer slapd.conf und starten unseren slapd neu: overlay refint refint_attributes member
Nun zum zweiten Test, vor dem wir das Userobjekt hcallahan natürlich wieder unserem DIT hinzufügen müssen. Nach erneuter Löschung werfen wir einen Blick auf die Gruppe superuser ... et voilà, der DN von hcallahan im memberAttribut wurde entfernt. Und nicht nur das: Wenn wir den relativen DN (RDN) eines Objekts modifizieren, also z.B. die uid unseres guten alten Kollegen hcallahan auf hcallahan1 umbenennen, passt refint den DN im member-Attribut der Gruppe superuser ebenfalls automatisch an. Genau das bringt uns zu einer wichtigen Spezifikation des Overlays refint, die unbedingt beachtet werden muss: Als refint_attributes dürfen nur Attribute zur Anwendung kommen, die eine DN-Syntax besitzen, also einen kompletten DN abbilden (wie manager, owner, seeAlso). Ein Attribut wie z.B. memberUID (posixGroup), das nur die uid eines Objekts ohne DN abbildet, verpufft wirkungslos in der Direktive.
Jetzt bohren wir die Funktionalität des Overlays weiter auf, indem wir multiple Attribute (mit einer DN-Syntax) für die referentielle Integritätsprüfung spezifizieren: overlay refint refint_attributes
member manager owner seeAlso
Für einen kleinen Test erstellen wir folgendes Objekt: dn: cn=44magnum,ou=verkauf,dc=local,dc=site objectClass: device
129
3.1
1198.book Seite 130 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
cn: 44magnum description: Harrys Liebling owner: uid=hcallahan,ou=verkauf,dc=local,dc=site
Auch ohne die description ist unschwer zu erraten, wem das Ding gehört. Modifizieren wir nun Harrys DN oder entfernen ihn, wird dank des von refint ebenfalls überwachten »owner«-Attributs die referentielle Integrität auch in diesem Fall sichergestellt. Über die zusätzlich Direktive refint_nothing
cn=dummy,dc=local,dc=site
kann ein (nicht zwingend existenter) dummy-DN angegeben werden. Dieser verhindert, dass alle member-Pflichtattributwerte komplett gelöscht werden, denn eine groupOfNames z.B. braucht zumindest immer ein (1) gesetztes memberAttribut. Bei der Spezifikation der refint_attributes sollten wir (je nach Anwendungsfall) also stets analysieren, welche Objekte innerhalb unseres DIT existieren, die eine DN-Syntax aufweisen und für die referentielle Integrität relevant sind. Berücksichtigen wir sie alle bei refint_attributes, sollte unser Tree immer schön sauber bleiben. Noch ein wichtiger Hinweis: Wurde ein Objekt per refint aktualisiert, findet sich im operational Attribute modifiersName typischerweise der Wert: cn=Referential Integrity Overlay. Das kann gegebenenfalls für die Auswertung dieses Attributes (z.B. per ACL) von entscheidender Bedeutung sein. Wer will, kann diese defaultEinstellung per refint_modifiersname
ändern. Overlay refint lässt sich auch als sinnvolle Ergänzung zu dynlist einsetzen und arbeitet problemlos mit der Online-Konfiguration zusammen. Ein weiterer Kollege aus der Overlay-Sippschaft arbeitet ebenfalls Hand in Hand mit refint und kümmert sich – wie dynlist und refint – ganz selbstlos um Mitglieder und solche, die es werden wollen ...
3.1.4
Members Only – Gruppenzuordnung mit Overlay »memberOf«
Nur für Mitglieder – ein Spruch, den jeder von uns so dringend benötigt wie eine Steueraußenprüfung und den wir nach Murphys Gesetz mit Sicherheit genau dann zu hören bekommen, wenn wir im strömenden Regen vor dem völlig überfüllten Szene-Laden stehen, der Handy-Akku leer und das letzte Taxi gerade von dannen gerauscht ist.
130
1198.book Seite 131 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Na und? Wen kümmert’s? Schließlich sind wir auch Herr und Meister über Mitglieder und Gruppenzugehörigkeiten. Und je nachdem, welchen Tree wir in welcher Institution verwalten, kann es dann vielleicht schon mal vier Wochen statt einem Tag dauern, bis die Aktualisierung der Führerscheinklassen des netten Türstehers auf den zuständigen Server repliziert wird. Aber im Ernst: Zwei Overlays kennen wir bereits, die sich mit der Zuordnung und Aktualisierung von Mitgliedschaften und Gruppenzugehörigkeiten beschäftigen: dynlist und refint. dynlist kollektiert die Mitglieder anhand filterspezifischer Eigenschaften und fügt sie zu einer Gruppe zusammen, refint kümmert sich um die Integrität des DIT bei Änderungen an DNs. Kommen wir nun zur Funktionsweise. Eine typische Gruppenzuordnung arbeitet üblicherweise nach dem Prinzip: Gruppe A hat die Userobjekte X,Y und Z als Mitglieder
Wobei logischerweise die Gruppe – und nicht der User bzw. das Userobjekt – die Information beinhaltet, welches Userobjekt Mitglied bei ihr ist. memberOf verfolgt hier einen anderen Ansatz. Hier heißt es »rückwärtige« Gruppenzuordnung (reverse group membership), und das sieht dann so aus: User X ist Mitglied bei den Gruppen A,B und C.
Vereinfacht ausgedrückt, führt bei diesem Ansatz das Userobjekt selbst die Information mit, zu welcher Gruppe es gehört. Damit das Userobjekt diese Info speichern kann, verwaltet das Overlay memberof ein fast gleichnamiges operational Attribute: memberOf. Im Attributwert selbst werden der oder die DNs der Gruppen gespeichert, denen das Userobjekt angehört. Ohne das memberof-Overlay weiß das (User-)Objekt selbst nicht, dass es zu einer Gruppe gehört, auch wenn es frisch zu einer hinzuaddiert wurde. Kleine Anmerkung: Einer der aktuellen Einsatzschwerpunkte ist z.B. Samba 4, wo memberof extensiv dazu verwendet wird, die etwas verschrobenen und performance-killenden Winzigweich-ADS-Gruppenzuordnungen nachzubilden, denn dort funktioniert die Zuordnung in der Regel immer über: »Zu welchen Gruppen gehört User X?« Das Setup von Samba 4 mit OpenLDAP-Backend werden wir uns im Abschnitt 4.1.8, »Staffelflug«, genauer anschauen, sogar in einem Multi-Master-Szenario mit 2 DCs. Aber letztlich muss der Admin (wie üblich je nach Einsatzfall) darüber entscheiden, welche Gruppenzuordnungs-Funktionalität für seinen Anwendungsfall am geeignetsten ist. Im Folgenden schauen wir uns das Setup des Overlays memberof an:
131
3.1
1198.book Seite 132 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Stufe 1: Automatisches Setzen des Attributs »memberOf« In der einfachsten Konfiguration (dem Setzen der Overlay-Direktive: overlay memberof in der DB-Sektion) kümmert sich das Overlay »nur« um Folgendes:
Wird ein Objekt (User) mit seinem DN manuell einer Gruppe (z.B. vom Typ groupOfNames) zugeordnet, wird das operational Attribute memberOf mit dem Attributwert der entsprechenden Gruppe in das Userobjekt geschrieben. Danach können wir das memberOf-Attribut einfach per ldapsearch bzw. mit einer entsprechenden ACL auswerten. Beispiel: Nachdem wir das Overlay aktiviert haben, löschen wir ckent als Mitglied der Gruppe cn=superuser und ordnen ihn anschließend der Gruppe manuell wieder neu zu, indem wir seinen DN wie gewohnt in ein zusätzliches member-Attribut schreiben. Danach fragen wir per ldapsearch das Userobjekt ckent ab, und siehe da: #> ldapsearch –x uid=ckent memberof -LLL dn: uid=ckent,ou=verkauf,dc=local,dc=site memberOf: cn=superuser,dc=local,dc=site
Stufe 2: Automatische Behandlung fehlerhafter Gruppenzuordnung Die Subdirektive memberof-dangling legt fest, wie sich das Overlay verhält, wenn bei einer Modifikation ein Fehler auftritt. Diese Subdirektive hat die default-Einstellung ignore: der falsche member-Eintrag in der Gruppe bleibt bestehen, das memberof-Attribut des Users wird jedoch gelöscht. Setzen wir den Wert für memberof-dangling auf drop, werden Falscheingaben in einem member-Feld einer Gruppe direkt verworfen, d.h. der entsprechende falsche member-Eintrag wird sofort aus der Gruppe entfernt. Als Beispiel: Angenommen, wir würden – natürlich nur, weil es viel zu früh am Morgen, und unser Koffeinlevel noch viel zu niedrig ist – Kents DN im memberAttribut der Gruppe versehentlich auf uid=Xkent,ou=verkauf ... abändern, hätten wir logischerweise ein Problem, denn dieses Objekt gibt es nicht. Im default-Verhalten (ignore) bleibt der falsche Attributwert im DN des member-Attributes bestehen. Ist die memberof-dangling Policy auf drop gesetzt, verschwindet der falsche member- Attributwert sofort aus der Gruppe. Eine andere, für Produktivumgebungen noch elegantere Lösung wäre, den Wert für memberof-dangling auf error zu setzen. Im Fehlerfall verhindert diese Direktive eine Modifikation des member-DNs und liefert stattdessen eine eindeutige Fehlermeldung (standardmäßig eine constraint violation (19)) zurück: „Constraint violation (19), additional info: adding non-existing object as group member.“
132
1198.book Seite 133 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Integrität in beiden Fällen bewahrt, Problem gelöst. In Verbindung mit der optionalen Subdirektive memberof-dangling-error kann auch ein userdefinierter Errorcode zurückgegeben werden, z.B. um eine vordefinierte Client-Reaktion zu triggern. Wie dem auch sei: Eine fehlerhafte Modifikation des member-Attributes ist auf diese Art komplett ausgeschlossen, womit auch in dieser Konfiguration die referentielle Integrität unseres DIT gewährleistet ist. Stufe 3: Automatische Gewährleistung der referentiellen Integrität Referentielle Integrität? Hatten wir doch schon – eben erst, und vor ein paar Seiten sogar als separates Overlay ...? Stimmt, aber die zusätzliche Subdirektive memberof-refint true
(ergänzend zu memberof-dangling ) sorgt auch ohne das Overlay refint dafür, dass die referentielle Integrität im DIT vollständig gewahrt bleibt, was die User- und gruppenbezogenen DNs angeht. Nehmen wir an, wir würden den DN unseres Userobjekts ckent ändern, der bereits Mitglied der Gruppe cn=superuser ist; dann würde dieser DN dank memberof-refint true ebenfalls im member-Attribut der Gruppe auf den neuesten Stand gebracht werden – womit das Verhalten dem von »refint« für das Attribut member entspricht. Das Gleiche gilt, wenn User- oder Gruppenobjekte umbenannt, verschoben oder gelöscht werden. Das memberof-Attribut des Userobjekts würde bei diesen Modifikationen ebenfalls automatisch aktualisiert, ebenso wie die korrespondierenden DNs. Stufe 4: Mehrere Gruppentypen memberof-group-oc memberof-member-ad <member-ad>
Die Subdirektive memberof-group-oc definiert die Objektklasse der Gruppe, mit der das Overlay memberof arbeiten soll. Standardmäßig wird die Objektklasse groupOfNames verwendet, theoretisch können aber auch andere (eigendefinierte bzw. abgeleitete) Gruppen, deren member-Attribut eine DN-Syntax (1.3.6.1.4.1.1466.115.121.1.12) besitzt, verwendet werden. Auch möglich, aber nicht wirklich hundertprozentig geeignet wäre die Objektklasse groupOfUniqueNames, die zwar mit uniqueMember ein »Mitglieds«-Attribut besitzt, dieses verwendet jedoch einen Distinguished Name plus UID-Syntax (1.3.6.1.4.1.1466.115.121.1.34).
133
3.1
1198.book Seite 134 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Gruppen vom Typ posixGroup bleiben, da sie keine DN-Syntax verwenden (wie so oft) außen vor. memberof-member-ad definiert analog hierzu das zu verwendende member-Attribut der jeweiligen Objektklasse. Wenn sich memberof um Gruppen, die auf unterschiedlichen Objektklassen basieren, kümmern soll, muss das Overlay mehrfach mit den entsprechenden Definitionen aufgerufen werden (die Kommentare dienen nur der Beschreibung und sollten nicht in der slapd.conf auftauchen): overlay memberof memberof-group-oc groupOfNames memberof-member-ad member memberof-dangling error memberof-refint true
# defaultwert # defaultwert
overlay memberof memberof-group-oc MYgroupOfNames memberof-member-ad MYMember memberof-dangling error memberof-refint true
Hinweis: Eine Doppelvergabe wie z.B. memberof-group-oc
MYgroupOfNames
groupOfNames ist nicht möglich, das heißt: pro Gruppendefinition immer ein Auf-
ruf des Overlays. Weitere Subdirektiven wären noch memberof-memberof-ad und memberof-dn. Über memberof-memberof-ad kann optional festgelegt werden, in welchem Attribut die Gruppenzugehörigkeit des Objekts gespeichert wird. Der Defaultwert ist memberOf. Soll ein anderes Attribut verwendet werden, muss sichergestellt sein, dass das Objekt es besitzt und dass es eine DN-Syntax hat. Die Direktive memberof-dn spezifiziert – ebenfalls optional – den modifiersName bei Änderungen am memberOf-Attributwert, was zu Debuggingzwecken durchaus interessant sein kann. Standardmäßig wird der rootdn des jeweiligen Kontextes verwendet. All together now: memberof und refint Um ganz auf Nummer sicher zu gehen, setzt man idealerweise beide Overlays zusammen ein. Obwohl memberof die referentielle Integrität ebenfalls sicherstellt, was User- und gruppenbezogene DNs und das memberof-Attribut selbst angeht, bietet Overlay refint einen ergänzenden Sicherheitsmechanismus, der immer dann greift, wenn es um DN-Attributwerte geht, um die sich Overlay
134
1198.book Seite 135 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
memberof selbst nicht kümmern kann, wie z.B. owner, roleOccupant, manager, seeAlso usw. Wichtig im Zusammenspiel mit refint und memberof ist die bereits angesprochene Reihenfolge der Overlays, da Letztere »gestapelt« abgearbeitet werden. Wie wir wissen, erfolgt die Abarbeitung der Overlays in umgekehrter Reihenfolge: das zuletzt definierte Overlay (an »unterster« Stelle) wird zuerst abgearbeitet. Für unsere nachstehende Konfiguration bedeutet dies Folgendes: Zunächst kümmert sich refint um gegebenenfalls verbogene Referenzen, Löschungen etc. in allen per refint_attributes definierten Attributen und berichtigt oder entfernt sie. Anschließend kümmert sich memberof (wenn memberof-refint auf true gesetzt ist) in dem dank Overlay refint »vorbereinigten« Tree um die korrekten Zuordnungen bzw. seinen Teil der referentiellen Integrität. In der Praxis könnte das Szenario also wie folgt aussehen: overlay memberof memberof-refint true memberof-dangling error memberof-dn cn=memberof-overlay overlay refint refint_attributes member memberOf manager owner seeAlso refint_nothing cn=dummy
Der Einsatz von memberof in der Online-Konfiguration ist problemlos möglich. In der folgenden Abbildung sehen wir memberof zusammen mit refint in der Online-Konfiguration (hier im Apache DS, siehe Abschnitt 4.7, »Auf den Schirm!«):
Abbildung 3.3
Overlays memberof und refint in der Online-Konfiguration
135
3.1
1198.book Seite 136 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Somit ergänzen sich refint und memberof fraglos zu einem perfekten, dynamischen Duo, das sich in der Praxis effektiv um die Prävention möglicher Inkonsistenzen kümmert und alle User- und Gruppenzuordnungen perfekt verwaltet. Apropos dynamisch – da war doch noch was?
3.1.5
Hochdynamisch – Dynamic Directory Services mit Overlay »dds«
Wir alle kennen das Problem: Manchmal verschwinden Dinge einfach, die wir eigentlich dringend brauchen. Der Lieblingssocken in der Waschmaschine, der Internet-Zugang während einer Termin-Überweisung oder die vier brandneuen Alufelgen samt Reifen an unserem in der Tiefgarage geparkten Untersatz nach einem netten Kinoabend. Bei anderen Dingen wiederum können wir es eigentlich kaum erwarten, dass sie sich so schnell wie möglich wieder verkrümeln: Herpesbläschen, die heißgeliebte und lautstarke Verwandtschaft x-ten Grades zu Besuch während des Pokalendspiels, ein mächtig ausgewachsener Kater oder, wie üblich, alles auf einmal. Genau die Momente, in denen man wir uns wünschen, dass solche Dinge so simpel zu handhaben wären wie dynamische Objekte in unserem LDAP. Denn das Overlay dds kann uns Objekte zur Verfügung stellen, die sich nach einer exakt vordefinierten Zeitspanne automatisch wieder spurlos verflüchtigen. Overlay dds implementiert – nach RFC 2589 – also den Einsatz von Objekten mit limitierter Lebensdauer. Eindeutig charakterisiert werden die Objekte durch die zusätzliche Objektklasse dynamicObject vom Typ AUXILIARY, die zur Laufzeit des slapd durch die Einbindung des Overlay dds zur Verfügung gestellt wird. Sie enthält die operational Attributes entryTtl und entryExpireTimestamp, die die Kerndaten des Objekts – bezogen auf seine eingeschränkte Lebensdauer – beinhalten: der Attributwert von entryTtl beinhaltet die absolute Lebensdauer des Objekts in Sekunden, bezogen auf den Zeitpunkt der Erstellung bzw. seines letzten refresh; entryExpireTimestamp enthält den Zeitpunkt (Zulu-Time), an dem das Objekt gelöscht wird, – wenn bis zu diesem Zeitpunkt kein weiterer refresh erfolgt. Apropos refresh: Damit wird eine sogenannte extended Operation bezeichnet, mit deren Hilfe die TTL der von Overlay dds bereitgestellten dynamischen Objekte verlängert werden kann. Wie das funktioniert, schauen wir uns gleich an. Die Verfallszeit eines dynamischen Objekts wird immer ausgehend vom Erzeugungs- bzw. letzten Refresh-Zeitpunkt aus berechnet. Nach Ablauf der Zeit bzw. dem Erreichen des in entryExpireTimestamp gespeicherten Zeitpunkts werden die Objekte gelöscht, allerdings ist nach RFC-Spezifikation nicht eindeutig festgelegt bzw. gewährleistet, dass die Objekte sofort gelöscht werden. Aber keine
136
1198.book Seite 137 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Panik! Die OpenLDAP-Crew arbeitet fehlende oder ungenaue Detailspezifikationen in der Regel so aus, dass sie 1.) Sinn ergeben und 2.) auch funktionieren. Deshalb werden die dds-Objekte in unserem Tree auch genau dann gelöscht, wenn sie gelöscht werden sollen. Leider kennen wir alle da auch andere Interpretationen von fehlenden Spezifikationen, und, was viel schlimmer ist, von vorhandenen Spezifikationen. Und um der unausweichlichen Frage vorzugreifen:Nein, das sind nicht nur die Jungs aus Redmond. Aber die können’s einfach am besten ... Prinzipiell können wir jedes Objekt durch Hinzufügen der Objektklasse dynamicObject in ein dynamisches Objekt verwandeln. Ob das sinnvoll ist, steht auf einem anderen Blatt. Denkbar wären hier temporäre Benutzer, die über einen zeitlich beschränkten Account und entsprechende ACLs Zugriff auf bestimmte Inhalte erhalten (z.B. Test-/Probe-Accounts für kostenpflichtige Dienste); das Ganze kann idealerweise natürlich auch zur ACL-Auswertung in einer Gruppe z.B. vom Typ groupOfNames zusammengefasst werden. Wie ACLs für solche Szenarien funktionieren, schauen wir uns in Abschnitt 3.7 über ACLs, »Nur mit Clubkarte«, mit einem weiteren kompletten Anwendungsbeispiel für dds an. Eine andere Anwendungsmöglichkeit wären DHCP-Host-Leases im LDAP, was in der Praxis jedoch eher ein wenig in die Rubrik Lass uns mal was Rundes erfinden und es Rad nennen ... fällt. Dynamische Objekte können – wie reguläre Objekte – Subentries besitzen, vorausgesetzt, diese Subentries werden dann logischerweise ebenfalls als dynamische Objekte erstellt. Daher kann es natürlich zu Überschneidungen kommen, die sich jedoch wie immer durch etwas Planung vermeiden lassen. Ein Beispiel: Wir erstellen eine ou, die als Standard-Unit für temporär angelegte Benutzer dienen soll. Diese User haben eine TTL (Time To Live = Lebensdauer) von 7 Tagen. Nehmen wir an, wir hätten der ou eine Lebensdauer von nur fünf Tagen spendiert, liegt das Problem auf der Hand. Regulär würde die Unit nach fünf Tagen gelöscht. Sie kann jedoch nicht von der Bildfläche verschwinden, solange sie noch Subentries besitzt, die eine längere TTL auf ihrer Countdown-Uhr haben. Fazit: Ein dynamisches Objekt mit Subentries lebt immer so lange wie das Subentry mit der längsten TTL. Noch ein wichtiger Punkt, der beachtet werden muss: Eine nachträgliche Umwandlung von Objekten (statisch ↔ dynamisch) ist nicht möglich!
Schauen wir uns nun das Setup des dds-Overlays an. Unterhalb der database-Sektion initiieren wir zunächst (wie üblich) das Overlay und passen anschließend die Subdirektiven entsprechend unseren Anforderungen an:
137
3.1
1198.book Seite 138 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
overlay dds dds-max-ttl 1d dds-min-ttl 10s dds-default-ttl 5m dds-interval 5s dds-tolerance 1s dds-max-dynamicObjects
3
Die Direktiven sind weitestgehend selbsterklärend, hier noch ein paar Eckdaten: min-ttl und max-ttl sind obere und untere Grenzwerte, die beim refresh eines Objekts nicht unter- oder überschritten werden dürfen. Passiert dies doch, erhält der Client eine sizeLimitExceeded-Nachricht. max-ttl gilt zudem als default-Wert für die TTL, sofern default-ttl nicht gesetzt ist. max-ttl kann gemäß RFC 2589 zwischen einem Tag und einem Jahr plus sechs Stunden liegen, min-ttl liegt default bei 0. dds-interval legt fest, in welchen zeitlichen Intervallen das Overlay prüft, ob ein Objekt gelöscht werden muss. Der Standardwert liegt bei einer Stunde; wir haben ihn in diesem Fall für unsere Testzwecke sehr niedrig angesetzt. In der Praxis sollte der Wert > 60 Sekunden gewählt werden. Mit ddstolerance kann eine Art Gracetime angegeben werden. Gemeint ist die Zeitspanne, die nach Ablauf der TTL des Objekts verstreicht, bis der Thread startet, der das Objekt löscht (default 0). dds-max-dynamicObjects definiert, wie viele dynamische Objekte (bezogen auf den gesamten Kontext, für den das Overlay implementiert wurde) gleichzeitig existieren dürfen (default: unlimited). Genug der grauen Theorie: Wir wollen dds im Einsatz sehen. Zunächst bauen wir uns ein einfaches User-Objekt zusammen, das die Objektklassen, die wir für einen temporären Account benötigen, mitbringt. Als da wären: Ein cn oder eine uid, ein userPassword und vor allem eine limitierte Lebensdauer. Keep ist simple – wir nehmen als Objektklassen person, simpleSecurityObject (für das Passwort) und natürlich dynamicObject. Das Userobjekt packen wir der Übersichtlichkeit halber natürlich in eine separate, statische Unit: dn: ou=tempuser,dc=local,dc=site objectClass: organizationalUnit ou: tempuser dn: cn=hulk,ou=tempuser,dc=local,dc=site objectClass: person objectClass: dynamicObject objectClass: simpleSecurityObject cn: hulk sn: the green one userPassword: {SSHA}tCUkX5PoyEYDhIUjppX7VpNu0K3AtOpz
138
1198.book Seite 139 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Nach dem Anlegen prüfen wir die relevanten Attribute für unseren meist hochgradig schlechtgelaunten grünen Kollegen, der sich nach 300 Sekunden hoffentlich wieder abregen und in Bruce Banner verwandeln wird: #> ldapsearch –x cn=hulk entryTtl entryExpireTimestamp dn: cn=hulk,ou=tempuser,dc=local,dc=site entryTtl: 300 entryExpireTimestamp: 20081104121137Z
Die entryTtl des Objekts beträgt, exakt gemäß unserer Spezifikation, fünf Minuten, und das Objekt wird, falls wir nichts unternehmen, nach Ablauf dieser Zeitspanne bzw. zu dem Zeitpunkt, der in entryExpireTimestamp gespeichert ist, gelöscht. Aber wie bereits erwähnt, können wir etwas dagegen tun, sofern wir das wollen. In der Welt der dynamischen LDAP-Objekte kann auch das elegant gelöst werden – per extended Operation und ACL. Wir haben uns zwar noch nicht ausgiebig mit ACLs beschäftigt (das werden wird im Abschnitt 3.7, »Nur mit Clubkarte«, tun), aber um die refresh-Operation zu erläutern, müssen wir etwas vorgreifen. Eine ACL definiert, vereinfacht ausgedrückt, immer, wer wie auf was zugreifen darf. Um nun die dynamischen Objekte mit einer refesh-Kapabilität »auszustatten«, müssen wir eine entsprechende ACL setzen. Typischerweise könnte man dem Objekt gestatten, sich selbst durch das Setzen einer neuen TTL zu »refreshen«. Allerdings funktioniert das nicht mit einem einfachen ldapmodify, denn das Attribut entryTtl gehört gemäß RFC4512 zu den NO-USER-MODIFICATION-Attributen, und dieser Name ist Programm. Und hier greift die in OpenLDAP 2.4 neu eingeführte ACL-Berechtigungsstufe manage, die – sehr vereinfacht ausgedrückt – trotzdem Vollzugriff auf das Attribut gestattet. Um sie anwenden zu können, setzen wir folgende einfache ACL unterhalb unserer Overlay-Deklaration in der slapd.conf: access to attrs=entryTtl by self manage by * read
Anschließend starten wir unseren slapd neu und versuchen einfach mal, unseren guten alten Hulk noch etwas zu nerven, damit er seinen frischen, grünen Teint noch ein paar Minuten länger behält. Die ACL war der erste Teil, im zweiten müssen wir den Zusatzschalter –e relax für ldapmodify anwenden, der per extended Operation das entsprechende Control (1.3.6.1.4.1.4203.666.5.12, manageDsaIT) für diese spezielle Operation aktiviert. Sollte sich unser Hulk in der Zwischenzeit wieder abgeregt haben, legen wir ihn einfach neu an, kontrollieren noch einmal die TTL und den Ablaufzeitpunkt des Objekts, dann führen wir unsere Modifikation mit folgendem LDIF (hulk_refresh.ldif) durch: dn: cn=hulk,ou=tempuser,dc=local,dc=site changetype: modify replace: entryTtl entryTtl: 600
139
3.1
1198.book Seite 140 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
#> ldapmodify -xWD cn=hulk,ou=tempuser,dc=local,dc=site \ -e relax –f hulk_refresh.ldif Enter LDAP Password: modifying entry "cn=hulk,ou=tempuser,dc=local,dc=site"
Anschließend sollte uns der entryExpireTimestamp zeigen, dass unser grüner Klotz noch mindestens für weitere zehn Minuten (ausgehend vom Modifikationszeitpunkt) wütend durch die Gegend turnen wird. Damit soll es dann auch gut sein, und er kann sich endlich abregen ... für heute. Eine andere Variante wäre die direkte Verwendung von ldapexop (Achtung: Debian bringt das ldapexop-Tool default nicht mit): #> ldapexop -x "refresh" "cn=hulk,ou=tempuser,dc=local,dc=site" \ "1200" -D " cn=hulk,ou=tempuser,dc=local,dc=site" -W newttl=1200
Das Ganze funktioniert natürlich auch hervorragend im Zusammenspiel mit Overlay refint. Würde ein dynamisches Objekt (versehentlich) einer statischen Gruppe zugeordnet, verschwindet dank refint der member-Eintrag in der Gruppe ebenso schnell wie das dynamische Objekt nach Ablauf seiner Zeit. Noch ein paar abschließende Anmerkungen zu dds, bevor wir uns den anderen Overlays zuwenden: Die Attribute entryTtl und entryExpireTimestamp dürfen gemäß RFC2589 bei einer Replikation nicht auf den oder die beteiligten Slaves mit repliziert werden. Nach der RFC-Spezifikation kümmert sich einzig und allein der Master um das Verfallsdatum der dynamischen Objekte, während die Replicas das Objekt als »normales« Objekt sehen sollen. Um das zu erreichen, darf das Overlay dds auf der Replica nicht eingebunden werden (klappt ohnehin nicht – spätestens beim Start meckert der slapd der Replica das dds-Overlay als unzulässig für einen Shadow-Kontext an). Zudem müssen einige syncrepl-Subdirektiven auf dem Slave bzw. der Replica ergänzt werden (syncrepl werden wir uns sehr ausführlich ab Abschnitt 3.2.6, »Synchronization without Frustration«, anschauen): schemachecking=off exattrs=entryTtl,entryExpireTimestamp
Aus Performancegründen sollte bei der extensiven Verwendung von dds das Attribut entryExpireTimestamp in jedem Fall indexiert werden. Falls wir es vergessen haben sollten – ein Blick in die Logs nach einer Suchoperation auf ein dynamisches Objekt hilft uns auf die Sprünge: bdb_inequality_candidates: (entryExpireTimestamp) not indexed
140
1198.book Seite 141 Donnerstag, 5. Februar 2009 3:02 15
Völlig überlagert – Overlays in OpenLDAP
Beispiele für ACLs, die den Zugriff auf dynamische Objekte regeln, finden wir in slapo-dds(5). Dieses spezielle ACL-Thema werden wir aber auch im Abschnitt über ACLs 3.7, »Nur mit Clubkarte«, aufgreifen. Overlay dds lässt sich ebenfalls problemlos in die Online-Konfiguration integrieren.
3.1.6
... und noch ein paar Overlays im Überblick
Overlay constraint ... kümmert sich darum, dass Attributwerte über die LDAP-Syntax hinaus (auf der Basis von regulären Ausdrücken) kontrolliert werden können. Typisches Beispiel wäre eine Einschränkung der LDAP-Syntax für Mailadressen. Die »normale« Zeichensatz-Syntax (IA5-Charset) für eine Mailadresse lässt leider bestimmte Sonderzeichen (wie z.B. Leerzeichen oder Slashes) zu, was in jedem Fall zu Problemen führt bzw. eine aufwändige Kontrolle/Nachbearbeitung der Mailadresse vor der eigentlichen Verarbeitung durch den MTA (Mail Transport Agent) erforderlich machen würde. Um dem vorzubeugen, könnte constraint z.B. über die entsprechende constraint-Subdirektive (Zeile umbrochen): constraint_attribute mail regex \ ^[^\.][a-z0-9]{1,16}[.][a-z0-9]{1,16}@local.site$
unzulässige Zeichen bereits im Vorfeld verbieten – der Modifikator des Objekts ist gezwungen, eine syntaktisch gültige Mailadresse zu verwenden. In unserem Beispiel darf der String nicht mit einem Punkt beginnen, und der Name muss das Format @local.site besitzen. Jeder Teilstring links und rechts vom Punkt muss mindestens ein und darf maximal 16 Zeichen lang sein und nur aus Kleinbuchstaben und Zahlen bestehen. Jede nicht konforme Modifikation wird auf der Clientseite mit einer umgehenden Rückmeldung: error code 19 - modify breaks constraint on mail belohnt. Mehr Infos zu diesem Overlay finden sich unter slapo-constraint(5). Overlay unique Unser slapd kümmert sich darum, dass eine Sache innerhalb unseres Trees garantiert immer einzigartig (unique) ist: der DN eines Objekts. Overlay unique kümmert sich darum, das ausgewählte Attribute in unserem DIT ebenfalls einzigartig bleiben. Ein typisches Einsatzgebiet (auch weil es eine ideale Ergänzung zum gerade vorgestellten Overlay constraint darstellt) wäre die Anwendung von unique in großen Trees, um dort eventuelle Dubletten bei den Mailadressen der Benutzerobjekte zu verhindern. Über die Subdirektive unique_uri kann eine komplette LDAP-URI angegeben werden (Host, Port, BaseDN, Scope, Filter usw.),
141
3.1
1198.book Seite 142 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
über die die gewünschten Attribute selektiert werden können. Wir könnten zum Beispiel mit der folgenden simplen unique-Subdirektive unique_uri ldap:///?mail?sub
erreichen, dass bei jeder add- oder modify-Operation einer Mailadresse für unseren Kontext der Attributwert auf seine Einzigartigkeit geprüft wird. Wenn die gewählte Mailadresse eine Dublette erzeugen würde, erhält der Client die eindeutige Rückmeldung error code 19 - some attributes not unique, und die Operation wird abgebrochen. Mehr Infos zu diesem Overlay finden sich unter slapo-unique(5). Overlay translucent ... bietet eine – und jetzt mal wieder eines der absoluten Top-Ten-Schlagwörter für viele Consulter – konsolidierte (IT-spezifisch und auf Deutsch: vereinheitlichte) Ansicht von verschiedenen Attributen und Objekten verschiedener LDAPServer. Verschieden? Nicht ganz. Denn translucent arbeitet standalone leider nur dann korrekt, wenn die Kontexte das gleiche Suffix haben (wie z.B. in den Abschnitten 3.2.2 und 3.2.3 über Partitionierung). Damit wird translucent allein genommen etwas witzlos, da kein internes Rewriting stattfindet. Eine denkbare Variante wäre translucent im Zusammenspiel mit vorgeschaltetem Overlay rwm, welches ein Suffix-Rewriting (gern auch als Suffix-»Massaging« bezeichnet – ein Schelm, wer Schlüpfriges denkt) ermöglicht. Da rwm aber zum einen gewaltig auf die Performance drückt und zum anderen immer noch explizit als experimentell gekennzeichnet ist, gehen wir an dieser Stelle nicht weiter darauf ein. Mehr Infos zu diesem Overlay und rwm unter slapo-translucent(5) und slapo-rwm(5). Eine Beispielkonfiguration findet sich zusätzlich unter: www.openldap.org/doc/ admin24/overlays.html#Translucent Proxy. Overlay valsort ... sortiert zurückgegebene ldapsearch-Requests nach vorgegebenen Kriterien. Stellen wir uns vor, wir hätten Gruppen mit Hunderten von Mitgliedern, wäre es schon durchaus nett und nützlich, alle DNs z.B. alphanumerisch gelistet zu bekommen, denn standardmäßig liefert ldapsearch die Attributwerte in der Reihenfolge, in der sie angelegt wurden: der jeweils aktuellste zuletzt. Auch der ldapsearch-Sortierungs-Schalter –S greift im Bezug auf die Reihenfolge der member-Attributwerte leider nicht. Mit Hilfe der Subdirektive valsort-attr member cn=superuser,dc=local,dc=site alpha-ascend
des Overlays valsort können wir uns die zurückgelieferten member-DNs bei einer erneuten ldapsearch-Suche (mit -S member) nun fein säuberlich und alphanumerisch absteigend sortiert anzeigen lassen. Da valsort serverseitig implementiert ist,
142
1198.book Seite 143 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
müssen sich LDAP-Client-Tools oder Browser wie der JXplorer nicht mehr um diese Funktionalität kümmern. Das Apache Directory Studio verfügt bereits intern über diese Funktionalität. Mehr Infos zu diesem Overlay unter slapo-valsort(5).
3.1.7
And the Rest?
Die nächsten beiden Overlays und ihre Funktionen möchten wir in ihren speziellen Einsatzgebieten zeigen, die jedoch tiefere Vorkenntnisse zu den jeweiligen Thematiken voraussetzen. Daher haben wir an dieser Stelle nur eine Übersicht eingefügt, die die Overlays kurz erläutert und einen Verweis auf den entsprechenden Abschnitt enthält, in dem wir sie in Aktion erleben. Overlay chain ... kümmert sich z.B. um die automatische Verkettung von Kontexten mit ausgelagerten Subkontexten (Partitionierung) und die serverseitige Verfolgung von Referrals. Was das bedeutet und wie das funktioniert schauen wir uns in Abschnitt 3.2.3, »Gesprengte Ketten«, an. Overlay syncprov ... Der Sync-Provider: eines der wichtigsten Overlays überhaupt, das die LDAP Sync Replikation (kurz: syncrepl) und ihre Ableger wie delta-syncrepl und Standby-/Multi-Master –Replikation überhaupt erst ermöglicht. Alles über syncprov und die entsprechenden Replikations-Varianten ab Abschnitt 3.2.6, »Synchronization without Frustration«. Apropos Partitionierung und Replikation: Davon gibt’s jetzt jede Menge mehr im nächsten Abschnitt. Geht sofort los …
3.2
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Deckard: »She's a replicant, isn't she?« Tyrell: »I'm impressed …« Blade Runner, USA 1981
3.2.1
Warum man LDAP-Datenbanken replizieren sollte
Punkt 1: Redundante Authentifizierungsserver Treffender als in der Überschrift dieses Abschnitts lässt es sich eigentlich kaum beschreiben. Denn wir leidgestressten Admins wissen eine Sache ganz genau:
143
3.2
1198.book Seite 144 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Irgendwann verabschiedet sich jeder Server, zumindest in unserem Raum-ZeitKontinuum. Und in diesem Moment interessiert uns neben dem üblichen, gehetzten Blick auf die letzten Backup-Logs eigentlich nur eines: Läuft die redundante Kopie? Durch Replikation des kompletten Kontextes auf einen oder mehrere Server bleibt gewährleistet, dass ein Zugriff auf den Datenbestand selbst dann noch erfolgen kann, wenn einer der (an der Replikation des gleichen Kontextes beteiligten) Server komplett ausfällt. Im Klartext: Ist einer weg, springt ein anderer für ihn ein. Die »Umschaltung« auf einen anderen Server läuft im Normalfall für den Benutzer (den LDAP-Client) vollkommen transparent ab – sofern er entsprechend konfiguriert ist. Selbst im »Worst Case«, dem gerade genannten Ausfall eines Knotens, können die User sich immer noch am Netz authentifizieren und, was ebenso wichtig ist, auf den kompletten Inhalt des DIT zugreifen. Das einzige Manko in einem typischen Master/Slave-Szenario wäre der temporär nur lesende Zugriff auf den DIT, insofern der schreibbare Master ausgefallen sein sollte. Aber selbst das ist seit OpenLDAP 2.4 und der Einführung des Standby-Master kein Problem mehr. In dieser Konfiguration werden nicht einmal mehr besondere Client-Settings benötigt, da der Reserve-Master über die gleiche Service-IP des Clusters ansprechbar ist. Im Klartext: Durch diese Ausfallsicherheit ist zunächst einmal eine der wichtigsten Eigenschaften eines Verzeichnisdienstes im Produktivumfeld erfüllt: Redundanz. Durch redundante Server auf Basis einer oder mehrerer Full-Replicas kann sich der Benutzer jederzeit authentifizieren und arbeiten, und der Admin kann seinen Pulsmesser etwas gelassener betrachten, sollte sich der Master final verabschiedet haben. In der Praxis würden sich die Einträge in der ldap.conf (Client, libldap.*), bezogen auf das Setup, das wir in den nächsten Abschnitten verwenden werden – auf einem Linux-Client, schematisch so darstellen: URI ldap://ldapmaster.local.site ldap://ldapslave.local.site
Ist einer der hier eingetragenen LDAP-Server nicht erreichbar, wird vom Client automatisch der nächste eingetragene Server kontaktiert. Voraussetzung für die Verwendung des FQHN in den vorgenannten Direktiven ist natürlich eine funktionierende Namensauflösung. Das gilt insbesondere für den Einsatz von TLS. Zudem wäre noch etwas Feintuning an den bereits bekannten pam- und nss-relevanten Konfigurationsdateien unter /etc (ldap.conf bzw. libnss-ldap.conf/pam_ ldap.conf) angesagt. Die dort vorhandene host/uri-Direktive ermöglicht es uns zum Beispiel, mehrere LDAP-Server als mögliche Authentifizierungs-Hosts anzugeben. Auf dieser Basis dieser Direktiven kann ein Server eine Authentifizierungsanfrage an einen anderen Server weiterleiten, sollte er selber nicht mehr
144
1198.book Seite 145 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
imstande sein, sie zu beantworten. Die host-Direktiven würden hierzu beispielhaft wie folgt angepasst; hier zunächst der Master (funktionierende Namensauflösung natürlich vorausgesetzt): host
ldapmaster.local.site ldapslave.local.site
Und ebenso auf dem ldapslave, jedoch in geänderter Reihenfolge: host
ldapslave.local.site ldapmaster.local.site
Alternativ zur Host-Direktive kann auch die bereits vorgestellte uri-Direktive eingesetzt werden. In Abschnitt 3.6, »Hör mal, wer da hämmert«, kommen noch weitere spezifische Optionen hinzu, die u.a. das Setup mit TLS betreffen. Die Thematik der Anmelde-Redundanz spielt ebenfalls eine wichtige Rolle, wenn es an das redundante Setup von Samba und OpenLDAP geht. Dazu mehr in Abschnitt 4.1, »Die Meister der Domäne«. Punkt 2: Performanceverlust durch ACLs Verzeichnisdienste, die die Berechtigungen der Zugriffe auf den DIT per ACLs (Access Control Lists/Zugriffskontrolllisten, siehe Abschnitt 3.7, »Nur mit Clubkarte«) auswerten, werden umso langsamer, je verschachtelter und komplexer die ACLs strukturiert sind. Das gilt vor allem dann, wenn die ACLs jede Menge regulärer Ausdrücke enthalten, die ausgewertet werden müssen. Einen praktikablen Lösungsansatz bietet hier die Verwendung einer X.500-konformen Readonly-Replikation, die im Idealfall nur einen Teilbaum oder bereits gefilterte Daten enthält. In dem Fall könnten die ACLs für diese Read-only-Replica wesentlich einfacher strukturiert werden (im Detail: jeder Zugriff auf den Slave erfolgt ohnehin nur lesend), wodurch sich natürlich auch die Auswertungszeit bei Zugriffen drastisch verkürzt. Punkt 3: Datensicherheit Einer der wichtigsten Punkte überhaupt: In der Regel sollte zumindest eine vollständige Replikation (Full Replica) des Masters existieren, die alle Objekte des DIT enthält. Durch diese vollständige Replikation des Masters auf einen Slave oder zweiten Standby-Master befindet sich immer ein komplettes »Backup« des DIT auf einem zweiten Server. Um die Daten-/Ausfall-Sicherheit bzw. Redundanz herzustellen, bietet OpenLDAP in Version 2.4 drei Varianten der Replikation: Die »einfache« Sync-Replikation (oder kurz syncrepl) von einem Master auf einen oder multiple Readonly-Slaves, die aufgebohrte Variante delta-syncrepl, welche durch eine separate Log-DB unter Mitwirkung des bereits vorgestellten Overlays accesslog zusätzliche Performance und Sicherheit bringt, und last, but surely not least, die allerneueste Vari-
145
3.2
1198.book Seite 146 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
ante der Standby-Master-Replikation. Letztere bietet die lang erwartete Funktionalität, eine zusätzliche, vollwertige Master-Kopie »schlafend« im StandbyModus einzurichten, die im Fehlerfall automatisch für den defekten Master einspringt. Eine weitere, allerdings nicht ganz X.500-konforme Redundanz-Variante stellt die Multi-Master-Replikation (abgekürzt: MMR) dar. Daneben gab es bis einschließlich OpenLDAP 2.3 noch die veraltete und extrem fehleranfällige Variante der slurpd-Replikation, auf die wir im konkreten Bezug auf OpenLDAP 2.4 konsequenterweise nicht weiter eingehen werden, da dieses Tool nicht mehr Bestandteil dieser Version ist, und das aus vielen guten Gründen. Ein ausführliches Statement hierzu gibt es in Abschnitt 3.2.5, »Vorbereitungen und Vorbetrachtungen zur Replikation«. Wie funktioniert’s? Vorab eine stark vereinfachte Funktionsbeschreibung: Alle syncrepl-Replikations-Varianten sorgen auf Basis des modifyTimestamps (siehe Abschnitt 2.3, »Fingerübungen«), der korrespondierenden entryCSN (CSN = Change Sequence-Number, mehr hierzu in Abschnitt 3.2.6, »Synchronization without Frustration«) und der Session-Cookies dafür, dass jede Änderung an Objekten in der Datenbank des Masters auf einen oder mehrere LDAP-Slaves (oder Master) im Netz repliziert wird. Die Replikation der Objekte selbst erfolgt dabei wahlweise auf Basis zeitkritisch oder periodisch gesteuerter Replikations-Varianten. Grundsätzlich darf nach X.500-Spezifikation der Schreibzugriff immer nur auf einen zentralen LDAP-Master bzw. den Master eines Subtrees erfolgen. Die Replicas sollten nach X.500-Spezifikation strikt readonly sein. Die neue StandbyMaster-Variante verstößt daher auch nicht gegen diese Spezifikationen, im Gegensatz zu gewissen Redmonder Produkten, die das Ganze zudem als Feature anpreisen. Diesen Irrglauben werden wir aber gleich in aller Ruhe sezieren. Und auch die ganz auf Sicherheit bedachten Admins können ihre Nachtruhe finden, denn wir werden dafür sorgen, dass alle Replikationsvorgänge komplett verschlüsselt ablaufen; hierfür stellen uns die Replikationsmechanismen verschiedene Verfahren zur Verfügung. Dazu später mehr in den Abschnitten über SSL/ TLS. Es ist allerdings ein Irrglaube anzunehmen, Replikationen seien dasselbe wie Spiegelungen. Dem ist definitiv nicht so. Daher hier zunächst einmal der wichtigste Unterschied einer Replikation zu einer einfachen Spiegelung: Bei einer Spiegelung werden die Daten einfach ungeprüft »parallel« in einen Datenbestand geschrieben (z.B. RAID Level 1-Spiegelung auf zwei oder mehr Disks).
146
1198.book Seite 147 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Bei einer Replikation werden die übermittelten Daten zunächst lokal erfasst und die Timestamps/CSNs/Session-Cookies der betreffenden Objekte auf den beteiligten Servern miteinander verglichen. Liegt dann eine berechtigte ReplikationsAnfrage vor, wird sie durchgeführt und das replizierte Objekt mit einem neuen, aktuellen Timestamp/CSN versehen. Auf diesem Weg kann die Aktualität der Datenbestände zwischen den beteiligten LDAP-Servern eindeutig sichergestellt werden. Weiterhin werden nur die Daten aktualisiert, die auch aktualisiert werden müssen, was wiederum die Performance erhöht und das Netz weitaus weniger belastet als eine komplette Datenbanksynchronisation. ... just in time Dazu noch eine wichtige Anmerkung: Datenbankoperationen sind zeitsensibel, für die Replikation von Datenbanken gilt dies in besonderer Weise. Das heißt: Um zu einem funktionierenden Replikationsmechanismus zu gelangen, müssen wir zunächst auf allen angeschlossenen Servern die Zeit sehr genau synchronisieren. Wie das in Verbindung mit NTP funktioniert, sehen wir in Abschnitt 3.2.4, »The Time Machine«. Insbesondere durch die Einführung der Multi-Master-Replikation benötigt dieser Punkt eine ganz besondere Aufmerksamkeit, denn die replikations-relevanten Zeitscheiben wurden von einem vormals verwendeten Sekunden-Intervall auf eine tausendstel Sekunde herabgesetzt. Also sollte die NTP-Synchro zwischen unseren LDAP-Maschinen so exakt wie möglich arbeiten, damit nichts in die Hose geht ... Die Zeitsynchronisierung wird ebenfalls dann noch einmal wichtig, wenn wir über Kerberos reden, denn unser scharfer Höllenhund kann und muss recht zickig auf Differenzen in den Serverzeiten reagieren. Und das ist auch gut so. Exkurs: Multi-Master-Replikation – Feature oder eher Fatal? Da die Fragen zu dem Thema bis heute immer noch nicht ausgestorben sind, und aller Logik zum Trotz anscheinend auch niemals aussterben werden: Eine Multi-Master Replikation beschreibt nach RFC 3384 (»LDAP V3- Replication Requirements«), Sektion 4.6, ein theoretisches Szenario, in welchem auf zwei oder mehrere Master gleichzeitig schreibend zugegriffen werden könnte. Die Wünsche und Ideen einiger Admins sind dabei immer die gleichen: »Hochverfügbarkeit«, »Skalierbarkeit«, »Datenkonsistenz« und – ebenfalls sehr interessant: Load Balancing. Und jetzt einfach mal der Reihe nach nüchtern betrachtet: Höhere Verfügbarkeit durch Multi-Master? Ja. Skalierbarkeit? Nö! Denn diese gleichberechtigten Master erzeugen einen exponentiell ansteigenden Traffic mit jedem neuen Master, da
147
3.2
1198.book Seite 148 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
sich zwangsläufig ALLE Master gegeneinander replizieren müssen, um die Datenkonsistenz über den gesamten DIT und alle beteiligten Server zu gewährleisten. Und genau damit tauchen auch die Probleme auf, die dem X.500-Standard komplett widersprechen. Denn echte Datenkonsistenz wird gemäß X.500 erst durch das Single-Master(Write) und Multiple-Slaves (Readonly) -Prinzip gewährleistet. Die Datenkonsistenz bei zwei oder n Master-Servern innerhalb eines Trees oder Subtrees zu wahren, auf die schreibend zugegriffen werden kann, ist –vorsichtig ausgedrückt – nicht trivial. Die Mechanismen, die dazu eingesetzt werden müssen, bringen jede Menge Overhead (siehe Skalierbarkeit) mit sich, sind extrem aufwändig, anfällig für Fehler (Datenkonsistenz!) und keinesfalls einfach und ohne Risiko zu realisieren: 왘 Perfekt arbeitende und extrem fein granulierte Zeitsynchronisation, die zu keiner Zeit aus dem Tritt geraten darf. 왘 Sicherstellung einer fehlerfreien »CrossOver«-Replikation des kompletten Contents (Haupt-Kontext, konfigurationsspezifische Einstellungen und Schemas) aller beteiligten Master untereinander. 왘 Ein deterministisches Verfahren, um zu entscheiden, welcher schreibende Zugriff, der von unterschiedlichen Servern zeitgleich auf ein und denselben Datensatz erfolgt, Priorität hat, bzw. ein effektiver Locking-Mechanismus, der im Fall der Fälle die Änderung verweigert. 왘 Automatische Prozeduren, die für einen korrekten Content-Abgleich nach Ausfall der Verbindung zwischen den beteiligten Master-Servern sorgen. Ein ganz simples Beispiel hierzu: Auf zwei Servern wird auf ein und denselben Datensatz innerhalb des gleichen Trees in exakt derselben Millisekunde mit der gleichen Berechtigung bzw. dem gleichen administrativen DN schreibend zugegriffen. Wer hat nun Vorrang? Der Admin mit dem höheren Gehalt oder der mit den meisten unbezahlten Überstunden? Klingt bescheuert? Mit Sicherheit, aber so ähnlich handhaben z.B. die Winzigweich-Server die Prioritäten, denn den Zuschlag für die schreibende Änderung erhält irgendwann nach stundenlangem und wenig informativem Palaver der Server mit der längsten Uptime. Und danach geht’s an die Replikation. Und bis dann endlich – dank toller Features wie ständiger Browsing-Election und den endlosen Wer-wie-wann-wohin-Replikations-Debatten – alle im Netz wissen, wer wohin wie und mit welcher Berechtigung replizieren darf, können in M$Netzen schon ein paar Stündchen ins Land gehen. Vielleicht wäre ein Zufallsgenerator genauso effizient. Dazu kommt – egal, ob bei ADS, dem Fedora Directory Server oder anderen Vertretern, die dieses »Feature« seit Längerem anbieten – ein deutlich größerer Daten-Overhead, der zwischen den beteiligten Mastern
148
1198.book Seite 149 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
jederzeit ausgetauscht wird, damit jeder wenigstens halbwegs weiß, wie aktuell seine Daten sind und wohin er sich replizieren muss. Nur als kurze Info nebenbei: Winzigweich-Server verwenden je nach Version üblicherweise bis zu vier(!) ADS-Attribute, um festzustellen, wer wann was wohin replizieren darf: Die MS-spezifischen Attribute uSNcreated und uSNChanged sind ein Redmonder Ansatz, um einen »Ausweg« aus den ach so ärgerlichen X.500-»Beschränkungen« zu finden und ihre Variante der Multi-MasterReplikation zu ermöglichen. Die uSN* -Attribute (uSN steht dabei für update Sequence Number) werden bei der Replikation vom replizierenden DC geändert und die Versionsnummer um 1 erhöht. Letztendlich wird dann noch über die Versionsnummer, einen GUID-Vergleich der beteiligten DC und über den Timestamp des Objekts entschieden, welches Objekt das »originale« ist und repliziert werden darf. Aber wie gesagt, wir reden hier über Redmonder »Standards«. Würfeln wäre vielleicht auch eine Alternative ... Nach X.500-Standards reicht zur Ermittlung der Aktualität eines Objekts exakt ein (Zahl: 1) Attribut: der Timestamp. Punkt. In einem Multi-Master-Szenario kann dieser, gekoppelt mit einem effizienten Locking-Mechanismus, dazu verwendet werden, einen exakt zeitgleichen, schreibenden Zugriff auf den gleichen Datensatz unterbinden. Das Attribut mit einem eindeutigen Timestamp nennt sich im Fall von OpenLDAP CSN (Change Sequence Number) und besitzt als Locking-Mechanismus einen zusätzlichen, an den Timestamp der CSN angehängten Hex-Counter (hierzu mehr in Abschnitt 3.2.6, »Synchronization without Frustration«). Aber vielleicht gibt’s in Redmond auch einfach immer noch keine klare Vorstellung darüber, welche Aufgaben ein Timeserver erfüllen soll – und vor allem kann ... Datenkonsistenz, Hochverfügbarkeit und Skalierbarkeit lassen sich ohne Probleme gemäß den X.500-Standards in einer Single-Master- oder Standby-MasterUmgebung (Letztere ab OpenLDAP 2.4.*) realisieren, denn es existieren genügend Vorgehensweisen und Möglichkeiten: Hardware-Redundanz von Master und Slave, Standby-Master, durchdachte Partitionierung des Trees mit SubtreeMastern und deren Slaves, multiplen Replikationen usw. Eine ausführliche Betrachtung dieser Problematik von Kurt Zeilenga (OpenLDAPFoundation) findet sich unter der Draft: draft-zeilenga-ldup-harmful-02.txt: »LDAP Multi-master Replication Considered Harmful«. Ein weiteres, unmissverständliches Statement zu dem Thema findet sich ebenfalls unter www.openldap.org/faq/data/cache/1240.html. Aus diesen guten Gründen haben die OpenLDAP-Entwickler lange Zeit einen großen Bogen um dieses »Feature« gemacht; einige von ihnen brachten die Sache
149
3.2
1198.book Seite 150 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
auch namentlich auf einen absolut stimmigen Begriff: BS (denken wir dabei einfach an den englischen Begriff für organische Abfallprodukte männlicher Rindviecher). Wie bereits erwähnt, führte das Gequengel zahlloser Admins schließlich doch dazu, das die Truppe um Howard Chu einen mehr als brauchbaren Kompromiss in die Roadmap von OpenLDAP 2.4 einfügte: Den Standby-Master, der nichts anderes als eine absolut exakte Kopie des »echten« Masters ist, und im Fehlerfall –gesteuert über Cluster-Software wie z.B. Heartbeat- automatisch für ihn einspringt. Das ist eine deutliche Verbesserung, was das Ziel – die Hochverfügbarkeit- angeht, und einem SpoF (Single Point of Failure) somit die Zähne zieht. Zudem bleibt die Datenkonsistenz in jedem Fall gewährleistet, da gemäß den X.500-Standards immer nur auf einen aktiven Master zugegriffen wird. Die »Multi-Master«-Replikation fiel bei der ganzen Geschichte eher als Nebenprodukt ab. Leider. Thema ein für alle Mal durch? Wir glauben nicht wirklich daran. Zum Schluss unseres kleinen Exkurses noch einmal zurück zum eingangs genannten Begriff Load Balancing, einem weiteren Irrglauben unfassbarer Größenordnung, weil trotz jedweder Logik immer wieder der Begriff Load Balancing in einen Korb mit Multi-Master-Replikation geworfen wird. Schon unglaublich, was riesige Werbebudgets großer Firmen – gekoppelt mit minimalem Fachwissen auf Seiten so genannter Consulter und leider ebenso oft auf Seiten der Entscheider – in Firmen aller Größenordnungen auslösen können: Migräne eines ungeahnten Ausmaßes – spätestens dann, wenn allen Beteiligten klar geworden ist, was da unter falschem Namen und Prämissen an den Mann oder die Frau gebracht worden ist. Load Balancing hat aber auch rein gar nichts (nothing, rien, nada) mit Multi-Master-Replikation zu tun. Punkt. In einem Multi-Master-Szenario entsteht – ganz im Gegenteil – ein deutlich erhöhter Traffic und damit mehr Last (Load), weil sich jeder Master gegen jeden anderen Master bei jeder Änderung eines Objektes replizieren muss. Mit jedem zusätzlichen Master erhöht sich der Traffic, und damit auch die Last. Okay, vielleicht sollten wir einfach die Definition des Begriffes Load-Balancing überdenken, dann wird alles schon wieder gut werden. Oder vielleicht doch nicht? Ach ja: Die Redmonder haben mit ihrem 2008-Server erstmals ein »nagelneues« Superfeature eingeführt: einen Readonly(!) Domain Controller für ihren ADS (≠LDAP). Man höre und staune. Vielleicht ist ja doch noch nicht alle Hoffnung verloren, und irgendjemand aus Billyboys Crew hat rein versehentlich mal einen Blick in die X.500-Spezifikationen geworfen. Aber auch daran wollen wir nicht so recht glauben ...
150
1198.book Seite 151 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Weiter im Text Im Folgenden werden wir zunächst die Partitionierung eines DIT erläutern, wobei das Overlay chain eine bedeutende Rolle spielen wird. Danach beschäftigen wir uns mit der Einrichtung einer exakt arbeitenden Zeitsynchronisierung zwischen allen beteiligten Servern; die zwingende Voraussetzung für eine korrekt funktionierende Replikation. Anschließend werden wir jede Menge (zunächst unverschlüsselter) Replikations-Szenarien durchspielen.
3.2.2
Lastverteilung/Partitionierung
Was ist mit diesen Begriffen gemeint? Nun, Lastverteilung dürfte auf der Hand liegen, und wer bei Partitionierung an seine Festplatte denkt, die in mehrere »Häppchen« eingeteilt ist, liegt in der LDAP-Analogie auch nicht voll daneben. Aber betrachten wir das Ganze einmal anhand des folgenden Modells: In einem Netzwerk mit Zehntausenden von Usern, die räumlich ebenfalls auf verschiedene, weit auseinanderliegende Standorte verteilt sind, würde jeder Zugriff, egal ob schreibend oder lesend, auf nur einen (!) zentralen Server erfolgen. Egal, wie gut die eingesetzte Hardware des Servers oder die Bandbreite des Netzwerks ist, irgendwann geht diesem LDAP-Server aufgrund der hohen Anzahl von Anfragen einfach die Luft aus. Abhilfe schafft hier die Partitionierung. Und ähnlich wie die Partitionierung einer Festplatte können wir uns auch die Partitionierung innerhalb des DIT vorstellen: Ein Bereich des DIT wird vom übrigen Tree separiert (partitioniert), und dieser Subtree wird einfach komplett auf einen externen Server ausgelagert, der sich selbst verwaltet bzw. verwalten kann. Exkurs: Superkleber – zwei Datenbanken per »subordinate« verknüpfen Da wir gerade über die Aufteilung unseres DIT sprechen, sollten wir an dieser Stelle auch noch kurz die slapd-Direktive subordinate (engl. untergeordnet) betrachten. Sie gehört genau genommen nicht in die Kategorie »partitionierter DIT«, sondern bietet »nur« eine vereinheitlichte Ansicht von mehreren Datenbanken des gleichen Suffixes, die von ein und demselben slapd bedient werden. Kurz und knapp: Mit dem Parameter subordinate lassen sich zwei Datenbanken relativ einfach »zusammenkleben« (engl. = glue). Minimale Voraussetzung: Sie sollten in der Regel zur gleichen BaseDN gehören und werden über den gleichen rootdn verwaltet. Eine untergeordnete Datenbank kann in der Praxis dahingehend Vorteile bringen, wenn es sich z.B. um einen sehr großen Datenbestand handelt, dessen Datenbankdateien aus Performancegründen auf physikalisch unterschiedliche Platten gesplittet werden sollen.
151
3.2
1198.book Seite 152 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Verantwortlicher Superkleber ist das ehemals externe Overlay glue, das seit Version 2.4 integraler Bestandteil unseres slapd ist und allein durch den subordinateAufruf in Aktion tritt. Eine separate Konfiguration ist daher nicht nötig; den Zeitpunkt seines Aufrufes können wir jedoch nach wie vor durch Einfügen von »overlay glue« bestimmen, da es gegebenenfalls nötig sein kann, ein explizite Reihenfolge der Abarbeitung (z.B. im Zusammenspiel mit Overlay rwm) einzuhalten. In der Praxis könnte ein einfaches subordinate-Setup so aussehen (Beispieldateien zu diesem Abschnitt unter: http://www.galileocomputing.de/1801. Die Kommentare hinter den Direktiven dienen nur der Verständlichkeit und dürfen nicht übernommen werden): database hdb suffix ou=externalunit,dc=local,dc=site # neuer Sub-Kontext rootdn cn=ldapadmin,dc=local,dc=site # kein rootpw directory /ext/ldapdata # Db-Dateien auf disk 2 index (indexierte Attribute) subordinate # "ich bin eine untergeordnete DB" ... database hdb suffix dc=local,dc=site # unser "normaler" Kontext rootdn cn=ldapadmin,dc=local,dc=site # identisch zum o.a. rootpw {SSHA}... usw. index (indexierte Attribute) # identisch zu den o.a. directory /var/lib/ldap # Db-Dateien auf disk 1
Das »Zusammenkleben« erfolgt dabei völlig transparent; der Baum stellt sich für den von außen zugreifenden User oder die Applikation wie aus einem Guss dar, insofern nur die Direktive subordinate verwendet wird. Ergänzen wir sie um den optionalen Parameter advertise, wird der Subtree als separater Tree im rootDSE annonciert. Allerdings sind mehrere Punkte zu beachten: Ein Verschieben von Objekten zwischen »normaler« und subordinate-DB ist nicht möglich. Hier ernten wir höchstens einen Error Code 71: Operation affects multiple DSAs / cannot rename between DSAs. Gehört der Subkontext nicht zu unserer BaseDN, kommen wir um den Einsatz von overlay rwm kaum herum. Allerdings macht dieses Szenario in der Praxis üblicherweise nur wenig Sinn. Weiterhin müssen sollten beide Datenbanken mit den gleichen Indexen konfiguriert sein; in der Regel sollten alle Datenbank-spezifischen Settings identisch gewählt werden, da subordinate logischerweise am effektivsten arbeiten kann, wenn beide DBs so ähnlich wie möglich sind.
152
1198.book Seite 153 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Genug geklebt – zurück zur »richtigen« Partitionierung. Nehmen wir als konkretes Beispiel an, in unserem DIT hätten wir eine Sub-Unit namens offshore, und diese Unit mit Ihren Mitarbeitern (James T. Kirk, Jean Luc Picard, Luke Skywalker und Han Solo) liegt räumlich ein paar Lichtjahre getrennt vom Hauptsitz unserer Firma. Wir könnten nun den kompletten Tree (inklusive der Unit offshore) weiterhin verwaltungstechnisch über unseren Server ldapmaster.local.site laufen lassen. Machbar – aber in der Praxis völlig unökonomisch. Die ideale Lösung für solche und ähnliche Szenarien bietet die Möglichkeit der Partitionierung. In der LDAPTerminologie bedeutet das, dass ein Teil des DIT, also ein Subtree, komplett auf einen anderen Server ausgelagert wird. Jede Anfrage von Benutzern, die diesem Subtree untergeordnet sind, sollte üblicherweise direkt an den für diesen Subtree zuständigen Server geleitet werden. Anfragen von LDAP-Clients, die sich innerhalb des ausgelagerten Teilbaums befinden, aber direkt an den LDAP-Master gerichtet sind, werden über einen so genannten Referral vom LDAP-Master an den für den fraglichen Subtree zuständigen LDAP-Server weitergeleitet (default allerdings nicht vollautomatisch, dazu gleich mehr). Die Vorteile liegen auf der Hand: Zunächst ergibt sich durch die Auslagerung bzw. Dezentralisierung ganzer Teilbäume des DIT an den Ort, wo sie räumlich und verwaltungstechnisch benötigt werden, eine erheblich verbesserte Lastverteilung, da nicht alle Anfragen automatisch über den gegebenenfalls weit entfernten Master laufen. Zum anderen ergibt sich – im Zusammenspiel mit einer Replikation – eine deutlich gesteigerte Ausfallsicherheit und Redundanz. Verweise ... Wir unterscheiden dabei so genannte subordinate Referrals (Verweis auf eine untergeordnete Partition) und superior Referrals (Verweis auf eine übergeordnete Partition). Das Verhalten eines Referrals lässt sich am ehesten mit dem eines Servicemitarbeiters vergleichen, der auf unsere Anfrage hin freundlich und spontan auf einen Kollegen verweist: Tut mir sehr leid, das ist leider nicht mein Bereich – versuchen Sie es doch bitte freundlicherweise bei dem Herrn da drüben ... Gut, den Realitätsbezug hinsichtlich Spontanität und Freundlichkeit lassen wir einfach mal außen vor und verdeutlichen das Ganze am besten ganz konkret anhand eines subordinate Referrals innerhalb unseres DIT. Dazu erstellen wir zunächst einen neuen LDAP-Server (ldapoffshore.local.site) mit einer leeren Datenbank, der die neue Partition unseres DIT aufnimmt, nämlich die dc=offshore und ihre vier User-Objekte (siehe die Beispiel-LDIF-Datei offshore.ldif für diesen Abschnitt). Die slapd.conf dieses Servers muss zwangsläufig
153
3.2
1198.book Seite 154 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
von der Konfiguration unseres ldapmaster-Servers abweichen, da sie sich um einen anderen (Sub-)Kontext unseres Bäumchens kümmert. Hier zunächst einige der wichtigsten Einträge der Datenbank-Sektion (die Datei ist in den Beispielen zu diesem Abschnitt): database suffix rootdn rootpw
hdb dc=offshore,dc=local,dc=site cn=ldapadmin,dc=offshore,dc=local,dc=site {SSHA}... # SSHA-gecryptetes Gegenstück von »linux«
Wir erkennen auf Anhieb, was los ist: Der Hauptkontext bzw. die BaseDN unseres offshore-Servers liegt unterhalb der uns bekannten dc=local,dc=site, und das aus gutem Grund. Dieser Server verwaltet »nur« die Partition dc=offshore,dc=local,dc=site und besitzt hierfür sogar einen eigenen Admin-Account, der ihn befähigt, Objekte unterhalb dieses Subtrees zu administrieren. Natürlich liegt dieser Admin-Account ebenfalls unterhalb der neuen BaseDN. Die pam_ldap/nss_ldap-Konfigurationsdateien sollten natürlich ebenfalls auf den neuen Kontext angepasst werden, damit es bei der Anmeldung von User-Objekten am System selbst keine Probleme gibt (siehe hierzu Abschnitt 3.6, »Hör mal, wer da hämmert«; ist für unser Test-Setup jedoch nicht zwingend erforderlich), ebenso sollte die Suchbasis für Client-Anfragen entsprechend bearbeitet werden. Das können wir wie üblich ganz einfach per BASE-Anweisung in der libldap-Clientkonfiguration (ldap.conf) oder per defaultsearchbase in der slapd.conf erledigen. Jetzt befüllen wir die Datenbank des ldapoffshore-Servers mit dem neuen Subtree. Hierzu verwenden wir natürlich den Admin-DN dieses Sub-Kontextes: #> ldapadd -xWD cn=ldapadmin,dc=offshore,dc=local,dc=site \ -f offshore.ldif
Nachdem wir diese LDIF-Datei in den jungfräulichen DIT des Servers ldapoffshore.local.site importiert haben, prüfen wir kurz per ldapsearch, ob alle Objekte sauber angelegt wurden und wir sie problemlos auslesen können. Ist das der Fall, sollte die Konfiguration bis hierher okay sein. Nun haben wir unseren autarken Teilbaum-Server schon fast einsatzbereit, aber das größte Problem haben wir noch nicht angefasst: Der Teilbaumserver ldapoffshore muß wissen, welcher sein übergeordneter Server ist, und unser alter Bekannter ldapmaster muss wenigstens wissen, wo der Teil seines Blätterwerks liegt, um den er sich selbst nicht kümmern muss. Nachdem wir die /etc/hosts auf beiden Maschinen so angepasst haben, dass die gegenseitige Auflösung der Hostnamen funktioniert, fangen wir mit der LDAP-technischen Konfiguration unserer Server an. Damit unser ldapmaster weiß, wohin er Clientanfragen umleiten muss, die für diesen ausgelager-
154
1198.book Seite 155 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
ten Teil seines Baumes bestimmt sind, benötigt er einen Eintrag innerhalb seines Trees – eine Art Weiche oder Link, die die Client-Anfragen auf den richtigen Weg bringt. Hierzu verwenden wir ein so genanntes referral-Objekt, das wir in den DIT unserer BaseDN dc=local,dc=site auf dem Server ldapmaster einfügen (Datei referral.ldif in den Beispieldaten zu diesem Abschnitt: http://www.galileocomputing.de/1801): Es handelt sich hierbei um ein so genanntes subordinate Referral, das auf die untergeordnete Partition dc=offshore auf dem Server ldapoffshore.local.site verweist (letzte Zeile im folgenden Listing ist umbrochen): dn: dc=offshore,dc=local,dc=site objectClass: referral objectClass: extensibleObject dc: offshore ref: ldap://ldapoffshore.local.site/dc=offshore,dc=local, \ dc=site
Die hier verwendeten Objektklassen (referral, extensibleObject) und Attribute (ref) lassen sich nicht in den Schemadateien finden; sie sind in unserem LDAP hartverdrahtet. referral (Typ: STRUCTURAL, RFC3296: »Named Subordinate References in Lightweight Directory Access Protocol [LDAP] Directories«) beinhaltet nur ein operational Attribute, und zwar ref, welches die LDAP-URL und damit den subordinate-Verweis als Attributwert beinhaltet. Die Objektklasse extensibleObject (Typ: AUXILIARY, RFC4512: »(LDAP) Directory Information Models«) kann beliebige Attribute enthalten, um ein Objekt um bestimmte Kapabilitäten zu erweitern, die sonst aufgrund seiner Objektklasse nicht abzubilden wären. In diesem Fall ermöglicht uns das Attribut die Angabe eines relativen DN, und zwar den RDN unserer benötigten Sub-Unit: dc: offshore. Alternativ kann statt des Hostnamens auch die IP-Adresse im ref-Attribut verwendet werden. So bleibt gewährleistet, dass die Weiterleitung unabhängig von der Namensauflösung funktioniert. Allerdings kann es dann Probleme mit TLS-verschlüsselten Requests geben, die über diesen Referral laufen. Das referral-Objekt kann bei Bedarf auch mehrfach angelegt werden und somit als Verzweigung auf mehrere untergeordnete Server und Subtrees dienen. Werfen wir einen kurzen Blick auf die Objektklasse referral: #> ldapsearch -x -b cn=subschema -s base \ objectClasses | grep referral
bevor wir uns den eigentlichen Referral-Eintrag im DIT anzeigen lassen: #> ldapsearch -M -x "(objectclass=referral)" '*' ref
155
3.2
1198.book Seite 156 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Hierfür muss die manageDsaIT-Option (-M) verwendet werden, denn ohne sie sehen wir in diesem speziellen Fall leider gar nüscht und können solche speziellen Objekte noch weniger administrieren. Eine kurze Erläuterung zu ManageDsaIT gemäß RFC 3296 (s.o): »Das manageDsaIT-Control gestattet es, Referrals und andere spezielle Objekte innerhalb des DIT wie normale Objekte manipulieren zu können.« Verdeutlichen wir die manageDsaIT-Option am besten kurz anhand des folgenden Beispiels: Normalerweise würde sich das referral-Objekt nicht wie ein normales Objekt ohne weiteres aus dem DIT löschen lassen. Der ldapdelete-Befehl müsste daher explizit mit der manageDsaIT-Option (-M) abgesetzt werden: #> ldapdelete -xWD cn=ldapadmin,dc=local,dc=site \ –M dc=offshore,dc=local,dc=site
Aber das hat Zeit, weil wir mit unserem Abschnitt über Partitionierung noch lange nicht am Ende sind und den referral-Eintrag daher noch ein wenig benötigen. Im nächsten Schritt müssen wir auf unserem ausgelagerten Server ldapoffshore natürlich auch noch einen Eintrag anlegen, der – als Pendant zum referral-Objekt im DIT des Masters – auf unseren übergeordneten Server ldapmaster zeigt. Hierbei handelt es sich um einen superior Referral, der auf einen übergeordneten Kontext verweist. Allerdings fügen wir den Verweis dieses Mal nicht als Objekt in den Teilbaum des ausgelagerten Kontextes ein, sondern ergänzen das SuperiorReferral-Statement als LDAP-URL in der slapd.conf des Servers ldapoffshore (in der Online-Konfiguration existiert hierzu das adäquate Attribut olcReferral), das auf den übergeordneten Server zeigt: referral ldap://ldapmaster.local.site/
Jetzt den Restart des Servers ldapoffshore nicht vergessen, um die Änderung in der slapd.conf zu übernehmen. Damit sind wir einsatzbereit, und können nun in aller Ruhe die Funktionalität an einem konkreten Fallbeispiel durchgehen: Einer unserer User im DIT des Masters – nehmen wir dazu unseren Kollegen Harry Callahan – hat als Standard-LDAP-Server in seiner Client-Datei ldap.conf (libldap) unseren Server ldapmaster.local.site eingetragen, da dieser Server auch für sein User-Objekt zuständig ist. Jede Anfrage über Objekte, die Harry (authentifiziert oder anonym) an den DIT stellt, wird also von seinem primären LDAP-Server (ldapmaster.local.site) beantwortet, seine Searchbase ist dc=local,dc=site. Nehmen wir nun weiter an,
156
1198.book Seite 157 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Harry stellt eine Anfrage über das User-Objekt uid=jtkirk aus der Unit dc=offshore. Die Anfrage geht logischerweise zunächst an den für ihn primär eingestellten Server ldapmaster.local.site: #> ldapsearch -x uid=jtkirk -LLL
Der durchsucht brav seinen DIT und findet natürlich herzlich wenig, denn schließlich gehört das Userobjekt NICHT direkt zu seiner Truppe, doch die Suchanfrage liefert zumindest einen Referral zurück, der dem Client auf die Sprünge helfen kann: # refldap://ldapoffshore.local.site/dc=offshore,dc=local,dc=site??sub
Dadurch weiß Harry zumindest schon einmal zwei Dinge: dass der Server ldapoffshore.local.site für den Teilbaum dc=offshore,dc=local,dc=site zuständig ist, und dass sich Jimmy Kirk, wenn’s ihn denn wirklich gibt, nur dort verstecken kann. Prima. Und so kann Harry seine Anfrage direkt an den Server ldapoffshore.local.site (mit dem Parameter -h für den Host und -b für Base) stellen, der sie dann auch tatsächlich bearbeitet. #> ldapsearch -x uid=jtkirk -h ldapoffshore \ -b dc=offshore,dc=local,dc=site -LLL
Das Ganze stellt sich grafisch betrachtet wie folgt dar:
Server ldapoffshore 3. Neue Anfrage
1. Anfrage
LDAP-Client 2. Antwort mit Verweis
Server ldapmaster
Abbildung 3.4 Suchanfrage mit zurückgeliefertem Referral
Dieser Vorgang läuft bei »intelligenten« LDAP-Client-Programmen, wie z.B. diversen LDAP-Browsern oder Mailclients, transparent ab (internes Chaining). Die ldapsearch-Anfrage, die wir eben auf der Kommandozeile ein zweites Mal manuell mit der passenden Host-/Base-Option (-h/-b) absetzten mussten, erfolgt dann automatisch. Aber auch unser ldapsearch-Tool muss hinter anderen ClientProgrammen keineswegs zurückstecken. Dank des zusätzlichen Kommandozeilenparameters –C (chaining, engl. = verketten) startet ldapsearch automatisch mit
157
3.2
1198.book Seite 158 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Hilfe des zurückgelieferten referrals die zweite Suchanfrage auf dem korrekten Host bzw. über die korrekte LDAP-URL, die Host und Base bereits beinhaltet: #> ldapsearch -xC uid=jtkirk -LLL # refldap://ldapoffshore.local.site/dc=offshore,dc=local,dc=site??sub dn: uid=jtkirk,dc=offshore,dc=local,dc=site objectClass: posixAccount ...
Das Ganze funktioniert natürlich ebenso folgerichtig auf dem ldapoffshore-Server, wenn wir dort nach einem Datensatz suchen, den unser ldapmaster hostet; je nach eingestellter Searchbase muss diese gegebenenfalls mit angegeben werden: #> ldapsearch -xC uid=ckent –LLL –b dc=local,dc=site dn: uid=ckent,ou=verkauf,dc=local,dc=site objectClass: posixAccount objectClass: inetOrgPerson ...
Seit OpenLDAP 2.3 existiert mit Overlay chain eine überaus praktische Erweiterung, die vom angefragten Server zurückgegebene Referrals automatisch verfolgt bzw. verkettet (Chaining). Somit kann auf clientseitige Chaining-Kapabilitäten völlig verzichtet werden. Zudem ermöglicht es im Bedarfsfall die Weiterleitung von Schreiboperationen zwischen Subtree-Master und Master, und das Ganze auch per TLS. Mehr zu Overlay chain im nächsten Abschnitt 3.2.3, »Gesprengte Ketten«.
Wie schon weiter oben angemerkt, liegt der große Vorteil der Partitionierung darin, dass der LDAP-Server, der die Anfrage weiterleitet (in dem Fall unser Server ldapmaster.local.site), überhaupt keine Kenntnis von der Struktur des Teilbaumes unterhalb der Sub-Unit offshore haben muss. Es reicht ihm völlig aus, anhand des DN in der Anfrage zu erkennen, dass es um ein Objekt unterhalb von dc=offshore,dc=local,dc=site geht, für das ein anderer Server zuständig ist. Sinnigerweise sollten natürlich alle Clients, die unterhalb der Unit offshore im DIT angeordnet sind, so konfiguriert werden, dass ihre Anfragen primär an den Server ldapoffshore.local.site gerichtet werden. Der Datenbestand unterhalb von dc=offshore kann nun sowohl von unserem ldapmaster als auch direkt über den Subtree-Master ldapoffshore gepflegt werden sollte. Erfolgt die Verwaltung der Unit offshore über Kommandozeilentools auf unserem eigentlichen Master-Server ldapmaster, müssen die Modifikationen innerhalb des Subtrees natürlich auf dem korrekten Host (-h ldapoffshore) und mit der Identität (-D cn=ldapadmin,dc=offshore,dc=local,dc=site) des rootdn des Subtree-Masters initialisiert werden.
158
1198.book Seite 159 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Bei der gesamten Betrachtung sollte die Redundanz natürlich nicht vergessen werden. Bezogen auf den gerade geschilderten Fall würde das bedeuten, dass sich sowohl ldapmaster als auch ldapoffshore auf jeweils einen, ihnen zugeordneten Slave komplett replizieren. Dieses Vorgehen wäre für partitionierte Produktivumgebungen empfehlenswert und wird in Abschnitt 3.2.8, »Beispielhafte Lösungsansätze mit syncrepl«, kurz erläutert. Nachdem wir nun die ganzen Grundprinzipien der Partitionierung und des Chainings abgehandelt haben: Wer möchte denn eigentlich noch manuelles Chaining oder sonstige Zusatz-Optionen für die ldap*-Tools verwenden, wenn wir doch den Verkettungsspezialisten par excellence an der Hand haben, der sich sogar vollautomatisch um alle Verquickungen kümmert? Nennen wir ihn mal Overlay chain ...
3.2.3
Gesprengte Ketten – serverseitige Verfolgung (chasing) von Referrals mit Overlay chain
Gesprengte Ketten? Eigentlich geht es doch darum, Referrals automatisch und serverseitig so miteinander zu verketten, dass Clients – unabhängig von ihren Kapabilitäten – den partitionierten Tree als Ganzes sehen und gegebenenfalls auch verwalten können? Geht es auch, und da uns das Overlay chain die ganze Arbeit abnimmt, müssen wir uns um eben diese Verkettungen auch keine Gedanken mehr machen. Zumindest, wenn wir unseren smarten Helfer korrekt konfiguriert haben. Und wie das geht, schauen wir uns nun an. Vorab noch ein kurze Anmerkung zu grafischen LDAP-Clients wie dem JXplorer oder Apache DS: Die Darstellung/Behandlung von Referrals ist bei externen Applikationen aufgrund ihrer internen Behandlung dieser Szenarien oft eine zweischneidige Sache. Weder der JXplorer noch Apache DS bekleckern sich in dieser Hinsicht mit Ruhm. Entweder kann es – je nach Settings – vorkommen, dass sie statt des Verweises auf die Sub-Unit offshore nur das referral-Objekt selbst auf dem Radar haben, wie z.B. beim JXplorer, oder dass alle Objekte des Subtrees direkt unterhalb der Struktur des Hauptkontextes eingebunden werden. Was das angeht: Entweder damit leben oder bei den Kommandozeilentools bleiben – denn die zeigen uns in der Regel die Dinge immer sprichwörtlich so, wie sie wirklich liegen. Nun zur chaining-Funktionalität selbst: Jedes Mal, wenn auf einen (anonymen) LDAP-Request ein referral zurückgeliefert wird, startet chain automatisch die Verfolgung (referral-chasing) des Requests anhand der im Referral übermittelten URL. Geht es nun um Operationen, die eine Identität, also einen BindDN erfordern, muss diese Identität dem jeweiligen Server automatisch mitgeteilt werden.
159
3.2
1198.book Seite 160 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Diese Fähigkeit wird im Rahmen der Proxy-Funktionalitäten durch das identityassertion-Feature des ldap-Backends zur Verfügung gestellt. Das bedeutet zum einen, das Overlay chain das ldap-Backend zwingend benötigt, zum anderen werden auch die ldap-backend-spezifischen Direktiven bei der Konfiguration verwendet (siehe hierzu auch slapd-ldap(5)), denen der Prefix chain- zusätzlich vorangestellt ist. Zum Setup: Was die bisherige Partitionierung unseres Baumes angeht, kann alles beim Alten bleiben. Wir kümmern uns im Folgenden »nur« darum, dass die bisher manuelle Referral-Verfolgung automatisiert wird. Das Overlay chain kann sowohl in der database- als auch in der globalen Sektion der slapd.conf initialisiert werden, eine Integration über die Online-Konfiguration ist ebenfalls möglich. Die jeweilige Platzierung des Overlays hängt von der gewünschten Funktionalität ab. Üblicherweise wird chain in der globalen Sektion konfiguriert, da Referrals dort behandelt werden. Wir konfigurieren chain daher in der globalen Sektion der slapd.conf zunächst auf unserem ldapmaster. Die chain-idassert-bind-Subdirektive binddn= ... ist im folgenden Listing umbrochen: overlay chain-uri chain-idassert-bind
chain-rebind-as-user chain-return-error
chain ldap://ldapoffshore.local.site/ bindmethod=simple binddn="cn=ldapadmin,dc=offshore, dc=local,dc=site" credentials=linux mode=self flags=non-prescriptive true true
Analysieren wir kurz die Direktiven: Nach der Initialisierung des Overlays geben wir per chain-uri die LDAP-URI an, die auf den Server verweist, mit dem unser Master verkettet werden soll; in unserem Fall logischerweise unser Subtree-Master ldapoffshore.local.site. Unbedingt beachten: Der in chain-uri verwendete Hostname muss exakt mit dem im Referral-Objekt (siehe voriger Abschnitt) verwendeten übereinstimmen, in unserem Fall also der FQHN ldapoffshore.local.site. Auch wenn chain sich die URL für einen anonymen Zugriff zunächst aus dem Referral selbst holt: Wird z.B. eine Modifikation vom ldapmaster aus für ein Objekt auf ldapoffshore bei fehlerhafter chain-uri initiiert, erhalten wir wahrscheinlich die (leider wenig fehlerbezogene) Fehlermeldung: »ldap_modify: Strong(er) authentication required (8)«. Eine funktionierende Namensauflösung ist logischerweise ebenfalls zwingende Voraussetzung.
160
1198.book Seite 161 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
chain-idassert-bind legt die fixe Identität und die korrespondierenden Optionen fest, mit denen die Anmeldung auf der Kontext-Datenbank des entfernten Servers durchgeführt wird. bindmethod, binddn und credentials sollten selbsterklärend sein. mode=self
legt zusätzlich fest, dass alle Operationen nach dem Bind-Vorgang mit der »echten« Identität des jeweiligen Users durchgeführt werden, der die Operation initiiert hat. Der Vorgang lässt sich im Debug-Mode (1) auf ldapoffshore gut beobachten, hier für Kent, der mit entsprechender ACL Kirks description-Attribut modifiziert: parseProxyAuthz: conn=0 "uid=ckent,ou=verkauf,dc=local,dc=site" ==>slap_sasl_authorized: can cn=ldapadmin,dc=offshore,dc=local,dc=site become uid=ckent,ou=verkauf,dc=local,dc=site? <== slap_sasl_authorized: return 0
Schlägt dies fehl, kann chain über die Sub-Direktive flags=non-prescriptive angewiesen werden, die angeforderte Operation anonym durchzuführen. Wird mode nicht auf self gesetzt, wird hierfür ausschließlich die in chain-idassertbind definierte Identität verwendet! Daher Achtung: Dem mode-Parameter muss besondere Aufmerksamkeit gewidmet werden. Wird die mode-Subdirektive nicht auf self oder gar nicht gesetzt, erfolgt der Zugriff immer mit der in idassert-bind festgelegten Identität, in unserem Fall also als rootdn; im Klartext: Jeder darf alles. Daher sollten in dieser chain-Konfiguration per mode=self alle Identitäten vom Subtree-Master auf den Master und umgekehrt gemappt werden, wo sie dann – falls erforderlich – per authz-regexp auf andere DNs umgesetzt und/oder bequem über ACLs limitiert werden können.
Die Subdirektive chain-rebind-as-user <true|false> steuert, ob alle IDs bzw. Bind-DNs vom Backend zwischengespeichert werden sollen, falls die Verbindung nach einer Unterbrechung wiederhergestellt werden muss. Diese Direktive sollte beim Chasing von Referrals immer auf true gesetzt werden. Zusätzlich kann noch über chain-max-depth die maximale Tiefe bei der Verfolgung verschachtelter Referrals angegeben werden. Der Defaultwert liegt bei 1. Die ebenfalls optionale Boolean-Subdirektive chain-return-error true sorgt dafür, das im Fehlerfall statt des wenig aussagekräftigen Referrals die echte Fehlermeldung angezeigt wird. Nach einem Neustart des slapd auf ldapmaster und ldapoffshore geht es ans Testen: Zunächst suchen wir auf unserem ldapmaster ohne Chaining-Parameter (-C) per ldapsearch nach Käpt’n Kirk (der sich ja im Subtree offshore befindet). Die Operation führen wir mit der Identität von unserem guten alten Clark Kent durch, die in der von uns gewählten Variante per mode=self gemappt wird. 161
3.2
1198.book Seite 162 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
#> ldapsearch -xWD uid=ckent,ou=verkauf,dc=local,dc=site \ uid=jtkirk
Der Vorgang der Proxy-Autorisierung lässt sich gut im Debug-Level 256 oder stats (wir erinnern uns: Connections, ldap-Ops) auf unserem Subtree-Server ldapoffshore beobachten: Zunächst erfolgt der bind mit der idassert-Identität, anschließend wird für die Operation der »echte« DN verwendet. 0 BIND dn="cn=ldapadmin,dc=offshore,dc=local,dc=site" mech=SIMPLE ssf=0 conn=10 op=0 RESULT tag=97 err=0 text= conn=10 op=1 PROXYAUTHZ dn="uid=ckent,ou=verkauf,dc=local,dc=site"
Soweit, so gut: Anschließend testen wir, ob wir mit Kents Identität – vom ldapmaster aus – Käpt’n Kirks description-Attribut auf dem Server ldapoffshore ändern können. Kleine Anmerkung: die hierfür erforderliche ACL access to attrs=description by uid=ckent,ou=verkauf,dc=local,dc=site write by * read
ist in der ldapoffshore-slapd.conf in den Beispieldaten bereits gesetzt und muss nur noch aktiviert werden. Mit ACLs beschäftigen wir uns natürlich noch ausführlich in Abschnitt 3.7, »Nur mit Clubkarte«. Setzen wir nun den Befehl ab: #> ldapmodify -xWD uid=ckent,dc=offshore,dc=local,dc=site \ –f kirk_mod.ldif modifying entry "uid=jtkirk,dc=offshore,dc=local,dc=site"
was ebenfalls problemlos klappen sollte. Auf der Master-Seite sind wir nun so weit vollständig: Wir können den ganzen Tree ohne Verrenkungen sehen und können vom Master aus auch Änderungen auf dem Subtree-Master durchführen. Wie sieht es nun aber mit dem Subtree-Master ldapoffshore aus? Recht dünn: denn dort sehen wir ohne explizites ldapsearch-Chaining nur die unterhalb der dc=offshore gehosteten Objekte, keine Objekte des Hauptkontextes. Da wir unsere beiden Server ja möglichst komfortabel und administrativ miteinander verketten wollen, schaffen wir über eine nahezu identische chain-Konfiguration auf ldapoffshore schnell Abhilfe. Lediglich zwei der folgenden Zeilen differieren von der chain-Konfiguration auf ldapmaster: overlay chain-uri chain-idassert-bind
chain ldap://ldapmaster.local.site/ bindmethod=simple binddn="cn=ldapadmin,dc=local,dc=site"
...
Die chain-uri zeigt logischerweise auf den Server ldapmaster, und der chainidassert-binddn entspricht natürlich dem rootdn unseres ldapmasters. Nun sind wir schon fast startklar. 162
1198.book Seite 163 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Je nachdem, was präferiert wird, kann auf unserem Subtree-Server ldapoffshore noch die BASE (ldap.conf Client) oder defaultsearchbase (slapd.conf) auf dc=local,dc=site gesetzt werden. Der Nachteil dabei: Jede Anfrage läuft in dem Fall automatisch über den Master und dann – insofern es um Objekte aus dem offshore-Kontext geht –- über das referral-Objekt zurück auf ldapoffshore. Insofern sollte die Base dc=local,dc=site gegebenenfalls besser nur für explizite Operationen gesetzt werden. Zudem sollte der ursprüngliche referral-Eintrag in der globalen Sektion der slapd.conf auf ldapoffshore nach wie vor aktiviert sein. referral ldap://ldapmaster.local.site/
Nach einem Restart das slapd sollten wir nun auch von ldapoffshore aus ohne Probleme den kompletten Tree inklusive der Unit offshore sehen können. Bleibt die Frage, ob wir vom Subtree-Master ldapoffshore ein Objekt auf ldapmaster ändern können. Wir modifizieren mit der Identität von Käpt’n Kirk das description-Attribut von ckent (entsprechende ACL ist in der Beispiel-ldapmasterslapd.conf vorhanden), was keine Probleme bereiten sollte. Aber: Versuchen wir nun mit der Identität des offshore-ldapadmins ein Objekt auf dem Master zu modifizieren, erhalten wir nur folgende Rückmeldung: ldap_modify: Insufficient access (50)
What’s up? Werfen wir einen Blick auf die Debug-Ausgabe (ebenfalls DebugLevel 256) unseres ldapmaster, wird schnell klar, was los ist: conn=0 op=0 BIND dn="cn=ldapadmin,dc=local,dc=site" mech=SIMPLE ssf=0 conn=0 op=1 PROXYAUTHZ dn="cn=ldapadmin,dc=offshore,dc=local,dc=site"
Zunächst führt das Overlay chain auf ldapoffshore den bind-Vorgang korrekt mit der in idassert angegebenen Identität durch, also dem ldapadmin des Masters. Anschließend erfolgt jedoch die Proxy-Autorisierung aufgrund mode=self mit der Identität (hier: ldapadmin des Subtree-Masters offshore), der die Modify-Operation initiiert hat. Und der hat alles, aber leider keine Schreibrechte auf dem Master – es sei denn, wir geben sie ihm. Die einfachste Art, das zu erledigen, ist die Umsetzung des DNs in einen anderen, der Schreibberechtigung hat. Und dies können wir über die Direktive authz-regexp <Suchbegriff> <Ersetzungsbegriff> (siehe hierzu auch slapd.conf(5)) erreichen. Damit setzen wir den rootdn des Subtree-Masters auf den des Masters um: authz-regexp "cn=ldapadmin,dc=offshore,dc=local,dc=site" "cn=ldapadmin,dc=local,dc=site"
Im Log des Masters sieht das Ganze dann (abgekürzt) etwa so aus:
163
3.2
1198.book Seite 164 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
>slap_sasl2dn: converting SASL name cn=ldapadmin,dc=offshore,dc=local,dc=site to a DN ... <==slap_sasl2dn: Converted SASL name to cn=ldapadmin,dc=local,dc=site
Jetzt sollten wir alle gewünschten Funktionalitäten des Crossover-Chainings für partitionierte Trees abgebildet haben. Natürlich können auch separate ACLs für den offshore-ldapadmin gesetzt werden, die bestimmte Operationen limitieren. Wenn in einer oder sogar beiden Richtungen kein administrativer Zugriff benötigt wird, lässt sich die chain-Konfiguration radikal vereinfachen. Auf dem Server, von dem aus kein administrativer Zugriff weitergeleitet werden soll, benötigen wir dann nur die folgende, stark abgespeckte chain-Variante: overlay chain-uri chain-rebind-as-user
chain ldap:/// true
Sollte bis hierher ein Fehler aufgetreten sein, geht’s wie üblich ans Debugging. Hier einige der wichtigsten Checkpunkte: 왘 Overlay chain jeweils in der globalen Sektion eingebunden? 왘 Typos in den chain-Direktiven in der slapd.conf? 왘 Alle Subdirektiven gesetzt? 왘 Server gegenseitig erreichbar? 왘 Namensauflösung funktioniert? 왘 Wurden an allen relevanten Punkten jeweils die vollständigen (FQHN) und korrekten Hostnamen verwendet? 왘 Referral-Objekt im DIT des Master-Servers existent und korrekt? 왘 Referral-Eintrag in der slapd.conf des Offshore-Servers existent und korrekt? 왘 chain-uri-Einträge auf beiden Servern existent und korrekt? 왘 Stimmt die Default-Searchbase auf beiden Servern? Ansonsten gilt wie immer: Debug-Level hochschrauben, und wenn alles nichts nützt, das Setup Step by Step wiederholen und nach jedem Einzelschritt die Funktionalität erneut testen. Noch eine sicherheitstechnische Anmerkung zum Schluss: Wir verwenden in dieser einfachen Konfiguration Klartext-DNs und Klartextkennwörter. Hier gilt natürlich wie immer: Zum Testen: Okay. In Produktivumgebungen: keinesfalls, dort immer nur verschlüsselt. Das setzt natürlich detaillierte Kenntnisse über die Verschlüsselung per SSL und TLS voraus, die wir in den Abschnitten ab 3.5 sehr ausführlich vorstellen und vertiefen werden. Weitere Infos zu allen verfügbaren chain-Direktiven und -Parametern finden sich in slapd-ldap(5) und slapo-chain(5).
164
1198.book Seite 165 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
So viel also zu Partitionen und Referrals, die bei großen oder weiträumig verteilten Netzen so unabdingbar sind, wie Replikation in allen LDAP-Netzen aller Größenordnungen. Bevor wir aber an die Replikation gehen können, müssen wir einen Punkt behandeln, der für eine korrekt funktionierende Replikation absolute Pflicht ist: die Zeitsynchronisation auf allen beteiligten Servern. Klingt doch eigentlich ganz simpel, oder?
3.2.4
The Time Machine – Zeit synchronisieren mit NTPD
Viele, die ihrer Zeit vorausgeeilt waren, mussten auf sie in sehr unbequemen Unterkünften warten. Stanislaw Jerzy Lec Nicht dass unseren NTP (Network Time Protocol)-Daemon das irgendwie schocken würde, den in aktuellen Versionen läuft er in der Regel ohnehin in seinem ganz persönlichen Knast, dem chroot-Jail. Aber ganz ohne korrekt aufgesetzten und vor allem exakt arbeitenden NTP hätten wir in unserem Netz alles Mögliche, aber keine synchrone Zeit auf den Servern, die miteinander sprechen. Schön. Und warum ist das von dermaßen elementarer Wichtigkeit für uns? Ganz einfach: NTP spielt insbesondere seit OpenLDAP 2.4 eine überaus bedeutende Rolle; denn: Jedes Objekt trägt in seinen operational Attributes zum einen seinen modifyTimestamp, zum anderen seine korrespondierende entryCSN (CSN = Change Sequence Number, erläutern wir später noch haarklein), die neben anderen Parametern ebenfalls den exakten Timestamp der letzten Modifikation enthält. Der entscheidende Punkt: Intern werden die Timestamps/CSNs von unserem slapd mit einer Genauigkeit im Mikrosekundenbereich generiert und miteinander verglichen, um absolute Einzigartigkeit und Exaktheit der Timestamps zu garantieren. Der übliche Toleranzwert liegt bei etwa einer Millisekunde, in OpenLDAP-Versionen vor 2.4 lag der Wert mit einer Sekunde um den schlappen Faktor 1000 höher. Diese Genauigkeit bzw. diese enge ZeitscheibenToleranz ist absolut unerlässlich für eine exakt funktionierende Multi-MasterReplikation, wie wir bereits aus unserem Exkurs in Abschnitt 3.2.1, »Warum man LDAP-Datenbanken replizieren sollte«, wissen. Nachdem das NTP-Setup nun unsere volle Aufmerksamkeit genießt, schauen wir uns zunächst kurz die Basics zu NTP an, bevor wir ans eigentliche Setup gehen: NTP ist die freie Implementierung eines Zeitsynchronisationsdienstes im TCP/IPStack und arbeitet verbindungslos per UDP auf dem für NTP reservierten Port 123. Es stammt in seiner Urform aus den frühen 80er-Jahren und wurde von Dave L. Mills entwickelt. Die zugrunde liegenden Protokolle und Algorithmen
165
3.2
1198.book Seite 166 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
wurden in mehreren RFCs veröffentlicht. Nach einer Reihe von Weiterentwicklungen ist NTP längst das führende Zeitsynchronisationsprotokoll im Internet und in privaten Netzwerken aller Art. Je nach Hardwareausstattung kann man per NTP einen Rechner bis in den Nanosekundenbereich hinein synchronisieren. Wie weit das tatsächlich machbar ist, hängt natürlich von den verwendeten Betriebssystemen und der Hardwarequalität der Hosts und des Netzwerkes ab. Heute wird hauptsächlich die NTP-Version 4 verwendet; es existiert aber auch eine SNTP-Version (Simple Network Time Protocol). Sie verwendet zwar die gleiche Paketstruktur, aber nur einen vereinfachten Zeitalgorithmus, ist also erheblich ungenauer. SNTP kommt fast nur noch zum Zuge in heterogenen Netzwerken, in denen veraltete Windows Clients (<=Win 2000) betrieben werden. Obwohl NTP eigentlich für die Unix/Linux-Welt entwickelt wurde, gibt es seit Längerem auch Portierungen für etwas neuere Windows Versionen, einschließlich XP und W2K3 Server. Eine genaue Liste befindet sich auf der NTP-Homepage www.ntp.org. Hier zwei übliche Grundkonzepte, NTP zur Zeitsynchronisierung im Netzwerk einzurichten: 왘 Die Installation eines lokalen NTP-Servers auf dem Internet-Gateway, der sich die Zeit wiederum von einem der bekannten Referenz-Timeserver im Internet holt. Alle Server und Clients des jeweiligen lokalen Netzes holen sich die Zeit dann von diesem »lokalen« Timeserver. Das ideale Verfahren für ein Wide Area Network, das z.B. Daten von einem Netz in ein anderes zeitkritisch überträgt bzw. repliziert, das den gleichen, externen Referenz-Timeserver als primäre Quelle nutzt. 왘 Man ernennt einen beliebigen Rechner im lokalen Netz zum Timeserver (ohne externe Zeitquelle) und synchronisiert alle Rechner mit diesem selbst ernannten Zeitdienst. Das ist allerdings nur praktikabel, wenn keine zeitkritischen Daten mit anderen, entfernten Netzwerken ausgetauscht bzw. repliziert werden müssen. Da die Atomzeit an Universitätsdiensten oder beim Physikalisch-Technischen Bundesamt (ptb.de) kostenlos zu haben ist, läuft es in der Regel auf die erste Variante hinaus, mit der man immer auf der sicheren Seite ist. In unserer Beispielkonfiguration betrachten wir daher diese Methode und gehen dabei folgendermaßen vor: Zunächst installieren wir die Pakete bzw. Tarballs ntp und ntp-doc (SUSE und Debian). Die genaue Installation mit allen Feinheiten und Optionen können wir den Manpages und der Dokumentation der Pakete entnehmen; wir werden hier eine konzeptionell etwas vereinfachte, aber für unsere Zwecke vollkommen ausreichende Konfiguration vornehmen.
166
1198.book Seite 167 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
In unserem Beispiel verwenden wir einen Gateway-Rechner, der sich seine Zeit von einem externen Referenzserver holt und als zentraler Timeserver für das lokale Netz fungiert. Von ihm holen sich unsere Maschinen die aktuelle Zeit – in Produktivumgebungen die einzig praktikable Variante. Hierfür müssen wir die Konfigurationsdatei /etc/ntp.conf jeweils auf Master und Slave anpassen, minimal brauchen wir dort den folgenden Eintrag, der auf den externen Timeserver zeigt: server
minpoll 4
maxpoll 10
Der Eintrag server gibt unserem ntpdaemon die externe Quelle an, die als Zeitgeber fungieren soll. Natürlich muss der Server erreichbar sein, und bei Verwendung des Full Qualified HostNames muss die Namensauflösung ebenfalls funktionieren. Die zusätzlichen Parameter minpoll und maxpoll steuern dabei, wie oft sich der lokale ntp-Dienst mit der externen Quelle synchronisiert. minpoll <Wert> gibt dabei das Intervall an, das maximal zwischen zwei Versuchen verstreicht, wenn die externe Zeitquelle nicht erreichbar ist. maxpoll gibt den Wert an, nach dem sich der lokale ntp-Dienst in jedem Fall erneut mit externen Zeitquelle resynchronisiert. Bei den angegebenen Werten handelt es sich allerdings nicht um Sekunden, sondern um numerische Gegenwerte zu bestimmten Zeitintervallen, die sich gemäß der folgenden Tabelle aufschlüsseln: Wert
Intervall
4
16 Sekunden
5
32 Sekunden
6
64 Sekunden
...
...
17
36.4 Stunden
Eine mögliche Adresse für einen »echten« externen Timeserver wäre z.B.: server
ptbtime1.ptb.de
Der Parameter stratum in den lokalen server/fudge-Einstellungen (insofern gesetzt) sorgt dafür, dass die lokale Uhr als Fallback-Reserve verwendet wird, wenn die externen Dienste nicht erreichbar sind. Diese Fallback-Reserve sollte immer einen hohen stratum-Wert (> 9 = sehr niedrige Priorität) aufweisen, damit die Prioritäten zwischen den Zeitdiensten klar bleiben. NTP verwendet ein hierarchisches System verschiedener strata (plural von stratum). Als Stratum 0 wird das Zeitnormal, z.B. eine Atom- oder Funkuhr, bezeichnet. Die unmittelbar mit dem Referenzzeitgeber gekoppelten NTP-Server haben in der Regel Stratum 1.
167
3.2
1198.book Seite 168 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Jede tiefer kaskadierte NTP-Einheit kann weitere Zeitversätze von einigen Millisekunden verursachen und erhält daher eine höhere Nummer (Stratum 2-n). Jede NTP Software eines bestimmten Stratum-Werts ist zugleich Client des darüber liegenden Stratums als auch Server des darunter liegenden Stratums, sofern vorhanden. Wenn wir einen externen Zeitdienst verwenden, kann es nützlich sein, zu Resynchronisations-Zwecken den ntp-Driftwert zwischenzuspeichern: Kommt es zu einem Restart des Systems, wird er vom ntpd wieder eingelesen; so lässt sich der Synchronisationsprozess deutlich verkürzen. Erreichen lässt sich das über folgende Zeile in der ntp.conf, die in der Regel aktiviert ist: driftfile
//ntp.drift
Nachdem wir die ntp-Dienste auf Master und Slave gestartet haben, sollten wir mit dem Befehl #> ntpq -p ldapmaster ldapslave
überprüfen, ob die beiden auch brav mit dem externen Timeserver sprechen – und vor allem möglichst synchron arbeiten. Der Output könnte so aussehen (hier aus Darstellungsgründen etwas vereinfacht dargestellt): server remote refid st t when poll reach delay offset jitter ============================================================================ ldapmaster (IP 1) (IP 2) 3 u 5 16 377 1.532 0.431 0.004 ldapslave (IP 1) (IP 2) 3 u 11 16 377 0.494 -0.584 0.004
Hier die Erläuterung der wichtigsten Parameter: Die Spalte remote gibt die IP des lokalen Timeservers an, von dem sich unsere beiden LDAP-Server direkt die Zeit holen, refid die IP des Timeservers im Netz, von dem sich unser Timeserver die Zeit holt. st gibt den aktuellen Stratum-Wert unseres Timeservers an, poll das Intervall in Sekunden zwischen den Aktualisierungen. Per reach wird angezeigt, wie gut der entfernte Timeserver erreichbar ist – ein Wert von 377 gibt an, das der NTP-Server die letzten acht Male ohne Probleme erreichbar war. Der Parameter delay gibt etwaige Verzögerungen der Paketlaufzeit beim ntpMessage Exchange zwischen Timeserver und lokaler Maschine an. Die Spalte offset zeigt die Zeitabweichung zwischen Timeserver und lokaler Maschine in Millisekunden an. Ein positiver oder negativer offset von mehr als eine Millisekunde kann durchaus vorhanden sein; er sollte in dem Fall jedoch auf allen beteiligten NTP-Clients möglichst identisch sein. Zu diesem Punkt gleich noch mehr Infos. Über die Spalte jitter wird die Schwankungsbreite der Antwortzeiten (die Streuung der letzten Offset-Werte) angegeben. Nach dem erfolgreichem Test sollten wir natürlich nicht vergessen, die ntpDienste permanent über init-Skripte einzubinden.
168
1198.book Seite 169 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Exkurs – (Virtual) Time Machines Bei der Verwendung von virtuellen Maschinen kann es bisweilen vorkommen, dass die Uhren der virtuellen BIOSse weitaus stärker abdriften, als dies bei »normalen« Rechnern der Fall ist – und diese Beschreibung ist noch harmlos. Gründe hierfür gibt’s genug: Die VM teilt sich bei voller Virtualisierung ihre ProzessorRessourcen mit anderen Prozessen des Host-Systems, das dadurch resultierende ungenaue Timing der virtuellen Interrupt-Controller (apic, lapic) und die automatische CPU-Frequenzanpassung in verschiedenen Betriebsmodi und/oder Lastfällen auf dem Host- und Gastsystem sind nur einige davon. Wir wissen bereits, dass wir dem NTP im Hinblick auf unseren slapd in Version 2.4 eine besondere Beachtung zukommen lassen müssen, und das Ganze noch wesentlich genauer, wenn die Maschinen, auf denen unser slapd läuft, VMs sind. Aber woran hakt es denn nun genau bei den VMs? Primär am Interrupt-Timer, den er ist derjenige, der den Takt vorgibt. Nur hat er leider niemanden, der ihm sagt, wie schnell oder langsam sein Takt wirklich ist. Zum elementaren Verständnis des Interrupt Timers – hier stark vereinfacht erläutert: abhängig von der eingestellten, internen Frequenz (siehe unten) löst der Interrupt-Timer in festgelegten Intervallen Unterbrechungen aus, anhand derer die interne Zeit bestimmt wird. Die Höhe der Frequenz ist dabei maßgeblich für die Genauigkeit der Zeitscheiben. Kurz: Der Interrupt-Timer ist das Herz des Systems. Alles – die Prozesse, ihre Zeitscheiben, Ausführungszeiten etc. – basiert auf der Genauigkeit des Interrupt-Timers. Auf echter Hardware kein großes Problem. Auf virtueller – kann’s schnell ein großes werden. Um nun herauszufinden, mit welcher Zeitscheiben-Genauigkeit wir intern tatsächlich arbeiten, lesen wir die relevanten Einstellungsparameter aus: #> grep -i hz /boot/config-
In den meisten aktuellen 2.6er Kernelversionen dürfte hier etwas in der Art wie CONFIG_HZ_250=y CONFIG_HZ=250 # CONFIG_HZ_1000 is not set
zu finden sein. Der Wert von 250 HZ für den Interrupt-Timer besagt, dass unser Kernel mit einer Zeitscheiben-Genauigkeit von etwa 4 Millisekunden (1000/250) arbeitet. Nicht optimal, für Test-Setups aber ausreichend. Ein Wert von CONFIG_HZ_1000=y und CONFIG_HZ=1000 würde die Zeitscheiben auf einen optimalen Wert von einer Millisekunde herabsetzen. Allerdings kann dies auch (zumindest bei virtuellen Gästen mit relativ schwachbrüstiger Host-CPU) mit Nachteilen verbunden
169
3.2
1198.book Seite 170 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
sein, da die höhere Rate mehr Overhead und somit Last erzeugt. Zum Vergleich: Microsoft verwendet (je nach OS) meistens Systemzeitscheiben von etwa zehn Millisekunden (adäquates Linux-Kernel-Timing: CONFIG_HZ=100, wurde in den meisten 2.4er Kerneln verwendet). Wer in Produktivumgebungen auf realer und leistungsfähiger Hardware OpenLDAP im Multi-Master-Mode betreiben und auf der sicheren Seite sein will, sollte sich über eine entsprechende Anpassung der vorgenannten Kernel-Parameter Gedanken machen. Um möglichst kurze Intervalle beim ntp-Resync zu erzielen, kann der minpoll-/ maxpoll-Wert des ntpd innerhalb einer Linux-VM zusätzlich auf ein möglichst kurzes Zeitintervall (minpoll 4 maxpoll 4 entspricht einem Resync-Intervall von 16 Sekunden) gesetzt werden; die ungenaue lokale Fallback-Uhr sollte dann in jedem Fall deaktiviert werden. Das können wir mit folgenden Einträgen in der ntp.conf erledigen: server <externer timeserver> minpoll 4 maxpoll 4 # server 127.127.1.0 ### lokale Uhr deaktiviert # fudge 127.127.1.0 stratum 10 ### s.o.
Eine Synchronisation per VMware-Tools mit dem Zeitgeber des Hosts sollte hierbei natürlich deaktiviert sein.
Über die Konfigurationsdateien des jeweils präferierten Bootloaders (grub/lilo) sollten einige Kernel-append-Parameter gesetzt werden, die das Zeitverhalten der VM in der Regel zusätzlich stabilisieren; z.B: clocksource=pit noapic nolapic nosmp acpi=off
Der Bootloader lilo benötigt nach der Änderung seiner Konfigurationsdatei einen Aufruf der Binary lilo, um die Änderungen dauerhaft abzuspeichern. Die verfügbaren clocksources sowie die aktuell gesetzte erhalten wir bei SUSE z.B. per: #> cat /sys/devices/system/clocksource/clocksource0/* acpi_pm pit jiffies tsc acpi_pm
Mit der zusätzlichen Einbindung bw. Aktivierung des folgenden Befehls im ntpdStartskript #> hwclock --systohc
wird die gesyncte Systemzeit direkt in die (virtuelle) CMOS-Uhr geschrieben, was einen möglichen Drift mit dem externen Timeserver beim (Re-)Start des Dienstes automatisch wieder auf 0 setzt.
170
1198.book Seite 171 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Zusätzlich sollte der powersave-Daemon permanent deaktiviert sein, da auch er Einfluss auf das Frequenzverhalten der (virtuellen) CPU hat. Wenn wir alles erledigt haben, sollten wir die Zeit in unseren VMs wie bereits bekannt per #> ntpq -p ldapmaster ldapslave
überprüfen. Die Erläuterungen zum Output haben wir bereits im letzten Abschnitt erörtert – daher nur noch einmal kurz zusammengefasst: Solange der Timeserver gut erreichbar ist und die offsets für beide VMs im Bereich von einer Millisekunde oder weniger auseinanderliegen, sollte es für unseren slapd perfekt sein, und für jedes Windowssystem so genau, dass es rein gar nichts damit anfangen kann. Zusätzlich sollte der stratum-Wert kontrolliert werden; er sollte in jedem Fall besser (kleiner) als 5 sein: #> ntpq -c rv | grep stratum processor="i686", system="Linux/2.6.25.16-0.1-pae", leap=00, stratum=4,
Wenn die Uhr des Hosts-Systems ebenfalls mit einem externen Timeserver synchronisiert ist und dank realer Hardware und/oder kurzer Resync-Intervalle sehr genau arbeitet, kann der Gast auch mit der Uhr des Hosts synchronisiert werden – die einzige Option, insofern gar keine Möglichkeit zur Synchronisation des Gastes mit einem externen NTP möglich ist. Wird ein Windows-Host verwendet, kann über das Registry-Setting HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Services\W32Time\TimeProviders\NtpClient
der Wert SpecialPollInterval auf einen Wert von z.B. 3600 (Decimal) für eine stündliche Synchronisierung des Hosts mit einem externen NTP angepasst werden. VMware bietet seinerseits über die VMware-Tools (in OSS 11 kann dies auch mit dem Paket open-vm-tools erledigt werden) die Möglichkeit, die Zeit direkt mit der Uhr des Hostsystems zu synchronisieren. Die zuvor im Text benannten Kernel-Append-Parameter sollten auch in dieser Variante gesetzt werden, da sie die CMOS-Uhr des Gastes zusätzlich stabilisieren. Allerdings ermöglicht die Variante mit einem externen NTP-Server erfahrungsgemäß einen genaueren Abgleich und stellt zudem die effektivste Synchronisationsvariante mit weiteren externen Maschinen auf anderen Hosts dar. Fassen wir kurz die Checkpunkte für einen Linux-Gast (VMware) auf einem Windows-Host zusammen: Synchronisation mit externem NTP-Server:
171
3.2
1198.book Seite 172 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
왘 powersave-Daemon abschalten 왘 Kernel: append-Parameter setzen 왘 ntp mit niedrigen Poll-Intervallen konfigurieren 왘 ntp in Intervallen per cron restarten 왘 hwclock --systohc für ntp aktivieren 왘 Interrupt-Timer-Frequenz anpassen (optional) 왘 VMware-Synchro mit Host deaktiviert (Default) Synchronisation mit Host: 왘 powersave-Daemon abschalten 왘 Kernel: append-Parameter setzen 왘 VMware-Synchro mit Host aktiviert 왘 Timesync-Zusatzparameter zur Driftkontrolle aktiviert (optional) Zur Zeitdrift-Thematik existieren (je nach Virtualisierungssoftware und eingesetzten Versionen) etliche Vorgehensweisen; Lösungsansätze für VMware und zusätzliche Hintergrundinformationen liefern z.B.: 왘 www.vmware.com/pdf/vmware_timekeeping.pdf 왘 http://kb.vmware.com/selfservice/microsites/search.do?language=en_ US&cmd=displayKC&externalId=1420 Okay, klingt alles nach mächtig viel Aufwand für so etwas scheinbar simples wie ntp und, zugegeben, das ist auch. Eine perfekte Zeitsynchro ist jedoch die unabdingbare Grundvoraussetzung für eine sauber arbeitende Replikation. Wer hier schludert, sucht in späteren Kapiteln vielleicht nach Konfigurationsfehlern, obwohl eigentlich nur die ntpd’s minimal voneinander abdriften. Wir haben die Wahl ...
3.2.5
Vorbereitungen und Vorbetrachtungen zur Replikation
Zunächst müssen wir einen neuen Server erstellen (ldapslave.local.site), der in den folgenden Beispielen als Slave für die Replikation unseres Masters (ldapmaster.local.site) fungiert. Alternativ können wir auch unseren ehemaligen ldapoffshore-Server umkonfigurieren. In dem Fall müssen wir darauf achten, die Datenbankdateien unterhalb von /var/lib/ldap/*.* (ohne DB_CONFIG) zu löschen und alle beteiligten Konfigurationsdateien (ldap.conf -PAM/NSS, ldap.conf – Client, /etc/hosts usw.) und den Hostnamen selbst entsprechend anzupassen. Seine slapd.conf ist mit der unseres ldapmasters – bis auf die in der database-Sektion eingefügten Replikationsdirektiven – vollkommen identisch. Gleiches gilt
172
1198.book Seite 173 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
für ldap.conf (Client und PAM/NSS); in diesen Dateien muss natürlich der Hostname entsprechend auf ldapslave.local.site angepasst werden. Die /etc/hosts auf beiden Maschinen muss ebenfalls so angepasst werden, dass die gegenseitige Namensauflösung problemlos funktioniert. Die LDAP-relevanten Beispieldaten hierzu finden sich in den Dateien zu diesem Abschnitt: http://www.galileocomputing.de/1801. Wichtig: Wir dürfen keinesfalls vergessen, die chaining-Direktiven in der slapd.conf von unserem ldapmaster.local.site zu entfernen und das Referral-Objekt aus dem Tree per ldapdelete -M zu löschen. Wenn wir den im letzten Abschnitt verwendeten ldapoffshore.local.site als Slave verwenden wollen, dürfen wir ebenfalls nicht vergessen, den referral-Eintrag und die chaining-Direktiven aus seiner slapd.conf zu entfernen.
Aber bevor wir loslegen, wird es endlich Zeit, »Auf Wiedersehen« zu sagen. slurpd – time to say goodbye »Slurpd replication has been deprecated in favor of Syncrepl replication and has been completely removed from OpenLDAP 2.4. Why was it replaced? … - It has been replaced for many reasons, in brief: - It is not reliable. - It is extremely sensitive to the ordering of records in the replog. - It can easily go out of sync, at which point manual intervention is required to resync the slave database with the master directory. - It isn't very tolerant of unavailable servers. If a slave goes down for a long time, the replog may grow to a size that's too large for slurpd to process. What was it replaced with? Syncrepl. Why is Syncrepl better? - Syncrepl is self-synchronizing; you can start with a database in any state from totally empty to fully synced and it will automatically do the right thing to achieve and maintain synchronization. - Syncrepl can operate in either direction. - Data updates can be minimal or maximal.«
173
3.2
1198.book Seite 174 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Nö, wir haben nicht vor, unser kleines Büchlein ab hier in Englisch fortzuführen. Das da oben ist nur der O-Ton der OpenLDAP-Entwickler (Zitat aus dem OpenLDAP Admin Guide zu Version 2.4), und dem ist eigentlich nicht mehr viel hinzuzufügen, oder? Zum zweiten Mal: Nö, eigentlich nicht, insbesondere, da die Jungs intern noch weitaus klarere Worte zu diesem Thema fallen ließen. Aber wir wollen zumindest kurz einige Hintergründe beleuchten, um auch den letzten slurpd-Verfechtern eindringlich klarmachen, dass ein Umstieg auf syncrepl nichts mit Paradigmenwechsel zu tun hat, sondern zunächst nur allein damit, dass der weitere Einsatz von slurpd grob fahrlässig ist. Beginnen wir: Unsere Trauer über den Rentenantritt von slurpd hält sich unschwer erkennbar in Grenzen, da seit OpenLDAP 2.3 die weitaus optimalere Sync-Replication oder kurz syncrepl zur Verfügung steht, die in allen Belangen flexibler, performanter und stabiler arbeitet als die slurpd-Variante, mit deren Unzulänglichkeiten wir uns leider viel zu oft herumschlagen mussten. Der einzige Grund, warum wir an dieser Stelle noch ein letztes Mal auf den wackeligen Kollegen slurpd eingehen, ist folgender: er wird trotz elementarer Schwächen bis heute leider immer noch in viel zu vielen Produktivumgebungen eingesetzt. Und das, obwohl OpenLDAP Version 2.3 – und damit auch die Replikation per syncrepl – seit Langem absolut stable sind. Leider hielt es lange Zeit kaum einer der Linux-»Enterprise«-Distributoren für nötig, ein längst fälliges Upgrade der OpenLDAP-2.2-Pakete überhaupt anzubieten, obwohl gerade eine stabile und störungsfreie Replikation ein elementares Kernfeature für jeden Verzeichnisdienst darstellt, das zudem absolut unabdingbar für seine Ausfallsicherheit ist. Ein Wort in eigener Sache: Wir betreuen seit vielen Jahren Kunden sowohl im Rahmen zahlreicher Consulting-Aufträge als auch in kundenspezifischen Workshops und Schulungen, und in diesem Kontext waren wir unter anderem für einige der größten deutschen Unternehmensgruppen wie auch für bundeseigene Institutionen tätig. Alle von ihnen setzen OpenLDAP im großen Maßstab ein, und ein Problem tauchte immer so sicher auf wie das Amen in der Kirche: Replikationsprobleme, und zwar in allen dort (üblicherweise aus Zertifizierungsgründen) eingesetzten »Enterprise«-Versionen ihrer jeweiligen Distributionen. Allesamt stets selbstlos präsentiert von unserem nervigen Kumpel slurpd. Nahezu alle Institutionen behalfen sich vor einer Umstellung auf syncrepl oder delta-syncrepl zwangsweise mit cron- und skriptbasierten Workarounds, die die Datenbanken ständig neu abglichen oder festgefressene slurpd-Prozesse neu starteten. Das eigentliche konzeptionelle slurpd-Problem konnte so natürlich nur umschifft, keinesfalls aber behoben werden.
174
1198.book Seite 175 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Das weitaus größere Problem an der vorgenannten Thematik stellen jedoch unserer Erfahrung nach immer noch viele selbsternannte LDAP-»Spezialisten« dar, die fernab der Praxis einfach nur stur die äußerst bedenkliche Ideologie einiger großer Softwarehäuser nachbeten. Diese wiederum waren in diesem speziellen Punkt lange Zeit einfach zu bequem, ein essentielles Feature trotz bekannter Schwächen auf den aktuellen und erforderlichen Paket-Stand zu bringen. Zwischen dem, was offiziell »supported« wird, und dem, was wirklich stabil läuft, gibt es in der Praxis oft genug einen mächtig großen Unterschied. Und auch das, was die Jungs mit den drei großen Buchstaben predigen, muss nicht in jedem Fall das in Stein gemeißelte 11. Gebot sein. Ja, tatsächlich. Auch die gehörten dazu. Wundert’s wen? Mit der offiziellen Entfernung des slurpd aus OpenLDAP 2.4 verstummten auch seine Verfechter schneller als ein Berufspantomime, der die Bühne betritt. Vor allem, nachdem ihnen die hinlänglich bekannten Probleme nun auch endlich seitens der Entwickler schwarz auf weiß und mit voller Wucht um die Ohren gehauen wurden. Die Gründe für die Probleme mit slurpd sind zahlreich, an dieser Stelle daher nur die allerwichtigsten: 왘 Der Standalone-LDAP-Update-Replication-Daemon ist völlig veraltet und wird seit OpenLDAP-Release 2.1(!), sprich dem Jahr 2001, nicht mehr vom OpenLDAP-Team gepflegt, geschweige denn weiterentwickelt. 왘 Der slurpd ist ein zusätzlicher Daemon, der in Produktivumgebungen mit überwacht werden muss, was noch das kleinste Übel darstellt. Denn selbst ein Service-Monitoring z.B. per mon(it) bringt in 99,9 % aller Fälle rein gar nichts mehr, denn: Falls sich slurpd auch nur ein einziges Mal verschluckt hat, repliziert er auch nach einem Restart einfach nicht weiter. Punkt. Danach hilft nur ein Datenbank-Abgleich zwischen Master und dem beteiligten Slave, entweder per slapcat und slapadd oder über das Kopieren der db-Dateien auf den Slave, und einem Neustart aller Dienste auf Master und Slave. 왘 Repliziert der slurpd aus den oben genannten Gründen nicht mehr, obwohl der Dienst noch läuft, nimmt der bei dieser Replikationsart absolut passive Slave einfach an, dass der Master für ihn nichts zu tun hat. Der Fehler kann bis zum jüngsten Tag unentdeckt bleiben. 왘 Befinden sich Einträge im Replikationslog nicht exakt in chronologischer Reihenfolge (z.B. nach einer etwas größeren Rekalibrierung durch den Timeserver), kann es vorkommen, dass sich Mister slurpd bis zum jüngsten Tag in den Dornröschen-Schlaf begibt. 왘 Geht ein Slave zu lange offline, kann die anwachsende Größe des Replikationslogs den slurpd ebenfalls killen.
175
3.2
1198.book Seite 176 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
왘 Das Replikationslog (die »Schnittstelle« zwischen slapd und slurpd zur Übergabe der anstehenden Änderungen) liegt in Klartextform auf dem Master. Daneben existieren noch etliche andere Probleme, die aber zum Teil auch in den Bereich Performance und Skalierbarkeit fallen, daher werden wir diese später im Abschnitt 3.2.7 über syncrepl eingehend erläutern. Fassen wir zusammen: 왘 Fakt ist, dass slurpd aus vielen guten Gründen nicht mehr Bestandteil von OpenLDAP 2.4. ist, um das es in diesem Buch geht. 왘 Fakt ist, dass syncrepl bereits seit OpenLDAP 2.3 zur Verfügung steht. 왘 Fakt ist, dass ein Umstieg mittlerweile in jedem Fall problemlos zu realisieren ist. Beispiel-Setups folgen in den nächsten Abschnitten zu genüge. Wer mit OpenLDAP-Version 2.3 arbeitet und an slurpd – aus welchen Gründen auch immer – festhalten will/muss/möchte, kann die Informationen zum Setup dem Admin-Guide zur Version 2.3 entnehmen: http://www.openldap.org/doc/ admin23/replication.html.
3.2.6
Synchronization without Frustration = Sync Replication
Bevor wir mit der Replikation per Sync Replication oder kurz syncrepl loslegen, betrachten wir zunächst die zugrunde liegende Funktionsweise. Der größte Unterschied zur alten slurpd-Variante besteht darin, dass es sich bei syncrepl um keinen eigenständigen Daemon wie slurpd handelt, sondern »nur« um einen Thread des slapd. Die syncrepl-Threads sind genau genommen nichts anderes als erweiterte ldapsearch-Requests eines beliebigen LDAP-Clients (siehe oben), und genau deswegen so stabil. Daraus werden schon zwei der vielen Vorteile ersichtlich: Zum einen wird kein zusätzlicher Daemon (und damit keine weitere potenzielle Fehlerquelle) mehr benötigt, zum anderen agiert der Slave wie ein »normaler« Client, der den LDAP-Server abfragt. Beziehen wir diese Aussage auf den Einsatz des uns bereits wohl vertrauten ldapsearch-Tools, wird klar, was sich hier so alles anstellen lässt. Wer hindert uns daran, nur nach bestimmten Objekten, Objektklassen oder Attributen zu suchen? Oder nur den Inhalt bestimmter Teilbäume zu finden? Genau. Bis auf fehlende Motivation eigentlich niemand. Für uns bedeutet dies in erster Linie, dass wir alle Vorteile, die uns die Flexibilität des ldapsearch-Requests bietet, auch ausschöpfen und voll auf die Replikation anwenden können. Hinzu kommen weitere, für die tägliche LDAP-Praxis sehr hilfreiche Vorteile: 왘 syncrepl ist auto-synchronisierend. Dies bedeutet, dass sich die Datenbank des Clients bei Beginn der Synchronisierung in jedem beliebigen Zustand befin-
176
1198.book Seite 177 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
den kann. Egal, ob leer oder voll befüllt, syncrepl kümmert sich automatisch um den Abgleich. In der Praxis bedeutet das auch, dass jeder Client mit einer leeren Datenbank starten kann bzw. kann nach einem Crash des Clients die Datenbank jederzeit gelöscht und sofort komplett über den Master re-initialisiert werden. 왘 syncrepl kennt primär zwei Verfahren: eine aktive und eine passive Replikations-Variante (bezogen auf den Master), weiß aber in beiden Fällen jederzeit über den Status der Replikation »Bescheid«. Nach einer Unterbrechung der Verbindung zwischen Master und Slave kümmert sich der Slave selbsttätig um die Rekonnektierung der Verbindung. 왘 Mit delta-syncrepl kommt eine noch sicherere und weitaus performantere syncrepl-Variante hinzu, da ein geringerer Overhead übertragen wird. Mehr dazu im Abschnitt 3.2.9, »Delta-Force«. Praktische Einsatzbereiche wären unter anderem: 왘 Eine komplette Full-RO-Replica, die neben Daten- und Anmelderedundanz in vielen Szenarios eingesetzt werden kann, wie z.B. in einer typischen Master/ Samba-PDC <-> Slave/Samba BDC-Konfiguration. 왘 Eine Subtree-RO-Replica für eine Zweigstelle oder untergeordnete Filiale. 왘 Eine gefilterte RO-Replica, die nur die Funktion eines Adressbuch-Servers erfüllen muss und daher nur eine Teilmenge aller Attribute (wie z.B. Mailadresse, Telefonnummer usw.) readonly repliziert und nicht das komplette Objekt mit nicht benötigten oder im schlimmsten Fall sogar sicherheitskritischen Informationen wie Passwörtern. 왘 Replikation der gesamten Konfigurationsdatenbank oder Teilen davon, wie z.B. nur den Schemas. 왘 Eine Full-RW-Replica, die als komplette Sicherheitskopie des Masters fungiert, mitsamt der kompletten Online-Konfiguration. Dies sind nur einige der Einsatzmöglichkeiten; aufgrund der Vielfältigkeit der Szenarien sind wir planungstechnisch kaum Einschränkungen unterworfen. Wie die ganze Mimik technisch gesehen im Detail funktioniert, schauen wir uns nun an. Der vollständige syncrepl-Mechanismus wird ausführlich in RFC 4533, »The LDAP Content Synchronization Operation«, von Kurt Zeilenga detailliert beschrieben (in den Beispieldateien zum Buch enthalten: http://www.galileocomputing.de/1801), daher erläutern wir im Folgenden nur die wichtigsten Grundlagen. Auch wenn die folgende Einführung ausnahmsweise etwas theorielastiger als die vorangegangenen ist, empfehlen wir, sie durchzuarbeiten. Zum einen wird das Verständnis über den Replikationsmechanismus an sich vertieft, zum
177
3.2
1198.book Seite 178 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
anderen sind die Kenntnisse zu Debugging-Zwecken in späteren Kapiteln sehr hilfreich. Los geht’s: Der syncrepl-Mechanismus hielt bereits in OpenLDAP Version 2.2 Einzug, war dort allerdings nur sehr »Beta« und nicht als Overlay implementiert. Mit Version 2.3 erfuhr syncrepl eine komplette Überarbeitung der Codebasis und wurde zudem als Overlay »ausgelagert«. Primär zielt die syncrepl-Spezifikation darauf ab, dass ein beliebiger LDAP-Client (Slave) den auf dem Master verwalteten DIT ganz oder in Teilen (z.B. einen kompletten Subtree oder bestimmte gefilterte Datensätze) als lokale »Shadow«-Copy verwaltet. Das gleiche Verfahren kann für die Replikation der Online-Konfiguration verwendet werden, ebenso für die Replikation gleichberechtigter Master untereinander. Für die folgenden Betrachtungen bleiben wir zunächst aus Gründen der Verständlichkeit primär beim Provider/Consumer-Modell, was uns direkt zur syncrepl-Terminologie führt: Bei syncrepl wird üblicherweise statt von Master und Slave auch von Provider und Consumer gesprochen. Der Provider entspricht dabei dem Master, der Consumer dem Slave bzw. Client. Daher auch die Overlay-Bezeichnung syncprov=Sync-Provider. Die Grundlage für dieses Verfahren bildet das LDAP Content Synchronization Protocol, kurz LDAP Sync. Es enthält einen erweiterten ldapsearch-Request auf der Consumer- Seite, der zusätzlich ein Sync-Request-Control beinhaltet. Der Provider verwendet zur Beantwortung dieser Client-Requests auch speziell dafür bestimmte Controls, und zwar die Sync-State- und die Sync-Done-Controls. Die dahinter liegende Funktionsweise lässt sich vereinfacht wie folgt beschreiben: Existiert eine syncrepl-Anweisung in der slapd-Konfiguration, wird ein syncreplThread innerhalb des slapd gestartet. Der Consumer fordert in jeder Konfigurationsvariante – sofern seine Datenbank leer ist – anfangs einmalig den kompletten Datenbestand vom Provider an. Dieser Vorgang wird als Initial Content Load bezeichnet. Danach wird der Datenbestand des Consumers entweder in periodischen Abständen oder bei erfolgten Änderungen aktualisiert. Die Aktualisierung des Consumers kann dabei aktiv (Polling oder auch pull-based) oder passiv (Listening oder auch push-based, Letzteres bezogen auf den Provider) erfolgen. Der aktive Modus (für den Consumer) nennt sich refreshOnly-Modus. Der Consumer fragt hierbei in festgelegten, periodischen Intervallen aktiv nach Änderungen auf dem Provider (Polling) und gleicht diese mit seiner Datenbasis ab. Der passive Modus für den Consumer nennt sich refreshAndPersist und lässt sich am ehesten mit der slurpd-Funktionsweise vergleichen, denn hierbei werden –
178
1198.book Seite 179 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
nach dem Initial Content Load durch den Consumer- alle Änderungen vom Provider auf den Consumer propagiert, nur eben ohne zusätzlichen Daemon. In dieser Konfiguration trennt der Provider die Verbindung zum Consumer nach dem Initial Content Load nicht, sondern versorgt ihn über diese persistente Verbindung weiter mit den jeweils aktuell am DIT vorgenommenen Änderungen. Am Ende einer refreshOnly-Synchronisierung sendet der Provider ein so genanntes Synchronization-Cookie an den Consumer. Das Cookie enthält mit der aktuellen contextCSN sowohl den Zeitstempel der letzten Aktualisierung am Provider als auch die eindeutige ID des Providers. Erfolgt nun die nächste Synchronisierungs-Session, checkt der Provider das vom Consumer übermittelte Cookie. Anhand des Zeitstempels erkennt er den Synchronisationsstatus des Consumers und versorgt ihn mit Updates zu allen Änderungen, die in der Zwischenzeit erfolgt sind. Nach erfolgreicher abgeschlossener Session sendet der Provider ein neues Synchronisations-Cookie mit der aktuellen contextCSN an den Consumer. Im refreshAndPersist-Modus sendet der Provider ebenfalls nach erfolgreicher Synchronisation ein Cookie (refreshDone TRUE) an den Consumer, allerdings werden die Cookies bei dieser Vorgehensweise vom Provider verwaltet, und die Verbindung zwischen Provider und Consumer bleibt nach der ersten Verbindung bestehen (persistent). Bei jeder Aktualisierung, die der Provider an den Consumer propagiert, wird ein aktuelles Session-Cookie mitgeschickt. Kommt es zu einer Trennung der Verbindung im refreshOnly-Modus, bemerkt der Consumer beim ersten Pollen nach dem Ablauf des gesetzten Synchronisationsintervalls, dass der Provider nicht mehr erreichbar ist. Im refreshAndPersistModus erkennt er es an der Unterbrechung der persistenten Verbindung. Im Gegensatz zur slurpd-Funktionsweise versucht der korrekt konfigurierte Consumer nun (sowohl im refreshOnly- als auch im refreshAndPersist-Modus) in periodischen Abständen den Kontakt zum Provider wieder aufzunehmen. Andersherum können wir auch ohne Probleme jederzeit die Replikation auf dem Consumer stoppen und sie zu einem späteren Zeitpunkt wieder aufnehmen. Nach erfolgreicher Wiederherstellung der Verbindung kann der Provider anhand des Cookie-Vergleichs auf Provider und Consumer den Synchronisationsstatus eindeutig bestimmen. Zur Auswertung und zum Abgleich des Replikationsstatus werden die Attribute contextCSN und entryCSN verwendet. CSN steht hierbei für Change Sequence Number, den Zeitstempel der letzten Änderung. Exkurs: Spiel auf Zeit – das CSN-Format Nach einigen Bierchen könnte man auch die Altrocker »Crosby, Stills und Nash« oder irgend eine andere hochgeistige Bezeichnung hinter der Abkürzung »CSN«
179
3.2
1198.book Seite 180 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
vermuten. Hinter den drei Buchstaben versteckt sich jedoch das objektbezogene A und O aller replikationstechnischen Vorgänge unseres LDAP-Systems. Warum das so ist, schauen wir uns kurz anhand des Formats einer beispielhaften Change Sequence Number an und zerlegen sie dazu in ihre Einzelteile: 20080904122159.147848Z#000000#001#000000
Der erste Part <20080904122159> bis zum Punkt gibt Datum (Jahr/Monat/Tag) und Zulu-Time (Z) mit einer Genauigkeit von Sekunden an. Der replikationstechnisch wichtigste Part befindet sich seit Version 2.4 hinter dem Punkt <147848 >: der sechsstellige (Nachkomma-)Wert in Mikrosekunden, den ältere OpenLDAPVersionen nicht besitzen bzw. verwenden. Wie bereits im Abschnitt über ntp erläutert, ist diese hohe Genauigkeit für eine fehlerfreie Replikation – insbesondere im Hinblick auf Multi-Master-Replikation – unabdingbar. Die nächste Sektion hinter der ersten Raute (#) definiert den so genannten COUNT (bzw. Operation Counter): ein sechsstelliger Hex-Zähler (000000-ffffff), der dazu verwendet wird, um multiple Änderungen innerhalb derselben Zeitscheibe exakt voneinander zu separieren. Hinter der nächsten Raute folgt die SID: ein dreistelliger Hex-Wert (000-fff) welcher die jeweils eindeutige Server ID beinhaltet. Der letzte Wert (MOD) ganz rechts ist ein sechsstelliger Hex-Wert (000000-ffffff), der dazu benutzt wird, die Reihenfolge der Modifikationen innerhalb einer LDAP Modify operation festzulegen. contextCSN Zurück zu context- und entryCSN: Unter der contextCSN verstehen wir dementsprechend die aktuelle, eindeutige CSN des jeweiligen Naming Context bzw. Suffix (regulär die höchste Ebene des jeweiligen DIT, in unserem Fall also dc=local,dc=site) eines LDAP-Servers. Die contextCSN entspricht dabei, stark vereinfacht ausgedrückt, der neuesten (bzw. aktuellsten) entryCSN des gesamten Kontextes. Das eigentliche contextCSN-Attribut ist dabei Multi-Value-fähig – eine unabdingbare Voraussetzung für Multimaster-Setups, denn nur so kann eine contextCSN für jede vorhandene ServerID verwaltet werden. Unser Provider verwaltet das gute Stück für jeden vorhandenen Kontext als so genannten synchronization state indicator, an dem er den aktuellen Replikationsstatus seines Kontextes festmachen kann. Er speichert die nach jedem ObjektUpdate aktualisierte contextCSN dabei als Entry des jeweiligen Kontext-Suffixes (in den Debug-Logs unseres slapd taucht dann üblicherweise diese Meldung auf: bdb_modify_internal: replace contextCSN). Allerdings geschieht das Speichern während des regulären Arbeitsbetriebes nicht in der Datenbank selbst, son-
180
1198.book Seite 181 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
dern »nur« im flüchtigen Speicher bzw. in den per syncprov-checkpoint-Direktive angegebenen Intervallen in der Datenbank. Wird unser slapd-Provider sauber heruntergefahren, speichert er die aktuellste contextCSN final in der Datenbank ab. Beim (Re-)Start liest er dann die zuletzt gespeicherte contextCSN aus und arbeitet dann mit der »In-Memory«-Copy weiter. Kommt es jedoch zu einem unsauberen Shutdown, ist der Provider daher in der Regel nicht imstande, die aktuelle contextCSN seines Suffixes zu ermitteln. Als Folge scannt er die komplette Datenbank seines Kontextes und versucht, eine gültige contextCSN zu finden, was je nach Größe der DB einige Zeit beanspruchen kann. Hat der Provider eine (mögliche) contextCSN gefunden, scannt er dennoch im Hintergrund die Datenbank des Kontextes nach etwaigen, größeren entryCSNs, um zu validieren, dass die gefundene contextCSN wirklich den aktuellsten Stand repräsentiert. Findet er keine verwertbare contextCSN, generiert er eine neue, basierend auf dem höchsten gefundenen entryCSN-Wert, und schreibt diese mit einem Checkpoint versehen direkt in die Datenbank. Aus diesem Grund (und anderen) sollte daher das entryCSN-Attribut indexiert werden. Das beschleunigt, insbesondere bei großen DITs in Verbindung mit einem syncrpov-checkpoint, die oben beschriebene Scan-Operation erheblich. entryCSN Das Attribut entryCSN beinhaltet – ebenso wie die contextCSN – die eben im Exkurs »Spiel auf Zeit« erläuterten Parameter. Die entryCSN wird von jedem Objekt innerhalb unseres DIT als operational Attribute mitgeführt. Wird ein Datensatz auf dem Provider geändert, aktualisiert der seine contextCSN sowie die entryCSN des modifizierten Objekts. Der Consumer speichert seinen aktuellen Replikationsstatus ebenfalls mit Hilfe der contextCSN des Providers, die er als Synchronisations-Cookie erhält. Über den Abgleich von contextCSN und den entryCSNs ist jederzeit gewährleistet, dass Provider und Consumer wissen, welche Objekte repliziert bzw. aktualisiert werden müssen. So viel zu den CSNs; bevor wir uns das syncrepl-Setup im Detail anschauen, noch ein paar grundsätzliche Dinge zur syncrepl-Terminologie und -Technik: Die syncrepl-Konfiguration erfolgt über das Einbinden des Overlays syncprov auf dem Provider, danach nur noch in der slapd.conf (bzw. der Online-Konfiguration unter slapd.d/) auf der Consumer-Seite, jeweils innerhalb der Datenbankdefinitionen. Daher ist es zum Beispiel auch nicht erforderlich, den Provider bei Änderungen an den Replikationseinstellungen neu zu starten. Arbeiten wir mit einer Online-Konfiguration, ist es theoretisch noch nicht einmal mehr nötig, den Consumer neu zu starten. Aber Achtung ...
181
3.2
1198.book Seite 182 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Rein oder raus? – Exkludierung von Attributen und Objekten Vor Änderungen an der Replikationseinstellungen des Consumers sollte in jedem Fall erst einmal etwas Gehirnschmalz angesagt sein, egal, welche Form der slapdKonfiguration wir wählen, denn: Ein nachträglich eingefügter Filter, um einige bestimmte Objekte im Nachhinein auszusieben bzw. mit Hilfe eines Filters »automatisch zu löschen«, bringt herzlich wenig. Wenn die Consumer-Datenbank dieses Objekt schon einmal repliziert hat, bleibt das Objekt an sich so lange bestehen, bis es auf dem Provider explizit gelöscht wird. Im Gegenteil: Ein etwaiger Filter der bekannten Konvention filter="(!(objectClass=posixAccount))"
würde alle Userobjekte, die die Objektklasse posixAccount besitzen, einfach nur von zukünftigen Replikationen ausnehmen, aber logischerweise keinesfalls löschen. Was machbar – und andersherum auch sinnvoll ist: Attributfilter. Über die Exkludierung bestimmter Attribute bzw. Anwendung eines positiv-/negativAttributfilters (attrs= | exattrs= ) kann eine Full-Replica im Handumdrehen in eine partielle Replica verwandelt werden, auf der z.B. nur noch Kontaktdaten der Userobjekte wie Name, Mailadresse, Telefonnummer und Beschreibung des Objekts liegen. Das Ganze funktioniert auch in der umgekehrten Weise. Aber: Das vorgestellte Verfahren funktioniert nur bei der »normalen« syncrepl-Variante, bei der ein Objekt (auch bei Änderung nur eines einzelnen Attributwertes) komplett repliziert wird; denn nur so kann ein Attributfilter (z.B. attrs="cn,mail,telephoneNumber,gecos") in der gerade beschriebenen Art und Weise greifen. Da delta-syncrepl zur Performance-Optimierung genau an diesem Overhead ansetzt, funktioniert das Vorgehen dort nicht. Wie delta-syncrepl funktioniert, schauen wir uns natürlich später noch genauer an.
Die eigentliche syncrepl-Engine kann mit jeder Datenbank arbeiten, jedoch wird die Verwendung der bdb- und hdb-Backends empfohlen. Bei Verwendung von ldbm als Datenbank-Backend (nur in OpenLDAP-Versionen vor 2.4) kann aufgrund des eingeschränkten Funktionsumfangs gegenüber dem bdb/hdb-Backend der refreshAndPersist-Modus nicht verwendet werden. Da? Oder schon weg? – syncrepl-Phasen Noch eine Hintergrund-Info, die wir später auch benötigen werden, wenn wir uns die Technik der Delta-Sync-Replikation anschauen: Prinzipiell unterscheiden wir in dem von syncrepl verwendeten LDAP Content Synchronization Protocol zwei Phasen: die present(»vorhanden«)-Phase und die delete(»löschen«)-Phase.
182
1198.book Seite 183 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Der refreshOnly-Modus – und das refresh-Stadium des refreshAndPersist-Modus – können sowohl in der present-Phase als auch in der delete-Phase durchgeführt werden. In der present-Phase sendet der Provider dem Consumer nur die Objekte, die seit der letzten Synchronisation aktualisiert wurden. Vom Objekt selbst werden alle Attribute gesendet, auch wenn nur eines oder wenige modifiziert wurden. Für jedes Objekt innerhalb des eigenen Kontextes, das unverändert geblieben ist, sendet der Provider eine present-Nachricht an den Consumer, die keine Attribute des Objekts enthält, sondern ihm neben dem DN des Objekts per sync-Control nur mitteilt, dass das »Objekt vorhanden« (present) ist. So kann der Consumer zuverlässig darüber entscheiden, welche Objekte er modifizieren muss, welche noch vorhanden sind und welche gelöscht werden können. Die Übertragung der aktualisierten Objekte erfolgt in der delete-Phase in der gleichen Art und Weise wie in der present-Phase: Der Provider sendet alle Attribute (der seit der letzten Synchronisation aktualisierten Entries) an den Consumer. Der Unterschied der delete-Phase zur eben erläuterten present-Phase liegt darin, dass der Provider statt einer present-Nachricht (»Objekt vorhanden«) eine deleteNachricht für jedes gelöschte Objekt an den Consumer sendet. Auch hier enthält die Nachricht nur den DN des Objekts und das sync-Control mit dem Status »Objekt löschen«. Im Prinzip kann man die ganze Mimik auch vereinfacht wie ein Positiv/negativAusschlussverfahren betrachten. Entweder: Behalte dies und das Objekt, alle nicht angegebenen löschst du. Oder: Lösche dies und das Objekt, alle nicht angegebenen behältst du. Nun zum Einsatz der unterschiedlichen Szenarien: Um den Content zwischen Provider und Consumer abzugleichen, versucht unser LDAP immer die günstigste Variante auszuwählen. Wenn das syncprov-Overlay auf dem Provider ein Sessionlog verwendet (dazu gleich mehr im syncrepl-Setup) und der Consumer halbwegs aktuell ist (keine gelöschten Entries in der History seit der letzten Synchro), wird immer die effizienteste Variante, die delete-Phase verwendet. Wenn kein Sessionlog verfügbar ist, es zu alt ist, oder der Consumer zu sehr out-of-sync ist, wird die im Gegensatz zur delete-Phase etwas ineffizientere present-Phase verwendet. Aber selbst die present-Phase stellt eine immer noch deutlich effektivere Variante im Gegensatz zu einem kompletten Initial Content Load dar. Dabei jedoch immer berücksichtigen: Das Sessionlog des syncprov-Overlay liegt im Speicher des Providers, nicht auf der Platte, ist also nicht persistent über Reboots oder über mehrere Provider hinweg.
183
3.2
1198.book Seite 184 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Aktiv oder passiv? - Grundsätzliche Überlegungen zur sync-Replikation Should I stay or should I go … sangen schon The Clash, und die Frage stellt sich im übertragenen Sinne auch für den Admin im Hinblick auf die zu wählende syncrepl-Variante. Soll der Provider auf der Stelle stehen, nichts tun und darauf warten, bis der Consumer die Änderungen abholt, oder soll er sich mit den Infos selbst auf den Weg machen? Prinzipiell hängt das von mehreren relevanten Punkten ab. Hier nur einige als Denkanstoß: 왘 Müssen Änderungen zeitkritisch auf die Consumer übertragen werden? 왘 Wie viele Änderungen werden im Schnitt in einer bestimmten Zeiteinheit übertragen? 왘 Wie groß ist die Datenmenge dieser Änderungen? 왘 Wie sieht die Bandbreite der Verbindung zwischen Provider und Consumer(n) aus? Drei grundsätzliche Lösungsansätze wären hier zu nennen: 왘 Geht es um zeitkritische Änderungen von Objekten mit einer relativ geringen Datenmenge, sollte in jedem Fall refreshAndPersist als Replikationsmethode gewählt werden. Der Begriff »Relativ« ist natürlich von Fall zu Fall zu bewerten und sollte natürlich stets in Abhängigkeit der verfügbaren Bandbreite betrachtet werden. 왘 Besteht keine Notwendigkeit, die Daten sofort brandaktuell auf alle verfügbaren Consumer zu schieben und sind Datenmenge wie Anzahl der Objekte recht groß, bietet sich natürlich refreshOnly an. So kann man die Replikation bequem in großen Intervallen laufen lassen – vorzugsweise nachts, vor allem, wenn kein 24/7-Betrieb vorliegt. 왘 Geht es um minimalen Overhead und maximal erreichbare Datenkonsistenz (egal, ob zeitkritisch oder nicht) muss die Wahl ohnehin auf delta-syncrepl fallen. Noch ein ergänzender Hinweis: Spielt die Bandbreite bzw. der Overhead keine Rolle und maximale Flexibilität im Hinblick auf die Attribute replizierte Objekte ist gefragt, sollte eine der Standard-Syncrepl-Varianten verwendet werden. Die Flexibilität wird jedoch mit einer etwas geringeren Konsistenz-Sicherheit im Gegensatz zu delta-syncrepl erkauft. Weiter im Text: Um nun einen Status quo bezüglich der Datenbank auf Consumer und Provider zu erreichen, können wir uns den ganzen nervigen Aufwand des für die slurpd-Replikation erforderlichen Verfahrens (slapcat Master, slapadd Slave – oder das Kopieren der bdb-Dateien per scp vom Master auf den Slave) einfach
184
1198.book Seite 185 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
komplett sparen. Wir warten nicht, wir starten. Und zwar den Consumer mit einer leeren Datenbank und den gewünschten Direktiven im syncrepl-Statement. Der Abgleich (Initial Content Load) erfolgt dann automatisch. Hinweis zu Erinnerung: Natürlich muss vorab eine korrekte Zeitsynchronisation zwischen Consumer und Provider sichergestellt sein, und es sollte in jedem Fall ein Backup der Provider-Datenbank erstellt und getestet werden, sofern es sich um eine Produktivumgebung handelt!
Um es an dieser Stelle nochmals zu betonen: Ein wichtiger Punkt ist die Gleichheit der Schemas und die Reihenfolge der Schema-Einträge in der slapd.conf auf Provider und Consumer. Wir müssen vorab in jedem Fall sicherstellen, dass die Include Statements für die Schema-Dateien (aufgrund der abgeleiteten/vererbten Objektklassen) in beiden slapd.conf die gleichen Einträge in der gleichen Reihenfolge enthalten. Wir setzen natürlich für unser Beispiel ebenfalls voraus, dass die eigentlichen Schemadateien den gleichen Versionsstand haben und exakt die gleichen Objektdefinitionen und Attribute beinhalten.
3.2.7
syncrepl – Setup
Seit OpenLDAP 2.3 wird syncrepl als Overlay implementiert, wie wir bereits wissen. Und auch die Technik und Funktionsweise, mit der Sync-Replikation arbeitet, kennen wir seit dem letzten Kapitel recht genau. Daher wenden wir uns an dieser Stelle zunächst der relativ simplen Integration des Overlays syncprov zu, das die syncrepl-Kapabilitäten des Providers bereitstellt. Als Erstes muss sichergestellt sein, dass slapd mit dem entsprechenden Overlay kompiliert wurde (--enable-syncprov) für Overlay syncprov, oder besser –enable-overlays=yes für alle Overlays). Eine Übersicht aller verfügbaren Direktiven für die Sync-Replikation liefern man 5 slapd.conf (slapd-config) und man 5 slapo-syncprov. Auf dem syncrepl-Provider wird zunächst das Overlay in der Datenbank-Sektion der slapd.conf mit der Direktive overlay syncprov
aktiviert und kann anschließend mit zwei zusätzlichen Direktiven konfiguriert werden. Die erste: syncprov-checkpoint
<minutes>
legt fest, nach wie vielen Operationen oder Minuten die contextCSN seit dem letzten Checkpunkt in die unterliegende Datenbank geschrieben werden. Gültig ist der Parameter, der zuerst eintritt: entweder die Anzahl der Operationen oder abgelaufene Minuten. Für unsere ersten Tests sollten wir die Werte niedrig
185
3.2
1198.book Seite 186 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
ansetzen, um sicherzustellen, dass die contextCSN in jedem Fall in die DB des Providers geschrieben wird; z.B.: syncprov-checkpoint
10
1
Eine Warnung vorab an dieser Stelle: Die syncprov-checkpoint-Direktive sollte in einigen älteren 2.4*-Versionen (typischerweise <=2.4.9) beim Setup einer Multi-Master-Konfiguration nicht angewendet werden. Ihre Verwendung kann in diesem Spezialfall dazu führen, dass die Replikation in beide (oder mehrere) Richtungen fehlschlägt:
das syncprov-Overlay hat die bestehende contextCSN nach einem Update bereits aktualisiert, während der syncrepl-Thread versucht, die alte (-und natürlich nicht mehr vorhandene) contextCSN zu löschen. Ende, aus, Micky Maus. In der MMR-Konfiguration dieser Versionen kümmert sich syncrepl automatisch um die Aktualität der contextCSN.
Mit syncprov-sessionlog <size>
wird die Größe des Sessionlogs festgelegt, wobei <size> nicht die Größe selbst, sondern die Anzahl der Einträge im Log festlegt. Über diese Direktive wird ein Log (bzw. eine History) im Speicher (nicht auf der Platte!) für LDAP-Sync- Suchoperationen erzeugt, welche Einträge beinhaltet, die zwischen den einzelnen Replikationsvorgängen geändert wurden (Ausnahme: add-Operationen) und die Performance der LDAP-Sync-Suchoperationen deutlich verbessert. Apropos Performance: Für eine optimale syncrepl-Performance sollten die Attribute entryUUID (bei Verwendung der syncprov-sessionlog-Direktive, siehe oben) und entryCSN indexiert werden. Keine Sorge, das erledigen wir gleich im Setup, allerdings würde unser syncrepl auch erst einmal ohne laufen. Alle Verfahren zur Indexierung von Attributen und Objektklassen kennen wir zwar schon ansatzweise, aber wir erläutern sie später noch ausführlicher, und zwar im Abschnitt 3.8 über die Oracle Berkeley DB, »Larry und die schläfrigen Katzen«. Neben den bereits vorgestellten existieren noch zwei weitere syncprov-Sub-Direktiven, die jedoch primär für den Einsatz mit delta-syncrepl verwendet werden, daher werden wir sie in dem entsprechenden Abschnitt 3.2.9, »Delta-Force«, erläutern.
Nun richten wir die syncrepl-Direktiven für den Consumer am Ende der Datenbank-Sektion der slapd.conf ein. Das Overlay syncprov muss in dieser einfachen Konfiguration auf dem Consumer nicht eingebunden werden. Auch hier ist die Einrückung der Direktiven zu beachten, da es sich bei a)–j) um Sub-Direktiven der syncrepl-Direktive handelt! (Die Nummerierung dient nur der Übersicht und ist nicht Bestandteil der Direktiven.)
186
1198.book Seite 187 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
1) syncrepl
a) b) c) d) e) f) g) h) i) j)
rid=1 provider=ldap://ldapmaster.local.site searchbase="dc=local,dc=site" type=refreshAndPersist retry="5 10 30 +" filter="objectClass=*" scope=sub attrs="*,+" sizelimit=unlimited timelimit=unlimited
Die Erläuterungen: 1) Aktivierung der syncrepl-Engine a) Festlegung der rid (replica-ID, positiver Integer-Wert zwischen 0–4095). Der Wert muss pro verwendetem Consumer (Slave) eindeutig sein! b) Provider (Master) – URI (ldap oder ldaps): entweder IP oder FQHN c) Suchbasis. Definiert, ab welchem Punkt im DIT des Providers der Consumer suchen darf. So kann über eine »tiefere« Searchbase wie z.B. ou=verkauf,dc=local,dc=site eine einfache Teilbaum-Replikation definiert werden. d) syncrepl-Modus: refreshOnly oder refreshAndPersist. Wenn refreshOnly verwendet wird, ist zusätzlich das Aktualisierungsintervall zum Abgleich der Daten anzugeben, in der Form interval="[dd:hh:mm:ss]". Im refreshAndPersist-Modus entfällt diese Direktive! e) Re-Konnektierungs-Intervall, wenn Verbindung zum Provider unterbrochen: Im oberen Beispiel startet alle fünf Sekunden einen Reconnect-Versuch (insgesamt zehn Mal). Danach alle 30 Sekunden ohne Anzahlbegrenzung (+). Für beide syncrepl-Modi anwendbar, sollte immer gesetzt werden. f) ldapsearch-konformer Filter, welche Objektklassen repliziert werden sollen. Hier ist Vorsicht geboten. Werden z.B. nur alle Objekte repliziert, die z.B. die Objektklasse posixAccount beitzen, fehlt die restliche Struktur des Trees. Default: objectClass=* (alle Objektklassen) g) ldapsearch-konformer Such-Scope (default: sub) h) ldapsearch-konformer Filter, welche Attribute repliziert werden sollen. Default: Alle »normalen« Attribute ("*") und alle operational Attributes ("+"). Würden wir einen Filter attrs="uid,cn,sn,description,mail" statt der Attribut-Wildcard "*" setzen, so würden nur noch diese Attribute repliziert, auch bei einem Initial Content Load. Innerhalb der Online-Konfiguration existiert zusätzlich das olcSyncrepl-Exkludierungs-Attribut exattr=.
187
3.2
1198.book Seite 188 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
i) Begrenzung für die Anzahl der zurückgegebenen Suchergebnisse (wird durch providerseitig gesetzte Werte überschrieben); Default: unlimited j) Begrenzung für Timeout bei der Suche (wird durch providerseitig gesetzte Werte überschrieben); Default: unlimited Die Werte f-j im oberen Beispiel repräsentieren Default-Settings und müssen daher nicht explizit gesetzt werden, sofern keine anderen Settings gewünscht sind. Eine kurze Anmerkung an dieser Stelle zum optionalen Consumer-Parameter schemachecking=<Wert> (Default = off). Wenn er aktiviert ist, prüft der Consumer-slapd, ob die replizierten Objekte eine strukturelle Objektklasse besitzen, die entsprechenden Schemas zu allen Attributen und Objektklassen der replizierten Objekte in der Shadow-DB vorhanden sind und ob die Objekte den Anforderungen der ihnen eigenen Objektklassen (MUST-Attribute) entsprechen. Im Default-Setting schemachecking=off werden die Objekte in der DB des Consumers gespeichert, ohne auf die oben angesprochene Konformität geprüft worden zu sein. Das kann manchmal erwünscht und auch notwendig sein (siehe Overlay dds oder partielle Replikationen von nur einzelnen Attributen bestimmter Objekte), kann aber bei einer Full-Replica auch zu ungewollten Inkonsistenzen führen. Weitere Infos zu allen verfügbaren syncrepl-Sub-Direktiven finden sich in slapd.conf(5) bzw. zu olcSyncrepl in slapd-config(5). Bei den hier vorgestellten Direktiven handelt es sich natürlich nur um einige grundlegende Einstellungen, die jedoch für unser erstes Setup völlig ausreichen. Spezialitäten wie verschlüsselungstechnische Direktiven schauen wir uns in den folgenden Kapiteln natürlich ebenfalls noch sehr genau an. Und nun – Time to replicate: Zunächst erstellen wir wie üblich offline ein Backup unserer aktuellen LDAP-Datenbank auf dem Provider per slapcat, stoppen den slapd des Consumers und löschen seine Datenbankdateien. Danach starten wir zunächst den slapd des Providers und anschließend den des Consumers, Letzteren im Debug-Mode 16384 (oder sync) und betrachten, was bei einer leeren Datenbank auf der Consumer-Seite so passiert: Genau, eine Menge, weil der Initial Content Load startet und der Consumer aufgrund der eingestellten Wildcards zunächst einmal alle Daten in seine DB repliziert. Alle Daten? Laut Debug-Ausgabe sollten zumindest alle Objekte angekommen sein: ... syncrepl_entry: rid=001 be_search (0) syncrepl_entry: rid=001 uid=rdeckard,ou=security,dc=local,dc=site
188
1198.book Seite 189 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
syncrepl_entry: rid=001 be_add (0) syncrepl_entry: rid=001 LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD) syncrepl_entry: rid=001 inserted UUID cf54e8c8-3eff-102d-91b8-f703b9d93552 <= bdb_equality_candidates: (entryUUID) not indexed syncrepl_entry: rid=001 be_search (0) syncrepl_entry: rid=001 uid=jmcclane,ou=security,dc=local,dc=site syncrepl_entry: rid=001 be_add (0) do_syncrep2: rid=001 LDAP_RES_SEARCH_RESULT do_syncrep2: cookie=rid=001,csn=20081107120511.974887Z#000000#000#000000 slap_queue_csn: queing 0xb81b10d0 20081107120511.974887Z#000000#000#000000 slap_graduate_commit_csn: removing 0xb81ba470 20081107120511.974887Z#000000#000#000000
Und so weiter und so fort. Zum Ende des ICL (Initial Content Load) kann man auch sehr schön den Austausch der contextCSN erkennen. Wurde als Replikationsmodus refreshOnly gewählt, wiederholen sich die Meldungen: do_syncrep2: rid=001 LDAP_RES_SEARCH_RESULT
in den per interval=... gesetzten Intervallen. Die Meldung in der Debug-Ausgabe: <= bdb_equality_candidates: (entryUUID) not indexed
stupst uns mit der Nase auf einen wichtigen Punkt, den wir bereits angesprochen hatten: Indexierung zwecks Performance. Da das LDAP Sync Protocol auch auf das operational Attribute entryUUID (die eindeutige ID eines Objekteintrags, wird intern per uuidgen(8) generiert) zurückgreift, sollte das Attribut indexiert werden, um die Performance zu verbessern, ebenso wie das Attribut entryCSN. Also setzen wir folgenden Eintrag in die slapd.conf unterhalb der Standard-Indexanweisung für alle Objektklassen (index objectClass eq), restarten unsere beiden slapd auf Provider und Consumer, und alles wird gut: index
entryUUID,entryCSN
eq
Aber zurück zum Thema: Sind wirklich alle Daten da? Werfen wir mal einen vertrauensvollen ldapsearch-Blick (per ldapadmin-DN auf dem Consumer) auf den Kollegen Clark Kent: #>ldapsearch –xWD cn=ldapadmin,dc=local,dc=site uid=ckent
Alles da? Fehlanzeige! Das Attribut userPassword wurde nicht mitrepliziert. Das Warum lässt sich schnell beantworten und führt uns direkt zum nächsten wichtigen Punkt bei der Sync-Replikation: Wie greift der Consumer auf den Provider zu? In unserer Konfiguration wie ein anonymer ldapsearch-Request, denn wir haben keinen expliziten binddn angegeben, also keine Identität, mit der sich der Consumer am Provider anmeldet. Also bekommen wir die gleichen Ergebnisse zurück, als würden wir auf dem Provider eine anonyme Suche per ldapsearch –x
189
3.2
1198.book Seite 190 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
abschicken. Und anonyme User bekommen aufgrund der von uns in der BeispielKonfiguration verwendeten ACL access to attrs=userPassword,userPKCS12 by self write by * auth
natürlich kein userPassword-Attribut zu sehen. Die hier verwendete ACL gestattet es nur dem User selbst (oder natürlich dem rootdn) nach erfolgreicher Authentifizierung das Attribut auszulesen und zu schreiben, sonst bekommt es niemand zu sehen. Hier lässt sich schon recht deutlich erahnen, wie wichtig die ACLs auch für die replikationstechnischen Zugriffe sind. Egal, was wir dem Consumer hinsichtlich Suchbasis, Attributen, Filter etc. vorgeben: er kann nicht mehr lesen und somit replizieren, als die ACLs auf der Providerseite zulassen. So betrachtet, besitzen wir damit die Möglichkeit, über die syncrepl-Statements auf Consumer- und die ACLs auf der Providerseite eine doppelte Sicherheit einzubringen. Allerdings muss man diesem Konfigurationsfall natürlich auch besondere Aufmerksamkeit schenken, damit der Schuss nicht nach hinten losgeht. ACLs werden wir uns sehr ausführlich in Abschnitt 3.7 über ACLs, »Nur mit Clubkarte«, vornehmen, das kurze Intro soll an dieser Stelle für uns reichen. Welche Zutaten fehlen also noch? Eine geeignete Identität, mit der wir auf den Provider zugreifen. Wir könnten natürlich den rootdn des Providers wählen, aber das wäre beileibe nicht die feine Art, da unser rootdn natürlich auch schreibenden Zugriff auf alle Objekte hat. Also gehen wir die Sache korrekt an: Als erstes fügen wir unserem Tree auf dem Provider einen speziellen, rollenbasierten Account hinzu, der nur Replikationszwecken dienen soll (siehe Datei replicator.ldif): dn: cn=replicator,dc=local,dc=site objectClass: organizationalRole objectClass: simpleSecurityObject cn: replicator userPassword: {SSHA}vSF2PR... # usw.
Die Objektklasse simpleSecurityObject bringt das Attribut userPassword mit, (hier das SSHA-gecryptete Passwort »linux«) das wir für die binddn- und credentialsDirektiven innerhalb der syncrepl-Konfiguration auf dem Consumer benötigen. In der slapd.conf des Providers legen wir unterhalb der Datenbanksektion eine Aufhebung der Limitierungen und eine ACL wie folgt an:
190
1198.book Seite 191 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
limits dn.exact="cn=replicator,dc=local,dc=site" size=unlimited time=unlimited access to * by dn.exact="cn=replicator,dc=local,dc=site" read by * break
Die gewählte limits-Direktive ermöglicht es dem replicator-Account auch bei großen Datenmengen (z.B. bei einem sehr großen Initial Content Load eines sehr umfangreichen DIT), ohne zeitliche und mengenmäßige Limits zu werkeln. Die darauf folgende ACL erlaubt dem replicator-Account lesenden Zugriff auf alle Objekte und Attribute unseres ganzen DIT. Durch die by * break- Anweisung wird diese ACL von allen anderen anfragenden DNs schlichtweg ignoriert. Mehr hierzu – wie eben erwähnt – in Abschnitt 3.7 über ACLs, »Nur mit Clubkarte«. Als Erstes starten wir den Provider neu, damit die beiden neu gesetzten Direktiven aktiviert sind. Danach stoppen wir den Consumer und löschen Quick & Dirty alle Datenbankdateien per #>rm /var/lib/ldap/*.* Erinnerung: Die Wildcard *.* verwenden wir, damit die Konfigurations-Datei DB_CONFIG für die BDB nicht mit einbezogen wird.
Nun aktivieren wir die zusätzlichen syncrepl-Sub-Direktiven in der slapd.conf des Consumers, die die Identität festlegen, mit der sich unser Consumer am Provider anmeldet: syncrepl
rid=001 ... binddn="cn=replicator,dc=local,dc=site" bindmethod=simple credentials="linux"
Nun starten wir den slapd auf dem Consumer, warten kurz, bis der Datenbestand synchronisiert ist, und suchen anschließend ein beliebiges Userobjekt, natürlich als ldapadmin. Und siehe da: Jetzt ist wirklich alles vorhanden. Kleine Ursache, große Wirkung. Wie so oft im Leben ... Rollenspielchen Da sowohl Provider als auch Consumer eine contextCSN (und damit die aktuelle Statusinformation) in ihrer eigenen, jeweiligen Datenbank verwalten, kann jeder Consumer zum Provider befördert werden (und ebenso anders herum degra-
191
3.2
1198.book Seite 192 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
diert), was in slurpd-Master/Slave-Umgebungen in dieser Form ohne erhebliche Verrenkungen nicht zu realisieren war. Und wie würde ein Tausch der Rollen von Provider und Consumer ablaufen? Ganz einfach. Nachdem unsere beiden Datenbanken auf Provider und Consumer nun über den gleichen Datenbestand (unser Consumer ist ja nun eine Full-Replica) und vor allem eine identische contextCSN verfügen, tauschen wir, nachdem wir beide slapd’s gestoppt haben, die slapd.conf des Providers gegen die des Consumers und umgekehrt (Achtung – Hostnamenauflösung! Gegebenenfalls einfach die IP in der Provider-URL verwenden). Danach starten wir beide und beobachten, was passiert. Wenn wir alles richtig gemacht haben, ist ldapslave nun der Boss im LDAP-Haus und pfeift »Master and Servant ...«. CSN-Debugging Wichtig dabei ist, dass die contextCSN in jedem Fall in der Datenbank des Slaves vorhanden ist (z.B. kurze syncprov-checkpoint-Intervalle) und die korrespondierenden Attribute entryUUID und entryCSN auf beiden Maschinen zuvor indexiert worden sind! Um die aktuelle CSN unseres Kontextes auszulesen, können wir folgenden Suchfilter verwenden: #> ldapsearch -x -s base -LLL contextCSN dn: dc=local,dc=site contextCSN: 20081107120511.974887Z#000000#000#000000
Einen manuellen Vergleich mit der aktuellsten entryCSN unseres DIT können wir auf dieser Basis ebenfalls problemlos initiieren: #> ldapsearch -x -LLL entryCSN | grep ^entry |sort -n | tail -n1 contextCSN: 20081107120511.974887Z#000000#000#000000
Im Normalfall sollte die contextCSN identisch mit der aktuellsten entryCSN unseres DIT sein, wie wir hier unschwer erkennen können. Wichtig in diesem Zusammenhang: In einigen Howtos und Büchern zu diesem Thema findet sich eventuell der irreführende Hinweis, dass die contextCSN erst durch umständliches Erstellen eines Datenbank-Dumps per slapcat und anschließende Neuanlage der Datenbank per slapadd –w (setzt explizit die contextCSN für syncrepl) erzeugt werden kann. Die beschriebene Vorgehensweise ist machbar, aber in der Regel unnötig, da die contextCSN nach der Aktivierung des syncrepl-Overlays in der slapd-Konfiguration des Providers automatisch für den jeweiligen Kontext erzeugt wird (siehe oben).
192
1198.book Seite 193 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
3.2.8
Beispielhafte Lösungsansätze mit syncrepl
In größeren Unternehmen kann – und sollte – aus Redundanzgründen die Anzahl der Replikationen erhöht werden, ebenso ist natürlich eine Kombination aus Partitionierung (Aufteilung des DIT) und Replikation denkbar. Die folgenden Vorgehensweisen entsprechen weitestgehend einer Kombination der bereits bekannten Verfahren hinsichtlich Partitionierung und Replikation. Daher beschreiben wir an dieser Stelle nur einige der möglichen Szenarien und die wichtigsten Konfigurationsparameter. Single Provider → Multiple Consumer Grundsätzlich muss bei multiplen Replikationen per syncrepl immer darauf geachtet werden, dass die Replica-IDs (rid) für jede Replica stets eindeutig gewählt werden. Ansonsten kann auf jedem Slave bzw. Consumer bei Bedarf eine individuelle Konfiguration (Full Replica, Subtree-Replikation, nur ausgewählte Attribute) mit Hilfe der bereits vorgestellten Direktiven gewählt werden. Partitionierter DIT mit Replicas
Provider dc=local, dc=site
Replikation
Consumer dc=local, dc=site
Referral
Provider der Partition dc=offshore, dc=local, dc=site
Replikation
Consumer der Partition dc=offshore, dc=local, dc=site
Abbildung 3.5 Partitionierter Tree mit R/W-Providern und Full R/O-Replicas
Der Provider für den Hauptkontext dc=local,dc=site und der Provider für den Subkontext bzw. die Partition dc=offshore (und alles darunter) sind Read/Write angelegt. Der Provider für dc=local,dc=site verwaltet den kompletten DIT bis auf
193
3.2
1198.book Seite 194 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
den Subtree dc=offshore. Beide Master werden in ihrem Bereich des DIT Readonly als Full Replicas repliziert. Kaskadierende Replikation Kaskadierende Replikation – das Verfahren kennen wir aus jeder Firmenhierarchie: Der Anschiss wird vom Boss (Provider) über verschiedene Ebenen (Consumer 1, Consumer 2) von oben nach unten repliziert. Allerdings bleibt in unserem Fall der replizierte Inhalt wenigstens über alle Ebenen exakt gleich, was für die reale Welt wohl kaum zutrifft. Ein möglicher Anwendungsfall wäre z.B. ein räumlich weit auseinanderliegendes Szenario, in dem die Bandbreite zur Anbindung des zweiten Consumers an den Provider unzureichend wäre, die Verbindung zum ersten jedoch schnell genug ist. Das Setup ist mit unseren bereits erworbenen Vorkenntnissen denkbar simpel, daher werden wir es nur kurz anreißen. Unser erster Consumer – ldapslave – (der sich die Daten direkt vom Provider – ldapmaster – holt) muss in unserer Konfiguration sowohl als Consumer (für ldapmaster) als auch gleichzeitig als Provider (für den zweiten Consumer ldapexternal) in Erscheinung treten; wenn wir so wollen, als Bindeglied. Dazu brauchen wir im Minimalfall neben den üblichen syncrepl-Direktiven auf Consumer 1 (ldapslave) lediglich einen zusätzlichen Aufruf des Overlays syncprov: syncrepl
rid=001 provider=ldap://ldapmaster.local.site ... overlay syncprov
Die syncrepl-Konfiguration auf dem externen (zweiten) Consumer (ldapexternal), der als »finaler« Consumer die Daten von unserem ldapslave erhält, ist trivial und entspricht der auf dem ersten Consumer. Theoretisch könnte sogar die Replikations-ID (rid) auf den gleichen Wert gesetzt werden, wie auf unserem ersten Consumer (da ldapslave ein Provider für ldapexternal ist), sollte jedoch zu Debugging-Zwecken einen anderen Wert besitzen. Der Prokurist – »schreibbarer« syncrepl-Consumer Das folgende Setup ermöglicht schreibenden Zugriff auf den Consumer. Schreibenden Zugriff? No way, denn wir befinden uns noch nicht im munteren MultiMaster-Reigen. Daher »schreibbar« auch nur in Anführungszeichen. Wie wir uns denken können, steckt das gute alte Overlay chain hinter dieser Funktionalität, die sich prinzipiell um nichts anderes kümmert, als die völlig transparente Weiterleitung der Modifikations-Requests vom Consumer an den Provider. So ein-
194
1198.book Seite 195 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
fach. Wie wir chain aufsetzen, wissen wir bereits, und auch das syncrepl-Setup sollte keine steigende Pulsfrequenz mehr bei uns hervorrufen. Also kümmern wir uns nur um die nötigsten Dinge: Auf dem Provider wird wie üblich »nur« das Overlay syncprov mit einer sessionlog-Direktive unterhalb der Kontext-DB initialisiert. Auf dem Consumer ist etwas mehr Arbeit angesagt: In der globalen Sektion fügen wir Overlay chain in folgender Konfiguration ein, die wir in der Form schon aus Abschnitt 3.2.3, »Gesprengte Ketten«, kennen: overlay chain-uri chain-idassert-bind
chain-return-error chain-rebind-as-user
chain "ldap://ldapmaster.local.site" bindmethod=simple binddn="cn=ldapadmin,dc=local,dc=site" credentials="linux" mode=self true true
Und unterhalb der syncrepl-Direktiven: updateref
"ldap://ldapmaster.local.site/"
Die updateref-(Update-Referral)-Direktive legt eine LDAP-URI fest, die der Consumer zurückgibt, wenn eine Modifikation seiner Shadow-Datenbank angefordert wird. In unserer Konfiguration zeigt sie natürlich auf den Provider. Über Overlay chain wird dieser Verweis völlig transparent für den User weitergeleitet, so dass der Eindruck entsteht, schreibenden Zugriffs auf den Consumer zu haben. Wie war das noch mit Schein und Sein? Another Brick in the Wall – Proxy Sync-Replikation als slurpd-Ersatz Bevor wir uns nun unseren Kollegen aus der Delta-Force-Spezialeinheit für replikationstechnische Einsätze anschauen, noch ein kurzes Wort zu aktiven und passiven Replikationsmechanismen. Ein minimaler »Vorteil« – wenn wir es mal wohlwollend so nennen wollen – lag bei der Verwendung von slurpd darin, dass er aus Firewall-technischer Sicht der einzige aktive Part der Replikationskette war. In einem Szenario, in dem der Master innerhalb des lokalen Netzes lag und seine Änderungen auf einen Slave im Internet pushen musste, konnten so die Regeln des jeweiligen Paketfilters auf den Traffic in einer Richtung – vom »sicheren« inneren Netz in das unsichere Internet – beschränkt werden. Wie wir wissen, geht der Initial Content Load bei jeder Syncrepl-Variante stets vom Consumer aus. Unter dem Strich kann das bedeuten, wenn wir vom glei-
195
3.2
1198.book Seite 196 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
chen Szenario wie in der Beispielkonfiguration ausgehen (Provider – internes Netz/Consumer – externes Netz) das der Traffic explizit vom äußeren ins innere Netz (refreshOnly) oder in beide Richtungen (refreshAndPersist) freigeschaltet werden muss. Andere Lösungsansätze, was den rein sicherheitstechnischen Aspekt betrifft, existieren zu genüge – ein VPN zwischen Provider und Consumer sei hier nur als eines der möglichen Beispiele genannt. Wollen wir jedoch syncrepl im reinen push-based-Modus nutzen (kaum vorstellbar) bzw. müssen es (schon eher vorstellbar) und wollen gleichzeitig die Nerven des stets nervösen Firewall-Admins schonen (was heutzutage im Hinblick auf die zig getunnelten Applikationen ohne echten Content Filter/Application Layer Gateway wohl ohnehin unmöglich ist), können wir syncrepl so umbiegen, dass der Traffic nur in einer Richtung stattfindet. Erreicht wird das durch einen kleinen Griff in die Backend-Trickkiste. Das ldap-Backend, das wir schon aus den vorangegangenen Kapiteln kennen, kann in einer möglichen Konfiguration z.B. zusätzlich zum normalen Kontext-Backend auf dem Sync-Provider arbeiten. Dabei bildet es als Proxy den gleichen Kontext wie das normale Backend ab und sorgt in Verbindung mit entsprechend konfigurierten syncrepl-Direktiven (stark vereinfacht ausgedrückt) dafür, dass die Änderungen per refreshAndPersist aktiv auf den oder die Consumer gepusht werden. Ein entscheidender Vorteil der Sync-Replikation bleibt bei diesem Setup jedoch wortwörtlich auf der Strecke: Der Initial Content Load muss übersprungen werden, denn diese Variante funktioniert üblicherweise nur, wenn beide Datenbanken (Provider und Consumer) vor dem Start der Replikation – wie in schlechten alten slurpd-Zeiten- manuell auf einen Status quo bezüglich ihrer Datenbank gebracht werden. Ausführliche Informationen mit Beispielen zu diesem Setup finden sich im OpenLDAP Admin Guide: http://www.openldap.org/doc/admin24/replication.html# Syncrepl Proxy
3.2.9
Delta Force – Replikation in Perfektion mit delta-syncrepl
Delta Force – klingt schwer nach Spezialeinheit für kritische Aufgaben, und wenn wir den Begriff in Analogie zu unserem LDAP und insbesondere der Replikation verwenden, trifft das den Kern der Sache ziemlich genau. Denn spezielle Aufgaben erfordern spezielle Lösungen. Einer der wenigen Schwachpunkte, wenn man ihn überhaupt so bezeichnen kann, liegt bei der Standardvariante der Replikation per syncrepl – ebenso wie vormals bei slurpd – darin, dass bei der Modifikation eines Objekts leider alle seine Attribute repliziert werden, selbst dann, wenn nur eines oder wenige geändert wurden. Ineffektiv, aber leider technisch nicht anders lösbar, da syncrepl
196
1198.book Seite 197 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
konzeptionell ein objektbasiertes Replikationsverfahren ist. Die performancetechnischen Auswirkungen, gerade bei sehr großen Datenbeständen, die repliziert werden müssen, liegen auf der Hand. Rein statistisch betrachtet, produziert ein Replikationsvorgang auf dieser Basis normalerweise deutlich über 90 % Overhead, den wir so nötig brauchen wie die neueste Diätenerhöhung unserer stets schwer unterbezahlten und absolut überarbeiteten Abgeordneten. Dazu ein nettes, kleines Rechenexempel aus dem Admin-Guide: Nehmen wir an, wir hätten 100.000 Objekte von jeweils 1 Kbyte Größe in unserem DIT. Nehmen wir weiter an, wir würden einen 16 Bit (2 Byte) Boolean-Attributwert in jedem der Objekte ändern – selbst ohne den LDAP- und TCP/IP-Overhead gerechnet, würden wir 1 GB Daten transferieren, um effektiv 200 Kbyte an Objektänderungen auszutauschen ... ja ne, is klar. Die Delta-Sync-Replikation –-oder kurz: delta-syncrepl – packt dieses Problem gekonnt bei der Wurzel, dem Overhead. Mit Hilfe des Overlays accesslog, das wir im Abschnitt 3.1 über Overlays, »Völlig überlagert«, bereits kennengelernt haben, wird auf dem Provider eine separate Log-Datenbank (Backend-Typ: bdb oder hdb) erstellt, in welcher sämtliche erfolgreichen(!) Modifikationsoperationen über einen definierbaren Zeitraum geloggt werden, und zwar nur die Attributwerte, die effektiv geändert wurden. Beim Initial Content Load (oder wenn der Consumer zu sehr out-of-sync zum Provider ist) erfolgt der Abgleich der Datenbank wie im »normalen« syncrepl-Modus, d.h. alle Objekte werden komplett aus der normalen Kontext-Datenbank repliziert. Im Normalbetrieb arbeitet delta-syncrepl jedoch wesentlich effektiver. Der Consumer erhält hierbei nämlich seine replikationsrelevanten Daten nur noch aus der Log-DB, und nur die dort geloggten »Deltas« – also die tatsächlich erfolgten Änderungen an den einzelnen Attributen – werden in die Consumer-Datenbank übernommen. Der syncrepl-Consumer greift dabei über spezielle syncrepl-Subdirektiven wie logbase und logfilter auf die accesslog-Datenbank des Providers zu, anstatt mit der regulären Datenbank des Providers zu kommunizieren. Dadurch ergeben sich mehrere Vorteile: eine erheblich verbesserte Performance, da ein deutlich geringerer Overhead übertragen wird, eine Entlastung der normalen DB des Providers, da die Replikationszugriffe im Normalbetrieb ausschließlich über die Log-DB erfolgen, und zusätzliche Sicherheit, da die Integrität aller erfolgten Änderungen vor der Replikation mehrfach überprüft wird. Klingt gut? Finden wir auch. Schauen wir uns zunächst die folgende Grafik an, die die delta-syncrepl-Arbeitsweise stark vereinfacht verdeutlicht, bevor wir ans eigentliche Setup gehen:
197
3.2
1198.book Seite 198 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Delta-syncrepl-Consumer
Delta-syncrepl-Provider
Kontext-DB
Initial Content Load
replizierte Kontext-DB
Kontext-DB Modifikation »normaler« delta-syncrepl-Betrieb
log-DB
Abbildung 3.6
Schematische Darstellung delta-syncrepl
Setup delta-syncrepl – Provider: Nun zum Setup, das sich zwangsläufig etwas komplexer gestaltet als in den bisher vorgestellten Replikationsvarianten. Betrachten wir zuerst das Setup des Providers. Hier müssen wir uns in der slapd.conf neben der Initialisierung des accesslog-Overlays zunächst um die Einrichtung einer zusätzlichen Log-Datenbank kümmern, die wir oberhalb der Datenbank unseres Hauptkontextes ansetzen: # Log-DB database suffix directory index index
hdb "cn=logs" /var/lib/deltasynclog objectClass,entryCSN,entryUUID eq reqEnd,reqResult,reqStart,reqMod eq
overlay syncprov syncprov-reloadhint true syncprov-nopresent true # Kontext-DB database hdb suffix ... index
198
"dc=local,dc=site" objectClass,entryCSN,entryUUID
eq
1198.book Seite 199 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Als Database-Backend für die Log-DB verwenden wir hdb. Der Kontext der LogDB wird auf cn=logs gesetzt. Achtung: Wie wir bereits aus dem standalone-Setup des Overlays accesslog wissen, wird von ihm als Kontext nur cn=* akzeptiert. Also Finger weg von dc=* oder anderen DN-Attributen. Aus Sicherheitsgründen sparen wir uns einen rootdn-Zugang, der manuelle Manipulationen der Log-DB gestatten und somit die Integrität der kompletten Replikation gefährden könnte. In diesem speziellen Fall sollte der Zugriff auf die Log-DB immer nur lesend erfolgen. Das Datenbank-Directory (directory /var/lib/deltasynclog) kann wie üblich frei gewählt werden, wir müssen jedoch wieder darauf achten, dass die entsprechenden Rechte und Eigentümer gesetzt sind, damit unser slapd problemlos schreibend darauf zugreifen kann. Auch nicht vergessen, im Produktiveinsatz eine entsprechend konfigurierte DB_CONFIG in diesem Ordner zu platzieren, um die Performance der Log-DB optimal einzustellen. Detaillierte Infos zur DB_ CONFIG finden sich im Abschnitt 3.8, »Larry und die schläfrigen Katzen«. Die letzten Direktiven der Log-DB-Sektion sorgen schließlich für die Indexierung der wichtigsten Attribute. Um die Replikation der Log-DB zu ermöglichen, wird das Overlay syncprov unterhalb des Datenbank-Kontextes der Log-DB zum ersten Mal initiiert, in diesem Fall mit zwei besonderen Einstellungen, die vornehmlich der Delta-SyncReplikation vorbehalten sind: syncprov-reloadhint true
Diese Subdirektive bewirkt, dass syncprov das »Booleansche« reloadHint-Flag im sync Control auswertet. Der Wert TRUE sorgt dafür, dass eine Replica, die zu sehr out-of-date zum Sessionlog des Providers ist (wir erinnern uns: present/ delete-Phase), eine reloadHint-Nachricht erhält und automatisch einen Fallback in den »plain syncrepl«-Status – also die normale syncrepl-Variante- macht, und einen »normalen« Initial Content (re-)Load gegen die DB mit dem Haupt-Kontext fährt. Das Flag muss bei delta-syncrepl immer auf TRUE stehen. Die Subdirektive syncprov-nopresent true
spezifiziert, dass die bereits erläuterte present-Phase des LDAP-Sync übersprungen wird. Dieses Flag muss in der delta-syncrepl-Konfiguration ebenfalls immer auf TRUE gesetzt werden. Betrachten wir nun den Rest der slapd.conf auf dem Provider, beginnend unterhalb der DB unseres Haupt-Kontextes:
199
3.2
1198.book Seite 200 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
# Anweisungen für Kontext dc=local,dc=site: ... # syncprov-Overlay für Kontext dc=local,dc=site: overlay syncprov sessionlog 100 ######################## overlay accesslog logdb cn=logs logops writes logsuccess true logpurge 07+00:00 01+00:00
Die komplette slapd.conf findet sich in den Beispieldaten (http://www.galileocomputing.de/1801) zu diesem Abschnitt. Betrachten wir nun die einzelnen Direktiven für die Log-DB. Ganz wichtig in dieser Konfiguration: Das syncprovOverlay wird zwei(!) Mal initialisiert: das erste Mal für die Log-DB mit den Spezialflags reloadHint und nopresent, das zweite Mal für unseren normalen DBKontext dc=local,dc=site. Mit overlay accesslog wird das Overlay aktiviert, logdb cn=logs gibt den Kontext für unsere accesslog-Datenbank an, die zu loggenden Operationen sollen logischerweise nur writes sein (add/modify/delete), das Ergebnis jeder Modifikation muss erfolgreich sein (logsuccess true), damit ein Eintrag in die Log-DB geschrieben wird, und logpurge definiert – wie bereits bekannt – die Parameter, nach denen alte Einträge gelöscht werden. Die Limits muss jeder Admin selbst entsprechend seiner Konfiguration auswählen (sie sollten nur nicht zu eng gewählt werden). In unserer Beispielkonfiguration haben wir gängige Werte eingesetzt: Das accesslog einmal täglich checken und alle Einträge löschen, die älter als sieben Tage sind. Setup delta-syncrepl – Consumer Das war’s auf der Providerseite, nun zur slapd.conf des Consumers (die Kommentare hinter den Direktiven dienen nur der Verständlichkeit und dürfen nicht übernommen werden): syncrepl rid=1 provider=ldap://ldapmaster.local.site bindmethod=simple binddn="cn=replicator,dc=local,dc=site" credentials=linux searchbase="dc=local,dc=site" schemachecking=on type=refreshAndPersist retry="10 +"
200
1198.book Seite 201 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
logbase="cn=logs" # Start delta-syncrepl-Subdirektiven logfilter="(&(objectClass=auditWriteObject)(reqResult=0))" syncdata=accesslog # Ende delta-syncrepl-Subdirektiven # Updates an den Provider weiterleiten, siehe voriges Kapitel # updateref ldap://ldapmaster.local.site
Die meisten Sub-Direktiven sind uns schon geläufig, also beschränken wir uns auf die delta-syncrepl-spezifischen; als da wären drei: logbase gibt dem Consumer die Searchbase für die Log-DB auf dem Provider an. Der logfilter definiert, nach welchen Objekten innerhalb der Log-DB gesucht wird. Hierdurch findet mittels UND-Verknüpfung eine Prä-Selektion auf zwei Arten statt: Zum einen wird die vom Overlay accesslog mitgebrachte Objektklasse auditWriteObject ausgesiebt, da in der delta-syncrepl-Konfiguration alle Objekte innerhalb der Log-DB ausschließlich zu Objekten gehören, die von auditWriteObject abgeleitet sind. Hier wäre ebenfalls die direkte Anwendung eines Filters objectClass=auditModify möglich. Zum anderen werden mit dem Attribut reqResult nur Einträge von Modifikationen ausgesiebt, die erfolgreich abgeschlossen wurden (Rückgabe-Code: 0). syncdata=accesslog legt schließlich fest, dass das accesslog-konforme Logformat
verwendet wird. Auch bei delta-syncrepl kann frei gewählt werden, wie der Consumer auf die Log-DB des Providers im »normalen« delta-syncrepl-Betrieb zugreift. Sowohl refreshOnly als auch refreshAndPersist sind möglich, hier liegt die Entscheidung beim Admin. Da aber in den meisten Anwendungsfällen der Replikations-Overhead durch das Verfahren bereits minimiert ist, stellt refreshAndPersist üblicherweise die bessere, weil zeitnahe Variante dar. Die letzte, optionale Direktive gibt einen Verweis auf den Provider zurück, sollte ein Client versuchen, schreibend auf den Consumer zuzugreifen. Analysieren wir nun anhand der Modifikation eines Objekts, wie der Replikationsvorgang abläuft. Wir starten zunächst den Provider, vor dem Start des Consumers löschen wir die gegebenenfalls vorhandenen Datenbankdateien unter /var/lib/ ldap/*.*, damit unser delta-syncrepl-System bei seinem ersten Start einen sauberen Initial Content Load fahren kann. Beide slapd’s starten wir im Debug-Level 4. Auf dem Provider nehmen wir eine kleine Modifikation der Mailadresse unseres Kollegen ckent vor und beobachten dabei den slapd-Output des Consumers: ldap_build_search_req ATTRS: reqDN reqType reqMod reqNewRDN reqDeleteOldRDN reqNewSuperior entryCSN ... <= ldap_dn2bv(cn=ldapadmin,dc=local,dc=site)=0 hdb_modify: uid=ckent,ou=verkauf,dc=local,dc=site bdb_modify_internal: replace mail
201
3.2
1198.book Seite 202 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
bdb_modify_internal: replace entryCSN bdb_modify_internal: replace modifiersName bdb_modify_internal: replace modifyTimestamp
Wie wir unschwer erkennen können, erzeugt der Consumer zunächst den entsprechenden ldapsearch-Request, bezogen auf die speziellen Attribute der deltasyncrepl. Anschließend wird die gewünschte Modifikation auf den Consumer repliziert, und zwar »nur« das modifizierte Attribut plus die erforderlichen operationalen Attribute. Minimaler Overhead, maximale Performance und Sicherheit. Und alles auch über die Online-Konfiguration integrier- und administrierbar. Was will man mehr? Okay, okay ... keine Bange – schließlich sind wir ja auch noch nicht fertig, was den fröhlichen Replikationsreigen angeht. Also gehen wir erstmal wieder online ...
3.2.10 Replikation der Online-Konfiguration – Provider/Consumer Replikation der Online-Konfiguration. Klingt doch spitze. Ist es auch, und genau genommen ist es auch das Vorspiel zur Standby-Master/Multi-Master-Replikation. Aber bevor wir loslegen und einfach stur die Konfiguration von einem Provider auf einen oder mehrere Consumer replizieren, sollten wir auf jeden Fall vorab ein klein wenig Hirnschmalz ins Spiel bringen. Warum? Ganz einfach: Würde es – rein theoretisch – wirklich Sinn ergeben, die komplette Konfiguration eines Providers auf einen Consumer zu replizieren? Sofern es sich nicht um ein Standby-Master/Multi-Master-Szenario handelt, wohl kaum – und selbst dort wären Ausnahmen möglich. Typischerweise unterscheiden sich Provider und Consumer schon allein aufgrund der Replikationsdirektiven, zum anderen sind in der Regel auch kontextspezifische ACLs unterschiedlicher Natur, da auf den Consumer nur Readonly zugegriffen wird. Eine Verkettung des Consumers mit dem Provider zu Schreibzwecken über das Overlay chain und/oder update referrals ist natürlich technisch machbar – wie wir in Abschnitt 3.2.8, »Beispielhafte Lösungsansätze mit syncrepl«, gezeigt haben – aber hier muss der Admin selbst entscheiden, ob er schreibende Zugriffe vom Consumer an den Provider weiterleiten möchte. Abgesehen davon verbietet uns schon die reine Logik eine komplette Replikation der Online-Konfiguration (im Folgenden auch »olc« genannt) in einem Provider/ Consumer-Setup. Betrachten wir die Sache im Detail: Würden wir die komplette olc replizieren wollen, müsste der Eintrag der syncrepl-searchbase des Consumers schlicht cn=config lauten. Theoretisch. Denn in der Praxis würde eine komplette Replikation der olc ohne jegliche Einschränkungen auf der Consumer-Seite und ohne bestimmte Vorkehrungen auf der Provi-
202
1198.book Seite 203 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
der-Seite nur zu einem Ergebnis führen: Crash & Burn. Warum das so ist? Ganz einfach: Unser Consumer würde den kompletten(!) Tree der Online-Konfiguration des Providers in sich aufsaugen, mitsamt den syncprov-Overlay-Objekten – was ihm nicht wehtut –, aber auch die kompletten olcDatabase-Kontexte cn=config und dc=local,dc=site, und das kann unser Consumer logischerweise nicht mehr verknusen. Blicken wir zurück auf die Art, wie syncrepl Objekte repliziert: Immer das ganze Objekt*2.Und dadurch wird zwangsläufig bei einer Änderung auch nur eines Attributes das komplette (olcDatabase-) Objekt repliziert, inklusive der auf dem Provider logischerweise nicht vorhandenen, aber auf der Consumer-Seite dringend benötigten olcSyncrepl-Direktiven. Wir sehen: Hier müssen wir mit Bedacht vorgehen Also schauen wir uns den olcTree genau an, und überlegen uns, wie wir mit etwas Hirnschmalz eine sinnvolle Replikation für ein Provider/Consumer-Setup realisieren können. Primär stehen uns für dieses Replikations-Szenario in Anbetracht der vorgenannten Punkte die beiden folgenden Lösungsansätze zur Verfügung: 왘 Der Provider hostet die relevanten Parts der Consumer-olc, sodass diese bei Änderungen an der Provider-Konfiguration den Consumer nicht beinflussen, sondern bei Bedarf separat repliziert werden. 왘 Wir exkludieren die kritischen Bereiche auf der Consumer-Seite per Filter. Wie Letzteres prinzipiell funktioniert, wissen wir schon, allerdings birgt dieses Setup auch einen dicken Nachteil, denn durch die Exkludierung verlieren wir ein gutes Stück Flexibilität. Übrig bleiben würden in der Hauptsache die Bereiche Schema, Global Settings und Frontend, und das ist aus konfigurationstechnischer Sicht herzlich wenig. Bevor wir die beiden oben genannten Lösungsansätze in die Praxis umsetzen, müssen wir natürlich einen Blick auf die Möglichkeiten werfen, die uns Setuptechnisch überhaupt zur Verfügung stehen: 왘 In der ersten Variante werden sowohl Provider als auch Consumer nach dem Setzen aller gewünschten und vor allem erforderlichen Direktiven in der bereits bekannten Art konvertiert. Dieses Modell eignet sich für alle Anwen-
2 Um der unausweichlichen Frage zuvorzukommen: Nein, delta-syncrepl klappt mit der OnlineKonfiguration – zumindest in der verwendeten Version – noch nicht. Bestimmte, für delta-syncrepl unabdingbare Funktionalitäten werden von database config aktuell nicht unterstützt. Aber jetzt mal im Ernst und scharf nachgedacht: Betrachten wir die »Menge« an Objekten in der config-Database und ihre potenzielle Anzahl von Modifikationen, hätte die (wenn mögliche) Anwendung von delta-syncrepl irgendwie schon den Beigeschmack eines applikationstechnischen Overkills.
203
3.2
1198.book Seite 204 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
dungsfälle, setzt jedoch wie üblich eine sorgsame Vorbearbeitung der statischen Konfiguration(en) voraus. 왘 In der zweiten Variante wird der Provider konfiguriert, anschließend konvertiert und der Consumer mit einer Minimal-Konfiguration »from the scratch« gestartet. Nach dem Start saugt der jungfräuliche Consumer in transsylvanischer Tradition den Rest seiner Konfiguration bzw. der Kontexte vom Provider. Dieses Modell eignet sich, um einen Consumer ohne große Vorarbeit an einen laufenden Provider zu hängen. Aber auch in diesem Setup müssen – je nach Umfang der gewünschten olc-Konfigurations-Flexibilität auf dem Consumer – gegebenenfalls bestimmte Vorarbeiten auf dem Provider erledigt werden. 왘 In der dritten Variante startet man sowohl Provider als auch Consumer ebenfalls »from the scratch« mit einer minimalen Konfiguration (LDIF-Datei), die zunächst auf beiden per slapadd offline eingelesen wird. Die Variante bietet die größte Flexibilität, erfordert jedoch auch die meiste nachträgliche Handarbeit. Im folgenden werden wir die beiden ersten Varianten durchspielen. Wie die dritte funktioniert, wissen wir spätestens, nachdem wir dem Consumer der zweiten Variante das Leben eingehaucht haben. Noch ein wichtiger Hinweis an dieser Stelle: Auch bei der Änderung (und damit auch Replikation) bestimmter Werte der Online-Konfiguration, die das Laufzeitverhalten des slapd direkt beeinflussen können – wie z.B. olcToolThreads – ist Vorsicht geboten: Bei Letzterem handelt es sich um einen Parameter, der von der Anzahl der CPUs im jeweiligen System und damit direkt von der Hardware des Hosts abhängig ist.
Zu Variante numero uno: Betrachten wir als Erstes die statischen slapd.conf’s, die wir zur Konvertierung verwenden: Die Replikation unseres bisher verwendeten »Standard«-Kontextes (dc=local,dc=site) soll natürlich beibehalten werden, wir wollen zunächst lediglich die Möglichkeit einbringen, Teile unserer Online-Konfiguration – wie z.B. die globalen ACLs – auf den Consumer zu replizieren. Im Anschluss daran schauen wir uns an, wie wir unseren Provider dazu bringen können, den Host für die syncrepl-Direktiven des Consumers zu spielen. Variante 1: Partielle Replikation mit konvertierter Konfiguration Provider-Setup Wie wir bereits wissen, benötigen wir zur Replikation eines Kontextes auf der Provider-Seite in der jeweiligen DB-Sektion die Einbindung je eines Overlay syncprov. Also verwenden wir folgende statische slapd.conf zur Konvertierung auf der Provider-Seite (hier nur die DB-Sektion mit den wichtigsten Erläuterungen; die komplette Konfiguration befindet sich in den Beispieldateien zu diesem Abschnitt):
204
1198.book Seite 205 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
## Direktiven für die Konvertierung der Online-Konfiguration database config rootdn cn=config rootpw {SSHA}iLwhoppdqOjJ+0HUroiScDJ3cpbOgo4u # syncprov-Overlay zur Replikation der Online-Konfiguration overlay syncprov ################################################################# database hdb suffix "dc=local,dc=site" checkpoint 1024 5 cachesize 10000 rootdn "cn=ldapadmin,dc=local,dc=site" rootpw {SSHA}iLwhoppdqOjJ+0HUroiScDJ3cpbOgo4u directory /var/lib/ldap index objectClass eq # syncprov-Overlay zur Replikation des Haupt-Kontextes overlay syncprov ...
Die Konvertierung starten wir in der bereits hinlänglich bekannten Weise, anschließend stellen wir wie üblich sicher, dass unser slapd nur mit der OnlineKonfiguration (-F) unter slapd.d/ arbeitet. Betrachten wir nach dem Start den cn=config -Kontext per JXplorer, sollte sich uns der DIT der Online-Konfiguration etwa so präsentieren:
Abbildung 3.7 Online-Konfiguration (cn=config) mit zwei syncprov-Overlays nach der Konvertierung
Wie wir unschwer erkennen können, sind auch die syncprov-Overlays für beide Kontexte (config und hdb) sauber eingebunden – zumindest, falls wir mit einer OpenLDAP-Version > 2.4.8 arbeiten. Denn in älteren 2.4.*-Versionen kommt es bei einer Mehrfach-Konfiguration des Overlay syncprov auf dem Provider üblicherweise immer zu einem leichten Schwund, und statt der erwarteten zwei findet sich plötzlich nur ein Overlay syncprov, das z.B. in der Online-Konfiguration
205
3.2
1198.book Seite 206 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
angelegt wurde. Im »Schwund«-Fall würde sich das in der JXplorer-Ansicht daher wie folgt darstellen:
Abbildung 3.8 Fehlendes Overlay syncprov in der config-Sektion nach der Konvertierung (nur OpenLDAP ≤2.4.8)
Wie bereits erwähnt, ist dieser Konvertierungsfehler üblicherweise auf Versionen <= 2.4.8 beschränkt, aber auch das kann uns herzlich egal sein. Entweder führen wir ein Upgrade auf die aktuellste Version durch (was immer der bessere Weg wäre), oder wir bauen das fehlende Overlay in Handarbeit einfach selbst ein, denn das Verfahren benötigen wir früher oder später ohnehin. Hierzu erstellen wir folgendes LDIF (syncprov.ldif): dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config objectClass: olcSyncProvConfig olcOverlay: syncprov
und fügen es per ldapadd unserem Konfigurationskontext hinzu: #> ldapadd –xWD cn=config –f syncprov.ldif
Kurze Anmerkung: Ein konvertiertes Overlay-Objekt enthält üblicherweise zusätzlich noch die strukturelle Objektklasse olcOverlayConfig. Weil wir hier »nur« das Overlay syncprov initiieren wollen, reicht die spezifische Objektklasse olcSyncProvConfig (ebenfalls structural) allemal aus. Consumer- Setup Zurück zu unserer (noch) statischen Consumer-Konfiguration: Entscheidende Direktiven für den Umfang der Replikation unserer Online-Konfiguration sind, wie wir uns unschwer denken können, searchbase, filter und attrs. Über die searchbase können wir – wie bereits bekannt – erzwingen, dass »nur« ein bestimmter Subkontext, z.B. der komplette cn=schema,cn=config –Zweig, repliziert werden würde, also alle Schemas. Konkret würde das (für diesen Fall) bedeuten, das jede Änderung an einem Attribut oder gar das Hinzufügen ganzer Schemas ohne Verzögerung wirksam und direkt auf den Consumer übertragen wird. Wie das genau
206
1198.book Seite 207 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
funktioniert, schauen wir uns in Abschnitt 3.9, »Selbst ist der Admin«, an, denn Modifikationen an Schemas beschränken wir schön artig auf eigendefinierte. Testen wir nun, wie wir die Replikation von der Consumer-Seite aus auf bestimmte Bereiche unserer Online-Konfiguration fixieren können: z.B. die frontend-Konfiguration (olcFrontendConfig) mit ihren globalen ACLs und die globalen Konfigurationsdirektiven der Online-Konfiguration (olcGlobal). Ob wir mit einem bestimmten Filter den gewünschten Effekt erzielen, können wir vorab bequem per ldapsearch vom Consumer aus testen. Hierzu verwenden wir die bereits bekannte ODER-Verknüpfung für Suchfilter: #> ldapsearch -xWD cn=config -b cn=config -h ldapmaster \ "(|(objectClass=olcGlobal)(objectClass=olcFrontendConfig))"
Dieser Filter sollte uns die gewünschten Teilbereiche der Konfigurationsdatenbank liefern, und so können wir im nächsten Schritt die filter- und searchbaseSubdirektiven der syncrepl-Anweisung in der slapd.conf des Consumers vor der Konvertierung wie folgt setzen (die zweite Zeile ist umbrochen): searchbase="cn=config" filter="(|(objectClass=olcGlobal) \ (objectClass=olcFrontendConfig))"
Als Searchbase verwenden wir den höchsten Kontext der config-DB, was kein Problem darstellt, da die Filterung nun über die angegebenen Objektklassen abläuft. Das hat unter anderem auch den Vorteil, dass die Overlay-Objekte nicht stur und unnötigerweise auf den Consumer repliziert werden (die filter-Zeile ist umbrochen): database config rootdn cn=config rootpw {SSHA}iLwhoppdqOjJ+0HUroiScDJ3cpbOgo4u # Replikationsdirektiven für die Online-Konfiguration syncrepl rid=002 provider=ldap://ldapmaster.local.site type=refreshAndPersist retry="5 +" searchbase="cn=config" filter="(|(objectClass=olcGlobal) \ (objectClass=olcFrontendConfig))" bindmethod=simple binddn="cn=config" credentials="linux" ################################################################# database hdb suffix "dc=local,dc=site"
207
3.2
1198.book Seite 208 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
# Replikationsdirektiven für den Haupt-Kontext syncrepl rid=001 provider=ldap://ldapmaster.local.site type=refreshAndPersist retry="5 +" searchbase="dc=local,dc=site" bindmethod=simple binddn="cn=ldapadmin,dc=local,dc=site" credentials="linux"
Ein wichtiger Punkt an dieser Stelle, der die Konvertierung betrifft: Führen wir die Konvertierung des Consumers »online« durch, während der Provider läuft, saugt unser Consumer je nach refresh*-Modus sofort Konfigurationsdaten vom Provider, was eventuell zu Inkonsistenzen führen kann. In der Praxis kann das sogar bei minimalen Zeitdifferenzen zwischen Provider/Consumer unter Umständen dazu führen, dass sich unser Consumer weghängt. Um ganz auf der sicheren Seite zu sein – und weil wir wohl kaum wie zu schlechten alten slurpd-Zeiten jedes Mal den Master/Provider stoppen möchten (und vor allem können!), bevor etwas geändert wird bzw. wir die Konfiguration konvertieren –, greifen wir einfach in unsere kleine Trickkiste: Die bereits erwähnte Offline-Konvertierung per slaptest (hier ohne Pfadangaben): #> slaptest -f
slapd.conf -F slapd.d
-d 1
No running Consumer-slapd, no trouble. Anschließend starten wir den Consumer wie gewohnt explizit mit der Online-Konfiguration (-F slapd.d/) und testen die Replikation. Um die Replikationsvorgänge zu beobachten, eignet sich natürlich Loglevel sync (16384) am besten. Bezogen auf die beiden rid’s (config 002 und Hauptkontext 001) sollten wir die folgende Ausgabe erhalten: do_syncrep2: rid=001 LDAP_RES_INTERMEDIATE - REFRESH_DELETE do_syncrep2: rid=002 LDAP_RES_INTERMEDIATE - REFRESH_DELETE
Modifizieren wir nun die Online-Konfiguration (olcGlobal), indem wir einen neuen, kombinierten loglevel setzen: dn: cn=config changetype: modify replace: olcLogLevel olcLogLevel: stats sync
Die Replikation des neuen loglevel-Attributwertes auf den Slave sollte je nach gewähltem refresh-Mode umgehend erfolgen. Bis hierher alles noch recht simpel, daher schalten wir wieder mal einen Gang hoch ...
208
1198.book Seite 209 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Variante 2: Komplette Replikation mit konvertierter und »from the scratch«Konfiguration Wollen wir die Replikationseinstellungen (olcSyncrepl) unseres Hauptkontextes modifizieren, z.B. um zur Laufzeit aus einer Full-Replica eine partielle zu machen, müssen wir schon etwas tiefer in die Trickkiste greifen. Dabei spielt unser Provider den Host für die syncrepl-relevanten Direktiven des Consumers – keine unüberwindbare Hürde für uns. Was wir aber in diesem Zusammenhang unbedingt berücksichtigen müssen: Die olcSyncrepl-Direktive des olcDatabase={0}config-Subkontextes sollte in einer arbeitenden Replikation nicht modifiziert werden; das hat unser guter alter slapd auf dem Consumer üblicherweise so gern wie das das Ziehen des Netzsteckers – natürlich ohne USV. Das Üble daran: Nach dem Crash, der üblicherweise in die nette Kategorie segmentation fault fällt, bringt auch ein anschließender Restart in der Regel meist wenig – hier hilft dann nur noch, die Consumer-Konfiguration wieder neu zu erstellen bzw. zu konvertieren.
Bei einer vollständigen Replikation des cn=config-Kontextes sollte daher auch die syncrepl-Direktive des Subkontextes olcDatabase={0}config vorzugsweise unan-
getastet bleiben. Wer den Subkontext olcDatabase={0}config per filter-Statement komplett aus der Replikation herausnimmt, ist immer auf der sicheren Seite. Zudem müssen die Attribute dieses Kontextes üblicherweise auch nicht modifiziert werden. Ein anwendbarer syncrepl-Filter hierfür wäre z.B.: filter="(!(olcDatabase={0}config))"
Provider-Setup Das Provider-Setup läuft in diesem Fall exakt so ab wie in der ersten Variante. Allerdings haben wir dieses Mal vor, den (fast) kompletten Konfigurations-Kontext – und damit auch das olcSyncrepl-Attribut – zu replizieren. Also muss der Provider die Direktiven für unseren Consumer hosten (hier nur Auszüge, die kompletten slapd.conf’s finden sich in den Beispieldaten zu diesem Abschnitt). slapd.conf des Providers: referral "ldap://ldapmaster.local.site" #### config –DB Provider #### ############################# database config rootdn cn=config rootpw {SSHA}iLwhoppdqOjJ+0HUroiScDJ3cpbOgo4u ### zusätzliche syncrepl-Direktiven (config-DB) für den Consumer syncrepl rid=002
209
3.2
1198.book Seite 210 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
provider="ldap://ldapmaster.local.site" searchbase="cn=config" filter="(!(olcDatabase={0}config))" type=refresAndPersist ... ### update-referral fuer Modifikationen der config-DB updateref "ldap://ldapmaster.local.site" ### syncprov Overlay fuer die config-DB overlay syncprov ### Kontext-DB dc=local,dc=site database hdb ... ### syncprov Overlay fuer die “normale” Kontext-DB overlay syncprov ... ### zusätzliche syncrepl-Direktiven (Kontext-DB) für den Consumer syncrepl rid=001 provider=ldap://ldapmaster.local.site searchbase="dc=local,dc=site" ... ### optional: update-referral fuer Modifikationen der Kontext-DB updateref "ldap://ldapmaster.local.site"
Wichtig in diesem Setup: Die zusätzlichen syncrepl-Direktiven, sowohl für die Online-Konfiguration als auch für unseren Hauptkontext (dc=local,dc=site) müssen auf dem Provider identische Kopien der Direktiven des Consumers sein; erstere zumindest, insofern der olcDatabase={0}config-Subkontext repliziert werden soll. Das das zum einen nicht erforderlich ist und zum anderen mit ziemlicher Sicherheit schwere Probleme bereiten kann, haben wir bereits in Bezug auf das olcSyncrepl-Attribut des {0}config-Subkontextes hinreichend erörtert. Jedenfalls sorgt die von uns auf Consumer und Provider zusätzlich eingebaute syncrepl-Filter-Subdirektive filter="(!(olcDatabase={0}config))" dafür, dass das Objekt selbst im Fall einer eventuellen Fehlkonfiguration auf dem Consumer nur genau einmal repliziert wird und danach von der Replikation ausgeschlossen ist. Betrachten wir es als eine Art zusätzlichen Sicherheits-Mechanismus, der normalerweise nicht in Kraft tritt, wenn der Filter schon auf dem Consumer korrekt gesetzt ist. Die updateref-Direktiven unter den syncrepl-Direktiven sorgen dafür, dass sich der Provider nicht irrigerweise für einen shadow-Kontext hält und weiterhin modifziert werden kann. Zudem können wir so bequem »schreibend« auf unseren Consumer zugreifen.
210
1198.book Seite 211 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Noch ein wichtiger Hinweis zur referral/updateref-Direktive: Wenn wir sowohl bei der Konvertierung als auch beim Start den slapd unseres Providers nicht explizit per zusätzlicher Host-Option (-h) //slapd <-optionen> -h ldap://ldapmaster.local.site
an seinen eigenen, voll qualifizierten Hostnamen binden, kann es zu Problemen bei der internen Auswertung der referrals kommen. Nach einer Konvertierung ohne die HostOption erblicken wir spätestens beim Neustart die folgende fröhliche Fehlermeldung: olcMirrorMode: value #0: database is not a shadow config error processing olcDatabase={1}hdb,cn=config: database is not a shadow
Haben wir die Konvertierung korrekt vollzogen, den Neustart jedoch ohne Host-Option abgewickelt, enden alle modify-Operationen lediglich mit einem traurigen Verweis auf den referral, den unser slapd nicht auflösen kann.
Consumer-Setup Betrachten wir zunächst der Einfachheit halber das Setup mit einer konvertierten slapd.conf des Consumers. Die Konfiguration der slapd.conf ist hierbei absolut identisch zu der des Providers. Richtig gehört. Wir merken schon – langsam geht’s in Richtung Standby-/Multi-Master und config from scratch. Auch hier erledigen wir die Konvertierung des Consumers wieder bequem per slaptest »offline«, anschließend starten wir den Consumer wie üblich explizit mit der olc und replizieren fleißig vor uns hin. Exkurs: Scratch it up – Consumer-Setup in Handarbeit Hierzu benötigen wir auf der Consumer-Seite eigentlich so gut wie gar nichts außer den Datenbank-Ordnern für die Kontexte und einer kleinen LDIF-Datei, die unserem Consumer sagt, wo er was saugen soll. Klingt einfach? Ist es auch. Hierfür verwenden wir die nachstehend gelistete LDIF-Seed-Datei (olcbase-consumer.ldif), die eine Replikation des Subkontextes olcDatabase={0}config von vornherein ausschließt. Das Wie und Warum der Exkludierung dieses Subkontextes wurde in den vorangegangenen Abschnitten hinlänglich erörtert. (In der Datei auf die Einrückung der olcSyncrepl-Folgezeilen achten!) dn: cn=config objectClass: olcGlobal cn: config dn: olcDatabase={0}config,cn=config objectClass: olcDatabaseConfig olcDatabase: {0}config olcRootPW: {SSHA}iLwhoppdqOjJ+0HUroiScDJ3cpbOgo4u
211
3.2
1198.book Seite 212 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
olcSyncRepl: rid=002 provider="ldap://ldapmaster.local.site" binddn="cn=config" bindmethod=simple credentials="linux" searchbase="cn=config" filter="(!(olcDatabase={0}config))" type=refreshAndPersist retry="10 +"
Nachdem wir das LDIF per #>slapadd -F slapd.d -n 0 –l olcbase-consumer.ldif
eingepflegt haben (Pfadangaben müssen gegebenenfalls ergänzt werden), starten wir den Consumer und beobachten ihn bei der Arbeit. Nach dem Initial Content Load sollte der Consumer komplett synchronisiert sein. Durch die sowohl auf dem Provider gehostete als auch in der Seed-Datei vorhandene Filter-Direktive filter="(!(olcDatabase={0}config))" ist der olcDatabase={0}config-Kontext in jedem Fall von der Replikation ausgeschlossen. So viel zum Thema »Setup from the Scatch«. Und wer partout nicht die Finger davon lassen kann: Die Seed-LDIFs für eine reine Konfiguration from the scratch, sowohl auf dem Provider als auch auf dem Consumer, liegen in den Beispieldaten zu diesem Abschnitt: http://www.galileocomputing.de/1801. Fazit und Debugging-Ansätze: 왘 Die Bereiche schema, global, frontend lassen sich problemlos ohne zusätzliche Modifikationen auf der Providerseite replizieren. 왘 Es werden bei Änderung eines olcAttributes gemäß syncrepl-Spezifikation (normaler, nicht delta) immer die GESAMTEN Attribute des Objekts repliziert, daher ist eine »doppelte« config für den syncrepl-consumer auf der Providerseite nötig. Delta-syncrepl kann nicht verwendet werden, da die configdatabase dies derzeit nicht unterstützt. 왘 Bei Fehlfunktionen in jedem Fall als Erstes die Zeitsynchro kontrollieren. 왘 Eine komplette Replikation der Konfiguration (wenn Subkontexte repliziert werden sollen, in denen syncrepl-Direktiven vorkommen) benötigt eine zusätzliche syncrepl-Konfiguration auf der Providerseite mit zusätzlichen Update-Referrals und globalem Referral. 왘 Der Provider muss im oben genannten Anwendungsfall mit seinem Full Qualified Hostname (-h ldap://ldapmaster.local.site) konvertiert werden, da sonst aufgrund der Referrals der config-Kontext unvollständig bzw. fehlerhaft erstellt wird. Eine typische Fehlermeldung wäre die in dem entsprechenden Abschnitt beschriebene. 왘 Wenn der slapd nach erfolgreicher Konvertierung (siehe oben.) auf der Kommandozeile nicht mit der vollen Hostname-Direktive (-h) gestartet wird, kann es vorkommen, dass updaterefs und andere Direktiven, die von einer exakten
212
1198.book Seite 213 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Namensauflösung abhängen, nicht greifen (typisch: referral-bezogene Fehlermeldungen). 왘 Bei einem bereits laufenden Provider sollte der Consumer stets offline per slaptest konvertiert und der olcDatabase={0}config-Kontext per Filter aus der Replikation exkludiert werden. 왘 Werden sowohl Provider als auch Consumer für eine komplette config-Replikation konvertiert, sollten beide slapd.conf’s möglichst identisch sein. 왘 Bei der Modifikation des frontend-Subkontextes können Replikationsfehler auftreten, wenn globale ACLs auf den involvierten Servern unterschiedlich gesetzt sind. 왘 Das LastMod-Flag (olcLastMod) muss für syncrepl immer auf TRUE gesetzt sein (Default). Dadurch kümmert sich unser slapd automatisch um die Aktualität der operational Attributes (modifiersName, modifyTimestamp, creatorsName, createTimestamp) und um entryCSN und entryUUID. Ein gutes Stück Arbeit bis zu diesem Punkt, aber mit unseren frisch erworbenen Kenntnissen besitzen wir nun alle Voraussetzungen, um ein brandneues Kapitel im OpenLDAP-Universum aufzuschlagen zu können: Die Standby-/Multi-MasterReplikation.
3.2.11
Bäumchen, wechsle dich: Standby-/Multi-Master-Replikation
Geht das? Nö. Unsere kurze Antwort auf genau diese immer gleich lautende Frage der Admins, mit denen wir in den vergangenen Jahren im Rahmen von Trainings, Workshops oder Beratungen zusammengearbeitet haben, musste zwangsläufig stets so kurz und eindeutig ausfallen. Na prima, aber was genau soll denn nun eigentlich funktionieren? Oder eben nicht? Die Beschreibung der Problematik ist trivial, die zugehörige Lösung war es bis zum Release von OpenLDAP 2.4 keineswegs: Die Frage drehte sich immer konkret um die Implementation einer einfachen, vollautomatischen Failover-Konfiguration, bei der ein LDAP-(Slave oder Consumer)-Server im Bedarfs- bzw. Fehlerfall ohne Umschweife die Funktion des Masters/Providers übernehmen kann. In Versionen <=2.3 (hierbei lassen wir Version 2.1 mal schön außen vor, bei der die damals extrem experimentelle Multi-Master-Replikation zwar für eine Schrecksekunde aufgetaucht, jedoch Gott sei Dank schnell wieder in der Versenkung verschwunden war) war es ohne mittelschwere Nervenzusammenbrüche, gigantische Verrenkungen, skriptbasierte Workarounds und oft genug auch zusätzliche manuelle Intervention nahezu unmöglich, die Slaves im zeitkritischen
213
3.2
1198.book Seite 214 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Ausfall-Fall automatisch zu einem Master zu machen. Auch der Einsatz einer HALösung (High Availability = Hochverfügbarkeit) wie Heartbeat brachte an diesem Punkt wenig, weil die Umschaltung der Nodes sicherlich funktionierte, es jedoch einfach keine direkte Möglichkeit der automatischen Konversion bzw. Promotion eines Slaves in einen Master gab. Und selbst ohne Zeitdruck und manuelle Intervention dauert es seine Zeit, bis man aus einem Slave/Consumer den neuen Master/Provider gemeißelt hatte. In den konkreten Fällen handelte es sich oft genug um LDAP-Datenbanken großer und zum Teil auch internationaler Unternehmen im Gigabyte-Bereich, bei denen 24/7-Betrieb und somit Hochverfügbarkeit zwingende Vorgabe war und ist. Sie alle sollten jetzt tief durchatmen können – aber auch die, die zwar kleinere, aber dennoch stets redundant verfügbare LDAP-Datenbanken benötigen, denn die Zeit der Frickelei ist nun vorbei: zumindest, was OpenLDAP und einen ausfallssicheren Standby-Master oder auch Mirror angeht ... Mirror? Mirror, mirror on the Wall… Standby-Master, Multi-Master, Mirror-Mode – verschiedene Namen für ein und dasselbe Prinzip in verschiedenen Anwendungsfällen. Prinzipiell geht es hierbei jedoch immer nur um eine Sache: Ausfallsicherheit bzw. Redundanz. Und sorry für die wiederum geänderte Terminologie: Genau genommen müssten wir von einem Standby-/Multi-Provider-Setup sprechen, aber da die OpenLDAPCrew in diesem Kontext den Begriff Master verwendet, werden wir der Terminologie natürlich folgen. Wie wir bereits im Exkurs über Multi-Master-Replikation in Abschnitt 3.2.1, »Warum man LDAP-Datenbanken replizieren sollte«, eingehend erörtert haben, dreht es sich bei einer Standby-/Multi-Master-Konfiguration keinesfalls um eine Art Lastverteilung (Load-Balancing), sondern immer »nur« um Hochverfügbarkeit – die je nach Variante mit einer Erhöhung des Netzwerktraffics einhergeht. OpenLDAP bietet seit Version 2.4 die Möglichkeit, eine oder mehrere identische Kopien eines Master-Servers zu erstellen und diese als Standby- oder Multi-Master-Varianten zu betreiben. Insofern wir nicht nur unseren eigentlichen Hauptkontext (dc=local,dc=site) »spiegeln« wollen, was recht trivial ist, muss natürlich auch die Online-Konfiguration unseres slapd repliziert werden. Die Funktionsweise der dafür benötigten Replikationsmechanismen haben wir bereits im letzten Abschnitt über die Replikation der config-Datenbank kennengelernt und ausführlich behandelt. Im den folgenden Abschnitten werden wir uns die verfügbaren Varianten anschauen, und analysieren, welche sich für welchen Einsatzzweck am besten eignet.
214
1198.book Seite 215 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Zunächst: Die Begriffe Mirror-Mode und Standby-Master implizieren ein- und dasselbe: Hot-Standby. Bei diesem Setup geht es darum, dass in einem DIT nur genau ein Master existiert – absolut konform zu den X.500-Standards Der einzige Unterschied zu einem »normalen« Single-Master-Szenario: es existiert zudem ein zweiter Master, der völlig identisch zum ersten »Betriebs«-Master ist. Und jede Änderung am Haupt- und Konfigurations-Kontext des »Betriebs«-Masters wird auf seine schlafende Kopie repliziert. Wichtig dabei: Die Clients und Consumer greifen im Normalbetrieb immer nur auf den Betriebsmaster zu. Sein Zwillingsbruder schläft den Schlaf der Gerechten und wird erst dann aktiv, wenn der Betriebsmaster aus irgendeinem Grund offline geht. Zwingende Voraussetzung für dieses Szenario ist natürlich eine Cluster-Software (wie z.B. Heartbeat in einem Active/Passive-Setup), die den Zugriff auf die identischen Master per Service-IP so regelt, dass sich für die Clients immer nur der Betriebsmaster im schreibenden Zugriff befindet. Im Fehlerfall sorgt Heartbeat dann dafür, dass der neue Spielmacher so schnell von der Ersatzbank eingewechselt wird, dass die Zuschauer davon rein gar nichts mitbekommen. Wird der ursprüngliche Master wieder in Betrieb genommen (als schlafende Kopie, denn ein Auto-Failback auf den »alten« Master würde nur einen zusätzlichen Clusterschwenk und somit zusätzliche Transitionen erzeugen), erfolgt ein automatischer Abgleich aller geänderten Inhalte seit seinem Ausfall. Extrem wichtig beim Standby-Master-Szenario: Es sollte immer sichergestellt sein, dass im »Normalbetrieb« kein administrativer Zugriff auf den Standby-Master erfolgen kann, damit seine Konfiguration immer dem des aktiven Masters entspricht, und nicht umgekehrt. Zudem sollte durch redundante Verbindungen zwischen den Servern sichergestellt sein, dass keine Split-Brain-Situation entstehen kann: Die Leitung zwischen den Servern ist getrennt/die Kommunikation ist gestört; jeder Server denkt, das der andere offline ist und hält sich für den aktiven Part des 2-Node-Clusters.
Um nun niemanden im Regen stehen zu lassen, werden wir, nachdem wir uns zunächst das slapd-spezifische Setup der Multi-Master Variante zur Brust genommen haben, eine einfache Standby-Master/Heartbeat-Konfiguration mit zwei Nodes in einem Active/Passive-Setup beschreiben, die als Ausgangsbasis für fortgeschrittenere Standby-Master-Szenarien dienen kann. Im folgenden Abschnitt beschreiben wir zunächst die Konfiguration mit zwei gleichberechtigten Master-Servern in einem 2-Node-Multi-Master-Setup. Diese Konfiguration lässt sich natürlich auch 1:1 als Standby-Master-Setup verwenden; der einzige Unterschied besteht darin, dass im Multi-Master-Setup nicht nur auf einen der Master (den »Betriebs-Master«) schreibend zugegriffen werden kann, sondern eben auf alle an der Replikation beteiligten Master, die logischerweise in dem Fall über ihre eigenen IPAdressen/Hostnamen erreichbar sind.
215
3.2
1198.book Seite 216 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
3.2.12
Double trouble? N-Way/Multi-Master-Replikation
Wie gerade erwähnt, starten wir nun mit dem konkreten Setup von zwei identischen Master-Servern, das sowohl für eine typische Multi-Master-Konfiguration mit 2-n Servern als auch für eine Standby-Master-Konfiguration verwendet werden kann. Dabei wollen wir uns nicht lange mit der Multi-Master-Replikation (im Folgenden auch als »MMR« bezeichnet) des Hauptkontextes aufhalten, da für diesen trivialen Fall neben den syncrepl-spezifischen Settings ohnehin nur zwei zusätzliche Direktiven (ServerID, MirrorMode) auf beiden Servern benötigt werden. Wir packen die Sache daher konsequent an und replizieren sowohl den Haupt-Kontext als auch den Konfigurationskontext – und das in beide Richtungen. Im Kern also das typische Mirror-Mode-/Standby-Master-Setup, nur dass in diesem Fall keine Cluster-Software den Zugriff auf einen einzelnen Master limitiert und der administrative bzw. schreibende Zugriff jederzeit auf beide Server erfolgen kann. Im Detail: Jede Änderung – sowohl am eigentlichen Kontext als auch am Konfigurationskontext – wird auf den jeweils anderen Master repliziert. Somit wird auch schnell klar, dass diese Variante zwar Redundanz bietet, da jeder Client im Fehlerfall immer noch auf den zweiten aktiven Master schreibend zugreifen kann – aber der Traffic erhöht sich mit jedem zusätzlichen Master um einen exponentiellen Wert, da sich jeder beteiligte Master bei jeder Änderung mit jedem anderen Master abgleichen muss. Wir sehen also: Mehr ist hier nicht mit besser gleichzusetzen. Daher sollte in einem Produktivumfeld die Zahl der aktiven Master immer so klein wie möglich gehalten werden; die effektivste, sicherste und vor allem den Standards folgende Variante ist und bleibt der Mirror-Mode mit zusätzlichen Readonly-Replicas. By the way: Der numerische ServerID-Bereich (siehe nächste Seite) ermöglicht im Multi-Master-Setup insgesamt 4096 identische, schreibbare Kopien. Eine grobe Vorstellung davon, wie das Geschnatter zwischen n-Servern dann hypothetisch aussehen könnte, geben wir am Ende des nächsten Abschnitts. Zum Setup: Als zweiten Master verwenden wir unseren alten Bekannten ldapslave; zuvor sollten wir jedoch seine vorhandenen DB-Dateien ins Nirwana aller Bits jagen. Wie im letzten Abschnitt über die Replikation der Online-Konfiguration haben wir auch hier bei der Erstellung unserer Serverkonfiguration die Wahl zwischen einer Konvertierung der slapd.conf oder einer Erstellung from the scratch per Seed-LDIF. Betrachten wir zunächst die Konvertierung. Die dazu verwendete slapd.conf findet sich in den Beispieldaten zu diesem Abschnitt, und entspricht in weiten Teilen der Konfiguration aus Abschnitt 3.2.10, »Replikation der Online-Konfiguration«, Variante 2. Schauen wir uns nur die wichtigsten Änderungen an:
216
1198.book Seite 217 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
ServerID 1 "ldap://ldapmaster.local.site" ServerID 2 "ldap://ldapslave.local.site" ### config –DB database config ... ### 2 syncrepl-Direktiven (config-DB) – 1 für jeden Server syncrepl rid=3 provider="ldap://ldapmaster.local.site" searchbase="cn=config" filter="(!(olcDatabase={0}config))" ... syncrepl rid=4 provider="ldap://ldapslave.local.site" searchbase="cn=config" filter="(!(olcDatabase={0}config))" ... ### schreibenden Zugriff auf Config-Kontext der Replica erlauben MirrorMode on ### syncprov Overlay für die config-DB overlay syncprov ######################################################### ### Kontext-DB dc=local,dc=site database hdb ... ### syncprov Overlay für die “normale” Kontext-DB overlay syncprov syncprov-sessionlog 100 ### syncrepl-Direktiven des Haupt-Kontextes syncrepl rid=1 provider="ldap://ldapmaster.local.site" searchbase="dc=local,dc=site" ... syncrepl rid=2 provider="ldap://ldapmaster.local.site" searchbase="dc=local,dc=site" ... ### schreibenden Zugriff auf Haupt-Kontext der Replica erlauben MirrorMode on
Die wichtigste Änderung bzw. Ergänzung zuerst: Wie wir bereits aus der Replikation der kompletten Online-Konfiguration wissen, benötigen wir für jeden aktiv an der Replikation beteiligten Server eine syncrepl-Anweisung. In diesem konkreten Fall also exakt zwei syncrepl-Statements für ldapmaster und ldapslave pro Kontext, da beide Server jeweils die komplette Replikations-Konfiguration hosten und gegenseitig schreibend aufeinander zugreifen dürfen. Das Gleiche gilt natür-
217
3.2
1198.book Seite 218 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
lich für den Hauptkontext, was also bedeutet: Jeder Master besitzt neben den syncrepl-Direktiven, die auf alle anderen Server zeigen, auch immer eine syncrepl-Direktive, die auf ihn selbst zeigt. Wichtig hierbei sind natürlich eindeutige Replica-IDs. Nun zu den zwei Kern-Direktiven, die die Multi-Master-Replikation überhaupt ermöglichen: Über die ServerID-Direktive (global) erhält jeder der beteiligten Server eine eindeutige, ganzzahlige ID, über die er identifiziert werden kann. Der zweite Parameter der ServerID-Direktive beinhaltet die komplette LDAP-URL des Servers, über die er angesprochen wird. Die Boolean-Direktive MirrorMode on (database) versetzt die Datenbank der Replica in den MirrorMode, wodurch schreibender Zugriff (je nach ACL) durch jeden User ermöglicht wird, nicht nur durch den updatedn. Da im Fall des Standby-/Multi-Master-Setups jeder Master auch gleichzeitig eine Replica ist, ist die Direktive zwingend erforderlich. Wichtig hierbei: würden wir nur mit einer »normalen« MirrorMode-Konfiguration (2 Server) arbeiten, in der lediglich der Hauptkontext gespiegelt werden soll, würden die beiden Direktiven ServerID <Wert> MirrorMode on
# Eine ID pro Server, ohne LDAP-URL # pro DB-Sektion
vollkommen ausreichen. Ohne Angabe der LDAP-URL ist ohnehin nur eine (1) ServerID-Direktive pro Server zulässig. Sind jedoch – wie z.B. im Fall einer Multi-Master-Replikation – zwei oder mehr Server aktiv an der Replikation beteiligt (deren Konfigurationskontext ebenfalls repliziert wird), sollten auf jedem beteiligten Server unbedingt alle(!) involvierten Server mit ihren ServerIDs und LDAP-URLs eingetragen werden. Nur so kann jedem Server jederzeit eine eindeutige ID exakt zugeordnet werden, und Probleme mit gegebenenfalls inkonsistenten CSNs werden so bereits im Vorfeld vermieden.
Wie in den vorangegangenen Beispielen zur Replikation der Online-Konfiguration sollte auch hier ein Filter zur Exkludierung des olcDatabase={0}config-Kontextes angewendet werden. Die slapd.conf unseres zweiten Masters (ldapslave) ist eine exakte Kopie der eben vorgestellten. Nachdem wir die Zeitsynchro auf beiden Maschinen noch einmal exakt überprüft und die Konfiguration in der nun hinlänglich bekannten Weise per slaptest konvertiert haben, wird es ernst. Wir starten beide Maschinen aus-
218
1198.book Seite 219 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
schließlich mit der Online-Konfiguration (-F) und im debug-Level sync, dann legen wir mit unserer Crossover-Replikation los. Sollten Probleme auftauchen, geht’s wie üblich an’s Debugging: 왘 Zeitabgleich genau kontrolliert bzw. durchgeführt? 왘 Identische, statische Konfiguration auf beiden Maschinen konvertiert? 왘 syncprov-checkpoint-Direktive in der overlay-Konfiguration verwendet? (Siehe den Hinweis für ältere OpenLDAP 2.4-Versionen in Abschnitt 3.2.7, »syncrepl«) 왘 Unterschiedliche RIDs für alle syncrepl-Direktiven auf einer Maschine verwendet? 왘 ServerIDs und LDAP-URLs korrekt gesetzt? Taucht der Fehler CSN too old, ignoring in den Replikations-Logs trotz absolut korrekter Zeitsynchronisation auf, ist Vorsicht angesagt. Der Bug tritt vereinzelt auf und kann im ungünstigten Fall dazu führen, dass Objekte – obwohl sie es sollten – nicht repliziert werden. Der Fehler ist dann in OpenLDAP-Versionen <= 2.4.12 sehr wahrscheinlich in der Datei ctxcsn.c (Revisionen < 1.51) zu finden. Für Version 2.4.12 existiert ein Patch, der hier zu finden ist: http://www.openldap.org/devel/cvsweb.cgi/servers/slapd/. In neueren Versionen wird der Patch direkt in den Source einfließen. Ein temporärer Workaround kann gegebenenfalls über den Reset der contextCSN auf den betroffenen Mastern erzielt werden. Über das explizite Setzen der CSN per slapd -c rid=,csn=0 wird, vereinfacht ausgedrückt- ein kompletter DB-Reload von der Gegenstelle für den jeweiligen Kontext initiiert.
Schauen wir uns nun noch das Setup from the scratch an, das ebenfalls keine große Hürde mehr für uns darstellen sollte. Zur Initialbefüllung per slapadd verwenden wir auf beiden Maschinen folgendes LDIF (olcbase-mmr-initial.ldif), das nur die wichtigsten Settings enthält: dn: cn=config objectClass: olcGlobal cn: config olcServerID: 1 ldap://ldapmaster.local.site olcServerID: 2 ldap://ldapslave.local.site dn: olcDatabase={0}config,cn=config objectClass: olcDatabaseConfig olcDatabase: {0}config olcRootPW: linux olcSyncRepl: rid=1 provider="ldap://ldapmaster.local.site" binddn="cn=config" bindmethod=simple credentials="linux"
219
3.2
1198.book Seite 220 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
searchbase="cn=config" filter="(!(olcDatabase={0}config))" type=refreshAndPersist retry="10 +" olcSyncRepl: rid=2 provider="ldap://ldapslave.local.site" binddn="cn=config" bindmethod=simple credentials="linux" searchbase="cn=config" filter="(!(olcDatabase={0}config))" type=refreshAndPersist retry="10 +" olcMirrorMode: TRUE dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config objectClass: olcSyncProvConfig olcOverlay: syncprov
Den Import erledigen wir in bekannter Weise (hier ohne Pfadangaben) per: #> slapadd -F slapd.d -n 0 -l olcbase-mmr-initial.ldif
Alle weiteren Settings erfordern ab hier natürlich Handarbeit bzw. die entsprechenden LDIFs. Für jeden weiteren Server wären in dem o.a. LDIF lediglich je eine zusätzliche Direktive mit der olcServerID (mit LDAP-URL!) sowie eine entsprechende olcSyncrepl-Direktive erforderlich.
3.2.13 Traumhafte Nachtruhe dank Schläfer – Hot-Failover mit Standby-Master und Heartbeat Kommen wir nun zum »echten«, dem ursprünglichen Einsatzgebiet des »MultiMaster«-Modes: dem voll X.500-konformen Standby-Master. Wie wir bereits wissen, ist das Standby-Master-Setup absolut identisch zu dem gerade durchgeführten Multi-Master-Setup mit zwei Nodes bzw. aktiven Servern, nur dass wir jetzt einem unserer Master-Server per Heartbeat friedliches Däumchendrehen verordnen. Zumindest so lange, bis sein Kollege eine störungsbedingte Verschnaufpause braucht. Auf die slapd-Konfiguration müssen wir daher nicht mehr eingehen. Der entscheidende Part liegt nun bei der Heartbeat-Konfiguration, und um die grundlegendsten Basics dazu kümmern wir uns jetzt. Heartbeat-Mini-Basics Hochverfügbarkeit – was bedeuten denn eigentlich die ganzen 99, irgendwas Prozent (Hoch-)Verfügbarkeit, die uns irgendwelche Reseller oder Consulter andauernd versprechen? Pro Jahr gerechnet, entsprechen 99,9 % beispielsweise einer Downtime von grob gerechnet 9 Stunden, 99,9999 % hingegen nur noch einer Downtime von rund 30 Sekunden. Wir sehen schon, auch ein paar kleine Nachkommastellen können einen mächtig großen Unterschied machen.
220
1198.book Seite 221 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Was soll mit Heartbeat erreicht werden? Redundanz, klar. Und die beginnt schon bei Einzelkomponenten wie Festplatten, Netzwerkkarten oder Netzteilen. Jede Komponente, die hohen Belastungen unterworfen ist und keinesfalls den Geist aufgeben darf, muss in Produktiv-Serverumgebungen redundant ausgelegt sein. Lokale Platten lassen sich einfach per Hard- oder Softraid zu einem einfachen Level1-Raid (Mirror) zusammenfassen, zwei oder mehr Netzwerkkarten sorgen für Konnektivität auch beim Wegfall einer Verbindung, und weitere redundante Komponenten runden die Gesamtredundanz des Einzelsystems ab. Aber irgendwann stößt jede lokal redundant ausgelegte Hardware an ihre Grenzen. Spätestens dann, wenn Mainboard, CPU und/oder RAM ihren Geist aufgeben oder sich der Server dank höherer Gewalt wie Naturereignissen und/oder unüberlegter menschlicher Interaktion komplett verabschiedet, wobei die Trennlinie zwischen den beiden Aspekten hier und da fließende Übergänge zeigt. Und noch ein Aspekt kann dem Standalone-Server den Garaus machen, und zwar auf Software-Ebene. Ist der Prozess, der zur Kernaufgabe des Servers gehört, so festgefressen, dass er ohne Reboot des Systems nicht wiederzubeleben ist, stehen wir ebenfalls dumm da. Und das ist nur eine sehr schmale Palette der möglichen Ereignisse, die den Betrieb unserer Systeme stören können. Wir sehen also: Lokale Redundanz, bezogen auf einen Server, ist ein guter Ansatz, aber mit Sicherheit nicht die finale Lösung für hochverfügbare Produktivumgebungen. Ohne eine im Idealfall räumlich getrennte zweite (oder dritte bis n-te) Maschine, die im Fehlerfall der ersten für sie einspringen kann, haben wir ein Problem. Hochverfügbarkeit beginnt bei redundanten Einzelkomponenten und endet frühestens bei redundanten, physikalischen Servern. Geht es darum, bestimmte Services ausfallsicher zu machen, müssen wir zunächst analysieren, ob diese Services nicht schon selbst für die Replikation ihrer Daten sorgen. Typische Beispiele hierfür wären MySQL, DNS und natürlich LDAP. Apache oder Samba 3 wären beispielweise hingegen Fälle, die das in der Regel nicht selbst erledigen. Als Lösungsansatz zur Replikation/Synchronisation dieser Daten über redundante Server könnte hier DRBD (=Distributed Replicated Block Device, auch als Netzwerk-Raid [Level 1] bekannt) eingesetzt werden, oder im allersimpelsten Fall ein Abgleich der Datenbestände per cron und rsync erfolgen. Allerdings löst dies auch nur das Problem der reinen Datenverfügbarkeit – eine applikationsbezogene Hochverfügbarkeit erreichen wir nur in Verbindung mit einer entsprechenden Cluster-Software wie z.B. Heartbeat. Eine session-spezifische Hochverfügbarkeit bei bestehenden persistenten Verbindungen hingegen stellt uns noch vor ganz andere Problematiken, die jedoch alleine schon ein ganzes Buch füllen können.
221
3.2
1198.book Seite 222 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Schauen wir zunächst, was Heartbeat überhaupt ist, und anschließend, wie uns Heartbeat bei der Hochverfügbarkeit unseres Standby-Master-Setups helfen kann. Das Linux-HA-Projekt (HA = High Availability = Hochverfügbarkeit) (www.linuxha.org) entstand bereits 1997, der erste Heartbeat-Cluster ging 1998 in Betrieb. Bis 2005 unterstützte Heartbeat nur Version 1-kompatible Installationen, die dann folgende Version 2 hob mit Einführung des CRM (Cluster Resource Manager) etliche der vorhandenen Einschränkungen auf und erweiterte Heartbeat um viele dringend benötigte Features, wie z.B. integrierte Ressourcenverwaltung und -überwachung auf Basis des CRMs sowie die Möglichkeit zur Definition komplexerer Abhängigkeiten/Bedingungen für Ressourcen (constraints). Mit Pacemaker (www.clusterlabs.org) entstand 2007 ein Spin-Off des Heartbeat-Projekts, unter dem nun die alleinige Weiterentwicklung des CRM und des zugehörigen GUI erfolgt. ... Proof of Life Heartbeat läuft typischerweise in einem 2- oder n-Server-Cluster als Dienst auf jedem der Server (»Nodes«), wobei sich die Nodes des Heartbeat-Clusters gegenseitig auf Lebenszeichen – ihren »Herzschlag« – überwachen. Dabei sind klassische Active/Passive-Szenarien möglich, bei denen der zweite, inaktive (und service-technisch identisch zum ersten konfigurierte) Node im Fehlerfall für ihn einspringt, oder auch Active/Active-Szenarien mit (vereinfacht ausgedrückt) zwei aktiven Nodes, die jedoch gegebenenfalls unterschiedliche Ressourcen verwalten. In unserem Setup werden wir uns auf die klassische Active/Passive-Variante beziehen. Zudem unterstützt Heartbeat die Überwachung und Verwaltung von Ressourcen, womit üblicherweise Services bzw. Dienste gemeint sind. Die Überwachung und Steuerung dieser redundant ausgelegten Dienste obliegt bei einem Heartbeat-Cluster logischerweise nicht mehr dem (Init-)System, sondern Heartbeat selbst. Die Überwachung und Steuerung der Services erfolgt dabei über so genannte Resource Agents: dies können einfache LSB (Linux Standard Base)-kompatible Init-Skripte sein (z.B. die Skripte unterhalb von /etc/init.d/, die auch im Normalbetrieb für die Kontrolle eines Dienstes zuständig sind) oder komplexere OCF (Open Cluster Framework)-Agenten, die eine erweiterte Funktionspalette mitbringen. Kommt es nun zu einem Fehlerfall, kann – je nach Konfiguration – zunächst versucht werden, die Ressource lokal neu zu starten, oder es wird direkt ein Failover der Ressource(n) vom defekten auf einen intakten Node eingeleitet, um einen möglichst unterbrechungsfreien Betrieb zu gewährleisten. Was Heartbeat letztlich als Fehlerfall interpretieren soll, kann natürlich definiert werden – im ein-
222
1198.book Seite 223 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
fachsten Fall wird der Failover durchgeführt, wenn ein Node im Standby oder nicht mehr erreichbar ist, alternativ kann er auch erfolgen, wenn ein einzelner Service nicht mehr reagiert. Heartbeat-Setup für Standby-Master Eins vorab: Natürlich kann dieser sehr kleine Exkurs in keinster Weise die Grundlagen ersetzen, die nötig sind, um ein tieferes Verständnis der Heartbeat (/Pacemaker)-Funktionalitäten zu erlangen. Wir empfehlen daher dringendst, einen Blick in die recht umfangreichen Dokumentationen und Beispiele unter www.linux-ha.org und www.clusterlabs.org zu werfen. Voraussetzung für das folgende Setup sind natürlich die installierten Heartbeat(/Pacemaker)-Pakete (siehe Anhang) auf beiden Maschinen. An dieser Stelle eine wichtige Anmerkung zu den verwendeten Paket-Versionen: OSS 11 bringt Heartbeat in Version 2.1.3 mit »ausgelagertem« Pacemaker in Version 0.6.3 mit. Letzterer bringt in dieser Version weder den mgmtd-Daemon, welcher (sehr stark vereinfacht ausgedrückt) für die Interaktion des grafischen Heartbeat-Frontends hb_gui mit dem CRM benötigt wird – noch die hb_gui selbst mit. Debian’s Lenny stellt ebenfalls heartbeat 2.1.3 zur Verfügung, allerdings mit den oben genannten Komponenten. SUSE-Nutzer und Heartbeat-Einsteiger, die auf die GUI nicht verzichten möchten, sollten für dieses Setup (siehe unten) eventuell alternative Heartbeat-Versionen (<= 2.1.4 mit integriertem mgmtd/hb_gui) ohne Pacemaker in Erwägung ziehen, die über etliche Repositories zur Verfügung gestellt werden, unter anderem hier: http://ftp5.gwdg.de/ pub/opensuse/repositories/server:/ha-clustering:/lha-2.1/openSUSE_11.0/i586/. Allerdings weisen die Entwickler darauf hin, dass der Einsatz der hb_gui auch Probleme bereiten kann; so können z.B. komplexere Konfigurationen nicht über sie erschlagen werden, zum anderen können sich auch Fehler in die Konfiguration einschleichen, die die XML-»Datenbank« des Clusters im schlimmsten Fall unbrauchbar machen. Wer auf die allerneuesten Heartbeat/Pacemaker-Versionen zurückgreifen will, kann dies freilich jederzeit tun. Allerdings ist zu beachten, dass sich die Syntax der XML-Konfigurationsdateien dort zum Teil geändert hat, sodass die von uns verwendeten BeispielKonfigurationsdateien (siehe unten) gegebenenfalls entsprechend nachbearbeitet werden müssten. Die Beispiel-XML-Dateien für unsere Heartbeat-spezifischen slapd-Ressourcen sind primär für die Verwendung mit der oben genannten Heartbeat-Version (2.1.3 bzw. <=2.1.4) konzipiert und lassen sich natürlich ohne grafische Oberfläche in die HA-Konfiguration integrieren.
Zurück zu unseren HA-Mini-Basics: In der Regel ist jeder Cluster-Node mit einer zweiten Netzwerkkarte ausgestattet. Für reine Testzwecke würde auch eine einzelne Verbindung reichen, jedoch bringt die zweite Karte im Produktivumfeld mehrere Vorteile: Zum einen erreichen wir so eine redundante Verbindung der Server, damit beim Ausfall einer einzelnen Leitung keine Split-Brain-Situation
223
3.2
1198.book Seite 224 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
(siehe Abschnitt 3.2.11, »Bäumchen, wechsle dich«) entstehen kann. In einem realen Netz könnten wir die zusätzlichen Karten z.B. über ein Crossover-Kabel direkt miteinander verbinden, um den Switch als potenzielle Fehlerquelle für diese Verbindung auszuschließen. Zusätzlich könnten wir diese Verbindung zum Datenabgleich z.B. für replizierte Fileservices verwenden, die auf einem DRBD untergebracht sind – allerdings bitte nicht für die bdb-Dateien unseres slapd, denn der kümmert sich selbst um die Replikation seiner Daten. Verwenden wir VMware, lässt sich die zweite (virtuelle) Karte natürlich mit minimalem Aufwand installieren. Die zusätzlichen Karten erhalten in unserem Fall IPs aus einem anderen Netz, z.B. 10.0.0.0/24. Die »normalen« Netzwerkkarten bleiben auf beiden Hosts unmodifiziert. Apropos Netzwerkkarten ... Exkurs: udev-Net-tigkeiten Wir kennen es alle aus der wunderbar dynamischen udev-Welt, insbesondere beim Klonen virtueller Maschinen: ständig neue Device-Bezeichner, immer fleißig um eine Zahl nach oben gezählt. Irgendwann nach der x-ten Klon-Operation liegen wir bei eth99, und die Sache wird langsam echt nervig. Nicht nur das – aus Gründen der Übersicht, insbesondere bei multiplen Interfaces auf korrespondierenden (Heartbeat-)Rechnern, sollte udev hier im Zaum gehalten werden. In der betreffenden udev-Datei (z.B. /etc/udev/rules.d/70-persistent-net.rules bei SUSE und Debian) können wir die unerwünschten Devices löschen, und das/die Devices mit der korrekten MAC auf den gewünschten Device-Namen (z.B eth0/ eth1) setzen. Gegebenenfalls sind noch die Namen der Konfigurationsdateien (bei SuE z.B. /etc/sysconfig/network/ifcfg-eth bzw. /etc/network/interfaces bei Debian) der Interfaces anzupassen. Nach einem Restart der erforderlichen Dienste bzw. dem Reboot des Systems sollte wieder Ordnung herrschen. Weiter im Text: Die /etc/hosts bzw. die DNS-Einträge sollten natürlich entsprechend angepasst werden, sodass alle Namenseinträge auf beiden Hosts aufgelöst werden können, z.B.: 192.168.198.11 10.0.0.11 192.168.198.12 10.0.0.12
ldapmaster.local.site ldapmaster ldapmaster.local.site ldapmaster ldapslave.local.site ldapslave ldapslave.local.site ldapslave
Im nächsten Schritt erstellen wir eine – bis auf die IPs und gegebenenfalls abweichende ethX-Interface-Bezeichner (siehe unten) – identische Heartbeat-Konfigurationsdatei /etc/ha.d/ha.cf auf beiden Maschinen (Nodes); die darin gesetzten Parameter definieren globale Heartbeat-Einstellungen.
224
1198.book Seite 225 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
Beispiel-Samples und weiterführende Infos zu dieser und anderen HeartbeatKonfigurationsdateien finden sich in den Paket-Dokumentationen und natürlich auf der Homepage des jeweiligen Projekts. Unsere sehr einfach gehaltene Minimal-Konfiguration der ha.cf sieht so aus (die Kommentare dienen nur dem Verständnis und sind nicht Teil der Konfigurationsdatei): # cluster members - immer das, was uname -n' ausgibt node ldapmaster ldapslave # IANA registrierter HA-Port udpport 694 # primaere HA-Connectivity per unicast, pro Node anpassen! # Format: <Modus> ucast eth0 192.168.198.12 # Backup HA-Connectivity, pro Node anpassen! ucast eth1 10.0.0.12 # aktivierung des crm (ha-v2) crm respawn # fuer zugriff auf die hb_gui muss ein passwort # fuer den user "hacluster" gesetzt werden
Wer in einer reinen Testumgebung mit nur einer Netzwerkkarte arbeiten will, kann die beiden ucast-Direktiven durch bcast eth ersetzen. Über die letzte Direktive wird der CRM (inklusive mgmtd, sofern vorhanden) aktiviert, den wir für unsere Konfigurationsvariante benötigen. In einigen Quellen bzw. Beispielen ist häufig auch der Wert crm on zu finden, der jedoch bei einer defekten CIB (Cluster Information Base, die XML-basierte »Datenbank« des Heartbeat V2-Clusters) zu einem harten Reboot der Maschine führen kann. Die Verwendung von crm respawn sorgt hingegen dafür, dass die CRM-relevanten Dienste ohne harten Reset einfach neu gestartet werden.
Die »althergebrachte« Datei /etc/ha.d/haresources – für relativ simple HeartbeatKonfigurationen im Version 1 Stil – wird von uns nicht benötigt. Der Einsatz der V1-Konfiguration wird zum einen von den Entwicklern aus verschiedenen, guten Gründen nicht mehr empfohlen, zum anderen wäre diese Konfigurationsvariante für unseren Anwendungsfall mangels Ressourcenüberwachung kaum ausreichend: Unser slapd muss aus replikationstechnischen Gründen auf beiden Nodes gleichzeitig aktiv sein und von Heartbeat überwacht und verwaltet werden – ein Job, den die alte Konfigurationsvariante in dieser Form nicht erschlagen kann. Hierfür verwenden wir daher eine einfache Clone-Resource im V2-Stil, zu der wir gleich kommen.
225
3.2
1198.book Seite 226 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Weiterhin benötigen wir eine identische Datei authkeys auf beiden Nodes, die wir ebenfalls unter /etc/ha.d/ platzieren. In ihr wird – unter Angabe des KryptoAlgorithmus und eines Schlüsselwortes – die Kommunikation der Clusterknoten abgesichert. Auf diese Art können nur autorisierte Clusterknoten miteinander kommunizieren. Die Datei darf 600 als maximale Berechtigung haben, andernfalls bricht Heartbeat seinen Start mit einer entsprechenden Fehlermeldung ab. Der Inhalt beschränkt sich auf zwei Zeilen: auth 1 1 sha1 dasistmeinsupergeheimerschluessel
Nach dem Setup der Dateien (und einer kurzen Kontrolle der Zeitsynchronisation zwischen den Nodes) starten wir Heartbeat auf beiden Nodes und warten in aller Ruhe, bis sich der CRM initiiert hat und die beiden Nodes ausgehandelt haben, wer der DC (keine Bange, nichts aus Redmond: DC=Distributed Coordinator) und somit Chef in der Cluster-WG ist. Ein kleiner Tipp an dieser Stelle: Ruhe ist oberstes Gebot. Auch wenn der Cluster üblicherweise schnell auf bestimmte Ereignisse reagiert, kann es in bestimmten Situationen etwas dauern, bis Konfigurationsänderungen in der CIB übernommen und auf allen Nodes propagiert werden. Eine Blick in die Logs schafft hier in der Regel Klarheit. Sind die Nodes ohne Fehler hochgefahren, sollten wir per crm_mon kurz prüfen, wie der aktuelle Status unseres Clusters ist: #> crm_mon ... Current DC: ldapmaster (77ec8d51-540c-4941-b3c5-5231abaac345) 2 Nodes configured. 0 Resources configured. ============ Node: ldapmaster (77ec8d51-540c-4941-b3c5-5231abaac345): online Node: ldapslave (de189e75-45c3-4b80-96ce-a88303e33251): online
Sieht gut aus bis hierher – aber: Resources 0? Das werden wir unverzüglich ändern. Hierzu fügen wir mit Hilfe der Datei slapd_cloneset.xml (aus den Beispieldaten zu diesem Abschnitt: http://www.galileocomputing.de/1801) die nötigen Ressourcen in die CIB ein, um unser Standby-Master-Szenario per Heartbeat steuern zu lassen. Der wichtigste Punkt bei diesem Setup: Wie eben schon angemerkt, müssen beide slapd’s (auf ldapmaster und ldapslave) genau wie beim Multi-Master-Setup auf beiden Nodes aktiv sein (auch wenn letztlich immer nur einer der beiden von außen erreichbar ist), damit alle Änderungen vom Betriebsmaster (dem »aktiven«) auf den Standby-Master (den »schlafenden«) repliziert werden können. Wie wir wissen, darf die Steuerung der Dienste nun nicht mehr dem init-System
226
1198.book Seite 227 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
obliegen, sondern muss zwangsläufig über Heartbeat erfolgen. Die XML-Ressourcendatei slapd_cloneset.xml beinhaltet eine einfache Clone-Ressource (slapd_cloneset), die es Heartbeat – stark vereinfacht ausgedrückt – in unserem Anwendungsfall ermöglicht, zwei identische, aktive Ressourcen (slapd) auf beiden Nodes zu überwachen und verwalten; im Fehlerfall wird dann mit Hilfe einer »virtuellen« Service-IP (ip0, ebenfalls als Ressource in der oben genannten XML-Datei definiert) vom defekten Node auf den anderen geschwenkt. Eine kurze Anmerkung zu unserer Ressourcendatei: Üblicherweise würde für ein Heartbeat-Cloneset ein OCF-kompatibler Resource Agent verwendet werden, da Letzterer im Gegensatz zu LSB-kompatiblen Resource Agents z.T. erweiterte Funktionalitäten bietet. Wir setzen in unserer XML-Ressource mit dem originalen slapd/ldap-Startskript (/etc/init.d/ldap|slapd) der Einfachheit halber einen LSB-kompatiblen Resource Agent ein, da ein entsprechender OCF-Gegenpart derzeit (noch) nicht verfügbar ist. Für unsere sehr einfach gestrickte Demo reichen die Kapabilitäten jedoch allemal aus. Was wir also beachten müssen: Vor dem Import der XML-Ressource slapd_cloneset.xml sollten wir sicherstellen, dass die LDAP-Dienste nicht permanent in die Runlevel eingebunden sind. Falls die LDAP-Dienste aktuell aktiv sein sollten, fahren wir sie auf beiden Nodes herunter – denn Heartbeat wird die Dienstkontrolle (und damit auch den Start/ Restart der Services) für uns übernehmen. Zudem muss noch die Service-IP in der slapd_cloneset.xml auf die gewünschten Gegebenheiten angepasst werden, denn sie stellt nach außen die immer gleiche IP dar, über die der aktive Node des Clusters erreichbar ist. Natürlich behalten die einzelnen Nodes ihre »echten« IPs, daher muss eine bisher nicht verwendete gewählt werden. Wichtige Anmerkung: Unter Debian muss die XML-Ressource vor dem Import noch minimal angepasst werden, und zwar muss die type-Anweisung in der folgenden Zeile: <primitive id="slapd_clone" class="lsb" type="ldap">
auf den für Debian korrekten Wert des LSB-Startskriptes unter /etc/init.d/ gesetzt werden: <primitive id="slapd_clone" class="lsb" type="slapd">
Zum Import der XML-Ressource können wir folgenden Befehl (hier ohne Pfadangaben) verwenden: #> cibadmin –o resource –C –x slapd_cloneset.xml
227
3.2
1198.book Seite 228 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Umfangreiche Informationen zum Befehl liefert natürlich cibadmin(8); hier nur die Erläuterung in Kurzform: -C =create, -x gibt die XML-Datei an, -o gibt die »Sektion« der CIB an, in die das XML-Snippet importiert werden soll. Das Tool crm_mon sollte uns nach erfolgreicher Integration der Ressourcen Folgendes zeigen: Clone Set: slapd_cloneset slapd_clone:0 (lsb:ldap): slapd_clone:1 (lsb:ldap): ip0 (ocf::heartbeat:IPaddr2):
Started ldapslave Started ldapmaster Started ldapmaster
In der hb_gui betrachtet, sollte sich unser Mini-Cluster momentan etwa so darstellen:
Abbildung 3.9 2-Node Heartbeat Cluster mit aktiven Ressourcen
Nun können wir einen einfachen Test mit einem manuellen Failover initiieren, indem wir den Node, auf dem die Service-IP aktiv ist (im oberen Beispiel ldapmaster) per #> crm_standby –U ldapmaster –v true
# alternativ: -v on
in einen inaktiven Zustand versetzen und gleichzeitig per
228
1198.book Seite 229 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
#> watch ldapsearch –x -h <service-ip>
die Erreichbarkeit unseres DIT püfen. Reaktivieren wir den 2.Master wieder, findet in der Standardeinstellung ein Rückschwenk auf ihn statt. Um das zu unterbinden und zusätzliche Transitionen zu vermeiden, können wir die Datei crm_config.xml aus den Beispieldateien z.B. per: #> cibadmin -R -x crm_config.xml
in die »globale« Heartbeat-Konfiguration einfügen. Die Datei ersetzt (-R = Replace) dabei in dieser sehr einfachen Konfigurations-Variante den Wert default-resource-stickiness von 0 (Default) durch 100; die »Klebrigkeit« sollte ausreichen, um einen Auto-Failback bzw. Rückschwenk der Ressourcen zu unterbinden. Zum Schluss noch ein paar kleine Tipps: Über die GUI lassen sich relativ schnell einfache Ressourcen erstellen. Diese lassen sich anschließend z.B. per cibadmin –Q –o resources > myresource.xml ebenfalls sehr einfach exportieren und können so manuell modifiziert, erweitert und in die aktive CIB re-importiert werden. Ein Backup von einer funktionierenden, aktiven Konfiguration lässt sich problemlos per cibadmin –Q > cib-backup.xml erstellen; per cibadmin –R cib-backup.xml kann die ursprüngliche Konfiguration jederzeit wieder zurückgesichert werden. Treten bei der Konfiguration von Ressourcen bzw. Constraints (siehe unten) oder Änderungen an ihnen Probleme auf, kann es manchmal hilfreich sein, zunächst per crm_resource –R einen manuellen Refresh einzuleiten. Treten größere Probleme auf, die sich nicht beseitigen lassen, und es existiert kein brauchbares Backup der CIB, können wir als Quick & Dirty -Workaround Heartbeat auf allen Nodes stoppen und die Dateien unterhalb des Ordners /var/ lib/heartbeat/* löschen, ebenso wie die Dateien in den dort vorhandenen Unterordnern crm und pengine. Auf diese Art startet Heartbeat beim nächsten Mal wieder komplett »jungfräulich«. Das war’s mit unserem wirklich kleinen Einblick in Heartbeat in extrem vereinfachter Kurzform. Viele der Punkte, die für ein adäquates Setup in einer Produktivumgebung noch relevant wären – wie z.B. Stonith zur Unterbindung von SplitBrain-Situationen, Constraints (Bedingungen) für den Einsatz und die Platzierung von Ressourcen und vieles andere mehr – konnten wir in unserem kleinen Exkurs natürlich nicht anschneiden, ohne den Rahmen des Buches zu sprengen.
229
3.2
1198.book Seite 230 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Für alles Weitergehende verweisen wir daher nochmals auf die Homepage des Heartbeat-Projekts www.linux-ha.org, auf der sich die Sourcen, umfangreiche Dokumentationen und Tutorials finden, sowie auf www.clusterlabs.org für weitergehende Infos rund um Pacemaker. Fazit Bis hierher haben wir einiges an replikationstechnischem Stoff betrachtet, verarbeitet und getestet, es wird also Zeit für ein Resümee: Für alle Replikationsverfahren – insbesondere natürlich die gerade vorgestellte Standby-/Multi-Master-Replikation – ist eine exakt funktionierende Zeitsynchronisation unabdingbare Voraussetzung. Wollen wir den Replikations-Overhead (und damit in logischer Konsequenz den Netzwerktraffic) bei maximaler Ausfallsicherheit so minimal wie möglich halten, muss unsere Wahl unweigerlich auf die redundante Standby-Master-Variante fallen. Denn diese Lösung bietet optimale Sicherheit bei gleichzeitiger Wahrung der X.500-Standards. Einzige zusätzliche und ebenfalls unabdingbare Voraussetzung ist eine Cluster-Software, die die redundanten Maschinen überwacht und so ausgelegt ist, dass Split-Brain-Situationen unbedingt vermieden werden. Eine derartige Redundanz-Lösung sollte natürlich räumlich relativ eng lokalisiert sein, um Latenzzeiten bei der Überprüfung der Erreichbarkeit zu vermeiden. Geht es um räumlich auseinanderliegende, identische Datenbestände, auf die jeweils schreibend zugegriffen werden soll/muss, kann Multi-Master-Replikation die Wahl sein. Hierbei spricht nichts dagegen, jedem lokalen Master zu Redundanzerhöhung einen zusätzlichen Standby-Master zu verpassen, sofern die Hardware-Ressourcen dies ermöglichen. Beim Einsatz mehrerer (n) Master darf nicht vergessen werden, dass sich der Traffic mit jedem neuen Master exponentiell (bzw. nach der Berechnungsvorschrift: n²-n, siehe unten) erhöht. Betrachten wir einfach folgendes Beispiel, in dem wir annehmen, dass multiple (n) Master im (logischerweise) gleichen DIT arbeiten und jeder von ihnen innerhalb der gleichen Zeitspanne einen anderen Modify-Request erhält: 왘 n=2: 1 Schreiboperation auf jedem Server → 2 x Traffic (2²-2) 왘 n=3: 1 Schreiboperation auf jedem Server → 6 x Traffic (3²-3 ) 왘 n=4: 1 Schreiboperation auf jedem Server → 12 x Traffic (4²-4) Und so weiter und so fort ... wir merken schon, dass sich das Ganze wie das typische, »super-sichere« Gewinnspiel nach dem Schneeball-Prinzip blitzschnell zu einem Schuss nach hinten entwickeln kann, vor allem wenn größere Modifikationen oder gar Initial Content Loads anstehen. Wenn Multi-Master, dann bitte
230
1198.book Seite 231 Donnerstag, 5. Februar 2009 3:02 15
Replikation – oder: Frag dich nie, ob ein Server ausfällt, frag dich immer nur, wann.
mit einer möglichst geringen Anzahl von Servern oder so viel Bandbreite, dass es keinem wehtut. Dreiecksbeziehungen – MMR, Standby-Master und Delta-Sync Weil’s an dieser Stelle passt: Schön wär’s gewesen – ist aber leider aktuell noch nicht implementiert, zumindest für Multi-Master-Replikation. Nach den Vorankündigungen der LDAP-Crew können wir jedoch noch während des 2.4er-Zyklus auf die Integration von Delta-Sync in die MMR hoffen. Vor allem in Anbetracht der gerade getätigten Betrachtungen ein nicht unwesentlicher Punkt, was die MMR-Performance angeht, insbesondere bei einer hohen Anzahl von Mastern. Wir könnten uns jetzt sagen: Delta-Sync im Provider/Consumer-Mode läuft doch schon – wo ist also das Problem? Ganz so einfach ist es nicht. Bis zur endgültigen Umsetzung einer Delta-Sync für MMR sind noch einige zusätzliche – und vor allem alles andere als triviale – Probleme zu lösen. Unter anderem müssen die Log-DBs auf allen beteiligten Mastern synchron gehalten werden ohne dass sich die Log-DBs dabei gegenseitig beeinflussen und dadurch gegebenenfalls ihre eigene Integrität verlieren. Im Standby-Master-Mode müssen wir mit diesen Problemen nicht kämpfen: Hier arbeiten wir nur mit zwei Nodes, und es erfolgt immer nur schreibender Zugriff auf genau einen der beiden Master. Das Delta-Sync-spezifische StandbyMaster-Setup erfolgt dabei analog zu der in Abschnitt 3.2.9, »Delta Force«, beschriebenen Vorgehensweise, natürlich auf beiden Nodes. Entsprechende Beispieldateien für ein statisches Setup finden sich in den Daten zu diesem Abschnitt (3.2.13, »Traumhafte Nachtruhe dank Schläfer«). Bei einer Konvertierung in das Online-Format sind die unterschiedlichen Direktiven auf beiden Nodes zu berücksichtigen. Zum Abschluss unseres Abschnitts über Standby-/Multi-Master-Replikation noch ein paar kurze Anmerkungen zum Thema Backup, das – wie in allen Bereichendie entsprechende Aufmerksamkeit verdienen sollte. Im Standby-Master-Mode sollte den Backups der Datenbank bzw. des Kontextes eine besondere Sorgfalt entgegen gebracht werden: Soll die Berkeley-DB mitsamt ihrer Transaktionslogs in regelmäßigen Intervallen gesichert werden (slapd natürlich im RO-Modus), sollte hierzu immer der gleiche Master des Paares verwendet werden. Denn: Geht einer der Master für einen bestimmten Zeitraum offline, sind seine Transaktionslogs im Vergleich zu dem anderen gegebenenfalls vorübergehend inkonsistent, zumindest so lange, bis er wieder online ist und sich mit dem aktiven Master wieder abgeglichen hat.
231
3.2
1198.book Seite 232 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Zur Konsistenzkontrolle des Backups bzw. der Aktualität des DIT zwischen multiplen Mastern sind mehrere Möglichkeiten denkbar. Eine Variante wäre ein skriptgesteuertes, zeitlich synchrones Backup per slapcat auf allen Maschinen im Readonly-Modus mit anschließendem automatisierten Vergleich der erzeugten Backup-LDIFs per diff oder ähnlichen Tools – was bei sehr großen Datenbeständen allerdings schwer bis gar nicht durchführbar ist. Über eine automatisierte Auswertung der contextCSNs auf allen beteiligten Servern sollte sich in diesem Fall jedoch zumindest eine grundlegende Aussage über den Aktualitätsstand der Replikation auf allen Nodes machen lassen. So – repliziert haben wir fürs Erste genug. Die Techniken sitzen, und alles wäre gut, wenn .... tja, wenn da nicht die nervigen, bösen Buben wären, die hinter jeder Ecke mit einem wireshark, tcpdump oder anderen Sniffern bewaffnet herumlungern und dem tapferen Admin das Leben schwermachen. Wer der irrigen Meinung sein sollte, das seine LDAP-Server ja innerhalb der Firma ruhig ungeschützt miteinander parlieren können, solange sie nur mit der bösen Außenwelt nicht in Kontakt stehen, sollte sich zunächst genügend Baldrian besorgen und anschließend einen vertrauensvollen Blick in die Statistiken der Gartner-Group werfen. Weit mehr als die Hälfte aller Angriffe kommen aus dem internen Netz. Aber keine Panik: Genau diesen Buben versauen wir den Tag, indem wir unsere komplette LDAP-Kommunikation zwischen den Servern (und natürlich auch den involvierten Clients) verschlüsselungstechnisch so wasserdicht machen wie das Hinterteil submariner Lebensformen. Geht sofort los ...
3.3
Feind hört mit: Verschlüsselte Übertragung
»Komplexität ist der schlimmste Feind von Sicherheit. Sichere Systeme sollten abgespeckt und so einfach wie möglich gemacht werden. Es gibt keinen Ersatz für Einfachheit. Leider geht Einfachheit gegen alles, was unsere digitale Zukunft repräsentiert.« Bruce Schneier, Auszug aus »Secrets & Lies« Vorbemerkungen zu OpenSSL Ein wahres Wort. Und auch schon lange bevor die ersten Bits und Bytes durch Kupferkabel oder Glasfasern rauschten, ging es um Verschlüsselung und Sicherheit bei der Übertragung von Informationen, und dies – technologisch zwangsläufig bedingt – wirklich mit sehr einfachen Mitteln. Seitdem Menschen sesshaft wurden, und sie Territorien ihr Eigen nannten, führten sie oft genug – meist
232
1198.book Seite 233 Donnerstag, 5. Februar 2009 3:02 15
Feind hört mit: Verschlüsselte Übertragung
wegen völlig unterschiedlicher Ansichten über eben genau jene territorialen Ansprüche – jede Menge gewalttätiger Auseinandersetzungen gegeneinander. Und die Idee des Krieges bedingt die Idee der Nachricht, der Anweisung oder der Information für einen oder mehrere Truppenteile. Schlecht, wenn die Nachricht in Feindeshand fällt. Noch schlechter, wenn der Feind sie entschlüsseln kann. Kryptografische Technik tat also not. Das älteste bekannte militärische Verschlüsselungsverfahren vor mehr als 2.500 Jahren war die Skytale: ein Holzstab mit einem bestimmten Durchmesser, um den ein Pergament- oder Lederband gewickelt und dann beschrieben wurde. Besaß der Empfänger nicht einen Stab gleichen Durchmessers, konnte er mit der Nachricht in der Regel wenig anfangen. Das konnte natürlich nicht lange gut gehen, und so wurden schon bald neue Maßnahmen notwendig. Es kam zur so genannten Caesar-Chiffrierung (ja, genau: Julius war der Vorname), die in einigen Mailclients und Editoren als Sonderfall der Caesar-Chiffrierung immer noch als ROT13-Funktion existiert. Hierbei wird der zu verschlüsselnde Text einfach um einen Betrag X verschoben. Für X = 3 gilt also A = C, B = D, C = E und so fort. Das genügte eine ganze Weile, um unsere europäischen Altvorderen über den Bock zu ziehen: Und wenn man weiß, um wie vieles klüger die Römer zur Zeitenwende waren im Vergleich zu den Hiesigen im Mittelalter, dann kann man ermessen, wie finster dieses Mittelalter wirklich war. Aber auch die Caesar-Chiffrierung gab dem Druck menschlicher Neugier bald nach, und so musste man neue, komplexere Formen der Verschlüsselung ersinnen. Zunächst beschied man sich mit Ausbaustufen der Caesar-Chiffre. Das machte den Weg frei für die so genannten Schlüsselwörter – später auch Schlüsselsätze, die entsprechend aufwändiger zu dechiffrieren waren. Eine solche Verschlüsselung heißt nach ihrem Erfinder Vignère-Verschlüsselung und galt viele Jahre lang als sicher. Der berühmte Mathematiker Charles Babbage gilt als der Erste, der ein Verfahren zur Codebrechung besaß. Babbage entwickelte mit der Difference Engine und der Analytical Engine zwei mechanische Rechenmaschinen, von denen er zu Lebzeiten zwar kein funktionstüchtiges Exemplar fertigstellen konnte, deren Letztere aber als Vorläufer des modernen Computers gilt. Es gab dann noch weitere Versuche, Nachrichten sicher zu verschlüsseln, wie z.B. die englische Playfair-Methode oder die mechanische Verschlüsselung mit der deutschen Enigma-Maschine. Interessierten Lesern sei hier das Buch »Verschlüsselte Botschaften« von Rudolf Kippenhahn empfohlen. Am Ende scheiterten jedoch alle Versuche, auf dem beschriebenen Weg Sicherheit zu erzeugen, an der exponentiell steigenden Rechenleistung der Computer und ihrer Vorläufer.
233
3.3
1198.book Seite 234 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Codeknacker Gebt mir einen Punkt außerhalb, und ich hebe die Welt aus den Angeln. Archimedes Jede Sprache hat ihre Eigenarten, und wir reden dabei nicht über grammatische Konstrukte. Es geht um etwas sehr viel Simpleres, was aber dennoch dazu angetan ist, Kryptografen das Leben interessant zu machen. Die Rede ist von statistischen Häufungen. Bevor mechanische Apparate wie die Enigma oder der Computer es der Kryptografie ermöglichten, Nachrichten zu Pseudo-Zufallsfolgen zu verwürfeln, war die Statistik die stärkste Waffe, um Nachrichten zu entschlüsseln. Solange ein Mensch die Texte von Hand verschlüsselt, muss der verwendete Algorithmus einfach genug bleiben, um die Nachricht in vertretbarer Zeit fehlerfrei zu chiffrieren. Diese Verschlüsselungsverfahren sind durch die Statistik angreifbar. Mit ihr wird die Häufigkeit bestimmter Zeichen und Zeichenfolgen bestimmt. Mit dem Wissen über die Gesetzmäßigkeiten einer Sprache können Buchstaben und Wörter zugeordnet werden und der Klartext rekonstruiert werden. Seitdem Computer durch ihre Geschwindigkeit und Präzision die statistischen Bindungen in einem verschlüsselten Text auf fast null reduzieren, müssen neue Analysetechniken verwendet werden mit den Zielen, den Verschlüsselungsalgorithmus aufzudecken, eine Schwachstelle im Algorithmus auszunutzen (wie auch schon die Statistik Schwachstellen nutzte) und den Schlüssel zu rekonstruieren, mit dem die Nachricht verschlüsselt wurde. Ziel eines Angriffes ist die Ermittlung des geheimen Schlüssels, der dann in der Zukunft beliebige Entschlüsselungen erlaubt. Alle bekannten Angriffsszenarien haben bei modernen Verschlüsselungsverfahren unter Verwendung eines entsprechend komplexen Schlüssels in der Praxis keine Aussicht auf Erfolg. Die Angriffe sind eher vom wissenschaftlichen Standpunkt aus interessant und haben sehr theoretischen Charakter. Wenn Kryptologen von Angriffspunkten und möglichen Schwachstellen sprechen, so ist das in der Regel keine Aussage über die grundsätzliche Sicherheit des verwendeten Verfahrens in der Realität. Moderne Algorithmen sind derzeit auch mit größtem Aufwand in der Praxis kaum zu brechen, es sei denn, die Entwickler des Algorithmus haben ein Hintertürchen eingebaut, also eine Art Generalschlüssel, der so gut wie immer funktioniert. Apropos Backdoor ... Der RNG (Random Number Generator) aus Windows Vista (ursprünglich aus Windows 2000) war so ein Grenzfall. Die scheinbar zufälligen Zahlen waren
234
1198.book Seite 235 Donnerstag, 5. Februar 2009 3:02 15
Feind hört mit: Verschlüsselte Übertragung
nach sehr genauer Prüfung doch nicht so zufällig, wie sie eigentlich sein sollten, was die Entschlüsselung von Keys, die mit diesem RNG erzeugt wurden, erheblich vereinfachen kann. Aber Security-Experte Bruce Schneier warnte auch vor dem nachgebesserten Dual_EC-DRBG-Generator in Vista: der US-Geheimdienst NSA favorisiert diesen Generator. Entweder, weil er wirklich gut ist. Oder, was wahrscheinlicher ist, weil er eine nützliche Backdoor enthält. Microsoft enthielt sich interessanterweise in beiden Fällen einer konkreten zur Äußerung zur Sachlage. Aber auch Linux, in diesem konkreten Fall Debian, hat sich Ende 2007 leider nicht mit Ruhm bekleckert: einige Monate später wurde per Zufall erkannt, dass die über den vergangenen Zeitraum hinweg verwendeten OpenSSL-Pakete einen extrem leicht knackbaren Schlüssel produzierten. Betrachten wir kurz einige mögliche Angriffsmuster. Ein relativ bekanntes Verfahren ist die so genannte Chosen Plaintext Attack. Bei dieser Art Angriff – mit frei wählbarem Klartext – kann der Angreifer die zu verschlüsselnden Klartexte frei wählen und hat Zugang zu den entsprechenden Geheimtexten. Gegenüber dem Angriff mit bekanntem Klartext hat diese Variante den Vorteil, dass der Angreifer gezielt den Klartext variieren und die dadurch entstehenden Veränderungen im Geheimtext analysieren kann. Typischerweise schiebt der Angreifer dem Opfer die zu verschlüsselnden Nachrichten so unter, dass dem Opfer die Selektion durch eine andere Person nicht bewusst wird. Aber auch andere, indirekte Angriffsvarianten sind möglich, z.B. eine Auswertung der Speichernutzung. Wenn sich Prozesse auf einem Rechner bestimmte Speicherbereiche teilen, können sie unter Umständen aus der Nutzung des Speichers durch den anderen Prozess auf die von ihm durchgeführten Operationen schließen. Ein entsprechender Angriff gegen OpenSSL konnte diese »shared memory«-Schwachstelle, die durch die gemeinsame Nutzung des L-1-Cache beim Hyper-Threading des P 4 vorlag, ausnutzen. Einige kryptographische Implementierungen reagieren explizit auf falsche Eingaben unterschiedlich, und zwar abhängig davon, an welcher Stelle der Verarbeitung ein Fehler auftritt. Aus der Art der Reaktion kann ein Angreifer bereits Informationen über den verwendeten, geheimen Schlüssel ableiten. Ein derartiger Angriff fand z.B. gegen einige weit verbreitete SSL-Implementierungen statt. Schlüsseltausch Gibt es den unknackbaren Code ? Die prinzipielle Antwort lautet: Ja. Allerdings war bisher jeder Versuch, eine sichere Methode zu entwickeln, mit schwer beherrschbaren Folgeproblemen verbunden. Beispiel dafür ist das One-TimePad-Verfahren (OTP):
235
3.3
1198.book Seite 236 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Der Name One-Time-Pad heißt übersetzt »Einmal-Block«, was sich auf die ursprüngliche praktische Anwendung bezieht, bei der Sender und Empfänger einen Papierblock voller zufällig erzeugter Schlüssel hatten und bei jeder Nachricht eine neue Seite des Blocks verwendeten und diese nach Gebrauch vernichteten. Heute wird die Bezeichnung One-Time-Pad oder Vernam-Code für Verfahren verwendet, bei denen jede neue Nachricht mit einem neuen Schlüssel codiert wird. Dazu muss der Schlüssel so lang sein wie die Nachricht selbst und aus absolut zufälligen Werten bestehen, die keine statistischen Abhängigkeiten aufweisen, um keinen Angriffspunkt für die Kryptoanalyse zu bieten. Weil der Schlüssel aus statistisch unabhängigen Werten besteht – z.B. weißes oder farbiges Rauschen – und nur einmal verwendet wird, ist er mathematisch nachweisbar sicher, das heißt, es gibt kein Verfahren, die übermittelte Nachricht zu entziffern, wenn man den verwendeten Schlüssel nicht kennt. Aber: Ein One-Time-Pad darf auf keinen Fall mehr als einmal eingesetzt werden, da sonst die Entschlüsselung sehr einfach wäre. Damit das Verfahren eingesetzt werden kann, müssen die Schlüssel zuvor über einen sicheren Kanal ausgetauscht werden. Ein weiterer Nachteil von One-TimePad besteht in dem Umstand, dass jeweils ein eigener Schlüssel für jede SenderEmpfänger-Beziehung verwendet werden muss. Damit steigt die Anzahl der Schlüssel quadratisch mit der Anzahl der Teilnehmer, wenn jeder mit jedem kommunizieren soll. One-Time-Pads werden in der Praxis nur für außerordentlich vertrauliche Nachrichten für einen oder wenige Empfänger in Organisationen mit straff organisierten Schlüsselverteilungsmechanismen genutzt, anders ausgedrückt: in Nachrichtendiensten. Für alltägliche Zwecke ist dieses sichere Verfahren nicht handhabbar. Asymmetrisch wird modern Das Problem der Schlüsselverteilung führte in den Siebzigern zur Entwicklung des Diffie-Hellman-Algorithmus. Das ist eigentlich kein Verschlüsselungssystem, sondern er ermöglicht den sicheren Austausch von Schlüsseln über unsichere Kanäle. Er führte weiter zur Entwicklung asymmetrischer Verschlüsselungsverfahren wie z.B. RSA (die Abkürzung setzt sich zusammen aus den Namen der Entwickler vom M.I.T.: Rivest, Shamir und Adleman). Aber auch diese Verschlüsselungssysteme setzen voraus, dass vorab Informationen über einen vertrauenswürdigen Kanal ausgetauscht werden. Dabei handelt es sich meist um die sichere Zuordnung von einem (einzigen) Schlüssel zu einem Kommunikationspartner oder um die Zuordnung eines Schlüssels zu einem vertrauenswürdigen Dritten, der weitere Schlüssel vermittelt.
236
1198.book Seite 237 Donnerstag, 5. Februar 2009 3:02 15
Feind hört mit: Verschlüsselte Übertragung
Wir ahnen schon: 1976 hat noch niemand so ein böses Wort wie X.500 in den Mund genommen, aber die Wurzeln der Entwicklung werden bereits sichtbar … Eine zentrale Rolle in der Kryptografie spielt die so genannte Modulo-Rechnung, insbesondere die Modulo-Wurzel und der Modulo-Logarithmus, üblicherweise »diskreter Logarithmus« genannt. Der diskrete Logarithmus ist beschrieben als ax = b mod n für gegebene a, b und n. Die Frage, ob zu den gegebenen Zahlen ein diskreter Logarithmus existiert, ist definitiv nicht trivial. Allerdings haben wir in modernen Verschlüsselungssystemen nur mit Konstellationen zu tun, in denen ein solcher diskreter Logarithmus existiert. Wer sich tiefer mit dieser Materie befassen will, beschäftige sich mit der Gruppentheorie und hier im Besonderen mit Untergruppen und Generatoren. Festzustellen bleibt für uns, dass die meisten Modulo-Operationen mit modernen Computern auch für sehr große Zahlen blitzschnell zu berechnen sind. Ihre Umkehrfunktionen dagegen erfordern mehr Rechenaufwand, als uns die voraussichtliche Existenz des Universums zur Verfügung stellt. Daher nennt man solche Funktionen Einwegfunktionen. Gibt es jedoch einen »Nebenausgang«, mit dem man die Umkehrung in kürzester Zeit erreichen kann, nennt man solch eine Funktion eine »Falltürfunktion«. Hier sind wir dann wieder bei Diffie und Hellman. Ihre berühmte Methode ist eine Falltürfunktion, die den diskreten Logarithmus benutzt. Die zentrale Schwachstelle des Diffie-Hellman-Verfahrens bleibt allerdings die Möglichkeit einer so genannten Man-in-the-Middle-Attacke, besonders während des Schlüsseltauschs. Um die Konsistenz der Nachrichtenübertragung dennoch zu gewähren, wurden Signaturverfahren wie MD5 oder Blowfish entwickelt, die im Gegensatz zu DES mit (fast) völliger Sicherheit garantieren, dass eine Nachricht nicht verändert oder verfälscht werden kann: 왘 DES (Data Encryption Standard) beinhaltet (normalerweise) nicht nachvollziehbare Substitutions-Boxen (Matrix von 4 Zeilen x 16 Spalten zur Wertekorrelation), angeblich wurden diese von der NSA in die heutige Form gebracht, im schlimmsten Fall mit Backdoor. Bekannte Angriffe sind differenzielle und lineare Analyse. Ein praktikabler Angriff war auch der Bruteforce mittels Deep-Crack. 왘 MD5 (Message Digest No. 5) von Ron Rivest ist in dem Sinne keine Verschlüsselung sondern »nur« eine Einweg-Hashfunktion, die aber für Passworte ausreicht. Allerdings sind hier auch schon einige Schwachstellen in Form von Kollisionen bei Variation der Startwerte gefunden worden. 왘 Blowfish (von Security-»Guru« Bruce Schneier) basiert wie DES auf einem Feistel-Netzwerk mit gleicher Blockgröße und Rundenzahl, aber mit variabler Schlüssellänge und S-Boxen, die vom frei gewählten Schlüssel abhängen. Der
237
3.3
1198.book Seite 238 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Algorithmus zeigt bei hohen Runden -Zahlen bis heute keine nennenswerten Schwächen. Und nun zur Anwendung Machen wir an dieser Stelle einen kleinen Zeitsprung: November 1993 entwickelte Marc Andreesen aus seinem Stanford-Projekt Spry Mosaic den berühmten Webbrowser der ersten Stunde namens Netscape. Neun Monate später veröffentlichte Netscape Communications die erste Version von SSL 1.0 (Secure Socket Layer). Dies folgte der Notwendigkeit, vertrauenswürdige Verbindungen zu erzeugen, um Online-Banking, Webshops und andere Anwendungen zu ermöglichen. Mittlerweile gab es einen Standard, der solche Verbindungen beschrieb, und mit SSL gab es eine Software, die diese Standards realisierte. Genau: Das X.500-Protokoll – hier im Besonderen die X.509-Spezifikation eines Schlüsseltauschverfahrens mit einer glaubwürdigen Prüf-Autorität, der so genannten Certification Authority (CA), und einer Methode, die dies in die Tat umsetzte. Ende 1995 kam Microsoft mit der ersten Version seines Internet Explorers. Kurz darauf wurde auch die erste Version ihres SSL-Pendants bekannt, PCT 1.0 (Private Communication Technology). PCT hatte einige Vorteile gegenüber SSL 2.0, und diese wurden dann auch in SSL 3.0 aufgenommen. SSL wurde von der IETF mit dem RFC 2246 »TLS Version 1.0« standardisiert und im Januar 1999 in Transport Layer Security (TLS) der Version 1 umbenannt. Die Unterschiede zwischen SSL 3.0 und TLS 1.0 sind sehr klein im Verhältnis zu den dabei entstandenen Versionsverwirrungen. So meldet sich TLS 1.0 im Header als Version SSL 3.1. Aktuelle Informationen zu TLS befinden sich unter anderem in RFC 4346 (TLS 1.1), RFC 5246 (TLS 1.2) und www.ietf.org/html.charters/tls-charter.html. Im Schichten-Modell ist SSL zwischen Transportschicht (TCP) und Applikationsschicht angeordnet. Aus Sicht der Transportschicht ist SSL eine Applikation, aus Sicht der Applikation ist SSL die Transportschicht. Durch seine transparente Arbeitsweise kann SSL so relativ einfach integriert werden, um Applikations-Protokollen ohne eigene Sicherheitsmechanismen stark verschlüsselte Verbindungen zur Verfügung zu stellen. Das SSL-Protokoll besteht intern aus zwei Schichten (Layers) und insgesamt fünf Protokollen. Die erste Schicht handelt die Vermittlungsbedingungen über IP aus und verwendet vier der fünf Protokolle. Die zweite Schicht ist für die kryptographische Behandlung des Datenstroms zuständig und befindet sich zwischen TCP und der ersten Schicht.
238
1198.book Seite 239 Donnerstag, 5. Februar 2009 3:02 15
Feind hört mit: Verschlüsselte Übertragung
Applikations-Layer
LDAP, HTTP, FTP etc.
SSL-Handshake, ChangeCiperSpec, Alert- und Application-Data-Protocol SSL-Record TCP IP Netz
SSL-Handshake-Protokoll Das Handshake-Protokoll startet den SSL-Aufbau, indem es, noch bevor die ersten Bits des Applikationsdatenstromes ausgetauscht wurden, Client und Server identifiziert, eine kryptographische Methode vereinbart und einen symmetrischen Schlüssel austauscht, mit dem in der oberen TCP-Verbindungsschicht zwei Teilschlüssel berechnet werden, für die Verschlüsselung des Datenstroms und die Hash-Funktionen 왘 ChangeCipherSpec teilt die getroffenen Vereinbarungen dem Record-Protokoll mit. 왘 Das Alert-Protokoll erzeugt Warnungen und Fehlermeldungen, falls die Übertragung Unregelmäßigkeiten aufweist. 왘 Das ApplicationData-Protokoll reicht schließlich den Datenstrom zum Layer des Record-Protokolls durch. SSL Record Protocol Dieses Protokoll ist die Verbindungsschicht zu TCP und dient der Absicherung der Verbindung. Es setzt direkt auf der Transportschicht auf und bietet zwei verschiedene Dienste, die einzeln und gemeinsam genutzt werden können: Es verschlüsselt den ausgehenden und entschlüsselt den eingehenden Datenstrom gemäß der Vereinbarungen, die das Handshake-Protokoll getroffen und ChangeCipherSpec übermittelt hat. Bei den abgehenden Daten verwendet es dazu ein schlüsselabhängiges Hash-Verfahren, dessen Daten werden dann samt HashWert symmetrisch verschlüsselt. Schauen wir uns den schrittweisen Ablauf einer SSL-basierten Client-Server-Verbindung an: 왘 Der Client initiiert die Verbindung und sendet eine Anfrage (Request) an den Server, die u.a. die unterstützte SSL-Version und Informationen über seine verschlüsselungstechnischen Kapabilitäten enthält, sowie Zufallsdaten für die Erzeugung eines Sitzungsschlüssels.
239
3.3
1198.book Seite 240 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
왘 Der Server antwortet mit derselben Nachricht und sendet je nach Typ des Requests sein eigenes Server-Zertifikat an den Client. 왘 Der Client versucht das übermittelte Server-Zertifikat zu authentifizieren, bei Misserfolg wird die Verbindung abgebrochen. Dieses Zertifikat enthält den öffentlichen Schlüssel des Servers. 왘 Nach erfolgter Authentifizierung erstellt der Client das Pre-Master Secret, verschlüsselt dieses mit dem öffentlichen Schlüssel des Servers und sendet es an den Server. Ebenfalls erzeugt der Client daraus das Master Secret. 왘 Der Server entschlüsselt das Pre-Master Secret mit seinem privaten Schlüssel, der komplementär zu seinem öffentlichen Schlüssel ist, und erstellt das Master Secret. 왘 Client und Server erstellen aus dem Master Secret den Session Key – einen einmalig verwendeten, symmetrischen Schlüssel, der während der Verbindung zum Ver- und Entschlüsseln der Daten genutzt wird. SSL unterstützt für die symmetrische Verschlüsselung mit diesem Session Key u.a. DES und Triple DES. 왘 Der Client teilt dem Server nun mit, dass alle weitere Kommunikation mit dem Sitzungsschlüssel verschlüsselt sein wird. Danach sendet er eine bereits verschlüsselte Meldung, dass der Handshake für ihn beendet ist. 왘 Der Server bestätigt dies, indem er die gleiche Nachricht an den Client schickt. 왘 Die SSL-Sitzung ist nun aktiv, und sowohl Client als auch Server verwenden den ausgehandelten Sitzungsschlüssel zum Ver- und Entschlüsseln aller Nachrichten – und um zu prüfen, ob die Daten auf dem Kommunikationsweg gegebenenfalls verändert wurden. Der Vorteil des SSL-Protokolls ist die Möglichkeit, jedes höhere Protokoll auf Basis des SSL-Protokolls zu implementieren. Damit ist eine Unabhängigkeit von Applikationen und Systemen gewährleistet. Der Nachteil der SSL-verschlüsselten Übertragung besteht darin, dass es (teilweise deutlich) langsamer ist, da aufwändige Berechnungen durchgeführt und mehr Daten übertragen werden müssen. Für Anwendungen wie OpenLDAP wird primär das freie Kryptographiepaket OpenSSL eingesetzt bzw. für LDAPv3 auch zwingend benötigt. Es bietet die Möglichkeit, mit dem Kommandozeilentool openssl bzw. den mitgelieferten Skripten eigene Zertifikate und Sperrlisten zu erzeugen. Letztlich kann man mit OpenLDAP und OpenSSL eine eigene Zertifizierungsinstanz erstellen. Im nächsten Abschnitt werden wir uns genau anschauen, wie wir mit Hilfe von SSL/TLS eine sichere Kommunikation zwischen unseren LDAP-Diensten und -Cli-
240
1198.book Seite 241 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
ents realisieren können. Für die Erzeugung der Zertifikate werden wir zunächst die vom OpenSSL-Paket mitgelieferten perl/bash-Skripte verwenden, mit denen die nötigen Schritte relativ einfach durchzuführen sind. Wie man derlei mit openssl am Prompt selbst erledigt, werden wir danach kurz anreißen.
3.4
OpenLDAP mit SSL und TLS
Paranoia heißt doch eigentlich nur, die Wirklichkeit realistischer zu sehen als andere. Strange Days, USA 1995
3.4.1
Familienbande - SSL und TLS
Im vorigen Abschnitt haben wir einige theoretische Vorkenntnisse über SSL/TLS und kryptographische Methoden erlangt. Jetzt ist es an der Zeit, die Praxis wieder in den Vordergrund zu rücken: die Anwendung von OpenLDAP in Verbindung mit SSL/TLS, denn wie wir wissen – ein wenig gesunde Paranoia im Hinblick auf das mögliche, kriminelle Potential böser Buben kann nie schaden. Wie wir bereits aus den vorigen Abschnitten wissen, kann sich der LDAP-Client im einfachsten Fall per simple bind am LDAP-Server anmelden. Dabei erfolgt die Übermittlung des Passworts – sofern keine anonyme Bindung gewählt wurde – im Klartext, und es kann somit auch jederzeit problemlos abgehört werden. Die andere Variante ist der so genannte strong bind, bei dem eine verschlüsselte Verbindung zwischen Client und Server erforderlich ist, bevor Daten ausgetauscht werden. Genauso wie bei SSL erfolgt bei TLS vor dem Aufbau der eigentlichen, verschlüsselten Verbindung ein Handshake, bei dem die Schlüssel ausgetauscht und verifiziert werden. Erst nach erfolgreichem Abschluss des Handshakes wird die verschlüsselte Verbindung hergestellt. Im letzten Abschnitt haben wir bereits erfahren, dass SSL und TLS aufgrund ihrer Verwandtschaft in vielen Bereichen identisch sind. Schauen wir uns einige der signifikantesten Unterschiede zwischen SSL und TLS im Detail an: 왘 Der MAC (Message Authentication Code), den SSL verwendet, wurde bei TLS gegen den sichereren keyed-Hashing for Message Authentication Code (HMAC) ausgetauscht. 왘 Bei TLS können statt der rootCA auch so genannte intermediateCAs verwendet werden.
241
3.4
1198.book Seite 242 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
왘 Erweiterte PseudoRandom Function (PRF): Über PRF werden Schlüsseldaten auf Basis zweier Algorithmen generiert. Dadurch ist selbst bei Kompromittierung eines Algorithmus gewährleistet, das die Verschlüsselung noch intakt ist. 왘 TLS kann mehrere so genannte Cipher Suites verwenden und hat dadurch den Vorteil der Flexibilität und Erweiterbarkeit. 왘 Erweiterte Alarm-Systemmeldungen 왘 Verbessertes, konsistentes Zertifikats-Handling: Client und Server können sich gegenseitig authentifizieren, wobei die Art des Zertifikatsaustausches exakt spezifiziert werden kann. Grundsätzlich ist dabei auf jeden Fall zu beachten, dass SSL und TLS nicht interoperabel sind, d.h., sie können normalerweise nicht zusammen bei ein und derselben Verbindung verwendet werden.
Bezogen auf unseren LDAP-Server bedeutet das bis zu diesem Punkt Folgendes: Alle Anfragen, die wir bisher an den DIT gestellt haben, sind von unserem LDAPServer unverschlüsselt auf Port 389 entgegengenommen worden. TLS bietet uns nun gemäß der LDAPv3-Protokollerweiterung für TLS (spezifiziert in RFC 2830 »LDAP V3 Extension for TLS«) per StartTLS-Request die Möglichkeit, alle TLSVerbindungen ebenfalls über Port 389 anzunehmen. Älteren LDAP-Versionen, die vor der TLS-Standardisierung für eine geschützte Kommunikation zwischen Client und Server eingerichtet wurden, mussten logischerweise einen anderen Weg gehen, und wie wir schon richtig vermuten: den über SSL.
3.4.2
636 – die alte Hausnummer
Wir wissen aus dem echten Leben, wie die Dinge üblicherweise laufen. Ist keine Verlockung da, passiert auch nichts. Egal, ob es sich um Exemplare des anderen Geschlechts handelt oder um schwere Jungs und die Türen an einem Haus. Bleiben wir bei dem Beispiel mit den schweren Jungs und den Türen, das andere führt in Bereiche, die der Menschheit wohl auf ewig Rätsel aufgeben werden. Je mehr Türen an einem Haus existieren, desto mehr potenzielle Möglichkeiten sind vorhanden, eine zu finden, die nicht ausreichend gesichert ist. Für uns bedeutet diese Analogie – auf unseren LDAP-Server umgesetzt –, dass es sehr wohl möglich ist, einen parallelen Betrieb (aber nicht für ein und dieselbe Session) von SSL und TLS zu ermöglichen. Ein Anwendungsfall könnten bestimmte Client-Applikationen sein, die nur per SSL mit unserem LDAP-Server kommunizieren können.
242
1198.book Seite 243 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
Praktisch würde aber beim Start des slapd -zusätzlich zum Standard-Port 389- der »alte« ldaps-Port (Standard: 636) geöffnet werden, über den verschlüsselte Verbindungen per SSL abgewickelt werden (hier auf localhost, ohne Pfadangaben und weitere Optionen): #> slapd -h "ldap:/// ldaps:///"
Und das würde sicherheitstechnisch bedeuten, dass wieder eine Tür mehr – nämlich Port 636 – sichtbar ist. Womit wir wieder beim Anfang des Problems mit den schweren Jungs und den Türen sind. Wir werden im Folgenden beide Ansätze aufzeigen, sowohl die SSL- als auch die TLS-basierte Kommunikation zwischen Client und Server. Dabei werden wir uns aber aus zwei Gründen hauptsächlich auf die TLS-Variante fokussieren. Zum einen bietet TLS gegenüber SSL einige der bereits zuvor genannten Vorzüge, zum anderen ist die TLS-Variante der eigentliche Standard für LDAP (siehe RFC 2830, »LDAP V3 Extension for Transport Layer Security« sowie RFC 4513 »LDAP V3 Authentication Methods and Security Mechanisms«). Dass uns SSL dennoch hilfreich sein kann, werden wir im Folgenden noch bemerken, wenn es z.B. um die einfache Verifikation von Zertifikaten geht. Nun stellt sich aber die Frage, wie die SSL/TLS-Implementierung unter LDAP überhaupt vonstatten geht. Zunächst: Neben der recht trivialen Einbindung von SSL bietet uns TLS gleich zwei Möglichkeiten an, mit denen wir unsere LDAP-Kommunikation verschlüsseln können. Die erste ist ebenfalls recht trivial und ähnelt der SSL-Methode, die zweite ist jedoch wesentlich eleganter, denn bei ihr benötigen wir nicht einmal mehr irgendwelche (Klartext-) DNs und Credentials auf der Clientseite. Zauberei? Nö, nur SASL.
3.4.3
Cyrus-SASL und seine SASLMechs – eine bunte Truppe
SASL klingt zunächst eher wie eine alkoholbedingte Sprachstörung, bedeutet aber einfach nur Simple Authentication and Security Layer. Und SASL macht genau das, was sein Name uns sagt. Es stellt eine am besten als »Zwischenschicht« (engl. Schicht = Layer) zu bezeichnende (Abstraktions-) Ebene zur Verfügung, die verbindungsorientierte Protokolle wie z.B. SMTP, HTTP und natürlich LDAP um Authentifizierungsfunktionalitäten erweitert. SASL ist daher also kein eigenständiges Protokoll, sondern eine Ansammlung von Bibliotheken, die gewisse Authentifizierungs-Mechanismen (Kurzform: SASLMechs) zur Verfügung stellen. SASL wurde ursprünglich 1997 in RFC 2222 definiert, 2006 kam mit RFC 4422 eine aktualisierte Version heraus, die die alte obsolet machte.
243
3.4
1198.book Seite 244 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Von den erwähnten SASLMechs stehen uns durch das Cyrus-SASL-Paket diverse zur Verfügung, die jeweils spezifische Authentifizierungsmechanismen zur Verfügung stellen, u.a. ANONYMOUS, PLAIN, OTP (One-Time-Password, siehe voriges Kapitel), CRAM-MD5, DIGEST-MD5, EXTERNAL, GSSAPI. Kleiner Tipp an dieser Stelle: Das Tool pluginviewer(8) (SUSE) bzw. saslpluginviewer(8) (Debian) des Cyrus-SASL-Pakets liefert uns hilfreiche Statusinformationen über die verfügbaren Mechs.
Bereitgestellt wird das Paket Cyrus-SASL, wie der Name Cyrus schon vermuten lässt, von den gleichen Entwicklern wie dem Cyrus-IMAP-Mailserver: die Carnegie Mellon University (http://asg.web.cmu.edu/sasl). Die etwas spärlich ausgefallene Dokumentation zum Cyrus-SASL -Paket findet sich im Unterordner ../doc des Paketes. Leider ist zudem die aktuellste CyrusSASL-Variante mittlerweile schon wieder über zwei Jahre alt, also beileibe nicht aktuell. Und leider gibt es derzeit keine Alternativen zu diesem SASL-Paket; der einzige andere Vertreter der Gattung – GNU-Sasl – kann aktuell leider aufgrund diverser Implementierungsprobleme immer noch nicht mit OpenLDAP eingesetzt werden. Weiter im Text: Mit Hilfe der eben genannten AuthMechs (kurz »Mechs«) bietet uns Cyrus-SASL also die relativ einfache Möglichkeit, unterschiedliche Authentifizierungsvarianten für bestimmte Applikationen einzusetzen. Schauen wir uns ein paar Mechs an. Den SASLMech GSSAPI (Generic Security Service Application Programming Interface) werden wir uns in einem späteren Kapitel noch genauer vornehmen, und zwar dann, wenn es um Kerberos geht. PLAIN verwendet Klartextpasswörter, CRAM- und DIGEST-MD5 bieten die Möglichkeit, Shared Secrets für die Verschlüsselung zwischen Client und Server zu verwenden, setzen jedoch eine separate Datenbank (sasldb2) voraus, in der die User und Credentials mittels saslpasswd2(8) separat verwaltet werden. Im Zusammenspiel mit OpenLDAP für uns daher so nötig wie eine Schwimmweste in der Wüste Gobi. EXTERNAL wird daher der SASLMech unserer Wahl sein. Warum? Das werden wir sofort durchleuchten. Zuvor aber zum funktionellen Modell. Die komplette SASL-Funktionalität wird in RFC 4422 (»Simple Authentication and Security Layer, – SASL«) beschrieben, wir beschränken uns in dem nachfolgenden SASL-Funktionsmodell nur auf eine Abstraktion der wichtigsten Punkte. Hier eine stark abstrahierte Darstellung:
244
1198.book Seite 245 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
SMTP
IMAP
LDAP
... weitere Protokolle
SASL Abstraction Layer
PLAIN
EXTERNAL
Abbildung 3.10
GSSAPI
... weitere Mechs
Vereinfachtes SASL-Funktionsmodell
Anhand der vereinfachten Darstellung lässt sich erkennen, wie SASL arbeitet: Wie bereits erwähnt, handelt es sich um einen Abstraktionsmechanismus, der zwischen den Protokollen (in unserem Fall ldap) und dem Authentifizierungsmechanismus (in unserem Fall EXTERNAL, später auch GSSAPI) »vermittelt«. Unser Ziel soll es am Ende sein, den anfragenden Client über TLS und den SASLMech EXTERNAL verschlüsselt gegen unsere LDAP-Datenbank zu authentifizieren. Wir wählen diesen SASLMech, weil er dabei – wie sein Name schon andeutet – als einziger auf externe Dienste zurückgreift, in unserem Fall soll er hierzu TLS verwenden. Ein weiterer Vorteil dieser Authentifikationsmethode besteht darin, dass wir mit Hilfe von Mech EXTERNAL den DN des Zertifikats dazu verwenden können, um uns zu authentifizieren. Mech EXTERNAL stellt dabei selbst keinen eigenen Security Layer zur Verfügung, wie z.B. GSSAPI, denn dies tut ja bereits TLS. Ebenso kann bei Verwendung von SASLMech EXTERNAL gemäß RFC4422 auch IPSec als externer Service [ RFC4301 »Security Architecture for IP« ] eingebunden werden.
Der Ablauf stellt sich dabei wie folgt dar: Der LDAP-Client initiiert – Protokollversion 3 und StartTLS-Extension (OID:1.3.6.1.4.1.1466.20037) vorausgesetzt – eine verschlüsselte Session mit dem LDAP-Server, wobei zunächst die zu verwendende SSL-/TLS-Version ausgehandelt wird, und anschließend der Austausch der X.509Zertifikate stattfindet. Erst nachdem die verschlüsselte Verbindung etabliert wurde, kommt unser SASLMech EXTERNAL ins Spiel und kümmert sich per übermitteltem Zertifikats-DN um die Authentifizierung gegenüber dem LDAP-Server. Unser Ziel Im ersten Schritt werden wir X.509-Zertifikate generieren, die wir in unseren LDAP-Server einbinden. Dadurch können wir – je nach gewählten Einstellungen – sowohl SSL als auch TLS nutzen, die notwendigen Vorgehensweisen hierzu
245
3.4
1198.book Seite 246 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
sehen wir uns natürlich auch im Detail an. Anschließend werden wir den SASLMech EXTERNAL so konfigurieren, dass wir mit ihm verschlüsselte Verbindungen (sowohl LDAP-Client und – Server als auch zwischen den LDAP-Servern zur Absicherung der Replikation) aufzubauen. Hierbei werden wir letztlich sogar ganz ohne Klartext-Nutzerdaten (DNs) und Passwörter auskommen, und alle Authentifizierungsvorgänge nur noch über den DN des Zertifikats abwickeln. Und nicht nur das – über entsprechende Umwandlung des Zertifikats-DN in den DN eines beliebigen LDAP-Objekts (z.B. unser replicator-DN) können wir elegant die Anwendung von ACLs auf diese Identität einbringen. Wenn wir alles fertig durchkonfiguriert haben, wird unser Konstrukt in allen Belangen eine verschlüsselte und abhörsichere Kommunikation zwischen allen beteiligten Parteien ermöglichen: vom Client zum Server und zwischen allen replizierenden Servern. Lauschangriff? Okay, Mister Innenminister, der kann kommen.
3.4.4
Ja siiiisscher dat: – TLS-Konfiguration mit SASLMech EXTERNAL
Los geht’s mit der Konfiguration für unseren ldapmaster.local.site. Im ersten Schritt kümmern wir uns um die Erstellung der Zertifikate, wobei das OpenSSLPaket ins Spiel kommt, das uns alles Erforderliche zur Verfügung stellt. Um eine verschlüsselte Verbindung zwischen der Client-Applikation und dem Server aufzubauen, benötigen wir in unserer Konfiguration mehrere Dinge: das eigentliche Zertifikat (Certificate), den Schlüssel (Key) und eine so genannte Certificate- bzw. Certification Authority (CA). Diese CA (oder auch rootCA) wird benötigt, um den unsignierten Zertifikats-Request zu signieren und damit eindeutig zu beglaubigen; Marke: Du kriegst jetzt einen Stempel mit Unterschrift – »tested and approved«. Bei kommerziellem bzw. öffentlich stark frequentiertem Einsatz sollte dabei üblicherweise auf Zertifikate von allgemein anerkannten Anbietern (okay, nachdem Verisign die beiden nächstgrößten Thawte und GeoTrust geschluckt hat, sind die Alternativen nicht mehr riesengroß) zurückgegriffen werden, um User nicht mit »von hauseigener CA« signierten Zertifikaten zu verschrecken. So können sie wenigstens den Aussteller des beglaubigten Zertifikats eindeutig verifizieren, was bei einseitiger bzw. rein serverseitiger Verschlüsselung aber streng genommen auch nicht wirklich viel bringt. Denken wir an das Debian/OpenSSL-Desaster ... Für unseren Testaufbau bzw. für den Betrieb in privaten/firmeninternen Netzen sollten die mittels eigener CA signierten Zertifikate mehr als ausreichend sein. Zuerst erstellen wir ein Backup der Datei openssl.cnf, die unter anderem für die DN-Einträge unseres Zertifikats zuständig ist. Bei Debian und SUSE finden wir die Datei unter /etc/ssl/. Danach beginnen wir mit unseren Modifikationen.
246
1198.book Seite 247 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
Diese sind zwar nicht zwingend notwendig, können uns aber gerade bei der Erstellung mehrerer Zertifikate jede Menge Tipparbeit abnehmen. Eine vorkonfigurierte Version findet sich in den Beispieldaten zu diesem Abschnitt (http:// www.galileocomputing.de/1801); hierbei sollte jedoch auf die tatsächlich eingesetzte Version und gegebenenfalls damit verbundene Einschränkungen/Änderungen geachtet werden. Im nachfolgenden Listing sind nur die geänderten Positionen der Datei openssl.cnf mit Kommentaren angeführt, und zwar so, dass die relevanten Parameter für den DN unseres LDAP-Servers ldapmaster.local.site angepasst sind: [ policy_match ] # countryName wurde deaktiviert, domainComponent hinzugefügt domainComponent = match ... [ policy_anything ] # countryName wurde deaktiviert, domainComponent hinzugefügt domainComponent = optional ... [ req_distinguished_name ] ... # countryName wurde deaktiviert, domainComponent hinzugefügt # die 0. und 1. vor den Einträgen bewirken eine multiple # Verwendbarkeit und Verkettung der Parameters -> local.site 0.domainComponent = TLD Domaenen-Komponente (dc=site) 0.domainComponent_default = site 1.domainComponent = Zweite Domaenen-Komponente (dc=local) 1.domainComponent_default = local stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = Deutschland localityName = Locality Name (eg, city) localityName_default = Dortmund organizationName = Organization Name (eg, company) organizationName_default = Brainstorm ... commonName = Common Name (eg, YOUR name) commonName_max = 64 # Der Parameter commonName ist einer der wichtigsten, da TLS # den DN aus dem Zertifikat ausliest. Stimmt der DN nicht # mit dem echten FQHN/Usernamen überein, kommt es zu # Problemen!
Die übrigen Parameter können bei Bedarf noch angepasst werden, für uns reicht die aktuelle Konfiguration jedoch soweit aus.
247
3.4
1198.book Seite 248 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Kommen wir nun zu den vier erforderlichen Schritten, um die CA, das Zertifikat und den Schlüssel zu generieren und zu extrahieren. Für die ersten drei Schritte bringt OpenSSL zwei Skriptvarianten in bash und perl mit (CA.pl/CA.sh), die diesen Job hervorragend erledigen und das Prozedere für uns um einiges vereinfachen. Wer einen Blick in die Skripte wirft, wird feststellen, dass dort auch keine schwarze Magie am Werk ist, sondern nur eine durchdachte Aneinanderreihung der zum Teil sehr komplexen Konfigurationsparameter des openssl-Kommandozeilen-Befehls. Die Skripte finden sich unter /usr/share/ssl/misc/ (SUSE) bzw. /usr/lib/ssl/misc/ (Debian). Aber da wir auch davon ausgehen müssen, dass in bestimmten Fällen eventuell keine Skripte vorhanden sind, betrachten wir am Ende des nächsten Abschnitts ergänzend die Vorgehensweise zur »manuellen« Zertifikatsgenerierung mit openssl-Kommandos – eben from the scratch. Das hatten wir ja schließlich schon ein paar Abschnitte lang nicht mehr. Debiles Debian Vorab noch ein wichtiger Hinweis zu Debian, das aus Lizenzgründen üblicherweise so gut wie alle Pakete gegen GnuTLS linkt, was in allen folgenden OpenSSL-relevanten Betrachtungen definitiv zu Problemen führt. Abhilfe schafft hier nur eine sauber gegen die OpenSSL-Bibliotheken kompilierte Version des jeweiligen Pakets, insbesondere natürlich OpenLDAP. Auf etwaige Debian-spezifische GnuTLS-Problematiken werden wir daher in allen folgenden Kapiteln nicht mehr gesondert eingehen. Howard Chu äußerte sich im Februar 2008 sehr eindeutig zu diesem Punkt: »… In short, the code [of GnuTLS] is fundamentally broken; most of its external and internal APIs are incapable of passing binary data without mangling it. The code is completely unsafe for handling binary data, and yet the nature of TLS processing is almost entirely dependent on secure handling of binary data. I strongly recommend that GnuTLS not be used. All of its APIs would need to be overhauled to correct its flaws and it's clear that the developers there are too naive and inexperienced to even understand that it's broken.« Dem haben wir nichts hinzuzufügen.
3.4.5
Eine Frage der Zertifizierung – X.509-Zertifikate per Skript
Vorab ein kurzes Wort zu den Befehlsoptionen -newcert und -signcert der im Folgenden genannten Skripte: sie sollten in unserem Fall tunlichst nicht verwendet werden, da sie selbst-signierte Zertifikate kreieren, die in Verbindung mit den nachfolgenden SSL/TLSKonfigurationen in jedem Fall zu Fehlern führen.
248
1198.book Seite 249 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
Schritt 1: Generierung der CA Eine extrem wichtige Anmerkung vorab: Den folgenden Schritt führen wir für unsere kleine Zertifikats-Infrastruktur nur genau ein Mal durch. Im Klartext: Wir erstellen nur genau 1 (eine) CA, die beliebig viele Zertifikate signiert. Bevor wir den ersten Befehl abschicken, wechseln wir natürlich in den entsprechenden ssl-Unterordner. Mit #> ./CA.pl -newca
wird zunächst die komplette Verzeichnisstruktur demoCA/ angelegt. Im folgenden Dialog können wir zunächst den Namen des CA-Files (optional) angeben, anschließend müssen wir ein Passwort für den Schlüssel der CA vergeben, wozu wir der Einfachheit halber »linux« wählen. Danach bestätigen wir alle DN-Vorgaben, bis die Abfrage zu common Name erscheint. Dort setzen wir einen eindeutigen Wert ein, z.B. »CA-Brainstorm«. Danach bestätigen wir alle weiteren Angaben mit [Return], bis das Passwort des eben gesetzten Schlüssels abgefragt wird. Wir bestätigen es mit »linux«. Die komplette Ausgabe des eben beschriebenen Dialogs sollte sich aufgrund unserer angepassten openssl.cnf-Datei, in etwa so darstellen: CA certificate filename (or enter to create) Making CA certificate ... Generating a 1024 bit RSA private key ..........................................++++++ .................++++++ writing new private key to './demoCA/private/cakey.pem' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----You are about to be asked to enter information that will be incorporated into your certificate request. ... ----TLD Domaenen-Komponente (dc=site) [site]: Zweite Domaenen-Komponente (dc=local) [local]: State or Province Name (full name) [Deutschland]: Locality Name (eg, city) [Dortmund]: Organization Name (eg, company) [Brainstorm]: Organizational Unit Name (eg, section) []: Common Name (eg, YOUR name) []:CA-Brainstorm Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: Using configuration from /etc/ssl/openssl.cnf Enter pass phrase for ./demoCA/private/cakey.pem:
249
3.4
1198.book Seite 250 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Check that the request matches the signature Signature ok
Anschließend bekommen wir die Details des CA(!)-Zertifikats zu sehen: Certificate Details: Serial Number: 8e:f0:d5:06:ef:d8:ad:51 Validity Not Before: Nov 21 15:23:54 2008 GMT Not After : Nov 21 15:23:54 2011 GMT Subject: domainComponent = site domainComponent = local stateOrProvinceName = Deutschland organizationName = Brainstorm commonName = CA-Brainstorm X509v3 extensions: X509v3 Subject Key Identifier: C9:B8:B6:33:B6:8C:EE:9B:25:A8:23:68:A8:CF:31:36:DC:65:55:E1 X509v3 Authority Key Identifier: keyid:C9:B8:B6:33:B6:8C:EE:9B:25:A8:23:68:A8:CF:31:36:DC:65:55:E1 DirName:/DC=site/DC=local/ST=Deutschland/O=Brainstorm/CN=CA-Brainstorm serial:8E:F0:D5:06:EF:D8:AD:51 X509v3 Basic Constraints: CA:TRUE Certificate is to be certified until Nov 21 15:23:54 2011 GMT (1095 days) Write out database with 1 new entries Data Base Updated
Das war’s schon. Unsere CA (Certification Authority) liegt nun im PEM-Format (Base64-kodiert) in der Datei cacert.pem unterhalb des Ordners demoCA/. Der zugehörige CA-Schlüssel wurde in der Datei demoCA/private/cakey.pem abgelegt. Der commonName des CA-Zertifikats spielt in diesem Ausnahmefall eine untergeordnete Rolle, da die CA »nur« zur Beglaubigung der eigentlichen Zertifikate verwendet, ihr eigener cn jedoch nicht ausgewertet wird. Da wir nun stolze Besitzer einer eigenen CA sind (wer braucht schon Verisign?), mit der wir unsere Zertifikate signieren können, können wir uns als Nächstes an die Erstellung des eigentlichen Zertifikats machen. Das läuft in zwei Schritten ab. Zunächst erstellen wir ein unsigniertes Zertifikat (einen so genannten ZertifikatsRequest), welches anschließend mit unserer CA signiert und somit beglaubigt wird. Die öffentlich zugängliche CA wird später von den Clients und/oder Servern benötigt, um die von der jeweiligen Gegenstelle angebotenen Zertifikate zu verifizieren. Dazu später mehr in den TLS-relevanten Settings unserer slapd-Konfiguration.
250
1198.book Seite 251 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
Schritt 2: Erzeugen des Zertifikat-Requests #> ./CA.pl -newreq
Das Vorgehen und die Eingaben gestalten sich analog zu Schritt 1, als Passwort verwenden wir wiederum »linux«. Die Ausgabe entspricht in größten Teilen ebenfalls der aus Schritt 1, da wir jedoch nun einen expliziten Zertifikats-Request für unseren Server ldapmaster.local.site erstellen, muss der Common Name im Zertifikats-DN auch exakt so lauten. Die letzte Zeile des Dialogs sagt uns, wo wir den Zertifikats-Request finden können, nämlich in der Datei newreq.pem: Request is in newreq.pem, private key is in newkey.pem
Achtung: Falls hier – abhängig von der verwendeten OpenSSL-Version und damit auch gegebenenfalls abweichenden Skripten – folgender Output erscheinen sollte: Request (and private key) is in newreq.pem
muss Schritt 4 mit der Datei newreq.pem anstatt mit newkey.pem durchgeführt werden. Schritt 3: Signieren des Zertifikates #> ./CA.pl -sign
Hierbei signieren wir unseren eben erstellten Zertifikats-Request (newreq.pem) mit unserer CA, am Ende erhalten wir das signierte Zertifikat newcert.pem. Als Passwort benötigen wir das des Schlüssels der CA (»linux«) und bestätigen die beiden Signierungs-Abfragen mit [y] (yes). Die Ausgabe sieht – stark gekürzt – wie folgt aus: Using configuration from /etc/ssl/openssl.cnf ... Certificate Details: ... Validity Not Before: Nov 21 15:50:15 2008 GMT Not After : Nov 21 15:50:15 2009 GMT Subject: ... commonName = ldapmaster.local.site ... Certificate is to be certified until Nov 21 15:50:15 2009 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated Signed certificate is in newcert.pem
251
3.4
1198.book Seite 252 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Schritt 4: Extraktion der Passphrase Wir sind kurz vor der Zielgeraden: Die Extraktion der Passworts aus dem Zertifikats-Request bzw. der Request-Key-Datei ist zwangsläufig erforderlich, wenn wir nicht jedes Mal beim Start des slapd zur Verifikation des Zertifikats das Passwort eintippen möchten. #> openssl rsa -in newkey.pem -out ldapkey.pem
Die Passwortabfrage verlangt das in den Schritten zuvor gesetzte Passwort, also »linux«. Die Ausgabe sieht wie folgt aus: Enter pass phrase for newkey.pem: writing RSA key
Der Passworteintrag wird dabei in die Datei ldapkey.pem geschrieben. Nun haben wir alle erforderlichen Schritte erledigt, die die Generierung der CA und des Zertifikats mit zugehörigem Key betreffen. Um alles schön übersichtlich zu halten, legen wir nun unterhalb unseres eigentlichen OpenLDAP-Konfigurationsordners (/etc/ldap bzw. /etc/openldap) einen Ordner namens certs an. Dorthin kopieren wir die zuvor generierten Dateien: cacert.pem, newcert.pem und ldapkey.pem. Anschließend nicht vergessen, den Ordner und die Zertifikate für den User/die Gruppe lesbar zu machen, mit deren Rechten unser slapd läuft. Aber allein damit sind wir natürlich noch lange nicht fertig. Schließlich müssen wir unserem slapd auch noch sagen, das er von nun an auch verschlüsselt kommunizieren soll. By the way: Auch wenn die Attributwerte für die Zertifikats-Pfade jederzeit in eine unverschlüsselt laufende Online-Konfiguration eingebunden werden könnten, wird der TLS-Modus nicht stante pede aktiviert. Eine derart tiefgreifende Änderung des Betriebsmodus kommt leider ohne Restart unseres slapd nicht aus, ohne ihn ernten wir höchstens das Übliche: unsupported operation "1.3.6.1.4.1.1466.20037" in den Logs, wenn wir eine TLS-Operation von der Clientseite initiieren. Schritt 5: Anpassung der slapd.conf auf unserem ldapmaster.local.site für die Verwendung von TLS Betrachten wir das Setup am Beispiel einer statischen slapd.conf. Dazu nehmen wir in der slapd.conf folgende Einträge in der globalen Sektion vor: TLSCertificateFile /etc/openldap/certs/newcert.pem # von unserer CA signiertes Zertifikat TLSCertificateKeyFile /etc/openldap/certs/ldapkey.pem # privater Schluessel TLSCACertificateFile /etc/openldap/certs/cacert.pem # Zertifikat unserer CA
252
1198.book Seite 253 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
TLSVerifyClient allow # Verfahrensweise fuer Handshake: bei Verwendung des SASL# Mechs EXTERNAL darf dieser Wert keinesfalls »never« oder # gar nicht gesetzt sein!
Die ersten drei Einträge zeigen auf den Ablageort von Zertifikat, Key und CA, der vierte, für Mech EXTERNAL relevante und unabdingbare Eintrag, bestimmt, wie beim Handshake mit gegebenenfalls vorhandenen Client-Zertifikaten umgegangen werden soll. Mögliche Einträge hierfür sind never, allow, try und demand(|hard|true); siehe hierzu unbedingt auch man 5 slapd.conf bzw. man 5 slapd-config. Allow besagt (vereinfacht ausgedrückt), dass auch für den Fall, dass kein oder ein ungültiges Zertifikat vom Client kommt, die Ausführung trotzdem fortgesetzt wird. Sobald die TLS- Funktionalität ausgiebig und erfolgreich getestet wurde, sollte der Parameter später in jedem Fall, vor allem in Produktivumgebungen, auf demand umgestellt werden. Noch einmal zur Erinnerung: "never" darf als Parameter für TLSVerifyClient in Verbindung mit dem SASLMech EXTERNAL keinesfalls verwendet werden, da der Server vom Client in jedem Fall ein Zertifikat für den Handshake erwartet!
Des Weiteren muß in der SASLMech-bezogenen Konfigurationsdatei des CyrusSASL-Paketes: .../sasl2/slapd.conf der Mech EXTERNAL in die Liste der verfügbaren Mechs eingetragen werden, falls er dort noch nicht aufgelistet ist, z.B.: mech_list: gssapi digest-md5 cram-md5 external
Weitere Infos zu dieser Datei finden sich in der Cyrus-SASL-Dokumentation, der Ablageort variiert von Distribution zu Distribution, bei OpenSUSE 11 ist es z.B. / etc/sasl2/ bei Debian /etc/ldap/sasl2/, default: /usr/lib/sasl2/. Schritt 6: Weitere Server-/Client-/User-Zertifikate und Anpassung Die Erstellung aller weiteren Zertifikate entspricht den bereits in Schritt 2 bis 4 erläuterten Vorgehensweisen, wobei der Common Name jedes weiteren Servers bzw. Users entsprechend seines FQHN’s bzw. LDAP- cn’s angepasst werden muss. An dieser Stelle sollten wir gleich die Zertifikate für unseren ldapslave.local.site generieren, da wir sie im übernächsten Abschnitt 3.5, »Replikation und Chaining auf Nummer sicher«, bereits benötigen werden. Noch einmal zur Erinnerung: Der erste Schritt (Erzeugung der CA) darf unter keinen Umständen erneut ausgeführt werden, da sonst unsere »alte« CA für die frisch erzeugten Zertifikate nicht mehr gültig wäre, und ebenso andersherum!
253
3.4
1198.book Seite 254 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Wir erstellen das Zertifikat und den Key des Slaves auf dem Master(!) und verwenden zur Signierung der Zertifikate also die gleiche, auf dem Master bereits vorhandene CA-Datei (cacert.pem), d.h., wir überspringen den Schritt 1 (./CA.pl -newca ) und beginnen im Ordner der Skripte direkt mit Schritt 2, der Erzeugung des Requests: #> ./CA.pl -newreq
Natürlich beachten wir dabei, den korrekten FQHN des Slaves zu verwenden: ldapslave.local.site. Anschließend verfahren wir mit Schritt 3 und 4 in der bereits bekannten Vorgehensweise. Schritt 7: Testlauf und Debugging Jetzt wird’s spannend, denn nun zeigt sich, ob wir die Zertifikate korrekt erstellt, alle Parameter richtig gesetzt haben und, und, und … aber auch hier gilt einfach: Keine Panik! Den meisten Fehlermeldungen lässt sich dank der vorhandenen Debugging-Möglichkeiten, die wir gleich ausführlich vorstellen werden, relativ schnell auf die Schliche kommen. Vor dem Test sollten wir natürlich nicht vergessen haben, unseren slapd auf ldapmaster zu Restarten, damit alle verschlüsselungsrelevanten Settings wirksam werden. Test 1: Einfache, anonyme Konnektierung via TLS
Noch nichts Wildes für den Anfang, wir probieren zunächst nur einen einfachen Connect via TLS ohne Mech EXTERNAL aus. Dazu schicken wir einfach eine entsprechend angepasste ldapsearch-Anfrage auf den Weg, wobei der zusätzliche Schalter -ZZ den Verbindungsaufbau per TLS erzwingt (-Z wäre »toleranter« und würde auch ohne erfolgreiche Server-Antwort weitermachen – sicher nicht das, was wir wollen): #> ldapsearch -x uid=ckent –ZZ
Wenn wir alles richtig gemacht haben, erhalten wir verschlüsselten, lesenden Zugriff auf den Datensatz von ckent; wenn nicht, taucht spätestens an dieser Stelle folgender oder ähnlicher Fehler auf: ldap_start_tls: Protocol error (2)
der dann in den Logs in der Regel noch durch eine Fehlermeldung unsupported operation "1.3.6.1.4.1.1466.20037" (OID der StartTLS extendend_operation) begleitet wird. In dem Fall heißt es einen Blick auf die Debugging-Verfahren am Ende dieses Abschnitts werfen und alles Schritt für Schritt in Ruhe noch einmal durchzugehen.
254
1198.book Seite 255 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
Test 2: Konnektierung via TLS und Mech EXTERNAL
Zum Testen des verschlüsselten Benutzerzugriffs auf die Inhalte unseres DIT via Mech EXTERNAL erstellen wir zunächst manuell den Home-Ordner /home/ckent für unseren Kumpel Clark (diese Erstellung lassen wir später ganz bequem und vor allem vollautomatisch von pam_mkhomedir.so(8) erschlagen, mehr dazu im Abschnitt 3.6 über PAM/NSS und LDAP) und passen den Eigentümer des Ordners entsprechend an. Anschließend bestücken wir ihn mit den entsprechend generierten Zertifikats-Dateien (ldapkey.pem und newcert.pem): Hierbei ist der cn des Zertifikats entsprechend des cn’s unseres User-Objekts anzupassen, in diesem Fall also Clark Kent. Zur exakten späteren Umsetzung des DNs per authz-regexp sollte die ou, in der sich der User befindet, in den Zertifikats-DN mit eingebracht werden. Hier ein Ausschnitt des signierten Zertifikats für den User ckent: Subject: domainComponent ... organizationalUnitName commonName
= site = verkauf = Clark Kent
Mit Zertifikat und Schlüssel (die natürlich ebenfalls für ckent lesbar sein müssen) allein ist es jedoch noch nicht getan. Wir benötigen noch eine Datei (.ldaprc) im Home-Ordner des Users, deren Konfigurationsanweisungen auf die oben angeführten Zertifikatsdateien verweisen: Datei /home/ckent/.ldaprc: TLS_CERT /home/ckent/newcert.pem TLS_KEY /home/ckent/ldapkey.pem
(Eine weitere, applikationsbezogene Möglichkeit wäre die Erstellung einer Datei ldaprc im Ordner der jeweiligen Client-Applikation; siehe hierzu auch man 5 ldap.conf.) In der systemweit gültigen Client-Konfigurationsdatei ldap.conf (libldap) ergänzen wir folgende Parameter: TLS_CACERT TLS_REQCERT
/etc/openldap/certs/cacert.pem allow
Mit dem ersten Eintrag machen wir die CA systemweit bekannt, mit dem zweiten wird das Zertifikatshandling bestimmt (siehe korrespondierender Eintrag TLSVerifyClient in der slapd.conf).
255
3.4
1198.book Seite 256 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Nun wechseln wir per su – ckent die Identität und in den Home-Ordner des Users (eine Anmeldung am System selbst können wir mit unserem LDAP-User noch nicht durchführen, das erledigen wir in Abschnitt 3.6 über PAM/NSS/ LDAP) und starten einen einfachen Test. Hierzu suchen wir als ckent nach dem User-Objekt skiu, und zwar exakt mit folgender ldapsearch-Syntax: ckent@ldapmaster> ldapsearch -Y EXTERNAL -ZZ uid=skiu -LLL
Ein paar kurze Erläuterungen zum kryptographisch relevanten Syntax: Der Parameter –Y leitet die Verwendung eines SASLMechs ein, gefolgt vom eigentlichen Mech, in unserem Fall EXTERNAL. Dieser gesamte Ausdruck ist eigentlich optional, ldapsearch versucht normalerweise, automatisch den geeignetsten SASLMech zu finden, was jedoch nicht immer zum gewünschten Ergebnis führt. Insbesondere wenn mehrere Mechs zur Verfügung stehen, sollte sicherheitshalber der explizit gewünschte angegeben werden. Da wir zusätzlich -ZZ angegeben haben, akzeptiert ldapsearch natürlich auch hier –wie im ersten Test – nur eine erfolgreich abgeschlossene TLS-Operation. Die Antwort auf unsere Suchanfrage sollte wie folgt aussehen; die Nummerierung dient nur der späteren Erläuterung (siehe unten) und ist nicht Teil der Ausgabe; Zeile 2 ist umbrochen: 1) SASL/EXTERNAL authentication started 2) SASL username: cn=Clark Kent,ou=verkauf,o=Brainstorm,l=Dortmund, st=Deutschland,dc=local,dc=site 3) SASL SSF: 0 dn: uid=skiu,ou=forschung,dc=local,dc=site ...
Gibt ldapsearch an dieser Stelle stattdessen das eben bereits erwähnte und höchst unerfreuliche ldap_start_tls: Protocol error (2)
zurück, und im Debug-Output des slapd bzw. seiner Log-Datei taucht die ebenfalls bereits erwähnte folgende oder ähnliche Fehlermeldung auf: unsupported operation "1.3.6.1.4.1.1466.20037"
so ist das ein eindeutiges Indiz dafür, dass TLS (die StartTLS extendend_operation mit der o.a. OID) gar nicht zur Verfügung steht. In der Regel liegt der Fehler hierfür nicht in den Zertifikaten (er würde sich dort normalerweise erst beim Handshake bemerkbar machen) sondern meistens in der LDAP-Konfiguration (Server/ Client/Pam). Analysieren wir nun das nummerierte Listing der oben stehenden, korrekten ldapsearch-Rückmeldung etwas genauer:
256
1198.book Seite 257 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
1) In der ersten Zeile wird bestätigt, dass die Authentifikation per SASLMech EXTERNAL gestartet wurde. 2) In der zweiten Zeile (SASL Username) wird der DN des vom Mech EXTERNAL zur Authentifizierung verwendeten Zertifikats ausgegeben, in unserem Fall also cn=Clark Kent,ou=.....
3) In der dritten Zeile wird der Security Strength Factor (SSF) angegeben, mit dem der Mech arbeitet. Der Wert 0 ist hier irritierend, aber korrekt: Mech EXTERNAL muss sich ja auch nicht um etwaige Verschlüsselungen kümmern, denn das erledigt ja, wie wir bereits wissen, TLS. Zur Übersicht hier eine kleine Auflistung diverser SSF: 왘 0: (null) keine Verschlüsselung 왘 1: Integritätsschutz 왘 56: DES oder vergleichbar 왘 112: Triple DES oder vergleichbar 왘 128: RC4, Blowfish oder vergleichbar 왘 128, 192, 256: AES (Advanced Encryption Standard, DES-Nachfolger) Ein kleiner Tipp an dieser Stelle, da er hier gut passt: Über den slapd.conf(5) bzw. slapd-config(5)-Parameter security (bzw. olcSecurity) können global oder pro Database bestimmte Vorgänge – basierend auf dem SSF, mit dem ein DN auf den DIT zugreift – erlaubt oder abgelehnt werden. Ein Beispiel: security update_ssf=256
erwartet für alle schreibenden Operationen einen SSF von 256, was einer erfolgreich abgeschlossenen StartTLS-Operation (siehe unten) entspricht. Für Produktivumgebungen mit Sicherheit kein schlechter Gedanke. Reicht der vom anfragenden Client verwendete SSF nicht aus, bekommt er von unserem slapd folgende oder ähnliche Fehlermeldung um die Ohren gehauen: (stronger) confidentiality required (13)
Interessant in dem Kontext ist auch der korrespondierende Parameter saslsecprops, der dazu dient, die Security Properties der eingesetzten Mechs zu definieren. Infos zu beiden Parametern liefert slapd.conf(5). Der von Mech EXTERNAL übermittelte DN des Zertifikats lässt sich z.B. auch in Verbindung mit authz-regexp und entsprechenden ACLs sehr gut zur Zugriffskontrolle auswerten, was sich schon hier anhand des slapd-Debug-Outputs während des Suchvorgangs erkennen lässt (Zeilen sind teilweise umbrochen), ebenfalls läßt sich hier sehr gut der effektiv verwendete SSF (256) erkennen:
257
3.4
1198.book Seite 258 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
conn=4 op=1 BIND authcid="cn=clark kent,ou=verkauf,o=brainstorm,l=dortmund, st=deutschland,dc=local,dc=site" authzid="cn= clark kent,ou=verkauf,o=brainstorm,l=dortmund, st=deutschland,dc=local,dc=site" conn=4 op=1 BIND dn="cn= clark kent,ou=verkauf,o=brainstorm,l=dortmund, st=deutschland,dc=local,dc=site" mech=EXTERNAL sasl_ssf=0 ssf=256
Sollten statt der zuvor besprochenen korrekten Ausgabe irgendwelche unschönen Fehlermeldungen den Bildschirm füllen, geht’s wie üblich an das Debugging. Im Detail: 왘 Stimmen alle Datei- und Pfadangaben in den Direktiven der beteiligten Dateien (slapd.conf, ldap.conf (2x))? 왘 Datei ~/.ldaprc mit korrekten Direktiven angelegt? (nur EXTERNAL) 왘 Falls die Datei .../sasl2/slapd.conf existiert: Ist der Mech EXTERNAL dort eingetragen? (nur EXTERNAL) 왘 TLSCertificateVerify in der slapd.conf auf allow, try oder demand gesetzt? (nur EXTERNAL) 왘 TLS_CACERT in ldap.conf (Client) gesetzt? 왘 Funktioniert die Namensauflösung? 왘 Stimmen der FQ Hostname in der Client-Datei ldap.conf und der CN im Zertifikat überein? 왘 Sind der Zertifikatsordner und die Zertifikate für den slapd bzw. den User lesbar? 왘 Läuft der slapd? (ps, nmap) 왘 Welche Rückmeldung liefert das Tool pluginviewer(8) des Cyrus-SASL Pakets über die verfügbaren Mechs? Taucht in der /var/log/messages oder der entsprechenden Logdatei die folgende oder ähnliche Fehlermeldung auf: SASL [...] Error: unable to open Berkeley db /etc/sasldb2: No such file or directory
so ist die Ursache eher kosmetischer Natur. Der SASL sucht die (von uns aus bekannten Gründen nicht verwendete) Datei /etc/sasldb2. Nachdem wir sie per #> saslpasswd2 –c irgendeinuser
mit einem Dummy-User angelegt und die Zugriffsrechte angepasst haben, sollte Ruhe im Karton sein. Als weitere Debugging-Maßnahmen stehen uns diverse Mittel auf der ClientSeite zur Verfügung, die konsequenterweise durch einen entsprechenden DebugMode auf der slapd-Seite ergänzt werden sollten:
258
1198.book Seite 259 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
→ Test: Ist der SASLMech EXTERNAL überhaupt verfügbar? #> ldapsearch -x -ZZ -s base -b "" supportedSASLMechanisms
Hier sollte in unserer Konfiguration minimal etwas in dieser Art erscheinen: supportedSASLMechanisms: EXTERNAL
Hinweis: Der durchführende User muss dabei natürlich eine entsprechende .ldpaprc-Datei in seinem Home-Ordner besitzen, die auf gültige Zertifikate verweist. → Test: Funktionieren die Verbindungsherstellung und der Handshake? #> ldapsearch –Y EXTERNAL –d 1 –ZZ
(Der Schalter -d aktiviert wie üblich den Debug-Mode des Client-Tools, alternativ kann der Test natürlich auch ohne Mech EXTERNAL gestartet werden.) Der Handshake (mit EXTERNAL) sollte auf der Serverseite unseres slapd (ebenfalls Debug-Level 1) für ckent etwa so aussehen: TLS trace: SSL_accept:before/accept initialization TLS trace: SSL_accept:SSLv3 read client hello A TLS trace: SSL_accept:SSLv3 write server hello A TLS trace: SSL_accept:SSLv3 write certificate A TLS trace: SSL_accept:SSLv3 write certificate request A TLS trace: SSL_accept:SSLv3 flush data TLS trace: SSL_accept:error in SSLv3 read client certificate A TLS trace: SSL_accept:error in SSLv3 read client certificate A connection_get(12): got connid=0 connection_read(12): checking for input on id=0 TLS certificate verification: depth: 1, err: 0, subject: /DC=site/DC=local/ST=Deutschland/O=Brainstorm/CN=CA-Brainstorm, issuer: /DC=site/DC=local/ST=Deutschland/O=Brainstorm/CN=CA-Brainstorm TLS certificate verification: depth: 0, err: 0, subject: /DC=site/DC=local/ST=Deutschland/L=Dortmund/O=Brainstorm/OU=verkauf/CN=Clark Kent,
issuer: /DC=site/DC=local/ST=Deutschland/O=Brainstorm/CN=CA-Brainstorm TLS trace: SSL_accept:SSLv3 read client certificate A TLS trace: SSL_accept:SSLv3 read client key exchange A TLS trace: SSL_accept:SSLv3 read certificate verify A TLS trace: SSL_accept:SSLv3 read finished A TLS trace: SSL_accept:SSLv3 write change cipher spec A TLS trace: SSL_accept:SSLv3 write finished A TLS trace: SSL_accept:SSLv3 flush data TLS trace: SSL_connect:SSLv3 read finished A ldap_sasl_interactive_bind_s: user selected: EXTERNAL ldap_int_sasl_bind: EXTERNAL ldap_int_sasl_open: host=ldapmaster.local.site SASL/EXTERNAL authentication started
→ Test: Sind die Daten bei der Übertragung wirklich verschlüsselt? #> tcpdump -xXs 10000 -i lo dst port 389
259
3.4
1198.book Seite 260 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Kurze Erläuterung zu den tcpdump-Parametern: -xX kümmert sich (stark vereinfacht ausgedrückt) um den Detailgrad der Ausgabe, -s (snaplen) gibt die zu verwendende Bytegröße an, die von jedem Datenpaket gesnifft wird, und sollte keinesfalls zu klein gewählt werden! Über -i wird das Interface angegeben, auf dem gelauscht wird (hier loopback), und dst (destination) port 389 gibt den Zielport der zu sniffenden Pakete an. Anschließend starten wir auf einer zweiten Konsole als cn=ldapadmin eine authentifizierte, aber unverschlüsselte Suchoperation auf ein beliebiges Objekt: 0x0040: 0x0050: 0x0060:
636e 3d6c 6461 7061 646d 696e 2c64 633d 6c6f 6361 6c2c 6463 3d73 6974 6580 056c 696e 7578
cn=ldapadmin,dc= local,dc=site..l inux
Und danach als ckent per EXTERNAL die verschlüsselte Gegenprobe. Letztere sollte uns bis auf den DN des Zertifikats nichts Verwertbares zeigen: 0x0120: 0x0130: 0x0140: 0x0150: 0x0160: 0x0170: 0x0180: 0x0190:
f22c 0603 6e64 746d 4272 5504 0603 7430
6401 5504 3111 756e 6169 0b13 5504 819f
1916 0813 300f 6431 6e73 0776 0313 300d
056c 0b44 0603 1330 746f 6572 0a43 0609
6f63 6575 5504 1106 726d 6b61 6c61 2a86
616c 7473 0713 0355 3110 7566 726b 4886
3114 6368 0844 040a 300e 3113 204b f70d
3012 6c61 6f72 130a 0603 3011 656e 0101
.,d....local1.0. ..U....Deutschla nd1.0...U....Dor tmund1.0...U.... Brainstorm1.0... U....verkauf1.0. ..U....Clark.Ken t0..0...*.H.....
Wer danach immer noch meint, ein authentifizierter, aber unverschlüsselter Zugriff wäre sicherheitstechnisch unkritisch, neigt wahrscheinlich auch dazu, seine Kreditkarten plus PINs dem nächsten vertrauenswürdigen Unbekannten auf der Straße zu überlassen. Eine weitere Debugging-Maßnahme stellt die Verifikation der Zertifikate dar. Dies kann im ../ssl/misc/-Unterordner zwar auch über das Kommando #>./CA.pl –verify
erfolgen, allerdings ist das direkte Debugging per openssl s_client da weitaus aussagekräftiger. Nur klappt das nicht über TLS und dem bis jetzt verwendeten Port 389, da sträubt sich SSL. Also kurz die zweite Haustür mit der Nummer 636 wieder geöffnet, und dann schau´n mer mal ganz kurz, wer zum Essen kommt.
3.4.6
Port 636, die Zweite
Das Setup der veralteten ldaps-Konfiguration ist schnell erklärt, prinzipiell ist nur ein manueller (Re-)Start unseres slapd mit folgenden Parametern notwendig (ohne Pfadangabe zur Binary): #> slapd -h "ldap:/// ldaps:///" <weitere Optionen...>
260
1198.book Seite 261 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
Ein anschließender Check per nmap sollte als Ergebnis unter anderem den frisch geöffneten ldaps-Port 636 anzeigen. Als weitere Debugging-Variante haben wir die Möglichkeit, die Zertifikate per openssl zu verifizieren. Dazu rufen wir openssl (im Beispiel ohne Pfadangaben) wie folgt auf: #> openssl s_client -connect localhost:636 -CAfile \ cacert.pem -showcerts
Der Output liefert nun die Zertifikate, der Abbruch erfolgt mit [Strg] + [C]. Die letzten Zeilen des Outputs sollten so aussehen: Acceptable client certificate CA names /DC=site/DC=local/ST=Deutschland/O=Brainstorm/CN=CA-Brainstorm --SSL handshake has read 2011 bytes and written 346 bytes --New, TLSv1/SSLv3, Cipher is AES256-SHA Server public key is 1024 bit Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES256-SHA ... Verify return code: 0 (ok)
Sollten sich stattdessen folgende oder ähnliche Fehlermeldungen einschleichen: error:...SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_ pkt.c:1053:SSL alert number 40 ...
stellen wir übergangsweise den Parameter TLSVerifyClient in unserer slapd.conf von demand auf das etwas weniger strenge allow zurück. Kurzer Hinweis zum oben aufgeführten openssl-Befehl: Die in etlichen Nachschlagewerken angeführte Syntax ohne explizite Angabe eines CAfiles: #> openssl s_client -connect localhost:636 –showcerts
führt typischerweise zu Fehlermeldungen dieser Art: ”Unable to get local issuer bzw. Unabe to verify first certificate.”
oder Verify return code: 19 (self signed certificate in certificate chain)
Eine »normale« ldapsearch-Anfrage über Port 636 sieht wie folgt aus: #> ldapsearch -x -H ldaps://ldapmaster.local.site uid=eripley
261
3.4
1198.book Seite 262 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Der slapd-Debug Output im Level 256 sollte uns zeigen, dass wie erwartet die ldaps-Query über Port 636 stattgefunden hat: conn=0 fd=14 ACCEPT from IP=192.168.198.11:39546 (IP=0.0.0.0:636) conn=0 fd=14 TLS established tls_ssf=256 ssf=256
Statt der früher verwendeten Parameter -h (Host) und -p (Port) sollte nur noch wie im Beispiel der Parameter -H in Verbindung mit der LDAP-URL verwendet werden. Fassen wir die möglichen Fehlerquellen/Checkpunkte noch einmal zusammen: 왘 SSL-Kommunkation läuft immer über Port 636 ab, TLS ausschließlich über Port 389. 왘 Die meisten Fehler bezogen auf TLS/SSL treten durch Fehler im Zertifikats-DN und der Namensauflösung auf. CN des/der Server(s) = Full Qualified Hostname! 왘 sasldb-Fehlermeldungen lassen sich u.a. durch Anlegen der /etc/sasldb2 per saslpasswd2 beheben. 왘 Cyrus-SASL funktioniert erst mit dann mit Mech EXTERNAL, wenn eine Datei ~/.ldaprc bzw. ldaprc existiert (siehe oben), die auf die entsprechenden ClientZertifikate verweist, und der Parameter TLSVerifyClient in der slapd korrekt gesetzt ist. Falls nötig, ist die Datei .../sasl2/slapd.conf anzupassen. 왘 In allen beteiligten Dateien müssen immer absolute Pfade zu den Zertifikaten angegeben werden. 왘 Die Prüfung der Zertifikate per openssl s_client muss über ldaps (Port 636) erfolgen, NICHT über 389. 왘 Stimmen Owner und Rechte der Zertifikatfiles bzw. sind sie für slapd bzw. die entsprechenden User lesbar? 왘 Für PAM/NSS per TLS relevant: Der FQ-Hostname im URI-Eintrag in /etc/ (open)ldap/ldap.conf muss gleich dem CN im Zertifikat sein (keine IP verwenden!) Am Ende unseres Kapitels über das Setup von OpenLDAP mit SSL und TLS schauen wir uns nun noch kurz an, wie wir Zertifikate in Handarbeit erzeugen. Wer es ganz eilig hat, kann die nun funktionierende Verschlüsselung auch direkt im nächsten Abschnitt im operativen Replikations-Einsatz testen. Aber später nicht meckern, wenn mal Zertifikate erzeugt werden müssen, kein Skript, Buch oder HowTo zur Hand ist und man gerade mal rein zufällig nicht mit einem Internetzugang ausgestattet sein sollte. Hört sich unwahrscheinlich an? Im Leben nicht ...
262
1198.book Seite 263 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
3.4.7
Handmade – X.509-Zertifikate in Handarbeit
Exkurs zur manuellen Erzeugung von X.509-Zertifikaten In unserem kleinen Exkurs schauen wir kurz hinter die Fassade der eben verwendeten CA.*-Skripte und erzeugen unsere CA, das Zertifikat und den Key manuell. Stichwort »klein«: Das hier beschriebene Vorgehen bezieht sich auf die Möglichkeit, eine eigene Zertifizierungsinstanz zu erstellen – ein höchst untriviales Problem. Daher werden wir uns darauf beschränken, es in Grundzügen zu skizzieren, weil der Umfang der Thematik mehr als mächtig ist. Dreh- und Angelpunkt unserer Konfiguration ist auch in diesem Fall die eben bereits angesprochene Datei openssl.cnf. Die Settings finden sich in der Sektion [ CA_default ] unserer /etc/ssl/openssl.cnf, auf die wir auch konkret Bezug nehmen. Dort wird alles unterhalb des Ordners demoCA/ angelegt. Wenn eine – auch nur mittelgroße – Firma eine Selbstzertifizierung für ihre Dienste und User erzeugt, wird die Verwaltung der Zertifikate, Schlüssel und Sperrlisten schnell eine Angelegenheit großer Unübersichtlichkeit. Aus diesem Grunde wird die openssl.cnf eines Zertifizierungsservers in der Regel um die Sektionen root_CA, server_CA und user_CA erweitert. Wir zeigen eine solche Sektion am Beispiel der dort vorhandenen Sektion [ CA_default ]: RANDFILE = $ENV::HOME/.rnd # Zufallsdatei des Benutzers [ ca ] default_ca = CA_default # The default ca section [ CA_default ] dir = ./demo_CA # Relativer Pfad zu unserem demoCA-Ordner certs = $dir/certs # Hier sind die ausgestellten Zertifikate crl_dir = $dir/crl # und die Widerrufs-/Sperrlisten database = $dir/index.txt # Indexdatei unserer Datenbasis new_certs_dir = $dir/newcerts # Ordner für neue Zertifikate certificate = $dir/cacert.pem # Zertifikatsname der CA serial = $dir/serial # Automatisch fortlaufende Seriennummer crl = $dir/crl.pem # aktuelle Sperrliste (current certificate revocation list) private_key = $dir/private/CAkey.pem # privater Schlüssel der CA default_days = 365 # Gültigkeitsdauer des Zertifikats default_crl_days= 30 # Zeit bis zur Veröffentlichung der # nächsten Sperrliste default_md = sha1 # md-Version, alles unter md5 ist unsicher preserve = no # DN-Reihenfolge einhalten policy = policy_match # policy fuer verwendete Attribute
263
3.4
1198.book Seite 264 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Wie wir erkennen können, bestehen solche CA-Sektionen zum größten Teil aus Pfadangaben. Indem man bei der Zertifikatserstellung auf die entsprechende Sektion korreliert, erreicht man eine klar vorbestimmte Struktur der angestrebten Zertifizierungsinstanz. Das Prozedere Die erste Regel lautet, dass alle erzeugten Zertifikate in ihrer Gültigkeitsdauer vollständig innerhalb der Gültigkeitsdauer ihres root-Zertifikats liegen. Sonst kann es z.B. passieren, dass Microsoft-Produkte das Zertifikat zurückweisen. Außerdem wird von den OpenSSL-Entwicklern empfohlen, einen Tag zu warten, bis man ein neues root-Zertifikat zur Generierung weiterer Zertifikate verwendet. Werden wir also praktisch … Im ersten Schritt muss die Konfigurationsdatei openssl.cnf den Notwendigkeiten unserer (OpenLDAP-)Benutzung angepasst werden. Wie das funktioniert, haben wir bereits im vorigen Abschnitt gesehen. Im zweiten Schritt werden wir mit Hilfe des Zufallszahlengenerators eine stochastische Zahlenkette erzeugen, die unseren Bedürfnissen genügt und sie in einer Datei speichern. Die Variable RANDFILE in unserer openssl.cnf definiert den Ort, an dem diese Datei gespeichert wird. Zur Erstellung solcher zufälligen Zeichenketten stellt uns Linux zwei Werkzeuge zur Verfügung: /dev/random und /dev/urandom. Dabei ist zu bedenken, dass /dev/random mit ungefähr zehn Bytes pro Sekunde recht langsam ist, während /dev/urandom mit ungefähr 50 KByte/s relativ schnell ist. Dies liegt daran, dass in /dev/random die Informationen gespeichert werden, die aus dem Zeitverhalten von »zufälligen« äußeren Ereignissen (Mausklicks, Tastaturbetätigungen usw.) gewonnen werden, während in /dev/urandom die Daten gespeichert werden, die ein Pseudozufallszahlen-Generator erzeugt, dessen Parameter aus /dev/random ausgelesen werden. Da /dev/urandom im Gegensatz zu /dev/random keine Entropiemindestwerte garantiert, liefert es nicht ganz so zufällige Werte wie /dev/random, aber trotzdem reichen sie völlig aus. Sie enthalten auch bit-, byte-, wort- und doppelwortweise keine signifikanten Korrelationen. Deshalb sind /dev/random und /dev/ urandom für relativ langsame Anwendungen wie langsame Simulationen oder das Erstellen von TAN-Listen sehr gut geeignet und auch empfehlenswert, denn diese Devices kosten nichts. Kurzum: Wir verwenden daher /dev/urandom. Mit dem Befehl: #> dd if=/dev/urandom of=.rnd bs=1 count=2048
264
1198.book Seite 265 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
lesen wir 2048 Byte zufälliger Bitmuster aus dem Zufallsgenerator aus und schreiben sie in die Datei .rnd. Wichtig: Weist die Umgebungsvariable RANDFILE nicht auf .rnd, wird ein einkompilierter Default-Wert verwendet. Das erhöht nicht wirklich die Sicherheit … Im nächsten Schritt erzeugen wir einen primären 2048-Bit-Schlüssel, wofür wir das openssl-Kommandozeilentool verwenden. Alternativ zur direkten Eingabe aller Parameter auf der Kommandozeile könnten wir auch eine interaktive OpenSSL-Shell mit der einfachen Eingabe von #> openssl
starten. Dicker Nachteil: Keine History-Funktionalität oder automatische Befehlszeilenvervollständigung wie in unserer Bash. Daher verwenden wir den opensslBefehl mitsamt aller Subparameter direkt auf der Kommandozeile. Eine komplette Übersicht aller openssl-Parameter findet sich in openssl(8). Im ersten Schritt generieren wir einen RSA-konformen Schlüssel für unsere CA, wobei wir uns auf die Ordner-Hierarchie unserer bereits erläuterten demoCAStruktur beziehen; alle Pfadangaben hier und im Folgenden sind relativ. Die folgende Befehlszeile ist umbrochen: #>openssl genrsa -des3 -out demoCA/private/cakey.pem \ -rand .rnd 2048
Die Direktiven im Detail: genrsa – generiere einen RSA-Schlüssel, -des3 – verwende die Verschlüsselungs Methode des3 (Triple DES, Achtung: Wird dieser Operator nicht angegeben, wird der Schlüssel unverschlüsselt abgespeichert!), erzeuge die Datei cakey.pem mit dem Schlüssel im demoCA/– Unterordner private. Verwende zur Erzeugung die Zufallsdaten aus der Datei .rnd, erzeuge den Key mit einer Schlüssellänge von 2048 Bytes. Der Output des oben genannten Befehls sollte so aussehen: 2048 semi-random bytes loaded Generating RSA private key, 2048 bit long modulus .........................................+++ ..................+++ e is 65537 (0x10001) Enter pass phrase for demoCA/private/CAkey.pem: Verifying - Enter pass phrase for demoCA/private/CAkey.pem:
Dieses Passwort soll den Schlüssel vor unautorisierter Verwendung schützen. Wir geben ein frei wählbares Passwort ein und bestätigen es durch eine zweite Eingabe. Dieser frisch erzeugte Schlüssel ist die »Mutter« unserer CA (Certification Authority). Der Schlüssel sollte mindestens so gut gehütet werden wie das Rezept für
265
3.4
1198.book Seite 266 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Coke, denn wer diesen Schlüssel in diesem Stadium in die Hände bekommt, kann damit – genau wie wir gleich tun werden – ein Root-Zertifikat und beliebig viele Requests erzeugen Wer die Sicherheit der CA in der richtigen Weise ernst nimmt, packt den Schlüssel auf ein externes Speichermedium und dann in einen Panzerschrank. Das gilt für das Root-Zertifikat natürlich ebenfalls. Im nächsten Schritt erzeugen wir das Wurzelzertifikat unserer CA (rootCA): #> openssl req -new -x509 -days 730 -key \ demoCA/private/cakey.pem –out demoCA/cacert.pem
Unser Befehl für die rootCA der Reihe nach: openssl req –new erzeugt ein neues Request nach den X509-Syntaxregeln mit einer Gültigkeit von 730 Tagen. Als Schlüssel verwenden wir unseren gerade erzeugten cakey.pem, die Ausgabedatei ist cacert.pem. Wenn wir alles richtig gemacht haben, erscheint der folgende Dialog, den wir bereits aus Schritt 1 des vorigen Abschnitts kennen. Hier wird der DN der CA erstellt: Enter pass phrase for demoCA/private/CAkey.pem: You are about to be asked to enter information that will be incorporated into your certificate request. ... dc (site) [site]: dc (local) [local]: ...
... und so weiter und so fort. Am Ende enthält die Datei cacert.pem das neue Root-Zertifikat, das wir mit dem folgenden Befehl im Klartext betrachten können: #> openssl x509 -in demoCA/cacert.pem -text | less
Anschließend generieren wir ein Schlüsselpaar für den Zertifikats-Request: #> openssl genrsa -des3 -out newkey.pem -rand .rnd 1024
Die Angabe -rand .rnd dient als zusätzliche Quelle von Zufallsdaten bei der Schlüsselerzeugung. Man hätte zwar mit der Option -newkey die Schlüsselerzeugung und die Anlage des Requests in einem Aufwasch erledigen können, hätte dann aber nicht die Möglichkeit gehabt, weitere Zufallsdaten einzusetzen und auf diese Art den Schlüssel sicherer zu machen. Unser privater Schlüssel unterscheidet sich optisch nicht vom privaten Schlüssel der CA – außer natürlich durch den Inhalt des Schlüssels. Im nächsten Schritt erzeugen wir unseren eigentlichen Zertifikats-Request: #> openssl req -new -key newkey.pem -out newreq.pem
266
1198.book Seite 267 Donnerstag, 5. Februar 2009 3:02 15
OpenLDAP mit SSL und TLS
Der Dialog entspricht wieder dem aus Schritt 1 und 2 des vorigen Abschnitts; es wird der DN des Zertifikat-Requests festgelegt. Die beiden letzten optionalen Abfragen stehen anschließend im Klartext im Attributteil des fertigen Zertifikats. So ist die Zertifizierungsinstanz in der Lage, auch bei verlorenen privaten Schlüsseln die Identität des Eigentümers prüfen zu können. Damit sind die wichtigsten Vorbereitungen erledigt. Mit dem vorhandenen Material können wir nun den Zertifikats-Request signieren, um unser eigentliches Zertifikat zu erhalten. Zuvor müssen wir gegebenenfalls noch folgende Dateien innerhalb unserer demoCA-Struktur generieren, falls sie dort noch nicht vorhanden sein sollten : #> touch demoCA/index.txt #> touch demoCA/serial && echo 01 >> demoCA/serial
Mit dem folgenden Befehl signieren wir unseren Zertifikats-Request, wobei wir uns auf die CA_default-Sektion unserer openssl.cnf beziehen: #>openssl ca -name CA_default -keyfile demoCA/private/cakey.pem \ -in newreq.pem -out newcert.pem
Was geschieht also? Um ein Server-Zertifikat zu erzeugen, greift OpenSSL wie von uns gewünscht auf den Abschnitt CA_default in seiner config-Datei openssl.cnf zurück und erzeugt dann aus dem Hauptschlüssel cacert.pem und dem Zertifikats-Request newreq.pem ein neues Server-Zertifikat newcert.pem. Nun muss aus der Schlüsseldatei noch das Passwort entfernt werden, um sie sicher einsetzbar zu machen. Dazu benötigen wir den bereits bekannten Befehl: #> openssl rsa –in newkey.pem –out ldapkey.pem
Damit haben wir alles, was wir brauchen: eine CA, ein von ihr signiertes Zertifikat und den extrahierten Schlüssel. Fassen wir noch einmal kurz die erforderlichen Schritte zusammen: 왘 Wurzelzertifikat der Zertifizierungsstelle erzeugen 왘 Schlüsselpaar erzeugen 왘 Request erzeugen 왘 Request mit dem Wurzelzertifikat signieren 왘 Key extrahieren Damit ist die Arbeit getan, und wir sind am Ende unseres wirklich kleinen Exkurses zu OpenSSL. Aber um es noch einmal deutlich zu sagen: Für den Aufbau einer echten Zertifizierungsinstanz wird das hier nicht genügen. Aber vielleicht konnten wir mit diesem kleinen Exkurs etwas Neugier wecken, um ein wenig tiefer hinter die Kulissen von OpenSSL zu blicken.
267
3.4
1198.book Seite 268 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Mit absoluter Sicherheit hilft es aber dabei, im Falle des Falles auch mal ohne CA.*-Skripte nicht im Regen stehen zu müssen.
3.5
Replikation und Chaining auf Nummer Sicher
»In dieser Welt gibt es zwei Arten von Kryptografie: Die Kryptografie, die Ihre kleine Schwester davon abhält, Ihre Dateien zu lesen, und die Kryptografie, die große Regierungseinrichtungen davon abhält, Ihre Dateien zu lesen.« Bruce Schneier Wenn es einer wissen muss, dann Security-Guru Bruce Schneier. Und man kann es eigentlich nicht besser beschreiben: insbesondere, weil es nicht nur zunehmend unser und anderer Länder »Vater Staat« ist, der von pathologischer Datensammelwut erfasst wird, sondern auch Konkurrenzfirmen und/oder eigene Mitarbeiter, die aus verschiedenen Motivation an die gleichen sensiblen Daten oder Zugangskennungen gelangen möchten. Fakt ist – wenn wir nicht wollen, dass unser Datenverkehr zwischen allen beteiligten Servern und Clients von irgendwelchen Hillbillys durchschnüffelt wird, die das rein gar nichts angeht, müssen wir Vorkehrungen treffen. Den ersten Schritt dazu haben wir bereits erfolgreich hinter uns gebracht – die Erzeugung der Zertifikate und Tests mit den LDAP-Client-Tools. Nun geht es darum, die Replikationsvorgänge unseres guten alten slapd gegen mutwillige Lauscher abzusichern. Wir haben in den Kapiteln über Replikation schon so ziemlich alle Varianten auf die Beine gestellt, die üblicherweise im Praxisumfeld eingesetzt werden. So weit, so gut. Der dicke Knackpunkt dabei: sie waren allesamt unverschlüsselt, und jeder vermeintliche Schlaumichel mit Pseudo-Hacker-Potenzial und rudimentären Sniffing-Kenntnissen kann so die Replikation belauschen und sich jede beliebige Information herausziehen. Wer’s partout nicht glauben will, möge bitte noch einmal einen vertrauensvollen Blick auf das tcpdump-Listing aus Abschnitt 3.4.5, »Eine Frage der Zertifizierung«, werfen oder mit dem gleichen, auf der nächsten Seiten nochmals aufgeführten tcpdump-Befehl einen unverschlüsselten Replikationsvorgang mitsniffen. Wer danach immer noch unverschlüsselt replizieren bzw. mit seinem LDAP-Server kommunizieren will, sollte eine analytische Layer-8-Beratung ernsthaft in Erwägung ziehen. Aber bleiben wir mal bei den privaten und industriellen Datenklauern: um genau solchen Typen – und auch professionelleren Kalibern – den Tag zu versauen, stehen uns grundsätzlich zwei Varianten der Absicherung zur Verfügung. Setup der
268
1198.book Seite 269 Donnerstag, 5. Februar 2009 3:02 15
Replikation und Chaining auf Nummer Sicher
Replikation per SSL oder per TLS, Letztere optional aber Empfohlenerweise per SASLMech EXTERNAL. Betrachten wir im Folgenden die Einbindung der relevanten Direktiven in die Konfiguration unseres slapd. Alle TLS-relevanten syncrepl-Settings gelten natürlich 1:1 für delta-syncrepl.
3.5.1
syncrepl mit TLS
Unseren ldapmaster (Provider) haben wir bereits im letzten Abschnitt über Verschlüsselung mit allen notwendigen LDAP-relevanten Direktiven und Zertifikaten ausgestattet. Auf dem Provider benötigen wir keine zusätzlichen syncreplrelevanten Verschlüsselungsdirektiven, zwingende Voraussetzung für alles Folgende ist natürlich ein funktionierendes TLS-Setup gemäß Abschnitt 3.4.5, »Eine Frage der Zertifizierung«. Da wir natürlich nicht mit einer einseitigen Verschlüsselung arbeiten (wie typische SSL-verschlüsselte Webangebote), braucht unser Consumer ldapslave ebenfalls ein entsprechendes (Client-)Setup. Im ersten Schritt erzeugen wir – sofern noch nicht geschehen – das signierte Zertifikat und den zugehörigen Key für unseren Server ldapslave.local.site entsprechend den Beschreibungen in Abschnitt 3.4.5, »Eine Frage der Zertifizierung«. Nachdem wir sichergestellt haben, dass wir alle notwendigen Zertifikats-Dateien für den Consumer vorliegen haben, kopieren wir diese (newcert.pem und ldapkey.pem des Consumers) sowie das CAfile (cacert.pem) des Providers(!) auf den Consumer, und zwar auch dort in den neu erzeugten Ordner /etc/(open)ldap/ certs/. Zur Eindeutigkeit und besseren Übersicht können wir die Zertifikatsdateien auf dem Consumer auch umbenennen, z.B: CAfile vom Server ldapmaster:
cacert-master.pem
Signiertes Zertifikat ldapslave:
newcert-slave.pem
Key-File ldapslave:
ldapkey-slave.pem
Die Zertifikate und den Key für den Consumer binden wir wie gehabt über die entsprechenden (olc)TLS-Direktiven in die slapd-Konfiguration des Consumers ein (hier in statischer Syntax, der Kommentar dient nur dem Verständnis und gehört nicht zum Listing): TLSCACertificateFile TLSCertificateFile TLSCertificateKeyFile TLSVerifyClient
//cacert.pem //newcert.pem //ldapkey.pem allow #später demand
Auf der Consumer-Seite benötigen wir im Gegensatz zum Provider folgende, zusätzliche und TLS-relevante syncrepl-Subdirektive:
269
3.5
1198.book Seite 270 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
starttls=yes
Alle anderen syncrepl-Direktiven können so belassen werden wie in einer unverschlüsselten syncrepl-Konfiguration. Des Weiteren dürfen wir die Anpassung der Datei ldap.conf (Client) analog zur Providerseite nicht vergessen. Wenn hier die CA nicht systemweit bekannt gemacht wird, haben wir ein Problem (der Kommentar dient nur dem Verständnis und gehört nicht zum Listing): BASE URI TLS_CACERT TLS_REQCERT
dc=local,dc=site ldap://ldapslave.local.site //cacert.pem allow #später demand
Achtung! Wie beim »normalen« TLS-Client-Setup müssen wir auch bei der Kommunikation der Server untereinander per TLS einen wichtigen Punkt beachten: die Client-Zertifikate. Client-Zertifikate? Wozu – wir haben doch schließlich zwei Server. Richtig, aber beim Aufbau der Verbindung – die in diesem Fall von unserem Consumer ausgeht – ist genau Letzterer der Client für unseren Provider. Und damit der TLS-Connect (und damit unser Mech EXTERNAL) problemlos und korrekt funktionieren kann, muss unser Consumer dem Provider gegenüber wie ein Client agieren, und ihm ein gültiges Zertifikat präsentieren. Dazu benötigen wir die bereits bekannte Datei .ldaprc, die wir direkt unterhalb von /etc/(open)ldap/ platzieren und für unseren slapd lesbar machen. In ihr verweisen wir auf das Zertifikat und den Key unseres ldapslave, die unserem Server ldapmaster als Client-Zertifikat übergeben werden (Pfade hier bezogen auf SUSE): TLS_CERT TLS_KEY
/etc/openldap/certs/newcert.pem /etc/openldap/certs/ldapkey.pem
Anschließend starten wir Provider und Consumer im Debug-Mode 1 mit dem »echten« User/ der Gruppe (SUSE: ldap/ldap) und betrachten zunächst, ob der Handshake klappt. Taucht schon hier (TLSVerifyClient auf allow gesetzt) auf der Providerseite etwas in der Art wie unable to get TLS client DN
oder bei TLSVerifyClient demand: SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate
auf, kann die Meldung mehrere Ursachen haben. Hier einige kleine DebuggingChecks vorab: 왘 Sind Zertifikats-Ordner und/oder die Zertifikate für den User/die Gruppe lesbar, mit dessen Identität der slapd auf der Consumer-Seite läuft? 왘 Wurde die Datei .ldaprc im Ordner /etc/(open)ldap/ angelegt, die auf die Consumer-Zertifikate zeigt und für den User/die Gruppe lesbar ist, mit dessen Identität der slapd auf der Consumer-Seite läuft?
270
1198.book Seite 271 Donnerstag, 5. Februar 2009 3:02 15
Replikation und Chaining auf Nummer Sicher
왘 Stimmen die TLSVerfifyClient-Settings in der slapd.conf und der TLS_REQCERT-Wert in der ldap.conf (Client)? 왘 Ist der Pfad zur Datei cacert.pem in der ldap.conf (Client) gesetzt, und ist die cacert.pem für den Consumer-slapd lesbar? Zu Kontrolle der Basisfunktionalität der Verschlüsselung kann der slapd auf beiden Maschinen auch direkt als Root (ohne Parameter -u und -g) gestartet werden, mit einer entsprechenden .ldaprc-Datei im jeweiligen root-Homeverzeichnis (/root). Eine korrekt konfigurierte slapd.conf bzw. ldap.conf (Client) vorausgesetzt, sollte der Handshake bei ebenfalls korrekt erstellten Zertifikaten problemlos über die Bühne gehen. Wenn nicht, hängt das Problem in der Regel nicht mit der zentralen slapd-Konfiguration zusammen.
Der korrekte Handshake (bei TLSVerifyClient demand) sollte auf dem Provider in etwa so aussehen: TLS trace: SSL_accept:before/accept initialization TLS trace: SSL_accept:SSLv3 read client hello A TLS trace: SSL_accept:SSLv3 write server hello A TLS trace: SSL_accept:SSLv3 write certificate A TLS trace: SSL_accept:SSLv3 write certificate request A TLS trace: SSL_accept:SSLv3 flush data ... TLS certificate verification: depth: 1, err: 0, subject: /DC=site/DC=local/ ST=Deutschland/O=Brainstorm/CN=ldapmaster.local.site, issuer: /DC=site/DC=local/ ST=Deutschland/O=Brainstorm/CN=ldapmaster.local.site TLS certificate verification: depth: 0, err: 0, subject: /DC=site/DC=local/ ST=Deutschland/L=Dortmund/O=Brainstorm/CN=ldapslave.local.site, issuer: / DC=site/DC=local/ST=Deutschland/O=Brainstorm/CN=ldapmaster.local.site TLS trace: SSL_accept:SSLv3 read client certificate A TLS trace: SSL_accept:SSLv3 read client key exchange A TLS trace: SSL_accept:SSLv3 read certificate verify A TLS trace: SSL_accept:SSLv3 read finished A TLS trace: SSL_accept:SSLv3 write change cipher spec A TLS trace: SSL_accept:SSLv3 write finished A
Sollte dort eine Fehlermeldung in der Art TLS trace: SSL_accept:error in SSLv3 read client certificate A
auftauchen, kann dies durch selbstsignierte Zertifikate hervorgerufen werden. Da wir in diesem Beispiel TLSVerifyClient auf demand gesetzt haben, wäre ein fehlerhafter oder unvollständiger Handshake in jedem Fall abgebrochen worden, so dass keine unverschlüsselte Kommunikation zustande kommen kann. Theoretisch können wir jetzt also davon ausgehen, dass unsere Kommunikation zwischen ldapmaster und ldapslave über Port 389 und TLS-verschlüsselt über die Bühne geht. Aber Theorie bleibt eben Theorie, und weil wir wie üblich genau wissen wollen, was los ist, sniffen wir selbst mal wieder kräftig auf der Leitung. Dazu lauschen wir per tcpdump auf der Netzwerkkarte unseres ldapslave (hier: eth0):
271
3.5
1198.book Seite 272 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
#> tcpdump -xXs 10000 -i eth0 dst port 389
und starten dann, nachdem wir die Datenbank unseres ldapslave-Servers gelöscht haben, unseren Consumer-slapd mit einem Initial Content Load: 0x00a0: 0x00b0: 0x00c0: 0x00d0: 0x00e0:
0408 1330 746f 6461 7369
130b 1106 726d 706d 7465
4465 0355 311e 6173 301e
7574 040a 301c 7465 170d
7363 130a 0603 722e 3038
686c 4272 5504 6c6f 3036
616e 6169 0313 6361 3137
6431 6e73 156c 6c2e 3131
....Deutschland1 .0...U....Brains torm1.0...U....l dapmaster.local. site0...08061711
... und so weiter und so fort: Bis auf Zertifikats-DNs sollte im tcpdump-Output nichts Verwertbares mehr auftauchen. Zur Gegenprobe (und natürlich für den Aha-Effekt) können wir die syncrepl starttls-Subdirektive noch einmal kurz auskommentieren. Und anschließend wiederholen wir den Vorgang (Initial Content Load): 0x0040: 0x0050: 0x0060:
636e 3d6c 6461 7061 646d 696e 2c64 633d 6c6f 6361 6c2c 6463 3d73 6974 6580 056c 696e 7578
cn=replicator,dc= local,dc=site..l inux
Wir erkennen unschwer den DN des Replikators mit seinem zugehörigen Klartext-Passwort. Also – starttls ganz schnell wieder aktiviert und gut. Oder nicht? Nö – nicht ganz. Denn wir haben immer noch einen Klartext-DN und Kennwörter in unserer Consumer-Konfiguration, und das muss nicht so sein. Schließlich gibt es ja noch unseren alten SASL-Kumpel EXTERNAL, der das perfekt übernehmen kann. Und wie das funktioniert, schauen wir uns im nächsten Abschnitt an. Noch eine kurze Anmerkung zum Schluss: Wir können den Wert für starttls als zusätzliche Fallback-Sicherung von yes auch auf critical setzen: starttls = critical
So wird gewährleistet, dass auch bei irrtümlich falsch gesetzten oder zu laschen globalen TLS-Settings die Replikation abgebrochen wird, wenn der StartTLSRequest fehlschlägt. Sollte bis hierher etwas schief gelaufen sein, und die Chose läuft gar nicht, oder wir erblicken Klartext-DNs, Passwörter oder Objektattribute auch im scheinbar verschlüsselten Modus, ist definitiv etwas schief gelaufen. Aber wie üblich: Keine Panik! Kurz durchatmen, Kaffee holen und in aller Ruhe(!) ans Debugging: 왘 Debug-Level auf beiden Maschinen hochschrauben. 왘 Grundsätzliches SSL/TLS-Setup auf beiden Maschinen in Ordnung? 왘 starttls=yes Subdirektive Consumer gesetzt? 왘 FQHNs statt IPs verwendet?
272
1198.book Seite 273 Donnerstag, 5. Februar 2009 3:02 15
Replikation und Chaining auf Nummer Sicher
왘 Namensauflösung funktioniert? 왘 Zertifikatsdatei und Key auf dem Provider für den Consumer erzeugt? (Nicht die CA cacert.pem, es wird die cacert.pem des Providers für den Consumer verwendet!) 왘 Zertifikatsdateien korrekt eingebunden? Syntax der slapd-Direktiven und die richtigen Dateien verwendet (siehe oben)? 왘 Im Zweifelsfall alle Zertifikate »in einem Rutsch« für Provider und Consumer noch einmal neu erstellen! (Insbesondere bei unspezifischen Fehlern, die mit der CA bzw. den Zertifikaten auftreten). 왘 Wurde die cacert.pem in der ldap.conf (Client) systemweit bekannt gemacht? (TLS_CACERT /etc/(open)ldap/certs/cacert.pem) 왘 Wurde eine Datei .ldaprc unter /etc/openldap/ mit den Verweisen auf die entsprechenden Consumer-Zertifikate angelegt? 왘 Alle Rechte beachtet? (Mit welcher ID laufen die slapd’s – alle Zertifikate/Ordner/Dateien für slapd lesbar?) 왘 TLSVerifyClient gesetzt und ungleich "never"?
3.5.2
syncrepl mit TLS und SASLMech EXTERNAL
Wie wir bereits aus unserem SASL-Test mit Hilfe der LDAP-Client-Tools wissen, wird bei der Anmeldung per EXTERNAL und TLS keine Username/DN und Passwort-Kombination mehr zur Authentifizierung übergeben, sondern stattdessen der Zertifikats-DN. Also genau das Verfahren, das wir jetzt brauchen, wenn wir unsere Consumer-Konfiguration von Klartext-Authentifizierungsdaten befreien möchten. Um unseren SASLMech zu aktivieren, brauchen wir, abgesehen von einem funktionierenden TLS-Setup, das wir ja nun hinlänglich getestet haben, nicht mehr viel. Genau genommen sind es neben der natürlich erforderlichen starttls-Direktive nur zwei neue und eigentlich völlig selbsterklärende Subdirektiven, die als Ersatz für die binddn und credentials Verwendung finden. Dazu wird die bindmethod logischerweise von simple auf sasl umgestellt. Die verschlüsselungsrelevanten syncrepl-Subdirektiven sehen in dieser Konfiguration wie folgt aus: bindmethod=sasl saslmech=EXTERNAL starttls=yes
Noch einmal der Hinweis: Die nun obligaten Sub-Direktiven binddn und credentials entfallen in dieser Konfiguration. Auf der Provider-Seite muss nach wie
vor nichts weiter angepasst werden. Wenn wir nun den Consumer mit einer lee-
273
3.5
1198.book Seite 274 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
ren Datenbank starten, werden wir – je nach gesetzten ACLs auf der Providerseite – spätestens beim ersten Zugriff auf die Daten die gleiche Überraschung erleben wie bei unserem ersten syncrepl-Setup in Abschnitt 3.2.7, »syncrepl«. Nehmen wir an, dass die häufig verwendete Zugriffslimitierung für das Attribut userPassword auf dem Provider aktiv ist, dann sehen wir von diesem Attribut auf der Consumer-Seite zunächst nichts. Warum? Die Auflösung ist so einfach wie logisch, wenn wir einen kurzen Blick in die Debug-Ausgabe unseres Provider-slapd beim Connect des Consumers werfen (2.Zeile umbrochen): do_bind: dn () SASL mech EXTERNAL ==>slap_sasl2dn: converting SASL name cn=ldapslave.local.site,o=brainstorm, l=dortmund,st=deutschland,dc=local,dc=site to a DN <==slap_sasl2dn: Converted SASL name to <nothing>
Unser Provider-slapd versucht nach erfolgreichem Handshake eine Regel zu finden, nach der er den Zertifikats-DN in einen existierenden Account umsetzen kann. Da keine existiert, muss das Konvertierungs-Ergebnis logischerweise <nothing> lauten, und der Request wird nun wie ein anonymer Bind behandelt. Das Verfahren zur Umsetzung eines DNs per authz-regexp kennen wir bereits aus dem Abschnitt 3.2.3 über Chaining, »Gesprengte Ketten«. Der einzige Unterschied liegt nun darin, dass wir keinen »normalen« User-DN, sondern eben den gesamten Zertifikats-DN des Consumers umsetzen, und zwar so, wie er im Debug-Ouput des slapd erscheint (2. Zeile ist umbrochen): authz-regexp "cn=ldapslave.local.site,o=brainstorm,l=dortmund, st=deutschland, dc=local,dc=site" "cn=replicator,dc=local,dc=site"
Natürlich könnten wir auch den kompletten DN des Zertifikats über ACLs auswerten, was aber insbesondere bei multipler Verwendung wohl eher eine Arbeitsbeschaffungsmaßnahme wäre. In unserem Beispiel verwenden wir für das Mapping den bereits bekannten replicator-Account, der über die bereits in Abschnitt 3.2.7, »Synchronization without Frustration«, verwendete ACL (lokale ACL, unterhalb der Datenbank-Sektion des Providers) zwar alles lesen, aber nichts schreiben darf: access to * by dn.exact="cn=replicator,dc=local,dc=site" read stop by * break
Beim nächsten Start im Debug-Mode sollten wir auf dem Provider die erfolgreiche Konvertierung beobachten können:
274
1198.book Seite 275 Donnerstag, 5. Februar 2009 3:02 15
Replikation und Chaining auf Nummer Sicher
do_bind: dn () SASL mech EXTERNAL ==>slap_sasl2dn: converting SASL name cn=ldapslave.local.site,o=brainstorm,l=dortmund,st=deutschland,dc=local,dc=site to a DN ... ==> rewrite_rule_apply rule='cn=ldapslave.local.site,o=brainstorm,l=dortmund,st=deutschland,dc=local,dc =site' string='cn=ldapslave.local.site,o=brainstorm,l=dortmund,st=deutschland,dc=local, dc=site' [1 pass(es)] ... <==slap_sasl2dn: Converted SASL name to cn=replicator,dc=local,dc=site do_bind: SASL/EXTERNAL bind: dn="cn=replicator,dc=local,dc=site" sasl_ssf=0
Job accomplished! Und wenn nicht, die folgenden Punkte prüfen: 왘 Funktioniert die Replikation per TLS ohne EXTERNAL? 왘 Stimmt die Anordnung der ACL, und stimmt der Zertifikats-DN mit dem <match>-Parameter der authz-regexp-Direktive überein? 왘 Bei Verwendung einer konvertierten Online-Konfiguration: TLSVerifyClient nicht gesetzt/nicht mitkonvertiert? (Kann in älteren 2.4.*-Releases vorkommen). Ansonsten hilft wie üblich ein genauer Blick auf die Ausgabe der Daemons im adäquaten Debug-Mode.
3.5.3
syncrepl mit SSL
Kurz erwähnt: Eine weitere – na ja, nennen wir es erstmal großzügig – Alternative ist die bereits bekannte Verwendung von SSL und damit des Ports 636. Ist ldaps:// in den Startoptionen des slapd aktiviert, kann die Replikation über die URI in der provider-Subdirektive von syncrepl ebenfalls auf ldaps eingestellt werden (die Port-Angabe ist optional, Default ist 636): provider=ldaps://ldapmaster.local.site
In dieser Konfiguration entfällt natürlich das starttls-Statement. Der dickste Nachteil: Ohne bindmethod=simple, Klartext-binddn und -credentials-Sub-Direktiven in der syncrepl-Konfiguration des Consumers läuft’s nicht. Also keine wirkliche Alternative zu TLS und EXTERNAL.
3.5.4
Chaining mit TLS und SSL
Die TLS-Verschlüsselung wird über die Overlay chain-Subdirektive: chain-tls
start
275
3.5
1198.book Seite 276 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
aktiviert. Dabei nicht vergessen, gegebenenfalls das zum Hostnamen passende Zertifikat zu generieren, insofern »ldapoffshore« als Hostname verwendet wird. Wir können in dieser einfachen Konfiguration alle chain-Direktiven aus dem unverschlüsselten Setup (»Gesprengte Ketten«) beibehalten, da die Proxy-Autorisierung über die normalen chain-idassert-bind-Direktiven durchgeführt wird, sicherheitstechnisch natürlich erst nach Etablierung der verschlüsselten Verbindung. Wer zudem keine Klartext-Anmeldedaten mehr in der chain-Konfiguration haben möchte, kommt logischerweise um die Konfiguration per Mech EXTERNAL nicht herum. Hierbei entfallen wie üblich die Subdirektiven binddn und credentials, stattdessen müssen die zugehörigen sasl-Subdirektiven von chain-idassert-bind aktiviert werden: chain-idassert-bind
bindmethod=sasl saslmech=EXTERNAL
Statt des idassert-binddn bzw. des »echten« DNs wird in dieser Konfiguration, wie in den vorangegangenen Beispielen, der Zertifikats-DN des jeweiligen UserZertifikats übergeben und ausgewertet. Im Debug-Log kann man den jeweiligen BindDN des Zertifikats klar erkennen (Zeilen sind umbrochen): conn=0 op=1 BIND authcid="cn=clark kent,o=brainstorm,l=dortmund, st=deutschland,dc=local,dc=site" authzid=" cn=clark kent,o=brainstorm,l=dortmund,st=deutschland, dc=local,dc=site" conn=0 op=1 BIND cn=" cn=clark kent,o=brainstorm,l=dortmund,st=deutschland, dc=local,dc=site" mech=EXTERNAL sasl_ssf=0 ssf=256
Das Problem: Der User clark kent existiert nicht in der Unit offshore auf unserem Subtree-Master. Also haben wir die Wahl, entweder eine Identität für die ProxyAutorisierung einzurichten oder einen einfachen Fallback auf eine definierte Identität; beide Varianten können relativ bequem per ACL ausgewertet werden. In diesem Beispiel verwenden wir einen einfachen Dummy-User; Infos und Beispiele zur Proxy-Autorisierung finden sich unter http://www.openldap.org/doc/ admin24/sasl.html#SASL Proxy Authorization. Den Dummy-User fügen wir mit folgendem LDIF im Subtree dc=offshore ein: dn: cn=userdummy,dc=offshore,dc=local,dc=site objectClass: top objectClass: organizationalRole cn: userdummy
Eine sehr einfache authz-regexp-Direktive zur Umsetzung der Zertifikats-DNs und späteren Auswertung per ACLs auf dem Subtree-Master könnte theoretisch so aussehen (zweite Zeile ist umbrochen):
276
1198.book Seite 277 Donnerstag, 5. Februar 2009 3:02 15
Replikation und Chaining auf Nummer Sicher
authz-regexp "cn=(.+),o=brainstorm,l=dortmund,st=deutschland, dc=local,dc=site" "cn=dummyuser,dc=offshore,dc=local,dc=site"
Die adäquaten Direktiven bzw. Objekte auf dem Master können je nach Einsatzzweck anschließend in entsprechender Form ebenfalls auf die Gegebenheiten angepasst werden. Abschließend noch ein paar kleine Tipps zum Chain-TLS-Debugging: 왘 Enstpricht die authz-regexp-Syntax dem korrekten Zertifikats- und Ersetzungs-DN? 왘 Stehen die authz-regexp-Direktiven in der richtigen Reihenfolge? 왘 User-Zertifikate für slapd lesbar? Wichtig bei der TLS-Konfiguration ist die Tatsache, dass die Zertifikate des jeweiligen Users und der Ordner, in dem sie sich befinden, für den slapd lesbar sein müssen. Falls nicht, taucht mit ziemlicher Sicherheit folgender oder ähnlicher Fehler im Debug-Mode auf: TLS: could not use certificate `/home/ckent/newcert.pem'. TLS: error:0200100D:system library:fopen:Permission denied bss_file.c:352
Eine andere Alternative zur Verschlüsselung der Weiterleitung per TLS und EXTERNAL wäre die Verwendung von ldaps über Port 636: Dazu müssten chaintechnisch die referral-Einträge (referral-Objekt im DIT des Masters, das referral-Statement in der globalen Sektion der slapd.conf des Subtree-Masters und die referral-Subdirektiven von Overlay chain auf Master und Subtree-Master) jeweils auf ldaps:// geändert werden. Die Direktive chain-tls entfällt natürlich, und die idassert-bind-Direktiven entsprechen denen der unverschlüsselten chain-Variante. Nachteil: Der binddn und die credentials liegen wieder im Klartext in der Konfiguration, und wir haben wieder einen weiteren, offenen Port. Wie üblich bei SSL nicht vergessen, die unseren slapd mit der entsprechenden Option zu starten.
3.5.5
... und dann war da ja noch die Sache mit den Zertifikaten im Failover-Fall
Ja, wir sehen schon, der Standby-Master lässt uns einfach nicht los, aber das ist auch gut so. Das Problem ist schnell erklärt. Wir haben unser typisches StandbyMaster-Setup mit unseren frisch erworbenen Kenntnissen verschlüsselt aufgesetzt, und alles ist perfekt, oder etwa nicht? Denken wir mal nach: Jeder der beiden Server besitzt sein eigenes Zertifikat, mit seinem jeweiligen FQHN im Zertifikats-DN, was auch völlig richtig ist und genauso sein muss. Aber: den Clients, die eine verschlüsselte Verbindung zum aktiven Master wünschen, kann und muss
277
3.5
1198.book Seite 278 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
es auch völlig gleichgültig sein, welcher der beiden Nodes gerade aktiv ist. Im Klartext: Wir benötigen einen für beide Master identischen »Zertifikats-Alias«, über den jeder der beiden Nodes immer für externe Clients erreichbar ist. Aber auch das ist kein Problem, denn die Möglichkeiten zur Lösung des Problems stellt uns OpenSSL zur Verfügung: Hierzu fügen wir in der /etc/ssl/ openssl.cnf in der Sektion [ usr_cert ] die Zeile subjectAltName mit einem gleichlautenden Alias-CN für beide Nodes ein, bevor wir die Zertifikate generieren. Bezogen auf unsere beiden Server ldapmaster und ldapslave könnten wir z.B. folgendes Setting vornehmen. subjectAltName = DNS: ldapmirror.local.site
Der dort angegebene Hostname muss natürlich im DNS bzw. der Hostnamenauflösung der Clients mit der entsprechenden Service-IP des Clusters assoziiert sein und jederzeit aufgelöst werden können. Im Zertifikat selbst sieht der Eintrag etwa so aus: X509v3 extensions: ... X509v3 Subject Alternative Name: DNS:ldapmirror.local.site
Starten wir nun eine Suche auf dem Mirror per EXTERNAL, sollte das Ergebnis so aussehen: #> ldapsearch -ZZ uid=skiu -h ldapmirror.local.site -LLL SASL/EXTERNAL authentication started SASL username: cn=clark kent,o=Brainstorm,l=Dortmund,st=Deutschland, dc=local,dc=site SASL SSF: 0 dn: uid=skiu,ou=forschung,dc=local,dc=site... und so weiter und so fort...
Noch ein kurze, abschließende Bemerkung: Die gesamte Mimik, mit der wir in den letzten Abschnitten die komplette Kommunikation unseres slapd abhörsicher verpackt haben, bringt uns rein gar nichts, wenn wir von einer unverschlüsselten Station aus adminstrativen Zugriff auf den Baum nehmen. Daher darf die Verschlüsselung der Client-Kommunikation keineswegs vergessen werden, sonst bringt alles vorher Genannte herzlich wenig. Das gilt insbesondere auch für grafische Clients wie den JXplorer oder Apache DS (die wir in Abschnitt 4.7, »Auf den Schirm!«, ausführlich vorstellen).
Das war’s mit unseren replikationstechnischen Betrachtungen. Eine letzte und definitiv absolut »kugelsichere« Variante der verschlüsselten Replikation –mit Kerberos, SASLMech GSSAPI und TLS – werden wir im Abschnitt 4.2 über Kerberos betrachten. Jetzt wird es aber Zeit, dass wir mal schauen, wer da so laut an die Tür des Systems klopft – klingt verdächtig nach einem LDAP-User.
278
1198.book Seite 279 Donnerstag, 5. Februar 2009 3:02 15
Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP
3.6
Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP
»Das ist doch viel zu kompliziert, Al!« »Das glaube ich nicht, Tim.« Tool Time Im Prinzip geht es doch immer nur um das eine: Kommt man rein oder nicht? Und wenn nicht, woran hat es gelegen, dass es nicht geklappt hat? Eine gute Frage. Denn in allen vorhergehenden Kapiteln haben wir ein Szenario bisher noch nicht beleuchtet. Die Anmeldung eines im DIT existierenden Users am System selbst. Genau dieser Betrachtung widmen wir uns in diesem Abschnitt. Es geht zunächst um die Analyse des eigentlichen Anmeldevorgangs am System. Nachdem wir verstanden haben, wie dieser »regulär« abläuft, ist es relativ einfach, die Funktionalität und Mechanismen auf OpenLDAP umzusetzen. Wir werden dabei allerdings nicht in die tiefsten Tiefen der nachfolgend beschriebenen PAM-Mechanismen absteigen, da dies den Rahmen sprengen würde, sondern uns primär auf die LDAP-bezogenen Funktionalitäten beschränken.
3.6.1
Nicht nur in Malibu Beach: PAM
Betrachten wir dazu zunächst das Kernstück: PAM. PAM trägt in diesem Fall keinen roten Badeanzug, sondern steht schlicht und einfach für Pluggable Authentication Modules und wird unter Linux zur Benutzerauthentifizierung verwendet. Eine der wichtigsten Eigenschaften von PAM ist die modulare Erweiterbarkeit. Hier werden die Ähnlichkeiten zwar wieder größer, aber das ist ein anderes Thema. Bei einem monolithischen Konzept (wie z.B. bei sendmail) müssten für jede weitere Applikation neue Authentifizierungsschemen fest in den eigentlichen Authentifizierungsmechanismus integriert werden, die im schlimmsten Fall miteinander kollidieren könnten. Daher liegt die Verwendung eines modularen Konzepts nahe, in dem die eigentliche Authentifizierung von der Anwendung getrennt ist. Auf diese Art können die Applikationsentwickler eigenständige Authentifizierungsschemas entwickeln, die zunächst lediglich auf das Kernmodul (libpam.so.*) zugreifen und dann – je nach Bedarf – applikationsspezifische PAM-Module für den jeweiligen Anwendungsfall nachladen. Dabei werden üblicherweise pro geladenem PAM-Modul Konfigurations-Direktiven definiert (entweder global über /etc/pam.conf oder separat über einzelne Dateien in /etc/pam.d/<Applikati-
279
3.6
1198.book Seite 280 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
onsname>). In diesen Dateien wird dann in Regeln festgelegt, wie welches PAMModul während der Benutzerauthentifizierung verwendet werden soll. Globale Richtlinien für PAM können dabei z.B. in /etc/security/pam_env.conf festgelegt werden. Auf jedem neueren Linux-System finden sich im Ordner /etc/pam.d/ zumindest die beiden folgenden Dateien, die unabdingbar sind: login und su (switch user). Anhand von login werden wir den Aufbau und damit die PAM-spezifischen Schritte beim Abarbeiten dieser Datei während des Login-Vorgangs nachvollziehen: Die Struktur einer PAM-Modul-Konfigurationsdatei unterhalb von /etc/pam.d/* gliedert sich üblicherweise in vier Bereiche: <Modultyp>
<ModulName/Pfad>
Kleine Anmerkung hierzu: Wird die Konfiguration über /etc/pam.conf vorgenommen, muss links eine weitere Spalte eingefügt werden, in welcher der Servicename (also z.B. login) angegeben wird. Betrachten wir zunächst folgendes Beispiel anhand der Einträge der /etc/pam.d/login aus der OSS 11-Distribution (3. Zeile ist umbrochen): #%PAM-1.0 auth requisite pam_nologin.so auth [user_unknown=ignore success=ok ignore=ignore \ auth_err=die default=bad] pam_securetty.so auth include common-auth account include common-account password include common-password session required pam_loginuid.so session include common-session session required pam_lastlog.so nowtmp session required pam_resmgr.so session optional pam_mail.so standard session optional pam_ck_connector.so
Die Anweisungen innerhalb dieser Datei werden dabei stapelweise abgearbeitet; der komplette Pfad zum Modul ist nur dann notwendig, wenn es nicht im Suchpfad (üblicherweise /lib/security/) liegt. Gehe wir nun die Direktiven der Reihe nach durch, und zwar so, wie sie beim login-Vorgang abgearbeitet werden würden.
280
1198.book Seite 281 Donnerstag, 5. Februar 2009 3:02 15
Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP
Authentifizierung Zunächst überprüft das Modul pam_nologin(8) in der Authentifizierungsphase (auth), ob die Datei /etc/nologin existiert (z.B. dank bevorstehendem Shutdown). In diesem Fall wird jedem User außer root die Anmeldung verwehrt. Das Modul pam_securetty(8) dient der Vorbereitung der eigentlichen Authentifizierung und gehört damit auch zu den authentifizierungsrelevanten Modulen des Typs auth. Dieses Modul gestattet root nur die Anmeldung an sicheren ttys (»secure-ttys«, spezifiziert in /etc/securetty). Das Kontroll-Flag required besagt, dass eine Meldung über einen eventuellen Misserfolg erst nach der Abarbeitung aller Module des gleichen Typs (auth) an die aufrufende Anwendung zurückgegeben wird. Im Gegensatz dazu verlangt requisite per Definition eine erfolgreiche Beendigung des Vorgangs, wie z.B. pam_nologin(8). Schlägt der Vorgang bei requisite fehl, werden keine anderen Module mehr abgearbeitet. Werfen wir nun einen Blick auf den Inhalt der Include-Datei common-auth, die als nächste abgearbeitet wird und in der wir unsere erste Ergänzung vornehmen (pam_ldap.so, siehe unten): Das Prinzip der Includes bringt auch hier den Vorteil, dass externe Konfigurationsdateien zur Vereinfachung und Verbesserung der Übersichtlichkeit eingebunden werden können: # Datei /etc/pam.d/common-auth ( OSS 11 ) auth required pam_env.so auth required pam_unix2.so auth required pam_ldap.so use_first_pass
Die erste Zeile spricht das PAM-Modul pam_env(8) per required-Flag an. Das Modul kann dazu verwendet werden, Umgebungsvariablen über die Datei /etc /security/pam_env.conf zu setzen. Das zweite Modul, pam_unix2(8), wird in jedem Fall abgearbeitet und stellt das eigentliche Authentifizierungsverfahren zur Verfügung. Es überprüft zunächst die Einstellungen des Name Service Switch (NSS). Ist dort ein Verweis auf »files«, werden Benutzername und Passwort gegen die /etc/passwd und /etc/shadow geprüft. Mit pam_unix(8) existiert ein weiteres PAM-Modul, das mit der Standard-Linux-Benutzerdatenbank /etc/passwd und /etc/shadow interagieren kann. Durch die von uns ergänzte Spezifikation des Moduls pam_ldap(8) legen wir fest, dass zusätzlich unser LDAP-Tree nach dem übermittelten Usernamen durchsucht werden soll. Der Zusatzparameter use_first_pass legt fest, dass pam_ldap dabei nicht erneut nach einem Passwort fragt, sondern das bereits übermittelte Passwort für die Authentifizierung verwendet.
281
3.6
1198.book Seite 282 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Autorisierung Die Zeilen, die mit account beginnen, definieren Autorisierungsmodule. In diesem Fall wird – genau wie zuvor bei auth – zunächst per Include-Statement die Datei common-account eingebunden, in der wir den gleichen Eintrag für das modul pam_ldap.so hinzufügen wie in der Datei common-auth: # Datei account account account
/etc/pam.d/common-account ( OSS 11 ) requisite pam_unix2.so sufficient pam_localuser.so required pam_ldap.so use_first_pass
Dort wird zunächst per required-Kontroll-Flag das Modul pam_unix2 eingebunden, das nun das Autorisierungsverhalten bestimmt. Hierdurch kann z.B. sichergestellt werden, dass sich kein User mit abgelaufenem Account autorisieren kann. Zudem wird geprüft, ob der User berechtigt ist, bestimmte Anwendungen und Dienste zu nutzen. pam_localuser(8) testet, ob der aktuelle Nutzer in einem definierten Password-File enthalten ist. Eine ähnliche Funktionalität bietet pam_ listfile(8). pam_localuser jedoch kommt im Gegensatz zu Letzterem mit den »:«Delimitern in den passwd/shadow-Dateien klar. Wir erweitern dieses Subset der lokalen User durch den erneuten Aufruf von pam_ldap, das auch unseren DIT in die Autorisation mit einbezieht. Passwort-Änderungen Die mit password beginnenden Zeilen spezifizieren das Modulverhalten in Bezug auf Änderungen des Passworts – heißt: sie werden nur dann aktiv, wenn eine Passwort-Änderung ansteht. Hierzu wird ebenfalls eine Include-Datei eingebunden: common-password, in der sich folgende Direktiven finden; die dritte, pam_ ldap-relevante Direktive ergänzen wir: password requisite pam_pwcheck.so nullok cracklib password sufficient pam_unix2.so use_authtok nullok password required pam_ldap.so try_first_pass use_authtok
Das Modul pam_pwcheck(8) (required) liest die Einstellungen der Datei /etc/ logins.defs aus, falls vorhanden. Dort werden z.B. minimale Passwortlänge, gültige Zeichen, Anzahl Fehlversuche, Passwort-Expiration und andere Parameter festgelegt. Über die Zusatz-Option cracklib wird das gewünschte Passwort gegen ein Dictionary mit gängigen Passwörtern auf seine Sicherheit hin überprüft. Danach wird pam_unix2(8) aufgerufen, welches das Verhalten bei Änderung eines Authentifizierungsmerkmals definiert. Will ein Nutzer auf ein anderes Authentifizierungsverfahren umstellen oder sein Passwort ändern, verlangt das System die an dieser Stelle eine definierte Vorgehensweise wie z.B. erneute Pass-
282
1198.book Seite 283 Donnerstag, 5. Februar 2009 3:02 15
Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP
wortabfrage. pam_unix2 liest dabei auch die Datei /etc/default/passwd (SUSE) aus, in der u.a. die zu verwendende Verschlüsselung definiert wird. use_authok legt fest, dass PAM das neue Passwort aus den zuvor im Stapel (auth) abgearbeiteten Modulen übernehmen soll. Optional kann wie im oben angeführten Beispiel eine nullok-Direktive angehängt werden, damit Logins und Passwortänderungen auch bei leerem Passwort möglich sind. Zu guter Letzt werden, wie bereits bekannt, durch das von uns addierte pam_ldap(8) – zusätzlich zur Datei /etc/shadow – ebenfalls alle zu den Userobjekten aus dem DIT gehörigen Passwörter mit einbezogen. ... und schließlich, wenn die Session läuft session-Module dienen der Verwaltung und Konfiguration von User-Sessions, also Benutzersitzungen. Session-spezifische Settings werden dann aktiv, wenn die Authentifizierung und Autorisierung geglückt ist und die Sitzung des Users beginnt. Session-Module können unter anderem verwendet werden, um die Benutzerumgebung zu definieren oder auch um Login-Versuche zu protokollieren (Auditing). Zunächst wird nur in /etc/pam.d/login ein für den login-Prozess spezifisches session-Modul aktiviert: session
required
pam_loginuid.so
pam_loginuid(8) setzt zu Auditing-Zwecken das loginuid-Attribut für den Prozess, mit welchem die Authentifizierung ursprünglich durchgeführt wurde, wie eben login oder sshd. Es sollte nicht für Prozesse wie su oder sudo verwendet werden, da dies – durch den dabei stattfindenden Wechsel der uid – nicht dem Einsatzzweck des Moduls entspricht. Im nächsten Schritt wird das Include-File common-session mit den folgenden Direktiven aufgerufen; die beiden letzten (pam_ldap und pam_mkhomedir) ergänzen wir: # Datei session session session session session
/etc/pam.d/common-session ( OSS 11 ) required pam_limits.so required pam_unix2.so optional pam_umask.so optional pam_ldap.so optional pam_mkhomedir.so
Der Reihe nach: Zunächst zu pam_limits(8), einem oft fälschlicherweise vernachlässigten Vertreter der PAM-Gang: mit seiner Hilfe und der korrespondierenden Einstellungsdatei /etc/security/limits.conf, können wirksame Maßnahmen getroffen werden, um das System zu schützen. Hierzu können in der gerade benannten Konfig-Datei Einstellungen getroffen werden, die z.B. die Anzahl der User-bezogenen Prozesse limitieren, die Größe von anzulegenden Dateien, CPU-Zeit,
283
3.6
1198.book Seite 284 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Anzahl der aktiven Sessions und einiges mehr. Zur Effektivitäts-Kontrolle einfach mal einen Blick per ulimit –a in die aktuellen Einstellungen werfen, die Einstellungen für die Anzahl der möglichen Prozesse in limits.conf ändern, uns neu einloggen und eine kleine Forkbombe starten. Wer danach noch nicht von der Effektivität des kleinen Helfers überzeugt ist, ist selbst schuld. Die nächsten Vertreter, pam_ldap und pam_unix2, kennen wir bereits. Über pam_umask kann – wir ahnen es – eine session-spezifische umask für den eingeloggten User gesetzt werden, die entsprechenden Direktiven finden sich in pam_ umask(8). Und last, not least: Wie der Name pam_mkhomedir(8) unschwer vermuten lässt, kümmert sich dieses PAM-Modul um die Erstellung eines Home-Directorys für den User, der sich gerade angemeldet hat. Existiert bereits eines, passiert nichts weiter, und das nächste Modul im Stapel wird abgearbeitet. Das Flag optional besagt, dass dieses PAM-Modul nicht unbedingt erfolgreich abgearbeitet werden muss. Wenn das Modul mit der optional-Regel das einzige Modul im Stack ist, ist seine Erfolgsrückmeldung jedoch ausschlaggebend für die erfolgreiche Abarbeitung des »gesamten« PAM-Stacks. Betrachten wir nun den letzten Block der Datei /etc/pam.d/login: ... session session session session
required required optional optional
pam_lastlog.so nowtmp pam_resmgr.so pam_mail.so standard pam_ck_connector.so
pam_lastlog(8) zeigt beim Login Informationen über den letzten Login-Vorgang des Users an. Die notwendigen Daten liefert die Datei /var/log/lastlog. Über das Modul pam_resmgr(8) kann der Zugriff auf bestimmte Ressourcen für den Nutzer explizit freigegeben werden, wie z.B. auf den xdm-Displaymanager oder Ähnliches. Die korrespondierende Konfigurationsdatei: /etc/resmgr.conf. pam_ mail(8) kümmert sich darum, uns nach dem Login mitzuteilen, ob wir neue Mail haben, und pam_ck_connector(8) kümmert sich in Verbindung mit dem ConsoleKit-Daemon um einen sauberen Shutdown der Session, falls diese im aktiven Zustand crashen sollte. Betrachten wir noch einmal kurz die Kontroll-Flags in der Zusammenfassung: required (engl. erforderlich) besagt, dass eine Meldung über einen eventuellen Misserfolg erst nach der Abarbeitung aller Module des gleichen Typs an die aufrufende Anwendung zurückgegeben wird.
284
1198.book Seite 285 Donnerstag, 5. Februar 2009 3:02 15
Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP
requisite (engl. Voraussetzung) verlangt dagegen eine erfolgreiche Beendigung des Vorgangs. Schlägt der Vorgang bei requisite fehl, werden keine anderen Module mehr abgearbeitet. optional bedeutet, dass der Erfolg oder Fehlschlag dieses Moduls nur dann von
Bedeutung ist, wenn es das einzige Modul im Stapel ist, das mit einem bestimmten Service assoziiert ist. sufficient (engl. genügend, ausreichend) besagt, dass bei einer erfolgreichen Abarbeitung das aufrufende Programm eine umgehende Erfolgsmeldung erhält. Es werden keine weiteren Module mehr abgearbeitet, insofern kein voranstehendes required-Modul fehlgeschlagen ist. Ein Fehlschlag des sufficient-Moduls hat keine Auswirkungen, alle folgenden Module werden abgearbeitet.
Vereinfacht ausgedrückt, spezifizieren alle Kontroll-Flags immer nur das Verhalten bei Erfolg/Misserfolg während der Abarbeitung des spezifizierten Moduls.
Wir wissen nun, dass die PAM-Truppe ein leistungsfähiges Völkchen ist, das sich völlig transparent für den User um wichtige Dinge während der Anmeldung, Ummeldung oder dem Aufruf eines Dienstes kümmern kann. Aber wie arbeiten denn nun eigentlich PAM, NSS und LDAP genau zusammen?
3.6.2
PAM, NSS und LDAP
Come on, come on, let´s stick together… Roxy Music, 1976 Aufgrund des modularen Konzepts klappt die Zusammenarbeit zwischen PAM, NSS und LDAP in der Praxis üblicherweise absolut reibungslos. Die beiden zuständigen LDAP-Module (pam_ldap/libnss_ldap) haben wir ja im Abschnitt »Irgendwie binär« schon kurz kennengelernt, aber wie schon dort versprochen, schauen wir den beiden nun in Verbindung mit PAM etwas genauer unter die Haube. Grundsätzlich verwenden fast alle bekannten Distributionen die beiden Module libnss_ldap und pam_ldap. Beide stammen aus der Entwicklerschmiede der Firma PADL, Software Pty Ltd. in Melbourne, Australien. Apropos: Schon mal LDAP rückwärts buchstabiert? Dann probieren Sie es mal … Vorab noch ein wichtiger Praxistipp: Bei allen »Experimenten« an den Authentifizierungsmechanismen sollte man sich stets eine Hintertür offen lassen. Hierfür reicht meist schon eine zweite Konsole, auf der man mit Root-Rechten eingeloggt ist und so etwaige Fehlkonfigurationen im laufenden System wieder richten kann.
285
3.6
1198.book Seite 286 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
3.6.3
pam_ldap
Das Modul, das wir bei der Konnektierung von PAM und LDAP immer heranziehen, ist pam_ldap.so. Es stellt im Prinzip nur einen weiteren Mechanismus zur Verfügung, der sich in diesem Fall um die Kommunikation zwischen der Applikation und LDAP über PAM kümmert. Wie wir wissen, übernimmt das Modul pam_unix2 auf Systemen ohne LDAP-Datenbank die Authentifikation. pam_ unix2 ist eine Variante des »traditionellen« pam_unix auth-Moduls, das zur Authentifizierung Standard-Calls der glibc NSS-Bibliotheken verwendet. pam_ldap kümmert sich (wie pam_unix2) einfach »nur« um die Authentifikation, Autorisation und alle anstehenden Passwort-Änderungen. Nur dass pam_ldap hierfür nicht auf die System-files (passwd/shadow) zurückgreift, sondern eben auf die User-Objekte in unserem DIT bzw. deren auszuwertende posix-Attribute wie uid/userPassword, die ihm natürlich mitgeteilt werden müssen. pam_ldap unterstützt dabei TLS, SASL-Authentifikation, Policys, Gruppen-basierte logons und etliche andere Features mehr. Die entsprechenden Einstellungen werden bei SUSE in der Datei /etc/ldap.conf festgelegt (die dort auch für alle nss-Settings verwendet wird), bei Debian in der Datei pam_ldap.conf. Alle pam-relevanten Settings beginnen in beiden oben genannten Dateien in der Regel mit pam*, die nssspezifischen logischerweise mit nss*. Bei der Authentifikation bzw. Autorisation mappt pam_ldap den Login-Namen (die uid) des Benutzers auf einen im DIT vorhandenen DN. Über die Konfigurationsdatei kann dabei unter anderem festgelegt werden, welche (Sub-)Kontexte des DIT hierzu herangezogen werden sollen. Bei Erfolg wird anschließend ein bind-Vorgang mit dem zurückgegebenen DN des Users durchgeführt, je nach Setting als simple bind oder strong bind.
3.6.4
(lib)nss_ldap
Sehen wir uns nun noch das NSS-relevante LDAP-Modul etwas genauer an. Die Bibliothek hat zwar auf den ersten Blick mit PAM nicht direkt etwas zu tun, spielt aber eine entscheidende Rolle für die Vorgänge bei der Anmeldung des Users über LDAP. Wie bereits im Abschnitt »Irgendwie binär« angesprochen, sorgt libnss-ldap bzw. nss_ldap in Verbindung mit der Konfigurationsdatei /etc/ldap.conf |/etc/libnssldap.conf dafür, dass wir unseren LDAP sozusagen als Name-Service-SwitchBackend (NSS) – anstelle von NIS oder /etc/passwd und /etc/shadow – nutzen können. Diese Bibliothek ist die Implementierung des in der RFC 2307 spezifizierten Konzepts: »Using LDAP as Network Information Service«.
286
1198.book Seite 287 Donnerstag, 5. Februar 2009 3:02 15
Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP
Zusammen mit der GNU C Library 2.0 hat der Name Service Switch unter Linux Einzug gehalten, der nach dem Vorbild der Funktionen und Methoden aus Suns Solaris, Version 2, entstanden ist. Ausführliche Informationen hierzu bietet auch »System Databases and Name Service Switch« aus dem »GNU C Library Reference Manual«. Über nss_ldap(8) bzw. libnss_ldap wird dabei die Namensauflösung der glibc – über den nsswitch-Mechanismus – an die Verwendung von LDAP angepasst. Das geschieht durch die Datei /etc/nsswitch.conf(5). Für die Benutzerverwaltung mittels LDAP müssen dort folgende Zeilen vorhanden sein: passwd: files ldap group: files ldap shadow: files ldap
Dadurch wird die Resolver-Bibliothek der glibc angewiesen, als Quelle für die Benutzerdaten sowohl auf die LDAP-Datenbank zuzugreifen als auch auf die lokalen Systemdateien (files) unter /etc/passwd, /etc/shadow. Alternativ könnten dort auch – wie z.B. SUSE es aus unerfindlichen Gründen immer noch tut – so genannte compat-Settings verwendet werden, die allerdings nur der Kompatibilität mit älteren Dateiformaten dienen. Diese Option kann theoretisch verwendet werden, wenn entweder NYS (Abwandlung von NIS) oder glibc 2.x für NIS(+)– Lookups verwendet werden sollen, z.B.: passwd: compat passwd_compat:
ldap
Für uns eher uninteressant, da wir sicher nicht vorhaben, die alten Yellow Pages aus ihrer wohlverdienten Versenkung zu holen. Mit dem Kommando getent passwd können wir sehr fix prüfen, ob denn auch alles in unserer WG von pam, nss und ldap in Ordnung ist: Das Ergebnis sollte eine Ausgabe aller auf dem System vorhandenen User sein, sowohl die Accounts aus unserem DIT als auch die aus der Systembenutzerdatenbank (/etc/passwd). #> getent passwd
sollte uns folgende Ausgabe liefern: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh ... ckent:x:901:100:Clark Kent:/home/ckent:/bin/bash hcallahan:x:902:100:Harry Callahan:/home/hcallahan:/bin/bash skiu:x:903:100:Susie Kiu:/home/skiu:/bin/bash ...
287
3.6
1198.book Seite 288 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Deutlich erkennen wir hier alle von uns angelegten LDAP-Accounts, wie auch die System-Accounts (z.B. root und daemon) aus /etc/passwd. Gibt es an dieser Stelle Probleme mit dem Zugriff auf die User unseres DIT, prüfen wir noch einmal kurz folgende Punkte der kleinen Checkliste: 왘 ldap gestartet? 왘 /etc/nsswitch.conf angepasst? 왘 /etc/(pam|nss)ldap.conf angepasst? (pam_filter objectclass=posixAccount) 왘 TLS deaktiviert? 왘 nscd deaktiviert / neu gestartet (siehe unten)? Grafisch lässt sich das zuvor beschriebene PAM/NSS/LDAP-Szenario vereinfacht darstellen:
Applikation
glibc PAM NSS
/etc/passwd /etc/shadow Abbildung 3.11
3.6.5
NIS
LDAP
Vereinfachter Aufbau – PAM, NSS, LDAP
nscd
Werfen wir nun einen Blick auf den eben angesprochenen Daemon, der als Ergänzung zum NSS, unabhängig vom verwendeten Backend, für eine optimierte Performance des Name Service sorgen soll: der Name Service Caching Daemon (/ usr/sbin/nscd, man 8 nscd). So weit die Theorie. Allerdings entpuppt sich dieser Kollege in der Praxis oft genug als echter Spielverderber, warum das so ist, sehen wir gleich. Zunächst die Basics: Der nscd dient als Cache für die in /etc/nsswitch.conf definierten Services und soll wie jeder Cache einer Beschleunigung des Zugriffs dienen. Der nscd »cached« dabei die in /etc/nscd.conf(5) konfigurierten Felder (z.B. passwd und group) und sorgt so bei einem Zugriff auf die (Benutzer-) Daten für eine verbesserte Performance.
288
1198.book Seite 289 Donnerstag, 5. Februar 2009 3:02 15
Hör mal, wer da hämmert – Authentifizierung und Autorisierung am System mit OpenLDAP
Der Grund für die Existenz des nscd ist schnell erklärt: Regulär würden sonst bei allen User-Operationen, die ein Auslesen der User- oder Gruppen-ID erfordern, Aufrufe/Requests an die unterliegende Userdatenbank gestartet werden. Um uns den dadurch zustande kommenden Traffic zu veranschaulichen, brauchen wir nur slapd im Debug-Modus (-d 1) aufzurufen und mehrmals ls -a durchzuführen, einmal mit und einmal ohne aktivierten nscd. Allerdings birgt er wie jeder Caching-Service auch gravierende Nachteile: Zum einen werden Änderungen erst nach einer gewissen Zeit propagiert, was sich durch einen manuellen Restart des Daemons umgehen lässt. Dies sollte bei einer Umstellung der Anmeldung, z.B. auf ldap oder kerberos, in jedem Fall beachtet werden. Zum anderen kann der nscd auch in Verbindung mit dem -leider immer noch benötigten- winbind-Daemon der Samba-Suite Probleme bereiten: Selbst dann, wenn der Name Service Switch korrekt konfiguriert ist, kann es passieren, dass die Namen von Domänenbenutzern und -gruppen nicht mehr korrekt aufgelöst werden.
3.6.6 ssl
Authentifikation am System mit aktiviertem TLS start_tls
Durch diese Anweisung in der /etc/ldap.conf (SUSE) bzw. /etc/libnssl-ldap.conf / /etc/pam_ldap.conf (Debian) wird TLS auch für die authentifikationsrelevanten Vorgänge (PAM/NSS) aktiviert. Hierzu ist – natürlich neben den korrekten TLSSettings unseres slapd – eine Datei .ldaprc im Home-Ordner des jeweiligen Users zwingend erforderlich, die auf die für ihn korrekten und lesbaren Zertifikate zeigt. Des Weiteren muss er natürlich lesend auf das CA-Zertifikat zugreifen können. Loggen wir uns nun als User ckent neu ein bzw. wechseln mit su – ckent auf seine Identität und in sein Home-Verzeichnis. Unser slapd sollte dabei im DebugMode 256 Folgendes ausspucken (letzte Zeile ist umbrochen): conn=0 fd=12 ACCEPT from IP=192.168.198.11:57012 (IP=0.0.0.0:389) conn=0 op=0 EXT oid=1.3.6.1.4.1.1466.20037 conn=0 op=0 STARTTLS conn=0 fd=12 TLS established tls_ssf=256 ssf=256 ... SRCH base="dc=local,dc=site" scope=2 deref=0 filter="(&(objectClass= posixAccount)(uid=ckent))"
Wir können hier wieder unschwer das aktivierte TLS-Control (oid= 1.3.6.1.4.1.1466.20037), den TLS-Start und den tatsächlichen SSF (Security Strength Factor = 256) erkennen.
289
3.6
1198.book Seite 290 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Redundante Anmeldeserver und TLS Noch ein allgemeiner Hinweis zu redundanten Anmeldeservern mit aktiviertem TLS: Die Home-Verzeichnisse der LDAP-User (mit entsprechender .ldaprc Datei und natürlich den Zertifikaten) sollten auf allen beteiligten Maschinen existieren bzw. eingebunden sein. Eine Variante wäre hier sicherlich, die Home-Ordner auf einen serverübergreifenden und zentral genutzten Mountpunkt zu legen.
3.6.7
Debugging
Real men dont’t need instructions. Just the right tools ... Tool Time Auch wenn Tim Taylors tiefschürfende Weisheit gerade uns Männern nur allzu oft aus der Seele spricht (und bei diesem Motto logischerweise ebenso oft fürchterlich nach hinten losgeht), sollten wir uns dennoch einige Debugging-Maßnahmen genauer anschauen, um dann mit den richtigen Werkzeugen die Fehler aus dem Weg räumen zu können: Taucht beim su oder Login am System folgende Fehlermeldung auf: I have no name!@
sollte zunächst geprüft werden, ob TLS in der /etc/ldap.conf bzw. libnss-ldap.conf aktiviert ist. Falls ja, muss auf jeden Fall im Home-Verzeichnis des Users, der sich anmelden möchte (bzw. zu dessen Account per su geswitcht werden soll), eine .ldaprc-Datei existieren, die auf entsprechende Zertifikate verweist. Taucht beim su oder Login folgende Fehlermeldung auf: user <username> does not exist
müssen wir prüfen, ob TLS auf Client- und Server-Seite übereinstimmend de-/ aktiviert ist, ebenso die Konfiguration in der /etc/nsswitch.conf . Taucht beim su oder Login folgende Fehlermeldung auf: Ungültige ID
kann das Problem im nscd liegen (siehe oben; diesen daher Testweise manuell Restarten bzw. deaktivieren!). Liegt gegebenenfalls ein uidNumber-Konflikt durch einen anderen User vor? Optional kann die Direktive TLSVerifyClient in der slapd.conf von demand auf das weichere try oder allow gesetzt werden. Sonstige Checkpunkte: 왘 Funktioniert die Namensauflösung korrekt (/etc/hosts bzw. DNS)? 왘 Ist der FQHN des LDAP-Servers statt der IP in der host-Direktive der /etc/ ldap.conf (bzw.pam_ldap.conf/libnss-ldap.conf) gesetzt?
290
1198.book Seite 291 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
왘 /etc/nsswitch.conf angepasst? 왘 /etc/(pam|nss)ldap.conf angepasst? (pam_filter objectclass=posixAccount) 왘 Sind die Zertifikate für den Client/User lesbar (Rechte/Owner)? 왘 Stimmt der CN der Clientzertifikate? 왘 Prüfen der Log-Dateien, Erhöhen des Debug-Levels. 왘 Test mit getent passwd.
3.7
Nur mit Clubkarte – Zugriffsregelung durch ACLs
Bowman: »Open the damn Pod bay doors, HAL!« HAL9000: »I'm sorry Dave, I'm afraid I can't do that.« 2001: A Space Odysee, USA 1968 Genau die Art von Situation, die wir keinen Millimeter brauchen, wenn wir rein zufällig David Bowman heißen, Astronaut sind und unser schizophrener Bordcomputer namens HAL9000 nicht die geringste Motivation zeigt, unsere Kapsel nach einem kleinen Bergungseinsatz in Höhe des Jupiter wieder zurück ins Mutterschiff zu lassen. Okay, in der Situation sollte uns wirklich der Schweiß auf die leider unbehelmte Stirn treten, aber bezogen auf unseren LDAP ist es genau das Verhalten, das wir letztlich benötigen, um einen effektiven Zugriffschutz für unseren DIT zu errichten und damit genau festzulegen, wer wie auf was zugreifen darf. Nachdem es im letzten Abschnitt es um die Anmeldung unserer Benutzer via LDAP ging, kümmern wir uns nun um das, was danach passiert – oder, besser, welche Einschränkungen wir definieren können, um nach dem erfolgreichem Login den Zugriff der Benutzer auf den DIT klar zu regeln. Im Folgenden werden wir uns daher anschauen, wie denn die Regelung der Zugriffe im DIT selbst funktioniert. Oder einfacher, mit den fünf großen »W’s« ausgedrückt: Wer darf auf Was mit Welchen Rechten zugreifen? Und vor allem: Wo und Wie wird das definiert? Das Wie ist Thema dieses Abschnitts, das Wo lässt sich relativ schnell erläutern, denn das Schlüsselwort hierfür ist ACL (Access Control List), auf Deutsch »Zugriffskontrollliste«. Diese ACL wird in der slapd.conf bzw. in der Laufzeitkonfiguration unterhalb von slapd.d/ über korrespondierende olcAccess-Direktiven festgelegt. Die Funktionalität dieser ACL besteht einzig und allein darin, ein Regelwerk für den Zugriff auf unseren DIT festzulegen (dieses Regelwerk lässt sich dabei in seiner Komplexität nahezu endlos aufbohren: für die einen ist es die
291
3.7
1198.book Seite 292 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
schönste Sache der Welt, die anderen ziehen eine Wurzelbehandlung ohne Narkose vor). Die Notwendigkeit der ACLs ergibt sich aus der Tatsache, dass es sich bei LDAP um ein Zugriffsprotokoll handelt, ähnlich wie HTTP oder SMTP. Durch das Protokoll wird zwar die eigentliche Session geregelt, aber nichts in Bezug auf die Rechte des bereits authentifizierten Benutzers im DIT. Diese Aufgabe bleibt somit am Server selbst, also unserem slapd, hängen. Standardmäßig finden sich in der statischen slapd.conf fast immer einige (globale) ACL-Einträge, die prinzipiell zunächst nur dafür sorgen, dass unser rootdn (in unserem Fall cn=ldapadmin,dc=local,dc=site) alles darf. Jeder andere darf größtenteils »nur« lesend auf den DIT zugreifen und gegebenenfalls einen kleinen Teil seiner eigenen Attribute, wie z.B. sein Passwort, modifizieren. Das ist aber so weit auch völlig in Ordnung, denn sicherheitstechnisch ergibt ein Zugriffsmuster, das nach dem Schema Verbiete zunächst erst einmal alles, aber erlaube dann explizit dies und das« arbeitet, immer mehr Sinn als die gegenteilige Variante, die lange Zeit als Standard in der Benutzerverwaltung einiger Redmonder OS zu finden war. Aber selbst wenn keine globalen ACLs definiert sind, gilt eine so genannte Default Policy, die auch dann wirksam ist, wenn überhaupt keine ACLs gesetzt sind: rootdn darf alles, jeder andere darf lesen. Statisch oder Dynamisch? Insofern die Zugriffsrechte per ACL über die »statische« Variante (Definition der access to ...-Direktiven in der slapd.conf) gesetzt sind, ist bei Änderungen an den ACLs logischerweise immer ein Restart unseres slapd erforderlich, damit diese Änderungen greifen können. Sicherheitstechnisch bietet dies einen Vorteil, da die ACLs ein unmittelbarer Bestandteil der Serverkonfiguration und damit so etwas wie »hartverdrahtet« sind. Je nach Einsatzzweck und Replikations-Konfiguration des Servers kann dies allerdings auch ein gravierender Nachteil sein: keine Möglichkeit, Änderungen an den ACLs zur Laufzeit durchzuführen, die sofort greifen – und keine Möglichkeit der Replikation der ACL-Konfiguration. Zur Lösung dieser Problematik bietet sich die dynamische Laufzeitkonfiguration per slapd.d/ mit einer Replikation der entsprechenden Sektion des cn=configTrees an. Wie das geht, wissen wir bereits aus den Kapiteln über Replikation; ebenso, das diese Variante für den Standby-Master-Einsatz unabdingbar ist, um eine stets aktuelle Kopie des aktiven Masters zu gewährleisten. Das Gleiche gilt natürlich für Multi-Master-Setups. Exkurs: ACI Eine andere Variante wäre theoretisch noch die Konfiguration per ACI. ACI steht für Access Control Information. Bei diesem Ansatz werden die Zugriffsrechte als
292
1198.book Seite 293 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
objektspezifische Attribute im DIT abgelegt. Die Nachteile überwiegen jedoch nach wie vor noch: Das Ganze befindet sich immer noch in einem experimentellen Stadium, der Verwaltungsaufwand (da jedes Objekt seine eigenen ACIs besitzt) ist extrem hoch, und es existiert immer noch kein einheitlicher Syntaxstandard. Daher werden wir zu diesem Zeitpunkt nicht weiter auf diesen Ansatz eingehen. Unsere LDAP-Jungs sagen dazu klar: »The OpenLDAP ACI mechanism is experimental, it is not provided for general use. Those who choose to toy with it are advised that the syntax and semantics of the mechanism may change in the future.« Zudem existiert aufgrund der nach wie vor niedrigen Verbreitung und in Ermangelung eines Syntax-Standards immer noch keine relevante Dokumentation. Aufgrund der oben angeführten Nachteile ist ein Einsatz im Produktivumfeld daher bis auf weiteres obsolet. Betrachten wir nun die prinzipielle Funktionsweise einer ACL. Zunächst erfolgt eine Client-Anfrage an den DIT, die entweder anonym bzw. per simple- oder strong-bind durchgeführt wird. Alle anonymen Anfragen sollten regulär stets nur als Readonly-Anfragen zulässig sein, und das auch nur auf »unkritische« Attribute (cn, mail, description usw.). Jedem Admin sollte das klar sein. Sobald ein Authentifizierungsvorgang erfolgreich abgeschlossen wurde, kann unser guter alter slapd den DN des authentifizierten Users durch die gesetzten ACLs jagen, um festzustellen, ob der User die angefragte Operation durchführen darf oder nicht. Bevor wir die ACL-Syntax nun im Einzelnen analysieren, stellt sich vorab noch eine wichtige Frage: Spielt die Reihenfolge der ACLs eine Rolle? Und wenn ja, welche? Die erste Antwort ist einfach: Ja. Und die zweite …
3.7.1
Wer ist hier der Boss? – ACL-Reihenfolge
Die Reihenfolge der ACLs ist von absolut elementarer Bedeutung. Das liegt an der Art und Weise, wie die ACLs abgearbeitet werden. Anhand unserer statischen slapd.conf betrachtet, ergibt sich eine grundlegende Abarbeitungsreihenfolge der ACLs von oben nach unten. Innerhalb der dynamischen Konfiguration wird durch einen führenden numerischen Wert in geschweiften Klammern vor dem by -Statement die Reihenfolge der olcAccess-Abarbeitung festgelegt. Zunächst sind im globalen Teil der slapd-Konfiguration üblicherweise so genannte globale ACLs definiert, die je nach Distributor unterschiedlich ausfallen können. Sie greifen immer dann, wenn keine Database-/Kontext-spezifischen ACLs existieren (siehe unten) oder diese nicht auf die Client-Anfrage zutreffen. Im Prinzip fallen sie aber fast immer nahezu identisch aus, nach dem bereits
293
3.7
1198.book Seite 294 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
erwähnten Format: rootdn darf alles, User dürfen auf (einen Teil) ihre(r) eigenen Attribute schreibend zugreifen, auf alles andere lesend, so wie z.B. auch auf den rootDSE (dn.base=""), um die Kapabilitäten des slapd auslesen zu können. Dazu später in diesem Abschnitt noch mehr. Existieren überhaupt keine globalen ACLs, gilt die weiter oben erwähnte Default Policy. Des Weiteren können, wie eben erläutert, pro Datenbank(-Backend) zusätzliche ACLs definiert werden, die ausschließlich auf den jeweiligen Kontext bezogen sind. Diese ACL-Einträge liegen – sofern vorhanden – in der Abarbeitungs-Hierarchie an erster Stelle und werden vor den globalen ACLs geparst. Sie müssen immer innerhalb der jeweiligen Datenbanksektion vorgenommen werden, jedoch erst nach den eigentlichen, Datenbank-spezifischen Direktiven. Veranschaulichen lässt sich das am besten, indem wir einen Backend-ACL-Eintrag innerhalb der Datenbanksektion unserer slapd.conf vornehmen, der wie folgt aussieht: # BDB database definitions ... suffix dc=local,dc=site ... # Hier folgt unsere eigendefinierte (Backend)-ACL, # Einrückung beachten access to dn="uid=ckent,ou=verkauf,dc=local,dc=site" by self write by * auth break
Die Syntax ist zunächst noch nicht relevant; sie besagt vereinfacht nur, dass unser guter alter Kumpel Clark Kent seine gesamten Attribute nach erfolgreicher Authentifizierung selbst lesen und modifizieren darf (wie es sich eben für Superman gehört) und für alle anderen diese ACL – vereinfacht ausgedrückt – nicht existiert (break). Starten wir unseren slapd im Debug-Mode (-d 128 oder -d acl) können wir prima erkennen, wie die ACLs intern interpretiert werden: @(#) $OpenLDAP: slapd 2.4.11 (Sep 2 2008 09:14:55) $ abuild@build12:/usr/src/packages/BUILD/openldap-2.4.11/servers/slapd Backend ACL: access to dn.base="" by * read Backend ACL: access to dn.base="cn=subschema" by * read Backend ACL: access to attrs=userPassword,userPKCS12 by self write by * auth Backend ACL: access to attrs=shadowLastChange
294
1198.book Seite 295 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
by self write by * read Backend ACL: access to * by * read Backend ACL: access to dn.base="uid=ckent,ou=verkauf,dc=local,dc=site" by self write by * auth break Backend ACL: access to * by * none config_back_db_open: line 0: warning: cannot assess the validity of the ACL scope within backend naming context hdb_monitor_db_open: monitoring disabled; configure monitor database to enable slapd starting
Anmerkung: Seit OpenLDAP Version 2.3 werden in diesem Debug-Mode alle ACLs als Backend-ACLs angezeigt, daher also nicht wundern. Taucht z.B. ein Fehler der Art cannot assess the validity of the ACL scope within backend naming context
auf, so wird er dadurch erzeugt, dass die ACL innerhalb der Database-Sektion einen erweiterten Scope verwendet, der auch Bereiche außerhalb des Kontextes betrifft, wie z.B. die Verwendung dieser ACL als Backend-ACL: access to * by * read
Wichtig hierbei ist die Unterscheidung zwischen Globaler und Backend-ACL. Die von uns definierte Backend-ACL wird zwar beim Einlesen der slapd.conf als letzte geparst, die Auswertung der ACLs bei Benutzeranfragen sieht jedoch ganz anders aus: Grundsätzlich werden Backend-ACLs (sofern vorhanden) immer als Erstes interpretiert. Erst nachdem unser slapd festgestellt hat, dass entweder keine Backend-ACL vorhanden ist, oder er in einer vorhandenen Backend-ACL keine passende Regel gefunden hat, durchsucht er die globalen ACLs nach passenden Regeln. Achtung: Beim Testen aller ACLs im Folgenden unbedingt immer darauf achten, dass wir die Operationen (search/add/modify/delete) auch mit der richtigen Identität (dem korrekten DN) durchführen!
Sorry, no points for second place … zumindest meistens Damit kommen wir schon zum nächsten wichtigen Punkt, was die Auswertung der ACLs durch den slapd betrifft: die hierarchische Abarbeitung. Unser slapd arbeitet die ACLs so lange ab, bis er ein passendes Statement – bezogen auf den DN des angefragten Objekts – gefunden hat (findet er gar keines, greift wieder die »hartverdrahtete« Default Policy). Findet er eine auf den angefragten DN pas-
295
3.7
1198.book Seite 296 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
sende ACL, steigt er aus, beendet die weitere Suche nach <was>, und beginnt die Suche nach <wer>. Im Normalfall wird ein Suchvorgang abgebrochen, sobald die erste passende ACL gefunden wurde. Das bedeutet, dass ACLs, die in der Hierarchie weiter unten angeordnet sind und gegebenenfalls auch passen würden, nicht mehr berücksichtigt werden. Daher ist eine sinnvolle Anordnung der ACLs oberstes funktionelles Gebot: Spezielle ACLs zuerst, danach gilt: Je allgemeiner, desto weiter unten. Allerdings kann das Verhalten beim Match (der Übereinstimmung) mit einer zutreffenden ACL noch über control-Flags innerhalb gewisser Grenzen gesteuert werden. Dazu aber später mehr. Nach unseren Vorbetrachtungen werfen wir nun einen detaillierten Blick auf die ACLs und ihre Syntax, die einerseits recht vielfältig sein kann oder im Zweifelsfall ganz einfach frei nach Kaya Yanar übersetzt: »Ey, passauf Altä! Du kummst hia nit rein, ey!« Betrachten wir zuerst den prinzipiellen Aufbau eines ACL-Statements, der immer die gleiche Syntax besitzt: Zugriff auf <Was> durch <Wen> mit <Welchen Rechten> [und Control-Flags].
Bezogen auf die LDAP-Syntax der statischen Konfiguration sieht das dann etwa so aus: access to <Was> by <Wer> <Welche Rechte> [Control-Flags]
Betrachten wir nun die einzelnen W’s mal etwas genauer, zunächst allesamt für die statische Konfiguration; die Portierung auf die olc-Syntax lässt sich danach einfach erledigen.
3.7.2
<Was> (access to)
Als ersten Punkt nehmen wird das <Was> unter die Lupe. Das <Was> beschreibt den DIT-Eintrag, für den die nachfolgenden Regeln gültig sein sollen. <Was> kann folgende Formen bzw. eine Kombination von ihnen annehmen: * [dn [.]=] [filter=] [attrs=[ val[.<style>]=]]
Schauen wir uns nun diese vier <Was> im Einzelnen genauer an:
296
1198.book Seite 297 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
1) * (Wildcard) Wird als <Was> die Wildcard “*“ angegeben, hat das nachfolgende (unkomplette) Statement Gültigkeit für den kompletten DIT (Zugriff auf alles ...), da es auf jeden DN passt: access to * ...
2) [dn[.]=] Ebenfalls kann für <was> ein DN-String gemäß RFC 4514 (aktualisierte Version der RFC 2253: »LDAP v3: UTF-8 String Representation of Distinguished Names«) angegeben werden, bezogen auf unseren DIT z.B.: access to dn=”ou=verkauf,dc=local,dc=site” ...
Das wäre eine einfache (unvollständige) Variation, die den Zugriff auf den oben genannten DN regelt. Betrachten wir nun die Ausdrücke . Dieser auch Scope-Style (Scope: engl. = Bereich) genannte Parameter dient der Ergänzung des DN- bzw. Group-Parameters: dn. – mögl. Scopes: regex | base | one | subtree | children
Per dn.regex können wir mit Hilfe regulärer Ausdrücke Suchmuster vorgeben, um den Zugriff auf bestimmte Objekte, die einem vorgegebenen Muster entsprechen, zu regeln. Das Thema »Reguläre Ausdrücke« würde den Rahmen dieses Buches sprengen, daher verweisen wir auf man 7 regex bzw. einschlägige Literatur zu diesem Thema. Prinzipiell gilt für das Thema »Reguläre Ausdrücke in ACLs« eine einfache Regel: So wenig reguläre Ausdrücke wie möglich! Denn die diese Truppe bremst den Zugriff – je nach Komplexität des Suchmusters – auf unseren DIT gewaltig aus. Hier gilt ausnahmsweise mal: Geiz ist geil. Auf den folgenden Seiten und in späteren Kapiteln geben wir natürlich auch zu dn.regexp Anwendungsbeispiele. dn.base (oder auch dn.exact) ist der Standardwert für , sofern explizit
nichts anderes angegeben wurde, und bezieht sich immer nur genau auf den angegebenen DN. Wird nur dn angegeben, bedeutet das also, dass dn.base gefordert wird. Dies lässt sich ebenfalls gut (siehe Ausgabe-Listing auf Seite 294/295) im Debug-Mode unseres slapd (-d 128) erkennen: Obwohl wir nur "dn=" angegeben hatte, interpretiert der slapd den Ausdruck als "dn.base=". dn.one (Kurzform von onelevel) trifft auf alle Einträge zu, die sich direkt unter-
halb des angegebenen DN befinden, allerdings nicht den DN selber (z.B. alle User einer ou, aber nicht die ou selbst) und auch keine untergeordneten Subtrees.
297
3.7
1198.book Seite 298 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
dn.sub (Kurzform von subtree) trifft auf alle Einträge zu, die sich im angegebenen DN befinden, den DN selbst und auch untergeordnete Units, also eben einen Teilbaum. dn.children betrifft alle Einträge unterhalb des DN und seiner Units (prinzipiell
also wie subtree), allerdings ohne den DN selbst mit einzuschließen. Verdeutlichen wir das nun anhand unseres DIT. Wir nehmen dazu folgende, bereits vorhandene Einträge: a) dc=local,dc=site b) cn=ldapadmin,dc=local,dc=site c) ou=forschung,dc=local,dc=site d) uid=eripley,ou=forschung,dc=local,dc=site e) uid=skiu,ou=forschung,dc=local,dc=site f) uid=eripley,ou=xeno,ou=forschung,dc=local,dc=site und betrachten den dnstyle in verschiedenen Variationen, bezogen auf den immer gleichen DN: dn.base="ou=forschung,dc=local,dc=site"
trifft zu auf (c)
dn.exact="ou=forschung,dc=local,dc=site"
trifft zu auf (c)
dn.one="ou=forschung,dc=local,dc=site"
trifft zu auf (d, e)
dn.sub="ou=forschung,dc=local,dc=site"
trifft zu auf (c, d, e, f)
dn.children="ou=forschung,dc=local,dc=site"
trifft zu auf (d, e, f)
dn.regex – Beispiele: Ein Ausdruck wie: access to dn.regex=".*,dc=local,dc=site$"
ist vom Ansatz her schon relativ okay, da der Ausdruck zumindest durch das $ (Zeilenende) nach rechts begrenzt ist, also werden nur DNs akzeptiert, die auf dc=local,dc=site enden. Allerdings sind auf der linken Seite alle DN-Kombinationen möglich. Wenn genau ein RDN (also z.B. eine ou) abgedeckt werden soll, muss der Ausdruck dementsprechend angepasst werden, z.B.: access to dn.regex="^uid=([^,]+),ou=forschung,dc=local,dc=site$" ...
298
1198.book Seite 299 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
Das "^" am Anfang des regulären Ausdrucks begrenzt ihn auf der linken Seite: Dieser reguläre Ausdruck wertet nur DNs aus, die mit uid= beginnen, an das sich der fixe DN ou=forschung,dc=local,dc=site anschließt. Durch den Ausschluss des Kommas [^,] wird der erste DN-Teilstring eindeutig auf uid= begrenzt. Das Suchmuster würde somit nur auf alle Userobjekte der Unit ou=forschung passen; Objekte in der darunter liegenden Unit ou=xeno werden hier nicht berücksichtigt. Performance ...
An dieser Stelle noch einmal der allgemeine Hinweis zur Verwendung von regulären Ausdrücken zur Auswertung von DNs: Wann immer möglich (z.B. um Bereiche einzugrenzen), sollten die dafür vorgesehenen dnstyles bzw. Scopes verwendet werden, wie base, one, sub oder children. Diese bieten im Vergleich zur Auswertung der DN durch regex immer eine wesentlich bessere Performance; der Unterschied vergrößert sich dabei proportional zu Ungunsten der regulären Ausdrücke mit ihrer steigenden Komplexität und der Größe des DIT.
3) [attrs=[ val[.<style>]=]] Betrachten wir zunächst die ACL-technische Attribut-Auswertung. Hierfür nehmen wir einen Beispieleintrag in der Form, wie er z.B. in der SUSE-slapd.conf als globale ACL zu finden ist. Beispiel 1 access to attrs=userPassword,userPKCS12 by self write by * auth
Die Funktionsweise entspricht dabei der bereits aus den vorangegangenen DNBeispielen bekannten, nur dass wir hier direkt den Zugriff auf alle Attribute innerhalb des DIT per attrs= regeln, die wir als <was> auflisten, in diesem Fall userPassword,userPKCS12. Daran erkennen wir auch, dass wir mehrere Attribute problemlos per Komma verketten können. Diese ACL gestattet dem erfolgreich authentifizierten User (by * auth), sein eigenes Passwort und das PublicKey-Attribut zu modifizieren (by self write). Da wir sie an dieser Stelle bereits verwenden, vorab schon ein kurzes Wort zu den Rechten bzw. Access Levels, die wir vergeben können: none, disclose, auth, compare, search, read, write, manage. Die Rechte none, read und write sollten keiner weiteren Erläuterung bedürfen, auth gestattet, vereinfacht ausgedrückt, einem Benutzer den Zugriff auf ein Attribut (z.B. userPassword), um sich authentifizieren zu können, disclose gibt lediglich Rückmeldung über Fehler. Das höchste (Schreib-)Recht (write) beinhaltet alle anderen; das noch höher privilegierte manage ist die »Alles-
299
3.7
1198.book Seite 300 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Darf-Freikarte« in unserem DIT. Dazu gleich mehr; die Details zu den jeweiligen Access Levels werden wir im Folgenden noch genauer erörtern. Beispiel 2 access to dn="uid=ckent,ou=verkauf,dc=local,dc=site" attrs=description,mail by self write by * read
Damit engen wir Clarks Rechte der Selbstmodifikation aus Abschnitt 3.7.1, »Wer ist hier der Boss?«, wieder erheblich ein, und zwar auf die Attribute description und mail. Testen wir das Ganze nun per LDIF-Datei mit geändertem descriptionAttribut und ldapmodify in bekannter Weise. Zur Gegenprobe können wir das Ganze anschließend noch einmal mit einer Änderungsanforderung für das telephoneNumber-Attribut testen. Betrachten wir nun die Möglichkeit, direkt Attribut-Werte als Kriterium anzugeben. Mit val[.<style>]=] haben wir die Möglichkeit, explizit ein Attribut anzugeben, das einen bestimmten Wert erfordert, um der ACL Genüge zu tun. Ein einfaches Beispiel könnte so aussehen: Beispiel 3 access to dn.children="dc=local,dc=site" attrs=description val.regex="^Mitarbeiter.+" by dn="uid=ckent,ou=verkauf,dc=local,dc=site" read by * none
Mit dieser ACL hätte nur ckent auf alle description-Attribute im DIT lesenden Zugriff, deren Inhalt mit »Mitarbeiter« beginnt. Alle anderen sehen nichts. 4) [filter=] Filter ermöglichen es uns, explizit Objekte als <was> anzusprechen, die einer gültigen LDAP-Filter-Syntax gemäß RFC 4515 (»String Representation of LDAP Search Filters«) entsprechen. Wenn wir uns die dort genannten Beispiele ansehen, sollte uns einiges bekannt vorkommen. Woher? Genau, aus unserem Abschnitt 2.3, »Fingerübungen«, denn dort hatten wir bereits mit typischen LDAP-Filtern dieser Art gearbeitet. Sehen wir uns ein paar ACL-Beispiele für Filter an, und analysieren sie:
300
1198.book Seite 301 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
Beispiel 1 access to dn.sub="dc=local,dc=site" filter=(objectclass=groupOfNames) by dn="uid=ckent,ou=verkauf,dc=local,dc=site" write by * read
Wir erinnern uns an unsere Gruppe cn=superuser,dc=local,dc=site vom Objekttyp groupOfNames, die einige Mitglieder hat (member: …). Mit dem oben getroffenen ACL-Statement hat unser User ckent die Berechtigung, alle Objekte innerhalb des DIT, die vom Objekttyp groupOfNames sind, zu modifizieren und somit neue Mitglieder zu addieren, wie z.B. den guten, alten Vito Corleone: acl_mask: access to entry "cn=superuser,dc=local,dc=site", attr "member" requested => acl_mask: to value by "uid=ckent,ou=verkauf,dc=local,dc=site", (=0) <= check a_dn_pat: uid=ckent,ou=verkauf,dc=local,dc=site <= acl_mask: [1] applying write(=wrscxd) (stop) <= acl_mask: [1] mask: write(=wrscxd) => slap_access_allowed: add access granted by write(=wrscxd) => access_allowed: add access granted by write(=wrscxd) ...
Aber: Obwohl wir ckent per ACL die Berechtigung gegeben haben, alle Objekte vom Typ groupOfNames im DIT bearbeiten zu können, beschränkt sich die Vielfalt der Modifikationen letztlich nur auf das Attribut member. Denn egal, ob wir versuchen, das ganze Gruppenobjekt per modrdn zu moven oder gar ganz zu löschen – wir erleben hier ganz schnell eine Überraschung. Superman ist auf grünes Kryptonit gestoßen. Betrachten wir einfach mal die Debug-Ausgabe (-d 128) eines Löschungsversuchs: conn=1 op=1 DEL dn="cn=superuser,dc=local,dc=site" => bdb_entry_get: found entry: "cn=superuser,dc=local,dc=site" => access_allowed: delete access to "dc=local,dc=site" "children" requested ... => acl_mask: access to entry "dc=local,dc=site", attr "children" requested => acl_mask: to all values by "uid=ckent,ou=verkauf,dc=local,dc=site", (=0) ... => slap_access_allowed: delete access denied by read(=rscxd) => access_allowed: no more rules conn=1 op=1 RESULT tag=107 err=50 text=no write access to parent
Das Betrachten der Debug-Ausgabe führt uns direkt zur unmittelbaren Lösung des Problems, auf das uns die Fehlermeldung »no write access to parent« mit der Nase stupst. Zusätzlich zu den möglichen Attributen, die angegeben werden können, existieren Spezialattribute, auch Pseudoattribute genannt: entry und children. (Weiterhin existiert die Möglichkeit, ganze Objektklassen anzusprechen. Mit @ beginnende Attribute werden automatisch als ganze Objektklasse betrach-
301
3.7
1198.book Seite 302 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
tet, d.h., ein Eintrag wie attr=@groupOfNames würde sich auf alle Attribute der Objektklasse groupOfNames beziehen. Ein ! statt des @ invertiert diese Auswahl.) Zurück zu den Pseudoattributen entry und children. Sie beziehen sich auf einen Eintrag selbst (entry) bzw. auf die einem Eintrag untergeordneten Objekte (children).Wollen wir nun ckent die Berechtigung geben, die groupOfNames cn=superuser komplett aus dem DIT zu löschen, müssen die ACLs zwei Dinge zulassen: Zum einen muss ckent schreibenden Zugriff auf das entry-Attribut des zu löschenden Eintrags selbst haben (dies betrifft also den dn: cn=superuser,dc=local,dc=site) und ckent muss gleichfalls schreibenden Zugriff auf das children-Attribut des parent-Eintrags (also dc=local,dc=site) haben, das dem zu löschenden Objekt übergeordnet ist. Für ACLs gilt das Gleiche wie für die Programmierung: Viele Wege führen nach Rom. Betrachten wir einen möglichen Ansatz als Ergänzung zum letzten Beispiel: Beispiel 2 access to dn="dc=local,dc=site" attrs=children by dn="uid=ckent,ou=verkauf,dc=local,dc=site" write # Alternative 1 access to dn="cn=superuser,dc=local,dc=site" attrs=entry by dn="uid=ckent,ou=verkauf,dc=local,dc=site" write by * read
Hierbei würde sich die zweite ACL direkt und nur auf den DN: cn=superuser … und damit das Objekt selbst beziehen, Ein weiterer Ansatz, der sich auf alle Objekte im DIT vom Typ groupOfNames beziehen würde, könnte z.B. so aussehen: # Alternative 2 access to filter=(objectClass=groupOfNames) attrs=entry by dn="uid=ckent,ou=verkauf,dc=local,dc=site" write by * read
3.7.3
<Wer> (by)
Im letzten Abschnitt haben wir uns eingehend mit dem <was> beschäftigt, nun erweitern wir unseren Blickwinkel auf den Teil der ACL-Syntax, mit dem <wer> definiert wird. Das by (<wer>) besagt dabei immer, für wen die zugehörige ACL Anwendung findet.
302
1198.book Seite 303 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
Wie wir in den letzten Beispielen aus <was> schon gesehen haben, kann by im einfachsten Fall z.B. ein "*" oder ein einfacher DN sein. Wie wir in den Beispielen des letzten Abschnitts ebenfalls schon erkennen konnten, kann das by-Statement mehrfach in einer ACL Verwendung finden. Sehen wir uns nun an, welche Variationen gemäß slapd.access(5) überhaupt möglich sind: 1) * 2) anonymous 3) users 4) self[.<selfstyle>] 5) dn[.[,]]= 6) dnattr= 7) realanonymous 8) realusers 9) realself[.<selfstyle>] 10) realdn[.[,<modifier>]]= 11) realdnattr= 12) group[/[/]] [.]= 13) peername[.]= 14) sockname[.<style>]=<sockname> 15) domain[.<domainstyle>[,<modifier>]]=<domain> 16) sockurl[.<style>]=<sockurl> 17) set[.<setstyle>]=<pattern> 18) ssf= 19) transport_ssf= 20) tls_ssf= 21) sasl_ssf= 22) dynacl/[/][.][=<pattern>] ...
Wie wir sehen, stehen uns ein paar Variationen zur Verfügung. Ergänzend hierzu existieren außerdem noch etliche verschiedene Styles, die wir syntaktisch auf die <wer> Komponente der ACLs anwenden können. Da es den Rahmen des Buches sprengen würde, alle möglichen Varianten bis ins letzte Detail zu erläutern, werden wir uns einige gängige anschauen, aus denen sich bei Bedarf weitere ableiten lassen. Weitere Beschreibungen und Beispiele finden sich in slapd.access(5), dem OpenLDAP-Admin-Guide und in der FAQ-O-Matic zur Access-Control unter www.openldap.org. Werfen wir nun einen Blick auf die Statements (die obige Nummerierung entspricht dabei der Nummerierung der nun folgenden Unterpunkte):
303
3.7
1198.book Seite 304 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
1) * (Wildcard) Die Wildcard "*" für <wer> bedeutet, dass diese ACL auf jeden DN zutrifft. Diese by-Klausel hatten wir im letzten Abschnitt bereits einige Male verwendet. 2) anonymous anonymous bedeutet, dass die betreffende by-Klausel in der ACL den Zugriff für
nicht authentifizierte User ermöglicht. 3) users users gestattet authentifizierten Benutzern den Zugriff auf die betreffende ACL.
4) self self bedeutet, dass der Zugriff auf ein Objekt im DIT nur durch das Objekt selbst erfolgen darf.
Einfache Beispiele für die vorgenannten vier Punkte könnten so aussehen: Beispiel 1 access to attr=description by self write by * none
Beispiel 2 access to * by anonymous auth by users read
Das erste Beispiel erlaubt es authentifizierten Benutzern, ihr eigenes (self) description-Attribut zu modifizieren (write). Anderen DNs/Benutzern ist der Zugriff auf das Attribut untersagt. Das zweite Beispiel gestattet anonymen Usern die Authentifizierung. Authentifizierte User haben lesenden Zugriff auf den ganzen DIT, alle anderen nicht. 5) dn[.[]=] Diese by-Klausel bezieht sich in diesem Fall auf einen DN, der die gleichen dnstyles besitzen kann, die wir bereits anhand der access to-Klausel im letzten Abschnitt erläutert hatten. Eine einfache Variante der by dn="..."-Klausel haben wir im letzten Abschnitt auch schon verwendet, nämlich die DN unseres Users ckent. Eine ebenfalls geläufige Variante ist die Auswertung des DN per Style dn.regex. Hierbei wird der bei der Authentifizierung übergebene DN mit Hilfe
304
1198.book Seite 305 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
regulärer Ausdrücke ausgewertet (wie ebenfalls bereits im letzten Abschnitt beschrieben). Betrachten wir ein paar einfache Beispiele: Beispiel 1 (erste Zeile ist umbrochen) access to dn.regex="^uid=([^,]+),ou=forschung,dc=local,dc=site$" by dn.regex="^uid=$1,ou=forschung,dc=local,dc=site$$" write by * break
Die Funktionalität entspricht in etwa dem dn.regex-Beispiel aus dem vorigen Abschnitt (<was>): der DN wird in der dort beschriebenen Vorgehensweise ausgewertet. Die ACL erlaubt in diesem Beispiel einem authentifizierten Benutzer unterhalb der ou=forschung schreibenden Zugriff auf seine eigenen Attribute, für alle anderen existiert diese ACL nicht (by * break, siehe Abschnitt 3.7.4, »<Wie> – und mit welchen Rechten?«). In der Variablen $1 wird das (durch die Klammer in der access to dn.regex-Klausel gefundene) uid-Attribut des ausgewerteten DN gespeichert und kann so in der by-Klausel zur Vervollständigung des DN wieder verwendet werden. Beispiel 2 Eine modifizierte Variante wäre diese: access to dn.regex="^uid=([^,]+,ou=[^,]+),dc=local,dc=site$" by dn.regex="^uid=$1,dc=local,dc=site$$" write by * break
Hierbei würden alle authentifizierten Benutzer berücksichtigt, die in einer beliebigen ou direkt unterhalb der BaseDN liegen. Der reguläre Ausdruck fasst dabei uid= ...,ou= ... zusammen. Die User der ou=xeno unterhalb von forschung gehen in diesem Fall leer aus, für sie gilt diese ACL nicht. An dieser Stelle sei noch einmal ausdrücklich darauf hingewiesen, dass aus Performancegründen wann immer möglich den Scopes der Vorzug vor regulären Ausdrücken gegeben werden sollte. Noch ein Wort zum [], der z.B. in Verbindung mit der by dn.regex-Klausel verwendet werden kann. Er bezieht sich momentan nur auf den Typ expand. Dieser Parameter gestattet die Verwendung von Zeichenkettenersetzung auch in Subtrees, selbst wenn als dnstyle nicht regex gewählt wurde. Der Parameter sollte allerdings sicherheitstechnisch mit Bedacht gewählt wer-
305
3.7
1198.book Seite 306 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
den, da sich die Substitution auf alle unterhalb des angegebenen DN liegenden Objekte beziehen würde. Die Syntax der by-Klausel könnte so aussehen: by dn.exact,expand="^uid=$1,dc=local,dc=site" write
6) dnattr= Mit diesem Statement können Attribute eines Objekts ausgewertet werden, bei unserer groupOfNames also z.B. member oder owner, oder auch operational Attributes. So kann z.B. festgelegt werden, dass nur der Ersteller (engl. creator) die Berechtigung erhält, ein von ihm selbst erstelltes Objekt zu modifizieren. Folgende einfache ACL würde z.B. dem owner jedes groupOfNames-Objekts die Möglichkeit geben, member hinzuzufügen oder zu löschen. Jeder member-DN hätte lesenden Zugriff auf das Objekt. access to filter=(objectClass=groupOfNames) by dnattr=owner write by dnattr=member read
Betrachten wir die folgende ACL: access to dn.exact="cn=superuser,dc=local,dc=site" attrs=member by dnattr=creatorsName write by dn.sub=ou=forschung,dc=local,dc=site dnattr=member selfwrite by * read
Die by dnattr-Klausel wertet das operational Attribute creatorsName aus und erlaubt dem Ersteller (z.B. cn=ldapadmin) des groupOfNames-Objekts »cn=superuser«, beliebige Mitglieder (member) hinzuzufügen und zu entfernen. Jeder authentifizierte User unterhalb der Unit ou=forschung kann sich selbst (addieren und) entfernen. 7)–11) Are You Real ...? Die Direktiven mit dem Präfix real verhalten sich wie ihre gleichnamigen Kollegen; der einzige Unterschied liegt darin, dass sie zusätzlich überprüfen, ob der authentifizierte DN gleich dem autorisierten DN ist. Denkbar wäre eine Verwendung, um z.B. »unechte«, proxy-authentifizierte User herauszufiltern. 12) group[/[/]] [.]= Vorab eine wichtige Anmerkung zur Verwendung der by group-Klausel: um sie in Verbindung mit statischen Gruppen einsetzen zu können, sollten die verwendeten Gruppenobjekte dem Typ groupOfNames angehören, so wie z.B. unsere Gruppe cn=superuser. Falls andere Objekttypen und Attribute gewünscht werden, muss die vollständige Syntax eingegeben werden, z.B.:
306
1198.book Seite 307 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
by group/organizationalRole/roleOccupant= \
Ein kleiner Tipp hierzu: Die Verwendung des vielleicht ebenfalls nahe liegenden Objekttyps posixGroup führt zu Problemen, da dieser Objekttyp nicht den Anforderungen entspricht. Die Syntaxdefinition des Attributs memberUid des Objekttyps posixGroup (nis.schema) lautet: 1.3.6.1.4.1.1466.115.121.1.26
und gehört damit zum Typ »IA5-String-Syntax«. Daher entspricht die Syntax nicht der geforderten Spezifikation »LDAP-DN« (1.3.6.1.4.1.1466.115.121. 1.12), da sie keinen Distinguished Name abbildet, der eindeutig ausgewertet werden kann. Umfassende Informationen zum Thema OIDs können wir im Netz unter www.alvestrand.no/objectid/top.html nachschlagen, einen Teil der OIDs nehmen wir später im Abschnitt 3.9, »Selbst ist der Admin – das eigendefinierte Schema«, unter die Lupe. Betrachten wir folgendes Beispiel: access to dn.sub="ou=marketing,dc=local,dc=site" by group="cn=superuser,dc=local,dc=site" write by * auth break
Mit dieser ACL erlauben wir den Mitgliedern unserer Gruppe cn=superuser (Objekttyp groupOfNames), auf den subtree ou=marketing schreibend zuzugreifen. Als groupstyle stehen exact und expand zur Verfügung. exact bezieht sich exakt auf den genannten DN, expand bezieht sich entsprechend den vorgenannten Beispielen aus dem letzten Abschnitt auf die Möglichkeit, mit Variablen-Substitution arbeiten zu können. Exkurs 1: Hochdynamisch – Auswertung von dynamischen Gruppen per ACL Wir erinnern uns dunkel – dynamische Gruppen? Klar, der zuständige Ansprechpartner aus der Overlay-Bruderschaft war dynlist, und sein bevorzugtes Gruppenobjekt war groupOfURLs. Die Fähigkeit, Gruppen on the fly zu generieren, ist klasse, jedoch spielt sie nur dann in der ersten Liga mit, wenn wir das dynamisch kollektierte Ergebnis per ACL auch eindeutig auswerten und limitieren können. Nehmen wir ein einfaches Beispiel: Wir wollen den Zugriff auf das Attribut description im ganzen DIT nur Mitgliedern der dynamischen Gruppe cn=dyngroup aus unserem dynlist-Beispiel des Overlay-Kapitels erlauben. Die Syntax ist ähnlich der eben bereits vorgestellten (by group//); auf unser konkretes Beispiel bezogen, stellt sich das Ganze so dar:
307
3.7
1198.book Seite 308 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
access to attrs="description" by group/groupOfURLs/memberURL="cn=dyngroup,dc=local,dc=site" write by * read
An dieser Stelle noch einmal der wichtige Hinweis: Bei der Auswertung dynamischer Gruppen durch ACLs ist Vorsicht geboten. Wird member in der Konfiguration des Overlays als Rückgabe gewählt (kompletter DN), aber vergessen, das Rückgabeattribut (z.B.: sn) aus dem Suchfilter zu entfernen, greift die ACL definitiv nicht, obwohl die zurückgegebenen Objekte korrekt ausgelesen werden!
Exkurs 2: Nicht minder dynamisch – Auswertung dynamischer Objekte (dds) per ACL Hier ein kleines, effektives und leicht modifiziertes Beispiel aus dem OpenLDAP Admin Guide. Es erlaubt Usern, mit Hilfe von Overlay dds einen (zeitlich limitierten) »Meeting Point« anzulegen und ihm beizutreten. Der User, der den Meetingpoint angelegt hat, kann neue Teilnehmer hinzufügen und das Meeting jederzeit per extended operation verlängern. Beliebige andere User können beitreten, diese können aber selbst keine anderen Teilnehmer hinzufügen. Die refresh operation zur Verlängerung der entryTtl ist auf den Ersteller und die Mitglieder beschränkt, das Löschen von Objekten dem Ersteller des Objekts. Die in den ACLS vorkommenden Rechte selfwrite und manage schauen wir uns gleich noch genauer an. access to dn.base="ou=meeting,dc=local,dc=site" attrs=children by users write access to dn.onelevel="ou=meeting,dc=local,dc=site" attrs=entry by dnattr=creatorsName write by * read access to dn.onelevel="ou=meeting,dc=local,dc=site" attrs=member by dnattr=creatorsName write by users selfwrite by * read access to dn.onelevel="ou=meeting,dc=local,dc=site" attrs=entryTtl by dnattr=member manage by * read
Zum Anlegen der erforderlichen Objekte kann die Datei meeting.ldif aus den Beispieldateien verwendet werden (http://www.galileocomputing.de/1801). Hier noch einmal zur Erinnerung die extended Operation zur Verlängerung der entryTtl:
308
1198.book Seite 309 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
#> ldapexop -x "refresh" \ "cn=test-meeting,ou=meeting,dc=local,dc=site" "120" \ -D "uid=hcallahan,ou=verkauf,dc=local,dc=site" -W Enter LDAP Password: newttl=120
13) peername[.]= Hierbei handelt es sich auch um eine gebräuchliche Methode der <wer>-Definition. Nur dass hierbei kein DN verwendet wird, sondern die IP oder der FQHN des anfragenden Rechners: access to * by peername="ldapslave.local.site" read
wodurch wir von einer hostbasierten Zugriffsmethode sprechen. Dieses Vorgehen könnte man z.B. bei Replikation oder Partitionierung verwenden. Über peername.ip=192.168.1.1%255.255.255.0{9000}
könnten wir Verbindungen nur über Port 9000 auf der genannten IP erlauben. 14-16) sockname[.<style>]=<sockname>, domain[.<domainstyle>[,<modifier>]]=<domain>, sockurl[.<style>]=<sockurl> Die Direktiven sockname=<sockname>, domain=<domain> und sockurl=<sockurl> beziehen sich allesamt auf Host- bzw. Domänen-spezifische Zugriffsvarianten. sockname erlaubt nur die per PATH= vorgegebenen Verbindungen über einen Unix-Socket; sockurl dito, nur wird hier eine URL statt eines physikalischen Pfades vorgegeben. 17) Set-(tings) Eine interessante Möglichkeit, Rechte per ACLs zu granulieren, bietet uns unser slapd mit so genannten sets an. Klingt unscheinbar, ist es aber durchaus nicht – im Gegenteil. Sets sind mächtige Werkzeuge, die die Fähigkeiten normaler ACLs um einige Extra-Features aufbohren. Schauen wir uns also mal an, wie das Ganze funktioniert: Ge-managed ... Nehmen wir an, wir hatten unseren guten alten Harry Callahan, der ja – wie wir wissen – gern mal ausdropst und mit seiner 44er große Löcher in böse Jungs schießt, um ein manager-Attribut erweitert. Wer könnte ihn wohl besser managen und im Zaum halten als unser Kollege mit dem »S« auf dem Cape? dn: uid=hcallahan,ou=verkauf,dc=local,dc=site changetype: modify
309
3.7
1198.book Seite 310 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
add: manager manager: uid=ckent,ou=verkauf,dc=local,dc=site
Und nun schauen wir uns an, wie wir das zusätzliche Attribut per set effektiv ausnutzen können. Betrachten wir die folgende ACL: access to dn.exact="uid=hcallahan,ou=verkauf,dc=local,dc=site" attrs=description by self write by set="this/manager & user" write by * read
Durch die Klausel by set="this/manager & user" kann unser Clarkie das description-Attribut von Harry Callahan managen (so wie er selbst auch) und ihn wieder auf die richtige Spur bringen. In den Logs stellt sich die erfolgreiche Operation dann so dar: check a_set_pat: this/manager & user ACL set[0]=uid=ckent,ou=verkauf,dc=local,dc=site <= acl_mask: [2] applying write(=wrscxd) (stop)
Sets eignen sich ebenfalls hervorragend, um ein anderes komplexes Problem zu lösen, und es geht mal wieder um Gruppentherapie ... Die Gruppe in der Gruppe Nested Groups – eingebettete Gruppen. Nette Sache, um Mitglieder einer bestehenden Gruppe einer anderen hinzuzufügen. Aber ohne die passenden ACLs bringt uns das rein gar nichts, und diesen speziellen Fall können wir ohne Sets auch kaum realisieren. Nehmen wir dazu in unserem folgenden Beispiel an, unsere Gruppe cn=superuser würde in einem ihrer member-Attribute den DN einer weiteren Gruppe beherbergen: dn: cn=superuser,dc=local,dc=site ... member: uid=ckent,ou=verkauf,dc=local,dc=site member: cn=webuser,dc=local,dc=site
Und zu dieser »Netz«-Gruppe würde konsequenterweise auch die freundliche Spinne aus der Nachbarschaft gehören, unser Kollege Peter Parker. Hätten wir nun eine »Standard«-ACL für die Gruppe cn=superuser aktiviert, würden die inkludierten User der Gruppe cn=webuser keine Beachtung finden: access to dn.subtree="ou=marketing,dc=local,dc=site" by group.exact="cn=superuser,dc=local,dc=site" write by * none
Würde pparker nun auf die Unit marketing zugreifen wollen, hätte er Pech. Denn wenn wir die Chose zunächst per slapacl mit der »normalen« ACL in einer Arbeits-
310
1198.book Seite 311 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
kopie unserer slapd.conf (slapd.acl-test) testen, läuft unsere Spinne voll gegen die Wand (mehr zu slapacl im Abschnitt 3.7.5, »Und was es sonst noch gibt ...«): #> slapacl -f slapd.acl-test \ -D uid=pparker,ou=verkauf,dc=local,dc=site -b ou=marketing,dc=local,dc=site
\
authcDN: "uid=pparker,ou=verkauf,dc=local,dc=site" entry: none(=0) children: none(=0) objectClass=dcObject: none(=0) objectClass=organizationalUnit: none(=0) ... und so weiter
Erschlagen wir jedoch den Zugriff nun über ein wohldefiniertes ACL-set, sieht die ganze Geschichte schon völlig anders aus: access to dn.subtree="ou=marketing,dc=local,dc=site" by set="[cn=superuser,dc=local,dc=site]/member* & user" write by * none
Mit dem gleichen slapacl-Statement wie oben erhalten wir nun folgende Ausgabe: authcDN: "uid=pparker,ou=verkauf,dc=local,dc=site" entry: write(=wrscxd) children: write(=wrscxd) objectClass=dcObject: write(=wrscxd) objectClass=organizationalUnit: write(=wrscxd) ... und so weiter
Mit etwas Anpassungsarbeit an den set-tings lassen sich auch unsere DN-technisch etwas beschränkten posixGroups bei verschachtelten Gruppen ACL-technisch vernünftig auswerten. Sets werden hier und da noch als experimentell betitelt, laufen jedoch in der Praxis stabil und sind fester Bestandteil unseres slapd. slapd.access(5) gibt leider nicht viel zum Thema sets her, aber eine relativ komplette Übersicht mit Syntaxbeispielen und weiterführenden Infos findet sich im OpenLDAP Admin Guide und in der OpenLDAP-FAQ unter: http://www.openldap.org/faq/data/cache/1133.html 18)–21) Äußerst kryptisch ...: ssf=, transport_ssf=, tls_ssf=, sasl_ssf= Die by-Klauseln 18)–21) beziehen sich allesamt auf den bereits bekannten Security Strength Factor verschlüsselter Verbindungen, z.B. um den Zugriff auf Objekte nur dann zuzulassen, wenn er einem minimal vorgeschriebenen Verschlüsselungsfaktor genügt. So könnten wir zum Beispiel durch ein einfaches Konstrukt:
311
3.7
1198.book Seite 312 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
access to dn.sub="ou=forschung,dc=local,dc=site" by * ssf=56 read
jeden lesenden Zugriff auf Objekte unterhalb der Unit forschung auf die Anfragen beschränken, die mit einem Security Strength Factor 56, also z.B. über SASLMech GSSAPI und Kerberos, erfolgen. Siehe hierzu auch den Exkurs in Abschnitt 3.4.5, »Eine Frage der Zertifizierung«, über globale Security-relevante Settings in der slapd-Konfiguration. 22) dynacl wird im Zusammenspiel mit ACIs benötigt und ist daher nicht unser Thema.
3.7.4
<Wie> – und mit welchen Rechten?
::= [[real]self]{|<priv>} ::= none|disclose|auth|compare|search|read| {write|add |delete} |manage <priv>::= {=|+|-}{0|d|x|c|s|r|{w|a|z}|m}+
Die grundsätzliche ACL-Syntax betreffend der zu vergebenden Rechte haben wir ja bereits in den letzten Abschnitten kennengelernt. Schauen wir uns nun die Syntax der Rechtevergabe etwas genauer an. Exkurs: Just me, myself and I ... Über [real]self können wir die Rechte auf einfache Art und Weise mit dem anfragenden DN verbinden. So erreichen wir, dass z.B. ein erfolgreicher authentifizierter User per self{write|add|delete} seine eigenen Attribute pflegen kann oder Zugriff auf sein eigenes member-Attribut innerhalb einer Gruppe erhält. Das folgende Beispiel kennen wir schon: access to dn.exact="cn=superuser,dc=local,dc=site" attrs=member by dnattr=creatorsName write by dnattr=member selfwrite by * read
Kurze Beschreibung der ACL: 왘 Sie erlaubt dem Eigentümer (creatorsName) des groupOfNames-Objekts »cn=superuser«, jedes beliebige Mitglied (member) hinzuzufügen und zu entfernen. 왘 Jeder authentifizierte User kann sich selbst addieren und entfernen. Dicker Schwachpunkt dabei: User können sich selbst jederzeit der Gruppe hinzufügen: »Ich bin jetzt Superuser – ho-ho-ho!« Das brauchen wir so wenig wie der
312
1198.book Seite 313 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
ewig gestresste John McClane eine Gruppe von bösen Buben pünktlich zum Fest der Liebe ... Lösung: Statt selfwrite verwenden wir selfdelete; so können sich bestehende Mitglieder zwar selbst entfernen, aber neue können sich nicht selbst hinzufügen, das kann nach wie vor nur der Ersteller der Gruppe (z.B. ldapadmin): access to dn.exact="cn=superuser,dc=local,dc=site" attrs=member by dnattr=creatorsName write by dnattr=member selfdelete by * read
Zurück zu den eigentlichen Rechten. Prinzipiell stehen uns zwei Verfahren der Rechtevergabe zur Auswahl: Access-Level und sogenannten Privileges: access-level
Entspricht Bedeutung privileg
none
(0)
keine Rechte
disclose
(d)
Erlaubt die Anzeige von Informationen zu einem gegebenenfalls auftretenden Problem.
auth
(x)
Der Zugriff auf authentifizierungsspezifische Attribute (z.B. userPassword) wird auch ohne ein vorheriges bind zum Zweck der Authentifizierung gestattet.
compare
(c)
Mit diesem access-level können Attribute von Datensätzen miteinander verglichen werden. Die reine Anwendung dieses Levels ist eher selten.
search
(s)
Bei Verwendung dieses Levels werden bei Suchoperationen im DIT keine Datensätze zurückgegeben. Stattdessen erfolgt nur die Rückmeldung in Form von Erfolg/Misserfolg. Die search-operation benötigt dabei search (=s) -privilegien auf das Pseudo-Attribut entry der Searchbase (neu in OpenLDAP 2.4).
read
(r)
Suchoperationen im DIT sind gestattet, gefundene Übereinstimmungen werden komplett ausgegeben.
write (w) {add|delete} {a|z}
Die Modifikation von Einträgen wird gestattet. Sub-Granulation per add|delete ist ebenfalls möglich. So kann z.B. nur das Recht gegeben werden, member-Attribute einer Gruppe hinzu zu addieren, aber nicht zu löschen, oder anders herum (s.o.).
manage
Administrativer Zugriff (siehe hierzu auch test037 in den Sourcen): Modifikationen an operational Attributes oder Objektklassen (wenn kompatibel) kann hierüber gewährt werden.
(m)
313
3.7
1198.book Seite 314 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Bei der Anwendung von access-level ist zu beachten, dass jeder Nachfolger die Rechte seiner Vorgänger beinhaltet, d.h., compare enthält auth, search enthält compare (und damit auch auth) usw., manage beinhaltet dementsprechend alle gelisteten Rechte (natürlich ohne none). Bei privileges sieht die Sachlage anders aus, dazu gleich mehr. Eine Verteilung der Rechte ist mit der access-level-Syntax »nur« in der bereits bekannten Form möglich, wie z.B.: by self write by anonymous auth by * none
Eine etwas feinere Granulierung bzw. andere Art der Rechte -Zuweisung ist mit den Privileges möglich. Hierbei besteht die Möglichkeit, bestehende Rechte nachträglich zu erweitern oder einzuschränken. Dazu lohnt es sich aber, im gleichen Zug auch einen Blick auf die eingangs erwähnten Control-Flags zu werfen. Wie wir bereits wissen, ist unser LDAP standardmäßig eher von der faulen Sorte, denn im Normalfall beendet er die Suche in den ACLs immer, sobald er eine passende Regel gefunden hat. Immer? Nicht ganz, ein kleines Set von Control-Flags leistet dagegen erbitterten Widerstand. Eines dieser Gattung, und zwar break, haben wir in den vergangenen Beispielen schon einige Male erfolgreich angewendet. Und da diese kleinen Flags recht viel bewirken können, schauen wir sie uns gleich mit an. Nehmen wir dazu folgendes (zunächst noch unsinniges) ACL-Beispiel: access to attrs=description by * +x by self +rw
Diese ACL gestattet jedem DN, sich zu authentifizieren (+x entspricht dem authlevel). Im nächsten Schritt würde rein syntaktisch dem eigenen Objekt (self) zusätzlich gestattet (+rw), sein Attribut description zu lesen (r) und schreiben (w). An dieser Konstruktion ist bereits der eindeutige Unterschied zwischen privileges und access-levels zu erkennen. Während die access-level hierarchisch aufgebaut sind und die Rechte ihrer Vorgänger beinhalten, wird bei den privileges jedes Recht einzeln zugewiesen. Das bedeutet im Klartext, dass ein zugewiesenes w noch lange kein r beinhaltet, wie es bei Access-Levels der Fall wäre. Die Werte der Privileges werden also unabhängig (!) voneinander gesetzt. Die Steuerung erfolgt über »arithmetische« Operatoren, +, – und =. Ein + fügt eine Berechtigung hinzu, ein – zieht dementsprechend eine ab. Ein = setzt bestehende Rechte genau auf die nachfolgend angegebenen.
314
1198.book Seite 315 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
Weiter im Text: Die Auswertung der zweiten by-Klausel aus dem obigen Beispiel (by self +rw) tritt erst gar nicht in Kraft, da ja bereits die erste by-Klausel zutrifft und unser slapd daraufhin die Abarbeitung der ACL beendet. Schauen wir uns die Debug-Ausgabe beim Versuch an, das description-Attribut zu ändern: => access_allowed: auth access granted by auth(=xd) ... => acl_mask: to all values by "uid=ckent,ou=verkauf,dc=local,dc=site", (=0) <= check a_dn_pat: * <= acl_mask: [1] applying +x (stop) <= acl_mask: [1] mask: =x => access_allowed: delete access denied by =x
Die erste passende ACL wurde abgearbeitet (auth), danach wurde die Abarbeitung gestoppt (stop). Dieses Verhalten kennen wir ja bereits, daher ist (im Normalfall) die korrekte Reihenfolge der by-Klauseln zwingend. Um nun zu erreichen, dass unsere zweite by-Klausel dennoch abgearbeitet wird, verwenden wir das ControlFlag continue. continue erzwingt die Abarbeitung weiterer by-Klauseln innerhalb der gleichen ACL(!), selbst wenn bereits eine passende gefunden wurde. access to attrs=description by * +x continue by self +rw
Checken wir nun ein weiteres Mal die Debug-Ausgabe (gekürzt): => slap_access_allowed: auth access granted by auth(=xd) => access_allowed: auth access granted by auth(=xd) => access_allowed: delete access to "uid=ckent,ou=verkauf,dc=local,dc=site" "description" requested ... <= acl_mask: [1] applying +x (continue) <= acl_mask: [1] mask: =x <= acl_mask: [2] applying +wr (stop) <= acl_mask: [2] mask: =wrx => slap_access_allowed: delete access granted by =wrx ... <= acl_mask: [1] applying +x (continue) <= acl_mask: [2] applying +wr (stop) <= acl_mask: [2] mask: =wrx => slap_access_allowed: add access granted by =wrx ...
Wie wir unschwer erkennen können, haben wir mit dem kleinen Flag continue einen großen Effekt erzielt. Ein weiteres Beispiel: access to dn.subtree="ou=verkauf,dc=local,dc=site" attrs=description by * =csr continue by self +w
315
3.7
1198.book Seite 316 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Die Control-Flags zur Steuerung des Abarbeitungsverhaltens bestehen aus drei Anweisungen: continue, break und stop. Die Wirkung von continue haben wir bereits kennen gelernt, allerdings gilt der Wirkungsbereich immer nur für genau die ACL, die auch die continue-Anweisung enthält. Die break-Anweisung erlaubt hingegen auch nach einem match noch die Abarbeitung weiterer ACLs. stop beendet nach einem erfolgten match die Abarbeitung sofort. Ein typisches Anwendungsbeispiel für control flags ist das Setzen genau jener für den Zugriff des replicator-Accounts, das wir bereits aus dem Kapitel über Replikation kennen: access to * by dn.exact="cn=replicator,dc=local,dc=site" read by * break
Durch die kleine, aber effektive Zeile by * break erreichen wir, dass diese ACL von allen anderen Objekten völlig ignoriert wird. Durch das break springt die Suche bei jedem anderen DN, der nicht rein zufällig auf den Namen replicator hört, sofort weiter zur nächsten ACL, als wäre nichts geschehen. Vereinfacht können wir sagen, dass wir durch dieses Control-Flag erreichen, dass die ACL für alle nicht zutreffenden DNs schlichtweg nicht existiert. Kontrollverlust – Tücken mit Control-Flags Bei allen Vorteilen, die uns die Control-Flags bieten, müssen wir auch beachten, dass jedes zusätzliche Feature mögliche Fehlerquellen implementiert – rein potenziell. Das die dann meist auf Layer 8 zu suchen sind, ist ebenfalls klar ... Um wenigstens die gröbsten Böcke zu vermeiden, hier ein kleines Beispiel dafür, wie wir es nicht tun sollen (Zweite Zeile ist umbrochen): access to dn.sub="ou=marketing,dc=local,dc=site" by dn.exact="uid=ckent,ou=verkauf,dc=local, dc=site" write continue by group="cn=superuser,dc=local,dc=site" read by * none
Sieht doch auf den ersten, schnellen Blick prima aus – aber nur auf den. In diesem Beispiel würde ckent schreibenden Zugriff auf die Objekte in der ou marketing haben, aber – da continue ebenfalls gesetzt ist, wird die by-group-Klausel auch noch abgearbeitet. Und da unser guter alter ckent leider auch zur Gruppe cn=superuser gehört, werden ihm durch das read für diese Gruppe seine frisch erworbenen Schreibrechte stante pede wieder entzogen!
316
1198.book Seite 317 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
Daher Achtung: continue kann bei korrekter Anordnung der ACLS weitestgehend vermieden werden (und sollte es auch), da es zu unerwünschtem Verhalten (Entzug von bereits gewährten Rechten) und einer Verkomplizierung der ACL führen kann.
Exkurs: Alles »ge-manage-d« oder was? – Access-Level: manage Mit Hilfe des neuen Access-Levels manage in OpenLDAP 2.4 lassen sich einige Dinge in unserem DIT ganz schön verbiegen. Daher ist Vorsicht angesagt, und die Gewährung von manage-Privilegien will wohlüberlegt sein. Wie uns allen klar sein sollte, benötigt unser guter alter rootdn keine zusätzlichen manage -Privilegien – dafür ist er ja schließlich der Chef. Für alle anderen, denen wir zusätzliche Rechte geben wollen, die zum Teil weit über das hinausgehen, was normalerweise möglich (und für unseren DIT auch gesund ist), können wir bei Bedarf das manage-Privileg (m) oder den Access-Level manage (der alle anderen Level beinhaltet) vergeben. manage benötigt nicht nur auf der ACL-Implementierungsebene eine gesunde Vorbetrachtung, sondern auch eine speziellen Syntax auf der Kommandozeile. Wir erinnern uns noch dunkel an ldapexop bzw. extended Operations der lapd-Tools, die wir mit dem kleinen Schalter -e aktivieren können? Gut, denn der Switch kommt hier wieder zu Einsatz. So viel zur Theorie; nun in die Praxis. Im ersten Beispiel demonstrieren wir anhand der Modifikation eines operational Attributes die weitreichenden Fähigkeiten und Konsequenzen des manage-Privilegs bzw. Levels. Nehmen wir dazu folgendes LDIF, mit dem wir, als ckent wohlgemerkt, uns selbst (statt cn=ldapadmin) als Ersteller von Harrys Datensatz eintragen möchten: dn: uid=hcallahan,ou=verkauf,dc=local,dc=site changetype: modify replace: creatorsName creatorsName: uid=ckent,ou=verkauf,dc=local,dc=site
Wenn wir nun mit dem DN von ckent ein ldapmodify auf Harrys Objekt absetzen (selbst wenn wir ckent zuvor per write-ACL »alle« Rechte verpasst hätten), ernten wir nichts anderes als ldap_modify: Constraint violation (19) additional info: creatorsName: no user modification allowed
Setzen wir nun die folgende Backend-ACL access to dn="uid=hcallahan,ou=verkauf,dc=local,dc=site" by dn="uid=ckent,ou=verkauf,dc=local,dc=site" manage by * break
317
3.7
1198.book Seite 318 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
und führen nach dem Restart unseres slapd ein etwas aufgemotztes ldapmodify durch: #> ldapmodify -xWD uid=ckent,ou=verkauf,dc=local,dc=site \ -e manageDIT -f harry.ldif
sieht das Ergebnis schon anders aus: acl_mask: access to entry "uid=hcallahan,ou=verkauf,dc=local,dc=site", attr "creatorsName" requested ... => access_allowed: manage access granted by manage(=mwrscxd)
Aber damit sind wir noch lange nicht am Ende. Mit entsprechendem manageRecht und einem passenden LDIF können wir sogar die strukturelle Objektklasse(!) eines Objekts ändern, ohne das Objekt erst zu löschen und dann wieder neu anzulegen. Voraussetzung ist natürlich, dass die Objektklassen zueinander kompatibel sind bzw. dass die neue strukturelle Objektklasse zumindest alle Attribute der alten besitzt. Ein typisches Beispiel hierfür wäre das »Upgrade« von person auf organizationalPerson oder inetOrgPerson. Da wir unseren kleinen Kumpel Hulk schon lange nicht mehr auf die Palme gebracht haben, ist er jetzt mal wieder dran. Die Objektdaten sind schnell gestrickt: dn: cn=hulk,ou=verkauf,dc=local,dc=site cn: hulk objectClass: person sn: hulk
So weit, so gut. Im nächsten Schritt setzen wir eine manage-ACL für unseren hulk, die wir bereits in der gleichen Form für hcallahan verwendet haben, um ihn von ckent managen zu lassen: access to dn="cn=hulk,ou=verkauf,dc=local,dc=site" by dn="uid=ckent,ou=verkauf,dc=local,dc=site" manage by * break
Um unseren grünen Klotz nun tiefgreifend zu modifizieren, verwenden wir folgendes LDIF (hulk_mod.ldif), das zunächst eine zusätzliche Objektklasse (inetOrgPerson) setzt, sie anschließend als strukturelle Klasse definiert und schließlich die alte und obsolete Objektklasse (person) entfernt. dn: cn=hulk,ou=verkauf,dc=local,dc=site changetype: modify add: objectClass objectClass: inetOrgPerson replace: structuralObjectClass
318
1198.book Seite 319 Donnerstag, 5. Februar 2009 3:02 15
Nur mit Clubkarte – Zugriffsregelung durch ACLs
structuralObjectClass: inetOrgPerson delete: objectClass objectClass: person
Und siehe da – unser Hulk ist plötzlich ein ganz neues Objekt. Ein Wort zum Schluss zu manage – und den möglicherweise negativen Konsequenzen bei unbedachtem Einsatz. Wie wir gesehen haben, ist es für uns mit der richtigen Technik ein Leichtes, selbst operational Attributes zu modifizieren. Und zu den operational Attributes gehören, wie wir längst wissen, auch die Timestamps eines Objekts. Wenn wir an solchen Schrauben drehen würden, könnte das insbesondere replikationstechnische Seiteneffekte hervorrufen, die wir so wenig brauchen wie die nächste Steuererhöhung. Also gilt auch hier wie im realen Leben: Der Manager trägt die Verantwortung, aber bei uns bekommt er – im Unterschied zur Wunderwelt der Wirtschaft – im Fehlerfall mit Sicherheit kein Dankeschön und keine dicke Abfindung ...
3.7.5
Und was es sonst noch gibt ...
Was haste denn drauf? Innerhalb der globalen ACLs werden üblicherweise auch ACLs spezifiziert, die es den Clients vor einer Authentifizierung ermöglichen, die Kapabilitäten unseres slapd auszulesen, denn wer will schon die Katze im Sack kaufen? Über access to dn.base="" by * read
und access to dn.base="cn=Subschema" by * read
erhält jeder Client lesenden Zugriff auf die vorhandenen Features unseres LDAPServers und kann so z.B. bequem auslesen, welche SASLMechs unterstützt werden und ob eine Authentifikation per TLS möglich ist. Wir erinnern uns hierzu an den ldapsearch-Befehl aus Abschnitt 2.3.1, »Die ldap*-Tools«: #> ldapsearch -x -b "" -s base +
UND …? Noch ein kleiner Tipp: Es ist auch möglich, mehrere by-Klauseln in einer logischen UND-Verknüpfung miteinander zu verbinden. Die by-Klausel gilt erst dann als erfüllt, wenn alle Bedingungen zutreffen. Ein kleines Beispiel, bezogen auf unseren DIT (die 3. Zeile ist umbrochen): 319
3.7
1198.book Seite 320 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
access to dn.sub="ou=verkauf,dc=local,dc=site" attrs=description by peername.ip="192.168.0.99" \ dn.exact="uid=hcallahan,ou=verkauf,dc=local,dc=site" \ ssf=56 write by * read
Zugriff auf das Attribut description im Subtree verkauf würde nur den Wert von Harry erhalten, und das auch nur, wenn er vom Host mit der korrekten IP und einem entsprechenden Security Strength Factor (ssf) verschlüsselt auf den DIT zugreift. Trockenschwimmen – ACL-Tests per slapacl Nicht immer, aber immer ... nein, nix mit Clausthaler, auch wenn das gut zum Begriff »Trockenschwimmen« passen würde. Trockenschwimmen passt aber ebenfalls hervorragend zum (Trocken-)Testen von ACLs. Nehmen wir an, wir müssten für unseren DIT ein paar neue ACLs erstellen, hätten aber – wie normalerweise üblich und auch sinnig – kaum die Möglichkeit, die ACLs direkt auf unserem Produktiv-Tree zu im Betrieb zu testen, ohne sämtliche angeschlossenen User zu Recht in Wallung zu bringen. Was tun? Die Antwort heißt slapacl, weil das hilfreiche kleine Tool es uns ermöglicht, ACLs im laufenden Betrieb auszuprobieren, und zwar ohne den laufenden Betrieb zu stören. Wie aber funktioniert das? Auch ganz einfach: Wir können slapacl eine auf unsere ACL-Bedürfnisse angepasste Kopie der im Betrieb befindlichen slapd.conf (oder des slapd.d/ Ordners) mit auf den Weg geben und die Auswirkungen unserer Modifikationen »offline« testen. Nehmen wir also konkret an, wir möchten eine ACL testen, die ckent schreibenden Zugriff auf das description-Attribut seines Kollegen Callahan aus der Unit Verkauf einräumt, z.B.: access to dn.exact=uid=hcallahan,ou=verkauf,dc=local,dc=site attrs=description by dn=uid=ckent,ou=verkauf,dc=local,dc=site write by * break
Diese ACL würden wir in eine Arbeitskopie unserer slapd.conf einpflegen, z.B. mit Namen slapd.acl-test. Während unser slapd weiterhin brav seinen Produktivbetrieb fährt, testen wir im Stillen die neue ACL-Konfiguration (hier ohne Pfad zur Datei slapd.acl-test) : #> slapacl –f slapd.acl-test \ -D uid=ckent,ou=verkauf,dc=local,dc=site \ -b uid=hcallahan,ou=verkauf,dc=local,dc=site \
320
1198.book Seite 321 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
description/write authcDN: "uid=ckent,ou=verkauf,dc=local,dc=site" write access to description: ALLOWED
und erhalten die gewünschte Rückmeldung. Wer einen kompletten Überblick über alle Attribute des Objekts haben möchte und wissen will, wie auf sie zugegriffen wird, lässt den Parameter Attribut/Zugriffsart einfach weg. So können wir ohne Risiko die Auswirkungen einer ACL testen und anpassen, bevor wir sie einpflegen. Die Parameter sind dabei relativ selbsterklärend, hier nur die wichtigsten: -f die (alternative) slapd-Konfigurationsdatei
(bzw. -F für den Konfigurations-Ordner) -D die Identität, mit der auf die ACL zugegriffen wird -b das Objekt, auf das zugriffen wird
Danach folgen optional das Attribut und die Zugriffsart auf das Attribut. slapacl bietet noch eine Menge weiterer Features. So können per –o weitere Optionen mit auf den Weg gegeben werden, wie z.B. der ssf für den gewünschten Zugriff. Weiterführende Informationen hierzu liefert uns slapacl(8). Wie schon eingangs dieses Abschnitts erwähnt, können ACLs nahezu endlos aufgebohrt werden, anhand der hier aufgezeigten Grundlagen sollte nun auch klar sein, warum. Am Ende unseres kleinen Exkurses in die Welt der ACLs empfehlen wir in jedem Fall einen ergänzenden Blick in man 5 slapd.access, die LDAP-FAQ-O-Matic über Access Controls unter www.openldap.org, und natürlich den OpenLDAP Admin Guide. Sodele, genug kontrolliert fürs Erste. Jetzt machen wir mal ganz was anderes, und schauen, was der kleine Stubentiger im slapd-Domizil so treibt ...
3.8
Larry und die schläfrigen Katzen
ACID – Atomicity, Consistency, Isolation, Durability: Sicherheitsstandards für Datenbanken mit Transaktionskontrolle. (Können im Fehlerfall heftige psychotische Reaktionen des Administrators hervorrufen.) ACID – Umgangssprachliche Abkürzung für die Droge LSD. (Kann auch ohne Datenbank-Fehlfunktion heftige, psychotische Reaktionen hervorrufen.)
321
3.8
1198.book Seite 322 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Wenn es ein Business gibt, in dem kein Stein auf dem anderen bleibt, zumindest über einen längeren Zeitraum, dann wohl in unserem guten und gar nicht so alten IT-Biz. Nur eins ist hier immer sicher: Dass rein gar nichts sicher ist. Fusion hier, Konkurs dort, Übernahme in freundlicher und anderer Manier gibt’s hier alle naselang. Und das ist beileibe nicht nur Billyboys Fenstertruppe aus Redmond. Nein, auch der gute alte Larry Ellison (falls der Name aus dem Intro des Buches nicht mehr geläufig sein sollte: der CEO von Oracle) zieht sich allzeit neue Fische in sein dickes Datenbank-Boot. Und manchmal hängt auch eine Katze am Haken. Katze? Yepp. Denn wenn die Vergangenheit eins ziemlich klar bewiesen hat, dann vor allem das: Früher oder später landet nahezu jedes gute (OpenSource-)Konzept in den Händen irgendeines Software-Magnaten. Die Frage unter dem Strich bleibt immer nur die, wie lange die Source anschließend noch Open bleibt. Und vielleicht noch, wie gut sie unter ihrem neuen Schirmherr gepflegt wird. Wollen wir einfach mal das Beste für unseren (nur dem Namen nach »schläfrigen«) Stubentiger Berkeley DB hoffen. Kleine Haustierkunde Das Open-Source-Projekt der Berkeley Database (oft auch nur als bdb oder BDB bekannt, nicht zu verwechseln mit dem bdb-Backend) befindet sich seit März 2006 nicht mehr in der Hand der Entwicklergruppe Sleeypcat3 Software Inc., weil das Unternehmen kurzerhand von Larry Ellisons Oracle geschluckt wurde. Zumindest zum Zeitpunkt der Erstellung dieses Buches vertreibt Oracle die bdb weiterhin mit der gleichen dualen Lizenz (Open-Source/kommerziell), so wie zuvor die schläfrigen Katzen; wie bereits gesagt – wollen wir hoffen, dass es so bleibt. Denn unser Gespann slapd ↔ bdb ist performancetechnisch allen anderen Verzeichnisdiensten um etliche Längen voraus, wie bereits in der Einleitung kurz erwähnt. Ein paar harte Zahlen und Fakten, die MS, Novell (und vielleicht auch ein oder zwei Leuten von Oracle) die Tränen in die Augen steigen lassen, liefern wir am Ende dieses Abschnitts. Storage Engine vs. RDBMS OpenLDAP setzt seit vielen Jahren auf die Berkeley Database als storage engine und das aus guten Gründen, die wir gleich ausführlich erörtern werden. Zuvor aber kurz zu einer anderen Frage, die an dieser Stelle gerne mal aufkommt: Warum verwendet man OpenLDAP nicht mit einem anderen Backend, wie zum Beispiel SQL, also einem relationalen Datenbank-Managementsystem (RDBMs)? 3 engl. schläfrige Katze
322
1198.book Seite 323 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Die Antwort ist einfach: Machbar, aber (und dieses »aber« ist mächtig groß) in einer tabellenbasierten, normalisierten Datenstruktur wie z.B. SQL führt der Umgang mit Objektattributen zu inakzeptabel aufwändigen Suchmanövern und/ oder einer inakzeptabel aufgeblähten Datenbank. Der Grund – stark vereinfacht erläutert – liegt darin, das die Datenmodelle und strukturen vollkommen unterschiedlich aufgebaut sind. Um LDAP-Daten über ein RDBMs abbilden zu können, müssen die Daten/Objekte in der Regel in unterschiedlichen Tabellen strukturiert werden. Jede Normalisierung eines MultiValued-Attributs (Attribut, das das mehrfache Setzen seines Wertes zulässt, z.B. access) würde wiederum eine neue Tabelle erfordern. Jede Suchoperation müsste nun beim Zugriff auf ein Objekt, das Multi-Valued-Attribute enthält, mehrere Tabellen öffnen. Letztlich resultiert daraus immer eine im Gegensatz zur bdb eher niedliche Performance. Dennoch bietet OpenLDAP seit Version 2.0 back-sql als Option an – allerdings mit vielen Einschränkungen. Im Grunde ist back-sql nur dazu geeignet, LDAP-artige Abfragen an eine relationale Datenbasis zu stellen. Wer in der Praxis performant arbeiten will, sollte daher eher keinen Gedanken an eine Datenbank in der Datenbank verschwenden. Eine neue Richtung könnte das ndb-BackendProjekt für SQL-Cluster aufzeigen, das vom theoretischen Konzept als Prozess auf jedem der SQL-Cluster-Nodes arbeiten soll. Der konzeptionelle Kern in Howard Chus Entwurf soll dabei den dicksten Schwachpunkt (fetch multiple Tables per Object) gegenüber einem »normalen«, monolithischen SQL-Backend umgehen, in dem das ndb-API – vereinfacht ausgedrückt – die sequentiellen Single-TableOperations pro Objekt zusammenfasst und parallel auf den SQL-Cluster loslässt, wodurch sich die Performance im Gegensatz zum Standalone-SQL-Backend deutlich verbessern sollte. Warten wir’s ab.
3.8.1
Die »Was«-Frage
Was ist die Berkeley DB? Nun, die Berkeley-DB ist kein Fertigprodukt, das out of the box als Datenbank funktioniert wie z.B. MySQL, das wissen wir bereits. Vielmehr verwenden ältere MySQL-Versionen die bdb sogar als storage engine. Die bdb kommt als Sammlung von Funktionsbibliotheken daher und soll dem Anwendungsprogrammierer Mittel an die Hand geben, Datenbankfunktionalität in seine Software zu integrieren. So ist der Einsatz der bdb für den zugreifenden Client letztlich völlig transparent, der externe Request kann »von außen« nicht ermitteln, ob unser slapd mit bdb-, hdb- oder einem sql-Backend betrieben wird. Auch hier bitte wieder beachten, dass es sich bei dem Backend »nur« um die Schnittstelle zur unterliegenden Datenbank handelt, nicht um die Datenbank selbst.
323
3.8
1198.book Seite 324 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Ein Vorteil von eingebetteten Datenbanksystemen liegt unter anderem darin, dass der Softwareentwickler eine für die spezielle Anwendung (slapd) ausgerichtete Anpassung vornehmen kann (hdb/bdb-backends ...), die über die Möglichkeiten der normalen Administration und Beschleunigung hinausgeht. Dadurch unterliegen Programme – wie unser slapd –, die die Berkeley DB als Datenspeicher verwenden, keinerlei Einschränkungen, in welcher Weise die Daten in einem Datensatz abgelegt werden. Ein Datensatz und sein zugehöriger Schlüssel kann bis zu vier Gigabyte groß sein. Eine Tabelle kann bis zu 256 Terabyte Speicher belegen. Die bdb benutzt denselben Adressraum, den auch die Anwendung verwendet, in die die Datenbank eingebettet ist. Das bedeutet einen Performance-Vorteil gegenüber serverbasierten Lösungen, die die angeforderten Daten vom permanenten Speichermedium erst in den eigenen Arbeitsspeicher lesen und dann an den Adressraum der Anwendung übergeben müssen. Außerdem ist der ausführbare Maschinencode der bdb kleiner als 500 KB, was den Einsatz auf beschränkten Rechnersystemen erleichtert. Wer seine Daten per OpenLDAP zentralisiert verwaltet, der will vor allem eines: relevante Daten schnell und vor allem sicher speichern. Hier findet sich schon das nächste Argument für die bdb: Sie ist vollständig ACID-konform (oder AKID, als deutsches Akronym). Das hat (in der Regel) nix mit 70er-Jahre-Drogen zu tun, sondern definiert die Standards für akzeptable Datenbanksysteme wie folgt: Atomarität Von einer atomaren Operation spricht man, wenn die Transaktion entweder ganz oder gar nicht ausgeführt wird. Die bdb verhält sich gegenüber dem Benutzer so, als ob die Transaktion eine einzelne elementare Operation wäre, die nicht von anderen Operationen unterbrochen werden kann. In der Praxis werden die einzelnen Datenbankanweisungen, aus der sich die Transaktion zusammensetzt, natürlich nacheinander ausgeführt. Wenn sich jedoch herausstellt, dass die Transaktion nicht abgeschlossen werden kann, wird ein Rollback durchgeführt, also alles bisher Erledigte wieder rückgängig gemacht. Konsistenz Oder im englischen Consistence (deswegen der Unterschied im Akronym); bedeutet, dass eine Transaktion nach Beendigung einen konsistenten Datenzustand hinterlässt, falls die Datenbank vor der Transaktion auch konsistent war. Isolation Die technische Realisation von Isolation gewährleistet, dass sich in Ausführung befindliche Transaktionen nicht gegenseitig beinflussen. Das wird erreicht durch die strikte Abarbeitung von Zeitstempeln und Sperrprotokollen.
324
1198.book Seite 325 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Dauerhafigkeit Jede vollständig ausgeführte Operation auf die Datenbank ist dauerhaft. Sie bleibt auch nach Systemabstürzen auf dem Speichermedium erhalten.
3.8.2
Kommen wir zum »Wie«
Die bdb kennt vier Verfahren, Daten zu organisieren und abzuspeichern. Als da wären: Queue, Record Numbers, Hashtabellen und das B-Tree-Verfahren. Queue Die Queue-Zugriffsmethode speichert Datensätze mit fester Länge und logischen Record Numbers als Schlüssel. Das Queue-Verfahren ist darauf ausgelegt, Datensätze schnell an das Ende der queue anzufügen; es kann mit einer array_shift-artigen Operation Datensätze vom Kopf der queue löschen und den gelöschten Datensatz als Rückgabewert übergeben. Queue Access verwendet record level locking als Sperrmethode. Record Number Bietet zusätzlich die Wahl zwischen festen und variablen Datensatzlängen, wahlweise unterstützt von einer einfachen ASCII-Textdatei. Hashtabellen Die Datenstruktur der bdb-eigenen Hashtabellen ist eine Implementation des Extended-Linear-Hashing-Verfahrens. Es ist besonders geeignet für extrem große Datenobjekte. Das B-Tree-Verfahren Das B-Tree-Verfahren verwendet eine sortierte, ausgewogene Baumstruktur. Such-, Einfüge- und Löschoperationen werden in berechenbarer Zeit bearbeitet ( O[log base_b N] ). Die bdb hat die Arbeit mit B-Tree-Datenbanken optimiert, so dass es viel kompakter und effizienter funktioniert als bei anderen Anbietern.
Baum in der Datenbank? Hat’s geklingelt bei dem Wort Baumstruktur? Richtig. OpenLDAP bevorzugt BTree-basierte Datenbanken, um den DIT zu speichern. Denn B-Trees sehen fast genau so aus wie der LDAP-DIT. Das sehen wir uns mal näher an. Wikipedia sagt hierzu: Ein B-Tree (B-Baum) ist ein immer vollständig balancierter Baum, der Daten sortiert nach Schlüsseln speichert. Das Einfügen, Suchen und Löschen von Daten in BBäumen ist in amortisiert logarithmischer Zeit möglich. B-Bäume wachsen und schrumpfen anders als die meisten Suchbäume von den Blättern hin zur Wurzel.
325
3.8
1198.book Seite 326 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Vollständig balanciert soll sagen, dass unser Baum »in der Höhe« nur im Rahmen einer logarithmischen Formel wächst, und nicht linear. Würde der Baum linear wachsen, würden seine Zugriffszeiten ebenfalls linear mitwachsen. Es sollte auf der Hand liegen, dass das niemand wirklich braucht, insbesondere nicht bei Suchoperationen in wirklich großen Bäumen. Die der Arbeitsweise von B-Trees zugrunde liegende Mathematik kann der Interessierte im Web leicht finden, sie würde allerdings den Rahmen dieses Abschnitts ein klein wenig sprengen. Entscheidend ist jedenfalls, dass ein B-Tree intern die gleiche Knotenstruktur abbildet, die wir vom DIT kennen: 왘 Jeder Knoten kann in mehrere gleichgewichtige Kindknoten verzweigen. 왘 Zu jedem Blatt führt eine eindeutige Adressbeschreibung. 왘 Auf dem B-Tree können die Operationen Suchen, Löschen, Einfügen, Verschieben und Verschmelzen ausgeführt werden. Das führt uns also dazu, die Berkeley DB mit unserem slapd zu verwenden. Bevor wir mit den technischen Details loslegen, noch ein kurzes Wort zum hdbBackend. Wir wissen, dass es schon seit geraumer Zeit neben dem bdb-Backend eine weitere Backend-Variante namens hdb existiert. Aber: Wat is denn jenau sonne »hdb-backend«? Das hdb ist, ebenso wie das bdb-Backend, ein Modifikator für den Zugriff unserer Applikation (also slapd) auf die eigentliche Berkeley DB, ebenfalls vom OpenLDAP-Team speziell auf die Verwendung mit slapd angepasst. Allerdings arbeitet das hdb-Backend mit einer zwingend hierarchischen Datenstruktur; daher das »h«( = hierarchical). Das ermöglicht es zum einen, mit der subtree rename-Operation Teildatenbäume zu bewegen (mit der gesamten daran hängenden Datenbasis). Das gehört zu den Grundforderungen der LDAPv3-Definitionen und wird von den meisten anderen Verzeichnisdiensten nicht unterstützt oder angeboten. Ein weiterer Vorteil der streng hierarchischen Struktur des hdb-Backends ist ein entschieden schnellerer Schreibzugriff auf die Datenbank: eine Tatsache, die sich auf Verzeichnisse mit häufigen Änderungen sehr positiv auswirkt. Die hdb kann weiterhin sehr viel effizienter mit Indexen umgehen, benötigt dabei aber einen großzügig dimensionierten Indexcache, der in der Regel etwa dreimal so groß dimensioniert sein sollte wie die objektbezogene cachesize-Direktive unseres slapd. Später mehr dazu in den Konfigurationsbeschreibungen (Punkt idlcachesize., siehe auch slapd-hdb(8)).
326
1198.book Seite 327 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
The Right Stuff – die richtige bdb-Version Machen wir es kurz und knapp – hier hat sich in den letzten Monaten einiges getan. Mitte 2008 äußerten sich Howard Chu und sein Team noch wie folgt zu den jeweiligen BDB-Versionen: BDB 4.2.52 hat sich in den vergangenen Jahren, bezogen auf Stabilität am längsten bewährt; Version 4.3 war ein völliges Desaster, 4.4, 4.5 und 4.6 waren absolut okay, wobei Letztere etliche nützliche Verbesserungen mit sich brachte, vor allem im Speichermanagement. BDB Version 4.7 wurde zu diesem Zeitpunkt von OpenLDAP noch nicht unterstützt, jedoch zeichnete sich dort bereits ab, dass 4.7 in der näheren Zukunft die BDB-Version der Wahl sein würde, nicht zuletzt durch ein noch weiter verbessertes Speichermanagement und einen stabileren Lock-Manager, vor allem bezogen auf den Einsatz in Multi-Core-Systemen. Und, ja ... die gute, alte, gepatchte 4.2.52: Lange im Dienst, treu und zuverlässig. Aber irgendwann treten auch die bewährtesten Kämpen vom Feld, und machen Platz für eine neue Generation: OpenLDAP 2.4.12 (Release am 12.10.2008) benötigt nun mindestens eine BDB der Version 4.4 (siehe hierzu auch unbedingt http://www.openldap.org/doc/admin24/ appendix-recommended-versions.html). Hinzu kommt, dass OpenLDAP 2.4.12 die BDB in Version 4.7 nun auch offiziell unterstützt. Zudem wird von den LDAP Guys noch einmal explizit darauf hingewiesen, dass die Oracle-Patches für die jeweils verwendete Version auf dem aktuellsten Stand sein sollten. Wer OpenLDAP 2.4 bereits in einer älteren Version einsetzt und einen Umstieg auf 2.4.12 plant, muss seine DB daher zwangsläufig auf den aktuellen Stand der Mindestanforderung bringen. Wer bereits eine BDB der Version 4.4 oder neuer einsetzt, aber eine OpenLDAP-Version < 2.4.12, sollte seinen DIT im Zuge eines Upgrades per slapcat/slapadd neu einlesen, da auch neue Matching Rules Einzug in OpenLDAP 2.4.12 genommen haben.
Eine Sache sollte nun glasklar auf der Hand liegen: Hier gilt keinesfalls: »Das Allerneueste ist immer das Beste, und Upgrades sind doch voll geil«. Hier gilt in der Regel: Etwas älter = stabiler = besser (dicke Ausnahme in der Vergangenheit: BDB 4.3). Selbst auf neuen OpenLDAP-Systemen kann eine nicht mehr ganz brandaktuelle BDB 4.5 durchaus klaglos ihren Dienst versehen, wie im konkreten Fall OSS11. Auf den meisten aktuellen Systemen werden in der Regel BDB-Versionen verwendet, bei denen die Distributoren auf die vorgeschrieben Kompatibilität zu OpenLDAP achten. Insgesamt gilt in Verbindung mit OpenLDAP eine einfache Regel: Keinesfalls die neueste, gerade vom Stapel gelaufene bdb-Variante, und auf das achten, was die Entwickler zu den Versionen sagen. Denn schließlich muss das verwendete bdb/hdb-Backend immer mit der eingesetzten BDB-Version auch harmonieren, bzw. für sie angepasst sein, sonst kann die Upgrade-Featureritis ganz schnell nach hinten losgehen.
327
3.8
1198.book Seite 328 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
3.8.3
Und nun zum »Warum«
Wie wir bereits zeigten, liegt die Besonderheit der bdb darin, dass sie für den Client völlig transparent arbeitet. Man sollte also annehmen, dass jedes Wissen über die Funktionsprinzipien rein theoretisch ist, weil die entscheidende Kontrolle über die Datenbank vom einbettenden Mutterprogramm, also in unserem Falle dem slapd, ausgeht. Aber es gibt einige Werkzeuge, die zusammen mit den bdbBibliotheken geliefert werden und eine Reihe von Kontroll-, Sicherungs- und Optimierungsoperationen auf die Datenbank erlauben – jenseits des ausführenden Programms. Denen wenden wir uns nun zu, allerdings nicht ohne schon hier darauf hinzuweisen, dass Eingriffe auf eine Embedded Database, während das einbettende System (slapd) läuft, vorsichtig formuliert, nicht ohne Risiken ist. Genau genommen riskieren wir die Konsistenz unserer Datenbank, wenn wir bei laufendem slapd einige der zur Verfügung stehenden Operationen benutzen wollen. Das Beste, was wir hier tun können, ist, diese Tools so zu verwenden wie die slap-Tools: Die vom Typ »Pfoten weg« am Besten gar nicht, und die anderen – wenn notwendig – niemals bei laufendem slapd. Die Tools finden sich meistens in einem separaten Paket, üblicherweise unter dem Namen db_utils oder einer ähnlichen Bezeichnung. Die distributionsspezifischen Päckchen zu den von uns eingesetzten Versionen finden sich natürlich im Anhang. Berkeley DB Tools Anwendung
Beschreibung
berkeley_db_svc
Serversteuerung (Nie bei aktivem slapd, besser: Pfoten weg!)
db_archive
Archivierungsinformationen
db_checkpoint
Transaktions- und Logüberwachung (Pfoten weg – wird über slapd initiiert.)
db_codegen
Anwendungscode generieren (Brauchen wir nicht.)
db_deadlock
tote Locks finden (Nur in Notfällen bei stehendem slapd.)
db_dump**
Datenbankdump (Nur in Notfällen bei stehendem slapd. Diese Daten niemals per db_load (siehe unten) wieder einlesen – das kann bei unserem slapd zu einer inkonsistenten Datenbank führen!)
db_hotbackup
Schnappschuss-Utility (Nur mit Vorsicht bei aktivem slapd!)
db_load**
Lädt Datensätze von der Konsole (In Verbindung mit unserem slapd: Pfoten weg! Stattdessen immer slapcat/slapadd, andernfalls Gefahr einer inkonsistenten DB!)
db_printlog
Debug-Hilfe, gibt Logs in lesbarer Form aus
db_recover
Wiederherstellung nach System- oder Anwendungscrash
db_stat
Statistische Auswertung der db
328
1198.book Seite 329 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Anwendung
Beschreibung
db_upgrade**
Führt ein Upgrade auf eine neue bdb-Version durch (Pfoten weg! Keinesfalls in Verbindung mit OpenLDAP!**)
db_verify
Datenbanküberprüfung
** Sollte ein Upgrade der bdb erforderlich sein – und die bdb versionstechnisch genehmigt sein – gilt hier die übliche Standardprozedur: per slapcat offline ein LDIF-Backup der bdb erstellen (oder alternativ von einer aktiven, jedoch Readonly-geflaggten DB). Dann mit dem LDIF-Backup per slapadd die bdb nach dem Upgrade neu befüllen. Zusätzlich haben wir das LDIF als Backup im Fehlerfall. db_upgrade und db_load sollten in Verbindung mit slapd niemals(!) verwendet werden. Sehen wir uns nun die Tools etwas genauer an. berkeley_db_svc sendet remote procedure calls (RPCs) an den laufenden Dienst. Damit kann man der Liste der gültigen Datenbank-Home-Verzeichnisse weitere Home-Pfade hinzufügen, die Idle-Time für Datenbankaufrufe des Clients einstellen (Standard ist 24 Stunden) oder mit dem Schalter -V anzeigen lassen, welche Bibliotheksversion gerade verwendet wird. Dieses Tool ist für LDAP-Zwecke tabu! db_archive gibt die Pfadnamen zu nicht länger benutzten Logfiles an der Konsole aus, jeweils einen Pfad pro Zeile. Die Ausgabe kann selbstverständlich in eine Datei umgeleitet werden. Archivierte Logfiles sind eine wesentliche Hilfe, wenn es zu Datencrashs kommt und wir unsere Datenbank gegebenenfalls manuell wiederherstellen müssen. Mit dem Schalter -d werden aber alle unbenutzten Logs gelöscht. Das kann eine Wiederherstellung verhindern. Vorsicht! db_checkpoint schreibt Prüfpunkte in die Datenbank. Wichtig sind die Optionen –k, bei der ein Prüfpunkt gesetzt wird, wenn Kilobyte Daten geschrieben wurden, und die Option –p, die einen Prüfpunkt alle <m> Minuten setzt. Auch hier gilt: Pfoten weg! Wir können das Setzen von Checkpoints via slapd.conf oder als olc-Direktive einstellen. db_codegen generiert aus einer existierenden Datenbank Anwendungscode – zur Zeit nur in C. Der generierte Code muss zwar meist angepasst werden, kann aber die Entwicklungszeit für eigene Anwendungen, die mit dieser Datenbank arbeiten sollen, deutlich verkürzen. Brauchen wir bei OpenLDAP nicht. db_deadlock überprüft die Datenbank auf Sperrvermerke, die »tot« oder »timed out« sind. Es wird empfohlen, dieses Programm als Daemon zu starten, wenn es mehrere Anwendungen mit Schreibrechten gibt, die auf eine Datenbank zugreifen. Mit dem Schalter -t wird alle n Sekunden nach Anforderungen gesucht, die
329
3.8
1198.book Seite 330 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
auf eine Sperrfreigabe warten und, falls ein toter oder abgelaufener Sperrvermerk existiert, diesen aufhebt. db_dump schreibt eine Datenbank als Flat-Text-Datei auf die Standardkonsole oder in eine Datei. Das Ausgabeformat ist dabei so, dass es von db_load verstanden wird. Letzteres sollte jedoch keinesfalls in Verbindung mit unserem slapd eingesetzt werden! db_dump kann beim Debuggen hilfreich sein. Dafür existiert der Schalter -d mit den Optionen a,h, und r. Hier liefert a einen vollständigen Dump, h gibt nur die Page Header aus, und r unterdrückt die Ausgabe der freelist oder der damit verbundenen Seiten. db_hotbackup erzeugt einen Snapshot (Momentaufnahme) der laufenden Datenbank. Laufende Transaktionen im Status »prepared« werden nicht verarbeitet. Kann bei aktivem slapd zu Datenverlusten führen. db_load liest aus der Datei, die wir mit -f angeben. Es erwartet eine einfache Textdatei, die der Formatierung durch db_dump genügt, und stellt die Datenbank aus dem Dump wieder her. (ACHTUNG: Niemals in Verbindung mit unserem slapd verwenden! Für Backup/Restore stehen uns slapcat und slapadd zur Verfügung.) Über -h kann der Pfad angegeben werden, indem die Datenbank erzeugt wird. Falls die Datenbank existiert, wird mit db_load ein Update dieser Datenbank durchgeführt – auch im laufenden Betrieb(!). Mit dem Schalter -t können wir auf diese Weise eine Hash-basierte Datenbank in eine B-Tree-Datenbank umwandeln und umgekehrt. Dasselbe gilt für die Formate queue und record number. Noch einmal: ACHTUNG! Nie! Nie! Nie in Verbindung mit unserem slapd! Die Daten sind danach für unseren slapd mit sehr großer Sicherheit nicht mehr verwertbar. Im laufenden System riskieren wir sogar den sofortigen Crash unserer Datenbank! db_printlog gibt die bdb-Transaktionslogs in einer »menschenlesbaren« Form aus. Nur für Debugging-Zwecke bei stehendem slapd. db_recover stellt die Konsistenz der Datenbank wieder her nach einem Applikations-, bdb- oder Systemzusammenbruch. Alle komplett übermittelten Transaktionen werden wiederhergestellt und eingefügt, alle unvollständigen Operationen werden verworfen. db_stat wertet die gesamte bdb-Datenbankumgebung statistisch aus und hilft uns damit erheblich weiter, die Performance unserer Datenbank zu analysieren und verbessern: 왘 -C wertet das Locking-System detailliert aus, der Schalter -a gibt alle verfügbaren Informationen aus; -c zeigt die Tabelle der Sperrkonflikte. 왘 -d zeigt die Datenbankstatistik des angegebenen DB-Files.
330
1198.book Seite 331 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
왘 -E beschreibt detailliert die Datenbankumgebung. 왘 -l wertet das Logsystem aus. 왘 -M zeigt detaillierte Informationen über den Cache. 왘 -A liefert die komplette Statistik der Datenbank samt aller Subsysteme. Im Praxisteil sehen wir gleich, wie db_stat eingesetzt wird. db_upgrade führt ein Upgrade der Datenbanken auf eine aktuelle, installierte Version der bdb durch. Und wieder: Niemals mit slapd/OpenLDAP zusammen verwenden (siehe Anmerkung** im letzten Abschnitt). db_verify führt eine Überprüfung einer oder mehrerer Datenbankfiles samt aller enthaltenen Datenbanken durch. Das war eine – natürlich unvollständige – Aufzählung aller möglichen Schalter und Optionen der db-Tools. Wer tiefer in den db-Werkzeugkasten schauen will, sollte einen Blick auf http://www.oracle.com/technology/documentation/berkeley-db/db/utility/ index.html werfen. Aber jetzt wird’s endlich wieder Zeit für die Praxis. Also: Werkzeug rausgeholt, die Motorhaube aufgemacht, und los geht’s: Der Blick unter die Haube Würden wir die LDAP-Systematik anhand eines Beispiels aus dem realen Leben – nein, nicht das vor dem Bildschirm, sondern das vor der Haustür – vergleichen, so könnte man am ehesten folgende Analogie aufstellen: Würden wir annehmen, unser LDAP wäre der Projektmanager eines großen Unternehmens, der sich um Einstellungen, Entlassungen, Änderungen und Transaktionen mit anderen Zweigstellen kümmert, dann wäre die Berkeley-Database seine Verwaltungs-Personalabteilung, in der alle Daten des Unternehmens gespeichert wären. Nehmen wir weiterhin an, diese Personalabteilung wäre optimierbar (okay, ab hier beginnt der Vergleich zum realen Leben zu haken), wäre es doch interessant zu wissen, an welchen Schrauben man drehen müsste, damit man schneller an eine Information kommt (oder an Urlaub, Beförderung – und vor allem an eine höhere Gehaltsklasse). Nun, Gott sei Dank sträubt sich die bdb nicht allzu sehr gegen Optimierung, daher werfen wir nun einen Blick auf die Schrauben, an denen gedreht werden kann. Allerdings können wir im Rahmen dieses Buchs nur einen kleinen Teil der
331
3.8
1198.book Seite 332 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
bdb-Thematik ansprechen, da diese für sich schon ausreichen würde, um ein ganzes Buch zu füllen. Allgemein sollte vor unserer Datenbank-Optimierung sichergestellt sein, dass andere allgemeine Störfaktoren, die sich negativ auf die Performance auswirken, so weit wie möglich beseitigt worden sind. Als da unter anderem wären: 왘 geringer Arbeitsspeicher 왘 langsame Festplatten 왘 mehrere Datenbanken auf einer Festplatte 왘 exzessive Verwendung von regulären Ausdrücken in ACLs 왘 ineffektive Anordnung der ACLs 왘 zu hoher Log-Level, keine eigene syslog-Facility für LDAP 왘 Transaktionslogs bei großen DITs auf der gleichen Disk wie die restlichen dbDateien Der vorletzte Punkt lässt sich am einfachsten und vor allem recht schnell ändern. Zum einen könnte man den Log-Level auf 0 setzen, was aber in der Praxis eher nicht anzuraten wäre. Eine eigene syslog-Facility lässt sich – bei Verwendung des älteren syslogd – durch folgende Zeile in der /etc/syslog.conf erreichen: LOCAL4.* -/var/log/ldap.log
Das »-« vor dem Eintrag sorgt dafür, dass die Einträge erst dann ins Log geschrieben werden, wenn der Rechner »idle«, also für ein paar Taktzyklen mit Däumchendrehen beschäftigt ist. Der syslog-ng, wie er z.B. in der OSS 11 und Debian Lenny verwendet wird, hat eine etwas komplexere Syntax, die etwa so aussehen könnte: filter f_ldap { program("slapd"); }; destination d_ldap { file("/var/log/ldap.log"); }; log { source(src); filter(f_ldap); destination(d_ldap); flags(final); };
Ausführliche Informationen zu beiden syslog-Daemons und ihren Konfigurationsdateien bieten syslogd(8), syslog.conf(5) sowie syslog-ng(8) und syslogng.conf(5).
332
1198.book Seite 333 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Ein paar der wichtigsten Eigenschaften der bdb neben der guten Skalierbarkeit sind: Page Caching Management, Transaction Control and Logging sowie das Locking von Datensätzen. Letzteres bedeutet, dass der so genannte multiple reader/one writer access auf Datensätze sichergestellt wird: Viele dürfen den gleichen Datensatz gleichzeitig lesen, aber nur einer von ihnen darf ihn schreibend bearbeiten (-> Datenkonsistenz). Die Transaktionskontrolle hatten wir bereits im Kapitel »Installation« angesprochen: sie stellt sicher, dass im Falle eines Datenbankfehlers alle fehlerhaften bzw. nicht kompletten Transaktionen entweder rückgängig gemacht oder neu gestartet werden. Dadurch wird ebenfalls die Konsistenz der Daten sichergestellt. Der erste Punkt (Caching) bezeichnet die Eigenschaft der bdb, dass sie Suchergebnisse in einem Cache zwischenspeichert, wodurch sie bei wiederholten Anfragen schneller abgerufen werden können.
3.8.4
Ein Blick aufs Messgerät: Performance-Check
Vorab werfen wir einen kurzen Blick auf die Dateien unterhalb des Datenbankordners /var/lib/ldap und kennzeichnen ihre Funktion. Minimal sollten dort folgende Dateien zu finden sein: __db.001 __db.002 __db.003 __db.004 __db.005 alock dn2id.bdb id2entry.bdb log.0000000001 objectClass.bdb
# # # # # # # # # # #
Datenbankumgebung, Cache etc. s.o. s.o. s.o. s.o. OpenLDAP-spezifisches Locking-File - (db_recover nur noch nach Bedarf) B-Tree Datenbankdatei s.o. Transaktionslog Indexdatei
Bevor wir nun anfangen, an den Einstellungen zu werkeln, sollten wir uns vorab den aktuellen Performance-Status unserer bdb anschauen. Dazu eignet sich das Tool db_stat bzw. db4.x_stat bei Debian (x = Minor Release Nummer), das meist unter /usr/bin zu finden ist und zu den bdb-utils gehört. Mit dem Befehl db_stat -V erhalten wir die eingesetzte bdb-Version; mit dem Befehl #> db_stat –h /var/lib/ldap/ -m
sehen wir die aktuellen Statistiken unserer bdb. In diesem und einigen der folgenden Beispiele haben wir ca. 11.000 Datensätze und eine Default-Cachegröße von 15 MB verwendet (in älteren OpenLDAPInstallationen wurden teilweise nur 265 KB allokiert):
333
3.8
1198.book Seite 334 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
17MB 904KB 436B Total cache size 1 Number of caches 17MB 912KB Pool individual cache size 0 Maximum memory-mapped file size ...
6879439 Requested pages found in the cache (99%) 440 1793 440 ... und
Requested pages not found in the cache Pages created in the cache Pages read into the cache so weiter
Wie wir an der Zeile »Requested Pages found in the Cache« erkennen können, liegt die Trefferquote der aus dem Cache (bei einer Cache-Größe von 15 MB) ausgelesenen Datensätze bzw. Pages (Speicherseiten) bei 99 %. 440 Datensätze mussten direkt von der Festplatte eingelesen werden (»Requested Pages not found in the Cache«). Eindeutiger Bedarf zur Vergrößerung des Cache ist immer dann angebracht, wenn die Anzahl der direkt von der Platte eingelesenen Datensätze (»Pages read into the cache«) im Verhältnis zu den im Cache gefundenen deutlich ansteigt, da jeder Lesevorgang auf der Festplatte natürlich ein Vielfaches der Zeit erfordert, die das Lesen aus dem RAM in Anspruch nimmt. Nur, falls es bis hierher noch nicht aufgefallen sein sollte: Der tatsächliche Cache ist fast 18 MB (»Total Cache Size«) groß, obwohl er mit »nur« 15 MB in der bdbKonfigurationsdatei DB_CONFIG definiert wurde. Keine Zauberei, nur eine kleine Prä-Kognition seitens der Sleepycat – sorry – Oracle-Entwickler. Warum dem so ist, schauen wir uns gleich an. Size does matter – Cachegrößen Klingt gut, aber wie kommen wir an einen praxisorientierten Wert für unsere Cachegröße? Nun, der Datenbank-Cache sollte immer so groß sein, dass er im »normalen« Betrieb mit einer möglichst hohen prozentualen Trefferquote arbeitet (in jedem Fall besser 90 %). Zugleich sollte er trotzdem immer noch etwas in »Reserve« haben, damit ihm in extremen Situationen nicht die Luft ausgeht. Die Entwickler der bdb sagen selbst: Cache ist gut, mehr Cache ist auf jeden Fall besser. Allerdings bietet die Vergrößerung des Cache nur bis zu einer gewissen Größe etwas. Diese Größe ist immer von der jeweiligen Anwendung bzw. der Anzahl der zu verwaltenden Datensätze abhängig und natürlich auch der Größe der einzelnen Objekte (z.B. wenn Zertifikate, Bilder o.ä. mitgeführt werden). Ab einer bestimmten Cachegröße wird jeder Datensatz direkt aus dem Cache gelesen, eine weitere Vergrößerung würde in dem Fall nichts bringen. Es sei denn, die Anzahl der Datensätze nimmt innerhalb kürzester Zeit schlagartig zu, wie z.B. bei einem Import von neuen Kundendatensätzen in erheblichem Ausmaß.
334
1198.book Seite 335 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Ein unnütz großer Cache würde dem System eher an anderer Stelle die Ressourcen entziehen als einen wirklichen zu Vorteil bieten. Und mangelnde Ressourcen könnten wiederum andere Prozesse dazu veranlassen zu swappen, was die Systemperformance – je nach Dienst – wiederum verschlechtern würde. Die bdbEntwickler sagen ebenfalls: Cache-Anpassung ist eine Art Kunst. Nach dem Studium ihrer Dokumentation geben wir ihnen Recht. Und vielleicht ist es nicht nur das, sondern auch gleichzeitig eine Fleißaufgabe, denn eine regelmäßige Überwachung der Cache-Auslastung bringt vor allem in expandierenden Umgebungen in dieser Hinsicht vielleicht am meisten. Denkbar wäre z.B. eine kleine ScriptingLösung, die per cron angestoßen wird und über grep in regelmäßigen Abständen die Ausgabe von db_stat auf einen minimal zulässigen unteren Schwellenwert überwacht. Wird dieser unterschritten (z.B. Cache-Hits kleiner als 90 %), erfolgt eine Warnungs-Mail an den Admin. Die meisten Distributionen haben die Cachegröße mittlerweile von ehemals 264 KB standardmäßig auf nunmehr knapp 18 MB aufgeblasen. Diese Größe ist für deutlich mehr als den üblichen Hausgebrauch ausreichend, was wir schon anhand der Cache-Hits für unsere fast 11.000 Entries erkennen können; die folgenden Betrachtungen werden noch genauer erläutern, warum. Weiter im Text: Die eigentliche bdb-Datenbank liegt in den Dateien dn2id.bdb und id2entry.bdb. Die Daten werden dabei in einem so genannten Balanced-Tree (B-Tree) gespeichert, wie wir bereits aus den Vorbetrachtungen wissen. Relevant für die Berechnung der Cache-Größe ist die Anzahl der Speicherseiten (Pages) innerhalb dieses B-Trees, denn in ihnen sind die eigentlichen Informationen hinterlegt. Dazu müssen wir uns die Statistik der Dateien dn2id.bdb und id2entry.bdb etwas genauer anschauen, und zwar ebenfalls per db_stat: #> db_stat -h /var/lib/ldap/ -d /var/lib/ldap/dn2id.bdb
Die eingefügten Kommentare dienen natürlich nur der Erläuterung und sind nicht Bestandteil der Ausgabe. Die Bezeichnung »Little-Endian« gibt an, dass die Byte-Ordnung in Intel-kompatibler Form vorliegt, »Big-Endian« wäre Motorolakompatibel: Tue Sep 23 15:42:36 2008 Local time 53162 Btree magic number 9 Btree version number Little-endian Byte order duplicates, sorted duplicates Flags 2 Minimum keys per-page 4096 Underlying database page size # Größe der Speicherseite – # abhängig von der Blockgröße des unterliegenden FS 1007 Overflow key/data size 3 Number of levels in the tree 21697 Number of unique keys in the tree
335
3.8
1198.book Seite 336 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
43339 22 72862 478 645972 64 47120 ...
Number of data items in the tree Number of tree internal pages # Anzahl der internen Speicherseiten Number of bytes free in tree internal pages (19% ff) Number of tree leaf pages # Anzahl der leaf-Pages # (Verzweigungen auf Blattobjekte / Speicherseiten) Number of bytes free in tree leaf pages (67% ff) Number of tree duplicate pages Number of bytes free in tree duplicate pages (82% ff)
Das Gleiche erledigen wir für id2entry.bdb: 53162 Btree magic number 9 Btree version number Little-endian Byte order Flags 2 Minimum keys per-page 16384 Underlying database page size # Grösse der Speicherseite (Festwert) 4079 Overflow key/data size 3 Number of levels in the tree 10840 Number of unique keys in the tree 10840 Number of data items in the tree # effektive Anzahl der Objekte 3 Number of tree internal pages # interne Speicherseiten 30884 Number of bytes free in tree internal pages (37% ff) 1009 Number of tree leaf pages # Anzahl der leaf-Pages 2007542 Number of bytes free in tree leaf pages (87% ff) ...
Relevant für unsere spätere Berechnung sind zum einen die Pagesizes (Größe der Speicherseiten) als auch die Pages selbst, sowohl die Internal- als auch die LeafPages (engl. leaf = Blatt). Interessant auch hier die unterschiedliche Größe der Pagesizes: während id2entry 16 KB als fixen Wert für die Pagesize verwendet, hängt der Pagesize-Wert von dn2id immer von der Blockgröße des unterliegenden Dateisystems ab (in der Regel 4 KB auf den meisten Linux-Systemen). Um nun (unter anderem) performance-relevante Einstellungen vorzunehmen, existieren grundsätzlich zwei Möglichkeiten: über die bdb-spezifische Datei DB_ CONFIG oder über die LDAP-spezifischen Settings per slapd.conf (man 5 slapdbdb) oder slapd.d/. Einige der datenbankbezogenen Direktiven können auf beiden Seiten (DB_CONFIG / slapd) über ähnliche Direktiven getroffen werden, wobei Überschneidungen möglich sind. Korrespondierende bzw. ergänzende Einstellungen sollten in beiden Dateien vorgenommen werden (set_cachesize, cachesize). Hierbei sollte stets darauf geachtet werden, dass identische Parameter nicht doppelt gesetzt werden (slapd.conf | slapd.d/ | DB_CONFIG). Falls es doch passiert, haben die Spezifikationen der DB_CONFIG Vorrang.
336
1198.book Seite 337 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
3.8.5
Feintuning
DB_CONFIG Das Verfahren über die bdb-spezifische Konfigurationsdatei DB_CONFIG bietet etwas mehr Optionen, da direkt auf die bdb-Einstellungen Zugriff genommen werden kann. Andererseits existiert auch die Möglichkeit, die Datei DB_CONFIG (sofern nicht vorhanden) über entsprechende slapd-Settings beim Start zu generieren. Wie das funktioniert, erläutern wir im Folgenden. Weiter im Text: Falls noch nicht vorhanden, legen wir eine Datei DB_CONFIG unterhalb des Ordners an, in dem sich unsere eigentliche LDAP-Datenbank befindet, z.B. bei SUSE und Debian /var/lib/ldap. In dieser Datei können etliche datenbankspezifische Einstellungen getroffen werden; eine komplette Auflistung der möglichen Parameter findet sich in der bdb-Dokumentation unter: http://www.oracle.com/technology/documentation/berkeley-db/db/api_c/env_ list.html. In jedem Fall ist im Zusammenhang mit der DB_CONFIG darauf zu achten, dass bei Verwendung von mehreren Datenbanken für jede dieser Datenbanken (unterhalb des jeweiligen Datenbank-Ordners) eine solche Datei existieren muss. Weiterhin müssen wir bedenken, dass in der DB_CONFIG gesetzte Parameter in der slapd-Konfiguration (siehe hierzu man 5 slapd-bdb) getroffene Einstellungen überschreiben! Um nun z.B. den Default-Cachesize zu verändern, könnte die Direktive in der DB_CONFIG wie folgt aussehen: set_cachesize
0
15000000
1
Die erste Zahl (0) gibt die Cache-Größe in GB an, die zweite (15000000) in Byte, die dritte die Anzahl der Caches, in diesem Fall 1. Die Angabe genau eines Cache (ein Wert von 0 oder 1) bedeutet, dass der angegebene Speicherbereich in einem Stück allokiert wird. Jeder Wert > 1 gibt die Anzahl der Stücke an, in die der Gesamt-Cache zerlegt werden kann. Hintergrund: Einige OS (z.B. Solaris) limitieren je nach Version den Speicherbereich, den ein einzelner Prozess für sich beanspruchen darf. Durch das Splitting bietet set_cachesize so eine Alternative. Die Cache-Größe selbst sollte dabei üblicherweise immer als Ergebnis von Exponentialwerten zur Basis 2 angegeben, also z.B. 2^24 = 16777216 KB für =~ 17 MB, um intern keinen Platz zu verschenken. Runde Zahlen tun unserer bdb aber auch nicht weh, falls wir die Exponentialzahl mal – rein zufällig – gerade nicht im Kopf ausrechnen können. In unserem Beispiel haben wir die Default-Settings einer OSS11 mit einer CacheGröße von runden 15 MB verwendet. Wie aber kommt das kleine, nichtsnutzige
337
3.8
1198.book Seite 338 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
db_stat nun dazu, uns einfach fast 18 MB statt der erwarteten 15 anzuzeigen? Dazu eine kurze, aber einleuchtende Erklärung. db_stat arbeitet völlig korrekt. Und die zusätzlichen 25 %? Ganz einfach: Alle angegebenen Cache-Werte kleiner 500 MB werden standardmäßig automatisch von der bdb um rund 25 % erhöht, um Buffer-Overheads mit abzudecken. Werte größer 500 MB werden exakt gemäß den Einstellungen in der DB_CONFIG gesetzt. Die maximale Cachegröße eines einzelnen Cache liegt derzeit bei 4 GB auf 32-Bit-System und bis zu 10 Terabyte (!) auf 64-Bit-Systemen. Die minimale Größe des Cache sollte selbst bei kleinen DITs nie kleiner als 20 KB gewählt werden, aber den Versuch können wir uns für verregnete Herbsttage aufsparen ... Aber: Welche Cachegröße benötigen wir denn nun wirklich? Hierzu existieren genau eine Berechnungsvorschrift (oder besser: Empfehlung) der bdb-Entwickler und einige Pi-mal-Daumen-Regeln, die allesamt mehr oder weniger gut passen. Rein rechnerisch können wir zumindest schon einmal die absolut erforderliche unterste Grenze ziehen, damit unser LDAP überhaupt läuft (wenn auch mehr schlecht als recht). Relevant für die Kalkulation sind, wie zuvor bereits angesprochen, die Pagesize der bdb-Dateien dn2id und id2entry sowie die Anzahl der Internal- und Leaf-Pages. Noch eine kurze Erläuterung zu den Pages. Nach der B-Tree-Terminologie handelt es sich dabei, wie wir mittlerweile wissen, um so genannte Speicherseiten, in denen Informationen gespeichert werden. In den Internal-Pages werden Daten zur Verwaltung des B-Trees gespeichert, in den Leaf-Pages liegen die eigentlichen Daten, als »Ausgangspunkt« existiert immer eine Root-Page. In der internen Baumstruktur werden die Pages über so genannte Nodes (Knoten) miteinander verknüpft. Um nun ein Minimal-Setting für die Cachegröße zu berechnen, beziehen wir dabei nur eine Root-Page, die Anzahl n der Internal-Pages und genau eine Leaf-Page ein. Die Berechnungsvorschrift stellt sich gemäß der vorab getroffenen Definitionen somit wie folgt dar: (1 root Page + n int. Pages dn2id.bdb + 1 leaf Page) x PageSize dn2id.bdb + (1 root Page + n int. Pages id2entry.bdb + 1 leaf Page) x PageSize id2entry.bdb In unserem Fall würden sich: (1+22+1) * 4kb + (1+3+1) * 16 KB = 176 KB ergeben. Dieses Ergebnis stellt in unserem Beispiel für die 11.000 Entries rein rechnerisch die absolut unterste Grenze (ohne jeden Spielraum für Operationen) dar und sollte in der Praxis keine Verwendung finden. Fehler aufgrund Speichermangels könn-
338
1198.book Seite 339 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
ten – trotz der 25 % »Reserve«, siehe oben – dennoch auftreten, die sich dann z.B. durch Abbrüche mit der recht eindeutigen Fehlermeldung äußern können: "txn_aborted! Cannot allocate memory".
(txn=synonym für transaxion =~ Transaction). Aber auch, falls es nicht zu Abbrüchen durch Speichermangel kommt, ist die Performance auf unterstem Niveau. Der Grund dafür liegt in der Anzahl der angegebenen Leaf-Pages, nämlich nur 1. Dadurch muss bei jeder neuen Datenbankanfrage die Root-Page und der komplette B-Tree bis hin zum geforderten Objekt neu eingelesen werden. Um nun im Hinblick auf unser Datensatzaufkommen einen annehmbaren Wert zu berechnen, verwenden wir die Anzahl der tatsächlich vorhandenen LeafPages. Dadurch decken wir alle (zumindest aktuell vorhandenen) Nodes vom Root des B-Trees bis zum angeforderten Objekt ab: (1+22+478) * 4 KB + (1+3+1009) * 16 KB = 18212Kb =~ 18 MB ... womit wir eigentlich schon an der Kapazitätsgrenze unserer Default-Einstellung kratzen. Aber schließlich kann bei heutigen RAM-Größen ein lächerlich kleiner Cache-Wert von 18MB für fast 11.000 Objekte als durchaus sparsam bezeichnet werden. Betrachten wir nun eine andere, sehr einfache Daumenregel, die besagt, dass man die Größe der Dateien dn2id.bdb und id2entry.bdb zusammengefasst als Cache veranschlagen könnte. Schauen wir mal nach: 2314240 Sep 23 15:45 /var/lib/ldap/dn2id.bdb 16596992 Sep 23 15:50 /var/lib/ldap/id2entry.bdb
In unserem Fall würden wir demnach bei 2314240 + 16596992 = 18.911.232 Byte liegen, das entspräche knapp 19 MB. Vergleichen wir den Wert mit dem oben errechneten, stellen wir fest, dass diese »Pi-mal-Daumen«-Regel zumindest als grober Richtwert dienen kann, sogar mit etwas mehr Luft nach oben, die sicher nicht schaden kann. Für unseren Test-DIT mit 11.000 Entries würden wir also mit knapp 24 MB (18 MB + 25 %) für den täglichen Betrieb auf der sicheren Seite liegen – vorausgesetzt, wir erwarten keinen spontanen Zuwachs im oberen, vierstelligen Bereich. Es kursieren noch andere Pi-mal-Daumen-Regeln, eine davon berechnet z.B. den set_cachesize-Wert über die Anzahl der DIT-Einträge, multipliziert mit der Pagesize (dn2id.bdb) + 25 % für Overhead. Bei sehr großen Bäumen (und damit einer entsprechend großen Datenbank) darf natürlich nicht aus den Augen verloren werden, dass der Rest des vorhandenen
339
3.8
1198.book Seite 340 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Arbeitsspeichers (nach Abzug des allokierten Cachesize) immer noch ausreichend für alle anderen Systemdienste sein muss. In dem Fall gibt es nur zwei »kaufbare« Lösungen: mehr RAM kaufen oder schlechtere Performance in Kauf nehmen. Wir werden gleich einige Cache-Größen-Varianten einem kleinen PerformanceTest unterziehen. Vorab aber noch eine wichtige Anmerkung: Bei allen Änderungen am set_cachesize-Parameter für eine bereits existierende Datenbank ist immer zu beachten, dass diese Änderungen auch nach einem LDAP-restart nicht greifen. Um die Änderungen zu übernehmen, benötigen wir eine Reinitialisierung der db-Umgebung per db_recover. Danach ist unbedingt als Erstes ein Neustart des slapd nötig, da die bdb-Umgebung von der ersten Applikation initialisiert wird, die sie aufruft, in unserem Fall also von unserem guten alten slapd. Allerdings betrifft das beschriebene Vorgehen nur bereits bestehende db´s, neue Datenbanken werden gleich mit den angegebenen Parametern angelegt. db_recover dient, wie wir wissen, regulär dazu, die db-Umgebung nach einem inkonsistenten Abschluss (z.B. Systemabsturz) wieder in einen konsistenten Zustand zu bringen. In diesem Kontext verwenden wir es dazu, die Cachegröße auf einen neuen Wert anzupassen. Wichtig: Unser slapd darf nicht aktiviert sein! #> db_recover -h /var/lib/ldap
Kommen wir nun zu unserer Vergleichsmessung. Wir importieren knapp 11.000 Datensätze per slapadd in eine leere Datenbank. Hierbei betrachten wir nicht die Hardware-Ausstattung der Maschine, da wir innerhalb von virtuellen Maschinen arbeiten (P4, 3.0 GHz, mit je 256 MB RAM pro VM). Signifikant ist für uns nur das Verhältnis der Zeitdifferenzen zwischen den Messungen, das schon recht aussagekräftig ist. Nach jedem Durchgang löschen wir die bdb-Dateien, re-initialisieren die neue Cachesize und befüllen die bdb erneut per slapadd. Dabei variieren den set_cachesize-Parameter in der DB_CONFIG wie folgt: Messung Nr.:
set_cachesize (ohne 25 %-Zuschlag):
Zeit für slapadd: (sec.)
1
176 KB (errechnetes Minimum)
60
2
265 KB (alter bdb-Defaultwert)
46
3
0.5 MB
27
4
1 MB
22
340
1198.book Seite 341 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Messung Nr.:
set_cachesize (ohne 25 %-Zuschlag):
Zeit für slapadd: (sec.)
5
8 MB
22
6
15 MB (SUSE-Defaultwert)
22
7
24 MB
22
Was wir unschwer erkennen können: Eine Vergrößerung des set_cachesizeParameters bringt bereits etwa ab der Hälfte der Tests kaum noch bzw. keine erkennbare Verbesserung. Aber(!): Wir müssen dabei auch berücksichtigen, dass diese Art des Zugriffs auf unseren slapd relativ statisch und nicht repräsentativ für den Produktivbetrieb ist, denn wir haben hier genau eine Operation, die n Daten in die Datenbank schreibt. Im realen Umfeld werden n Requests mit m Daten in die Datenbank geschrieben oder aus ihr gelesen. Für genau solche relativ praxisnahen Tests eignet sich slamd, den wir gleich kurz vorstellen. Eine deutliche Tendenz lässt sich dennoch mit diesem Test allemal erkennen. Und da wir ja anhand der Berechnungsvorschriften bereits wissen, was unsere bdb mindestens an Cache haben muss, damit alle Objekte bequem im Cache vorgehalten werden können ... wird alles gut. Eine Universalregel zur Ermittlung von set_cachesize, die für wirklich alle LastSituationen und Hardware-Voraussetzungen einhundertprozentig passt, kann schlichtweg nicht existieren. Daher sollte in der Praxis als Ausgangsbasis die zuvor erläuterte Berechnungsvorschrift bzw. eine Addition der dn2id/id2entryFiles verwendet werden; anschließend kann die getroffene Einstellung mit Tests, z.B. per slamd, verifiziert und gegebenenfalls optimiert werden. Dabei immer im Hinterkopf behalten, welchen Schwankungen – bezogen auf die Anzahl der Objekte im DIT – die bdb möglicherweise im Echtbetrieb unterworfen ist. Exkurs: Under pressure – bdb unter Druck mit slamd Die Tests sollten dabei in einer Umgebung, die den »realen« Einsatzbedingungen möglichst ähnlich ist, stattfinden (multiple und gleichzeitige Lesezugriffe etc.). Da die meisten von uns kaum auf ein echtes Netzwerk mit drei Fantastilliarden, echten Usern verfügen können, die nur darauf warten, ihre ldapsearch/modify/ delete-Befehle auf unser Kommando auf unseren armen slapd loszulassen, bleibt uns »nur« die virtuelle Alternative. Allerdings ist »nur« etwas untertrieben, denn per slamd lassen sich Last-Szenarien recht realitätsnah durchspielen. Aber zunächst: Wat isn slamd? Nehmen wir doch am besten Sun’s Erklärung dazu, denn die haben das Ding schließlich ursprünglich auf den Weg gebracht: Die SLAMD Distributed Load Generation Engine (SLAMD) ist eine JavaTMAnwendung, die dazu entwickelt wurde, die Leistung von netzwerkbasierten
341
3.8
1198.book Seite 342 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Anwendungen zu testen und zu analysieren. Sie wurde ursprünglich von Sun Microsystems, Inc., entwickelt, um die Leistung von LDAP-Verzeichnisservern zu testen und zu analysieren. SLAMD steht unter der Sun Public License, einer von OSI genehmigten Open Source-Lizenz, als Open Source-Anwendung zur Verfügung. Weitere Informationen über SLAMD finden Sie unter http://www.slamd.com/. SLAMD steht auch als java.net-Projekt zur Verfügung. Siehe https:// slamd.dev.java.net/. Im Klartext: slamd existiert zum Zeitpunkt der Bucherstellung in der stabilen Version 1.8.2 (2.x ist als Alpha verfügbar) und läuft als Java-Applikation auf jeder Plattform, die Java-Unterstützung (mindestens 1.4.0) bietet. slamd setzt unseren slapd (oder bei Bedarf auch andere Protokoll-orientierte Server wie z.B. http, smtp usw.) unter Druck (Last), indem er eine Vielzahl von Client-Abfragen gegen den Server laufen lässt. Festgelegt werden können dabei unter anderem die Laufzeit des Tests, die Anzahl der konkurrierenden Client-Requests und vieles andere mehr. slamd benötigt dazu einen – idealerweise separaten – LDAP-Server, der V3 spricht (wie unser slapd), in dem er seine Job-Daten und Konfiguration speichern kann; über diesen werden auch die slamd-Clients koordiniert. Die Administration erfolgt komplett über ein webbasiertes Frontend, das intern auf einen Tomcat-Server zurückgreift. Benötigt werden in der Regel 3-Komponenten: der eigentliche slamd-Server (Konfiguration, Koordination), der slamd-Client (der auf der oder den Client-Maschinen installiert wird, die die Last für den Ziel-LDAP generieren) und eine Monitor-Applikation zur Auswertung der Testergebnisse. Die stark vereinfachte Funktionsweise: Der slamd-Server koordiniert die slamdClients, welche wiederum die eigentlichen Requests an den Ziel-LDAP senden. Für eine möglichst »echte« Lastverteilung sollten in der Regel mehrere slamd-Clients konfiguriert werden. Alle slamd-Komponenten können auf Linux-, Unix- oder Windows-Maschinen (Letztere mit Einschränkungen, Stichwort client-manager im Admin Guide, siehe unten) installiert werden, in den entpackten slamd-Ordnern finden sich Startskripte für die jeweilige Plattform (.bat/.sh), die gegebenenfalls vorab noch etwas angepasst werden müssen, z.B die JRE-Pfade. Der Client besitzt neben den Startskripten zusätzlich eine Klartext-Konfigurationsdatei (.conf), in der u.a. die relevanten Parameter zu Kommunikation mit seinem slamd-Server eingepflegt werden (damit das ganze Konstrukt funktioniert, müssen die slamd-Clients problemlos mit dem slamd-Server kommunizieren können); Gleiches gilt für die Konfiguration des Monitoring-Clients.
342
1198.book Seite 343 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Alle konfigurierbaren Direktiven sind im slamd-Admin-Guide (siehe unten) sehr ausführlich erläutert. Das Setup würde unseren Rahmen leider komplett sprengen, aber unter http://www.slamd.com/documentation.shtml findet sich umfangreiche Dokumentationen zum Thema (u.a. Quick-Start-Guide, Admin-Guide, LDIF Usage Guide, Job Reference Guide, und vieles mehr), die das Setup von Anfang an Step-by-Step erläutern. Neben einer FAQ befinden sich dort auch Screenshots, die vorab einen Eindruck der Usability vermitteln. Aber ganz ohne Zahlen wollen wir unseren Exkurs natürlich nicht stehen lassen – am Ende dieses Abschnitts schauen wir uns per slamd generierte Vergleichsmessungen an; an der Startlinie: ADS und OpenLDAP. Wer da wohl die Nase vorn hat? Zurück zur DB_CONFIG und cachesize: Weitere Infos hierzu finden sich in der bdb-Dokumentation unter: http://www.oracle.com/technology/documentation/berkeley-db/db/ref/toc.html Ebenfalls kann ein Blick auf http://www.oracle.com/technology/documentation/berkeley-db/db/ref/transapp/ tune.html durchaus nützlich sein. Allerdings spielt set_cachesize performancetechnisch nicht die Solo-Geige. Noch eine Reihe weiterer Parameter sind entscheidend für die Gesamtperformance der Datenbank im laufenden Betrieb, wenn auch nicht ganz so extrem wie set_cachesize. So z.B. auch die korrespondierenden slapd-Parameter cachesize, idlcachesize und vor allem index, die wir in einem späteren Abschnitt dieses Kapitels (über die bdb-relevanten Direktiven unsers slapd) noch aufgreifen werden. Wichtig dabei ist vor allem auch, das Zusammenspiel der Konfigurationsdirektiven unter- bzw. miteinander nicht aus den Augen zu verlieren. Weitere Beispieldirektiven für die DB_CONFIG könnten wie folgt aussehen: set_lg_max
verändert die Dateigröße des Transaktionslogs (Standard 10 MB). Da aber gerade das Transaktionslog eine besonders performanceträchtige Rolle spielt, sollte im Zweifelsfall der Originalwert belassen werden (zu groß dimensioniert: langsamer beim Öffnen und Schreiben; zu klein: zu viele Rotationen). Apropos: Um die Rotation der log.*-Dateien kümmert sich die bdb beim Erreichen der Maximal-
343
3.8
1198.book Seite 344 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
größe selbst. Und per Flag DB_LOG_AUTOREMOVE (siehe unten) auch um die Entsorgung der veralteten Logs. Alternativ kann die Datei aus Performancegründen (große DITs) auch auf einen komplett separaten Datenträger ausgelagert werden. Das geht über: set_lg_dir
In Verbindung mit dem Transaktionslog existieren weitere, interessante Parameter: set_lg_regionmax # Filename – Cache set_lg_bsize # Buffergröße, ab welcher der Log-Cache # auf die Platte geschrieben wird set_flags # Diverse Flags, die gesetzt werden # können, wie z.B. DB_LOG_AUTOREMOVE oder # DB_TXN_NOSYNC (*)
(*) DB_TXN_NOSYNC bedeutet, dass Datenbankoperationen, die im Cache gespeichert sind, nicht direkt auf die Platte ins Transaktionslog geschrieben werden, sondern immer erst dann, wenn das System relativ »idle« ist. Dabei bitte immer bedenken, dass diese Einstellung definitiv zu Lasten der Sicherheit und Datenbankkonsistenz geht! Adäquater Parameter in der slapd.conf: dbnosync. Auf Produktivsystem niemals aktivieren.
Zur Übersicht aller verfügbaren Parameter, Direktiven und Funktionen der bdb verweisen wir an dieser Stelle noch einmal auf die sehr ausführliche bdb-Dokumentation von Oracle, den OpenLDAP Admin Guide und die LDAP-Faq-O-Matic. bdb-Settings per slapd Die zweite – ergänzende – Variante zur Steuerung der Datenbankperformance besteht im Setzen von Direktiven in der bdb-Sektion der slapd.conf (slapdbdb(5)) oder über die entsprechenden olc-Direktiven im Konfigurations-DIT, z.B. cn=config,olcDatabase={1}hdb.ldif. Im Folgenden sind zu den jeweiligen Direktiven größtenteils auch die olc-Entsprechungen für die Verwendung der Laufzeitkonfiguration aufgeführt. Exkurs: dbconfig on- oder offline? Dabei ist ein wichtiger Punkt zu beachten: Das Setzen der Parameter in der der slapdOnline-Konfiguration führt nicht dazu, dass sich die DB_CONFIG-relevanten-Settings (set_cachesize, set_lg_max usw.) on the fly ändern. No way. Aber fangen wir klein an. In der slapd.conf (oder online per slapd.d/) können wir mit dbconfig oder olcDbConfig bdb-spezifische Settings setzen. Die bewirken jedoch Unterschiedliches:
344
1198.book Seite 345 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Exkurs: dbconfig on- oder offline? Arbeiten wir mit einer statischen Konfiguration ( in der slapd.conf), wird die DB_CONFIG – sofern vorhanden – beim (Re-)Start des slapd nicht überschrieben, und ihre Einstellungen haben Präzedenz. Die DB_CONFIG wird nur dann in Verbindung mit dbconfig-Settings in der slapd.conf beim (Re-)Start des slapd neu erstellt, wenn sie noch nicht vorhanden war. In der Online-Konfiguration sieht die Geschichte anders aus: Auch hier wird die Datei DB_CONFIG – sofern nicht vorhanden – mit den entsprechenden Settings beim (Re-) Start des slapd erstellt. Existiert sie bereits, wird sie jedoch bei einer Online-Modifikation (Achtung, siehe weiter unten!**) mit den slapd-spezifischen db-Settings sofort überschrieben. Gegebenenfalls noch nicht vorhandene Direktiven werden ergänzt. Somit ist auch keine Präzedenz irgendeiner Konfiguration mehr vorhanden, da beide Settings (olcDbConfig und DB_CONFIG) identisch sind! Zudem bietet die Online-Variante den Vorteil, dass Änderungen – je nach Replikations-Konfiguration – auf beteiligte Master oder Slaves repliziert wird. Allerdings gilt auch hier die Limitierung, das die geänderten db-Settings erst nach einem slapd-Restart (gegebenenfalls mit db_recover vorab) greifen.
Kommen wir nun zu den Direktiven: Mit dbconfig
in der slapd.conf (bzw. olcDbConfig in cn=config) werden DB_CONFIG-spezifische Einstellungen in die Datei DB_CONFIG geschrieben, sofern diese noch nicht existiert. Bereits bestehende Settings in der DB_CONFIG-Datei werden nur bei Online-Modifikationen aktualisiert. Ein Anwendungsbeispiel: slapd.conf (statisch) dbconfig
set_cachesize 0 64000000 1
oder für slapd.d/ olcDbConfig:
set_cachesize 0 64000000 1
ACHTUNG!: DB_CONFIG-spezifische Modifikationen an der olc-Konfiguration müssen mit Bedacht vorgenommen werden, da das Attribut olcDbConfig typischerweise MultiValued ist! Wollen wir daher eine Modifikation vornehmen (die frühestens nach dem nächsten Start, gegebenenfalls mit einem db_recover vorab, greift), müssten wir alle(!) olcDbConfig-Direktiven angeben, und die ersetzen oder hinzufügen, die wir benötigen (der Kommentar gehört nicht zur Datei): dn: olcDatabase={1}hdb,cn=config changetype: modify replace: olcDbConfig olcDbConfig: {0}set_cachesize 0 15000000 1 # alt olcDbConfig: {1}set_lg_regionmax 262144 # alt
345
3.8
1198.book Seite 346 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
olcDbConfig: {2}set_lg_bsize 2097152 # alt olcDbConfig: {3}set_flags DB_LOG_AUTOREMOVE # alt olcDbConfig: {4}set_lg_max 20000000 # neu
Diese Modifikation würde z.B. die Größe der Transaktionslogs beim nächsten slapd-Restart von 10 auf 20 MB anhieven. Betrachten wir nun weitere der (olc)dbconfig-Direktiven sowie ihre potenziellen Gegenstücke aus der DB_CONFIG: cachesize olcDbCacheSize
Dieser Parameter gibt an, wie viele Datensätze/Objekte(!) des DIT von unserem slapd(!) im Cache gehalten werden. Achtung: Der Parameter ist nicht identisch mit dem set_cachesize-Wert aus der DB_CONFIG, da Letzterer die Größe des Caches für die BDB beschreibt. Als praktikabler Wert empfiehlt sich mindestens die Anzahl der im DIT vorhandenen Entries plus Reserve, bei kleinen DITs kann der übliche Standardwert von 10000 belassen werden. checkpoint <minutes> olcDBCheckpoint: <minutes>
Dieser Parameter dient dazu, um so genannte Checkpunkte (oder auch Wiederherstellungs-/Prüfpunkte) im Transaktionslog zu setzen, von denen aus die Datenbank bei Bedarf wiederhergestellt werden kann. Es können zwei Parameter (Größe, Zeit) angegeben werden, derjenige, der zuerst erreicht wird, hat Präzedenz. Wird einer der Parameter erreicht (z.B. 1MB oder 5 Minuten), wird der Inhalt des Bufferspeichers auf die Platte in das Transaktionslog geschrieben und mit einem Checkpunkt versehen. Standardmäßig ist dieser Parameter bei SUSE und Debian gesetzt. Der Wert kann auch über die txn_checkpoint-Direktive in der DB_CONFIG gesetzt werden. Allgemein gilt: Falls dbnosync (nächster Punkt) gesetzt ist, sollten die Intervalle aus Gründen der Datensicherheit keinesfalls allzu groß gewählt werden. dbnosync olcDbNoSync:
(Siehe analog DB_TXN_NOSYNC-Flag aus der DB_CONFIG.) Achtung! Dieser Parameter sorgt dafür, dass der Datenbankbestand (das Transaktionslog) bei Änderungen nicht sofort mit dem Speicherinhalt synchronisiert wird. Performanceverbesserung zu Lasten der Datensicherheit: Choose your poison – oder besser: Finger weg! dirtyread olcDbDirtyRead
346
1198.book Seite 347 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Erlaubt das Auslesen gerade getätigter Änderungen im Speicher, die noch nicht auf die Platte geschrieben sind: Ein User schreibt und ändert Daten, die ein anderer kurz danach liest. Falls die Änderungsoperation fehlschlägt, liegen dem lesenden User falsche Daten vor. Also auch hier: Performance versus Datenkonsistenz. In Produktivumgebungen: Finger weg! searchstack olcDbSearchStack:
... definiert die maximale Tiefe von mit UND/ODER verschachtelten Suchfiltern (siehe Abschnitt 2.3, »Fingerübungen«). Jeder Server-Thread erhält einen Stack zugewiesen. Innerhalb dieser zugewiesenen Tiefe wird kein zusätzlicher Speicher für Suchoperationen benötigt. Bei Suchanfragen mit tieferer Verschachtelung wird zusätzlicher Speicher bereitgestellt, was bei vielen Anfragen mit hoher Verschachtelungstiefe zu Performanceeinbußen führen kann. In der Grundeinstellung sind 16 Verschachtelungen möglich, von denen jede 512 KB Speicher beansprucht, also insgesamt 8 MB. idlcachesize olcDbIDLCacheSize:
Das definiert die Größe des Index-Caches im Speicher, der für Index-Suchvorgänge verwendet wird. Standardmäßig ist der Wert 0, eine Erhöhung beschleunigt die Suchvorgänge von indizierten Objekten. Achtung: Verwenden wir das hdb-Backend, müssen wir darauf achten, diesen Wert entsprechend groß zu dimensionieren, um seine bessere Performance optimal auszunutzen. In der Praxis sollten die Werte etwa dreimal so groß gewählt werden wie der cachesize-Wert (entry-bezogen). index {|default} [pres,eq,approx,sub,<special>] olcDbIndex: {|default} \ [pres,eq,approx,sub,<special>]
Schon mal versucht, einen einzelnen Begriff in einem kleingedruckten Buch mit vierstelliger Seitenzahl zu finden, und zwar ohne Index? Okay, das brauchen wir so wenig wie unser slapd, denn das würde für uns beide bedeuten: »Dann such mal fleißig.« Um genau diese Beschäftigungstherapie zu vermeiden, ist ein Index die beste Lösung. Sinnvoll eingesetzt, bringt er unseren ohnehin gnadenlos schnellen slapd noch weiter auf Trab. Im Detail: Dieser Parameter hat einen erheblichen Einfluss hinsichtlich der Zugriffszeit auf Objekte bzw. bestimmte Attribute im DIT. In den meisten slapdKonfigurationen ist bereits dem Standard entsprechend ein Index für objectClass
347
3.8
1198.book Seite 348 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
gesetzt. In der statischen Konfigurationsvariante greift index nur beim Befüllen der Datenbank (oder bei gestopptem slapd mit statischer Konfig und anschließendem slapindex) und generiert Indexdateien (unter /var/lib/ldap/) für die im index-Statement angegebenen Attribute und Parameter. Als Faustregel sollten stets die Attribute indiziert werden, nach denen innerhalb unseres DITs am häufigsten gesucht wird (z.B. cn, sn, uid, mail usw.). Eine besondere Beachtung verdienen dabei auch die Attribute, die von bestimmten Funktionalitäten (syncrepl: entryCSN, entryUUID) und/oder angebundenen Applikationen wie z.B. Samba(3) häufig benötigt werden, als da wären: sambaNTPassword, sambaSID usw. Hilfreich ist auch immer ein Blick in die Logs unseres guten alten slapd: Taucht hier zu irgendeinem Attribut die Meldung »...not indexed« auf, sollten wir auf ihn hören und das Ding ganz schnell auf den Index setzen. Schnell? Da war doch was ... Eins, zwei, drei – noch’n Index on the fly Werden nachträglich Attribute und/oder Parameter zum Index hinzugefügt, müssen die Indizes in der statischen Konfiguration per slapindex reorganisiert werden; unser slapd muss dazu in jedem Fall gestoppt sein. Einen Ausweg aus dieser unbequemen Limitierung bietet uns einmal mehr die Online-Konfiguration. Sie ermöglicht das Setzen der gewünschten Indexe on the fly, und nicht nur das: die Indexe werden sofort im db-Ordner (/var/lib/ldap) angelegt und sind wirksam. Klingt klasse? Ist auch so, und das Beste daran, insbesondere für Replikations-Szenarien: Die Settings werden (je nach Replikationseinstellungen) auf die Replicas übertragen und werden dort ebenfalls sofort aktiv. Hier ein kleines Beispiel, in dem wir zusätzliche Indexe für uid und cn on the fly generieren: dn: olcDatabase={1}hdb,cn=config changetype: modify add: olcDbIndex olcDbIndex: uid,cn eq
Aber ... welche Art von Index benötigen wir denn nun?
3.8.6
Ab auf den Index
Eine pauschale Antwort auf die Art des Indexes gibt es nicht, hier ist vorab immer etwas Überlegung angesagt. Zudem müssen wir auch bedenken, dass die exzessive Verwendung von Indizes ein wenig zu Lasten des Speicherbedarfs geht, da es sich logischerweise auch um einen (in diesem Fall attributspezifischen)
348
1198.book Seite 349 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Cache handelt, der sich sein Stück vom RAM abzwackt. Da die bdb-Indexe aber bezogen auf heute gängige Speichergrößen einen eher kleinen Verbrauch an RAM haben, ist das durchaus verschmerzbar. Vor allem, wenn wir dabei berücksichtigen, dass unsere kleinen Indexfreunde den Zugriff auf die ihnen zugeordneten Attribute um bis zu 50 % und mehr beschleunigen. Aber zunächst zur Technik selbst. Indexe können wir einzeln oder als Attribut-/ Parameterliste angeben: index index
sn cn,uid,sn
pres,eq,sub eq
Wird ein Attribut ohne Indexparameter gesetzt, gelten für das Attribut die in index default getroffenen Einstellungen, z.B. im folgenden Beispiel pres und eq für uid: index index index
default uid sn,cn
pres,eq eq
Betrachten wir nun die zur Verfügung stehenden Indexparameter: pres(ent)
→ vorhanden
eq(ual)
→ exakte Gleichheit
approx(imate)
→ annähernd
sub(...)
→ Teilstring, siehe auch special
special
→ Ergänzungsparameter (bei sub z.B.: initial, any, final)
Indexparameter sorgen dafür, dass ein Index anhand bestimmter Spezifikationen erstellt/ergänzt wird; sie können für die meisten Attribute kombiniert werden: Der Indexparameter pres(ent) erstellt/ergänzt den Index daraufhin, ob das entsprechende Attribut vorhanden ist. Der Suchstring, der in diesem Fall greift, wäre: ldapsearch –x cn=*. Die Verwendung von pres eignet sich z.B. für die Auswertung des indizierten Attributs durch ACLs. eq(ual) erstellt/ergänzt einen Index, bezogen auf die exakte Gleichheit des Suchstrings, also z.B.: ldapsearch –x uid=mueller
Der Parameter approx(imate) sorgt dafür, dass der Index hinsichtlich einer vorhandenen Ähnlichkeit erstellt/ergänzt wird: ldapsearch –x uid~=schulze könnte so z.B. auch »schultze« zurückliefern. Dieser Parameter kann nicht auf numerische
349
3.8
1198.book Seite 350 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Einträge wie z.B. uidNumber angewandt werden und benötigt dann die --enablephonetic-Kompilationsoption (Default in 2.4 gesetzt). sub erstellt/ergänzt den Index, bezogen auf Teilstrings eines Attributs, also z.B.: ldapsearch –x cn=*hase. Dieser Parameter kann über den special-Parameter
erweitert werden. So bedeutet z.B. subinitial Indexierung von =hase*, subany von =*hase* und subfinal =*hase. Bei Angabe von sub wird subany angenommen. Weiterhin existieren noch die Special-Types nolang (Index sprachspezifisch verbieten) und nosubtypes (Zugriff von definierten Subtypen auf einen Index verbieten). Tipp: Über die Einstellungen index_* in der slapd.conf bzw. olcIndex* der Online-Konfiguration können korrespondierende Einstellungen zu den einzelnen Index-Typen wie z.B. integer oder substring getroffen werden. Als Referenz hierzu können wir auch einen Blick in RFC 4515, »String Representation of LDAP Search Filters«, werfen. Betrachten wir in der Zusammenfassung die Suchfilter der verschiedenen Filtertypen: 왘 (sn=Meier)
Gleichheitsfilter
(eq)
왘 (sn=Mei*)
Substringfilter
(sub)
왘 (sn~=Meier) Ähnlichkeitsfilter
(approx)
왘 (mail=*)
(pres)
Existenzfilter
왘 (gidNumber>=100) Bereichsfilter (less/greater eq), kann aber nur auf Attributtypen mit einer ORDERING-MatchingRule verwendet werden. Die Wahl der Indexparameter sollte ebenfalls mit Bedacht stattfinden, da jeder unnötige Eintrag die Größe der Indexdatei und damit auch den Speicherbedarf erhöht. Zum Beispiel wird eine Indexierung des mail-Attributs auf sub nichts bringen, wenn ohnehin nur per equality match nach diesem Attribut gesucht wird. By the way: Zu den Vergleichsregeln (wie equality match) für Attribute etc. kommen wir im nächsten Abschnitt über selbstdefinierte Schemas. Jetzt kurz zum Speicherbedarf der jeweiligen Index-Varianten. Wir betrachten das Attribut cn bezogen auf 11.000 Datensätze und variieren lediglich die IndexParameter wie folgt: Index pres eq,pres eq,pres,sub
350
Index-Größe 0.122 MB 0.356 MB 2.5 MB
1198.book Seite 351 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
Das Ergebnis war zu erwarten, da die Teilstringsuche per Wildcards die meisten Kombinationen abzudecken hat. Daher sollte der Parameter sub, ebenso wie approx, nur mit Bedacht bei den Attributen eingesetzt werden, die auch dementsprechend abgefragt werden sollen (und dürfen). Hierbei bitte beachten: Wenn wir Index-Einstellungen in der statischen Konfiguration per slapd.conf ändern, muss der Index neu generiert werden. Den Job erledigt slapindex offline, oder wir führen einfach einen Restart unseres slapd durch.
3.8.7
Built for Speed – Zahlen und Fakten
Und jetzt, wie versprochen, ein kleiner Benchmark-Exkurs. Zu diesem Thema machen wir so wenig Worte wie die LDAP Guys und lassen lieber Zahlen sprechen. Die Jungs stellten sich die äußerst interessante Frage, wie schnell unser slapd (2.3)/bdb-Gespann im Vergleich zu Microsofts ADS (W2K3 Enterprise Edition SP2 64 Bit) auf absolut identischer Hardware (AMD Celestica A8440 mit vier Opteron 875 dual core 2.2GHz und 16GB DDR333 RAM) wirklich ist, und das Ergebnis war mehr als eindeutig: Drei Minuten und neun Sekunden, um mit slapadd eine Million Einträge in eine hdb zu schreiben – und fast viereinhalb Stunden, um die adäquate Operation auf einem Active Directory auszuführen. Isnichwahr? Doch. Der Test wurde Ende 2007 durchgeführt. Aber nicht nur jener. Die kleine nachfolgende Tabelle zeigt uns die Werte im Einzelnen und wie viele Authentifizierungsprozesse pro Sekunde von dem jeweiligen DS bearbeitet werden können. Der Auth-Benchmark wurde per slamd erzeugt. Kurze Erläuterung zu den MS-Kürzeln: ADS = Active Directory ADAM = Active Directory Application Mode Letzterer hat nix mit Eva zu tun, zumindest nicht in diesem sprichwörtlichen Kontext. Wen’s interessiert: Der Dienst wurde erstmals in Windows Server 2003 implementiert und dort als Active Directory Application Mode (ADAM) eingeführt. Aktuell nennt sich das Ding: Active Directory Lightweight(!) Directory Services (ADLDS) und stellt eine funktional eingeschränkte Version des ADS mit geringerem Overhead dar, die selbst gar kein ADS abbilden kann und primär der Anbindung von Applikationen dient, die LDAP-konforme(!) Informationen, z.B. Authentifizierungsdaten aus dem Verzeichnis benötigen.
351
3.8
1198.book Seite 352 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Werfen wir nun einen Blick auf ein paar konkrete Zahlen: Eine Million Einträge System OpenLDAP hdb MS ADAM MS ADS
Initial Content Load/hh:mm:ss.ss 00:03:09.31 00:27:33.84 04:23:46.85
Auth Rate/sec 23272.948 5738.017 4661.686
Betrachten wir Spalte 2: Okay, ADS hat (mit einem halben Arbeitstag) für den Initial Content Load nur geringfügig länger gebraucht als unser OpenLDAP mit drei Minuten und neun Sekunden; für den ADS-Hiwi ADAM – der nur knapp zehnmal so lang gebraucht – sieht’s nicht ganz so übel aus, allerdings kann der Kollege im Gegenzug auch nicht als vollwertiger DS gewertet werden. Spalte 3 zeigt uns den per slamd generierten Authentifikations-Benchmark für abgeschlossene Authentifikationsvorgänge pro Sekunde, der auch kaum misszudeuten ist. Schauen wir uns nun den gleichen Test mit fünf Millionen Einträgen sowie zusätzliche der Höhe des verbratenen Plattenspeichers an: Fünf Millionen Einträge System OpenLDAP hdb MS ADAM MS ADS
Zeit (ICL, s.o.) 00:16:18.67 02:59:44.78 23:51:22.07
DB-Grösse 6.533800 GB 21.170192 GB 39.288848 GB
Auth Rate / sec 20178.852 5423.759 216.359
Im günstigsten Fall erreicht AD(AM) gerade mal ein Viertel der OpenLDAP-Performance, ADS ein Hundertstel(!). Ein weiterer interessanter Punkt war der RAM-Verbrauch der LDAP-relevanten Prozesse in den Test-Szenarien: System OL hdb MS ADAM MS ADS
1 Mio Entries 4.0 GB 6.0 GB 10.0-11.0 GB
5 Mio Entries 14.5 GB 14.8-16.0 GB 15.5+ GB
Die Werte sprechen allesamt eine klare Sprache, aber auch dadurch werden wir in Zukunft mit Sicherheit nicht von den schönen, bunten und aufwändig illustrierten Seiten in populären Computerzeitschriften verschont bleiben, auf denen total unabhängige und über jeden Zweifel erhabene Consulting-Unternehmen die unglaublichen Vorteile, die niedrige TCO und vor allem die wahnsinnige Performance anpreisen, die uns Directory-Serverprodukte aus Redmond so bieten. Was soll’s. Wir können uns dann jedenfalls mit einem entspannten Lächeln auf dem Gesicht zurücklehnen, weiterblättern und das Papier einer besseren Verwendung zuführen.
352
1198.book Seite 353 Donnerstag, 5. Februar 2009 3:02 15
Larry und die schläfrigen Katzen
3.8.8
Die Sache mit dem Backup ...
Genau das Ding, um das sich in der Regel keiner kümmern will, das im Fehlerfall entweder nicht da ist, veraltet und/oder beim Restore einen freundlichen Integritätsfehler präsentiert. Unser alter Freund, die Sicherung. Und da sich die Daten unseres guten alten slapd allesamt im Bauch der schläfrigen Katze befinden, werfen wir einen kurzen Blick auf mögliche Szenarien. Backups sind für alle Datenbestände unabdingbar, das soll hier auch nicht unser Thema sein. Jedem verantwortungsbewussten Admin ist klar, dass er seine Daten, insbesondere wenn sie das Herzstück seiner ganzen Netzwerkservices darstellen, pfleglich sichern muss – und ebenso sicherstellen muss, dass ein Restore im Notfall auch ohne Probleme funktioniert. Um die Datenbank unseres slapd inklusive aller Objekte zu sichern, existieren, wie wir wissen – einige Ansätze, die je nach Anwendungsfall mehr oder weniger gut geeignet sind. Die einfachste Lösung ist sicherlich, cron-gesteuert slapd zu stoppen, anschließend per slapcat einen Datenbank-Dump zu ziehen und den slapd danach wieder neu zu starten. Einfach, simpel, kaum fehleranfällig, aber nur für einfache Installationen geeignet, die keinen 24/7-Betrieb fahren und überschaubare Datenmengen an Bord haben. Denn auch ein slapcat arbeitet nicht in der Matrix, sondern nach Prinzipien unserer physikalischen Welt, und ein DB-Dump von einigen TB kann hier eben bisweilen ein klein wenig dauern ... Bleiben wir bei der Problematik 24/7 und/oder großen Datenmengen, die einen längeren Shutdown des slapd keinesfalls zulassen. Hier bieten sich mehrere Szenarien an. Wie wir wissen, können wir die Datenbank(en) unseres slapd mit Hilfe der Online-Konfiguration im laufenden Betrieb bequem in einen Readonly-Modus schalten, sodass die Konsistenz der Datenbank während des Dumps gesichert ist. Allerdings bleibt die Frage, wie lange die DB – je nach Umfeld – readonly bleiben darf. Wir sehen: Auch dieses Konzept kann an seine Grenzen stoßen. Die mit Sicherheit effektivste Lösung bietet einmal mehr unsere gute, alte Replikation. Das Szenario: Wir setzen eine typische Provider/Consumer-Full-Replikation auf, in der die Änderungen -je nach Einsatzfeld- zeitsensitiv oder zu einer festen Uhrzeit auf den (üblicherweise ohnehin nur lesbaren) Consumer übertragen werden. Kommt die Zeit fürs nächtliche Backup, fahren wir den slapd unseres Consumers beruhigt herunter (denn für alle auflaufenden Schreib- und Lesezugriffe steht der Provider in dieser Zeit ja schließlich zur Verfügung) und starten dort den DB-Dump per slapcat. Danach erneuter Start des Consumer-slapd, der dank syncrepl seinen Content wieder zügig auf den aktuellsten Stand bringt, egal, wie lange er offline war. Eine zweite, einfache Alternative zu dieser Vorgehens-
353
3.8
1198.book Seite 354 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
weise wäre das direkte Kopieren aller *db-relevanten Dateien des gestoppten Consumers in einen entsprechenden Backup-Ordner. Das sind nur einige wenige Ansätze; der entscheidende Punkt ist jedoch auch hier, dass man sich vorab in Ruhe und gegebenenfalls mit Papier und Stift bewaffnet daranmacht, ein sinniges Backup/Disaster-Recovery-Konzept zu erstellen. Und dazu sollte in jedem Fall ein regelmäßiger Recover-Test gehören, der auf einem (nicht ins Produktivumfeld integrierten) slapd mit den Daten aus den Backups durchgeführt wird. Per Scripts lässt sich auch diese Aufgabe hervorragend automatisieren. Das war nur ein kleiner Exkurs, weitere Tipps zu diesem Thema finden sich unter http://www.openldap.org/doc/admin24/maintenance.html. Weiterführende Informationen zur Oracle Berkeley-DB gibt es unter http:// www.oracle.com/database/berkeley-db/index.html.
3.8.9
Und zum Schluss ein bisschen Replikation ... schon wieder?
Ja, tatsächlich – die bdb besitzt einen eigenen Replikationsmechanismus, der primär dazu gedacht ist, Redundanz in das bdb-Datenbanksystem zu bringen. Vom Funktionsprinzip her ähnlich wie uns slapd im normalen syncrepl-Mode, können sich bdb-Datenbanken gegeneinander replizieren – üblicherweise mit einem R/ W-Master und einem oder multiplen R/O-Slaves auf physikalisch getrennten Maschinen. So weit die Theorie ... Bevor wir uns jetzt ernsthaft fragen, ob man sich dadurch nicht eventuell die ganze Replikation auf LDAP-Ebene eigentlich sparen könnte: Nein! In unserem Fall kümmert sich unser slapd auf Applikationsebene um die Aufbereitung, Verwaltung, Ablage und vor allem auch Replikation der Daten. Die OpenLDAP-Replikation arbeitet in diesem Fall erheblich effizienter als ihr bdbstandalone-Gegenstück. Wenn ein Objekt modifiziert wird, geht auch nur das Objekt übers Netz – im Fall von Delta-Sync sogar nur die modifizierten Attribute. Würden wir das auf bdb-Ebene erschlagen, wäre das Datenaufkommen replikations- und db-designtechnisch bedingt in jedem Fall höher. Und noch ein Problem muss dabei beachtet werden: Unser slapd cached die Daten, bevor sie letztlich in die bdb geschrieben werden. Und wie wir wissen, hat das einen ganz gewaltigen Einfluss auf die Performance – und nicht nur das. Würden wir eine Replikation auf bdb-Ebene bei aktiviertem Cache gestatten, hätten wir ganz schnell alles Mögliche, aber mit Sicherheit keine konsistente Datenbank mehr.
354
1198.book Seite 355 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
Um der unsausweichlichen Frage vorzubeugen: Ja, klar – hier und da etwas rumschrauben und den Cache einfach abschalten. Und das Schlimme daran: das funktioniert sogar – zumindest in der Theorie. Aber selbst wenn, um welchen Preis? Ergibt es einen Sinn, einen Ferrari zu fahren, in dem nur der erste Gang funktioniert? Wohl kaum. Daher gilt: Wenn wir unser Leben nicht spannender machen wollen – Pfoten weg. Es bringt nichts, zumindest nicht in Verbindung mit OpenLDAP. Punkt. Wenn wir schon schrauben wollen: Im nächsten Abschnitt gibt’s rein schematisch jede Menge zu tun. Wetten? Geht sofort los ...
3.9
Selbst ist der Admin – das eigendefinierte Schema
Tim: »Tag Wilson. Was machen Sie da?« Wilson: »Ich schnitze mir ein Kanu.« Tim: »Schwere Arbeit, was?« Wilson: »Nein, eigentlich nicht, Tim. Man nimmt nur einen dicken Stamm und schnitzt alles weg, was nicht zu einem Kanu gehört.« Tool Time Klingt doch recht einfach, oder? Und das ist es auch. Denn die Grundlagen zum Arbeiten mit Schemas kennen wir bereits aus dem Abschnitt 1.7, »Nicht nach Schema F«. Und wie dort bereits erwähnt, kommt irgendwann einmal der Zeitpunkt, an dem der ambitionierte Admin die vorhandenen LDAP-Schemas um eigene erweitern möchte. Oder es einfach aus betriebsbedingten Gründen muss. Vor dem Gang zur digitalen Schema-Werkbank sollten wir uns aber stets ein paar grundlegende und extrem wichtige Fragen stellen und beantworten: Kann die gewünschte Funktionalität nicht doch über die Standard-Schemas erschlagen werden, und wenn nein, welche Objektklassen und Attribute benötige ich? Wie muss das Schema aufgebaut sein? Und wie sorge ich dafür, dass das neue Schema mit den Schemas anderer Abteilungen oder gar Firmen kompatibel ist, mit denen Daten ausgetauscht werden müssen? Diese Punkte – rechtzeitig geprüft – können uns im Nachhinein gegebenenfalls eine Menge Arbeit ersparen. Vorab: Die vorhandenen Schemas lassen im Regelfall kaum Wünsche offen. Werden aber doch zusätzliche Objekte benötigt, lassen sich diese meist durch Vererbung auf Basis bestehender Objekte erstellen. Wichtig hierbei ist jedoch immer, zuvor eindeutig festzustellen, ob Kompatibilität zu anderen Zweigstellen/Firmen erforderlich ist und ob die OIDs rein privater/firmeninterner Natur sein können oder lieber doch offiziell registriert werden sollten.
355
3.9
1198.book Seite 356 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Nachdem wir diese Fragen eindeutig geklärt haben, können wir uns an die erforderlichen Vorbetrachtungen und Vorbereitungen machen. Für unsere folgenden Beispiele verwenden wir eine private OID-Klasse aus dem Bereich 1.1.* (offiziell als »toter« Namens- bzw. OID-Raum deklariert). Offiziell bei der IANA beantragte Enterprise-OIDs liegen üblicherweise in der Form 1.3.6.1.4.1.* vor, die sich am Beispiel der offiziellen OpenLDAP-OID 1.3.6.1.4.1.4203.* wie folgt decodieren: 1 - ISO assigned OIDs 1.3 - ISO Identified Organization 1.3.6 - US Department of Defense 1.3.6.1 - OID assignments from 1.3.6.1 - Internet 1.3.6.1.4 - Internet Private 1.3.6.1.4.1 - IANA-registered Private Enterprises 1.3.6.1.4.1.4203 - OpenLDAP
Die Beantragung einer offiziellen OID kann über www.iana.org/cgi-bin/enterprise.pl erfolgen. Wir weisen nochmals darauf hin, dass man keinesfalls willkürlich irgendwelche OIDs verwenden sollte, da diese bereits offiziell belegt sein könnten und so Kollisionen unweigerlich vorprogrammiert wären. Um die hinter den Attribut- und Objektklassen-Definitionen steckende Logik zu erkennen, müssen wir uns vor Augen führen, dass beim Informationsaustausch zwischen Server und Client Strings (z.T. codierte, wie für Bilddateien) übermittelt werden. Dadurch ist ein strenges Regelwerk vonnöten, das die Attribute in verschiedene Typen – also Attributtypen – einteilt, sowie die zugehörigen Attributsyntaxen und Vergleichregeln. Primäre Referenzen hierfür sind die RFCs 4512, 4517, 4519 sowie 2252, deren Teile 4, 5 und 7 durch RFC 4512 obsolet wurden. Genau hier liegt einer der Hauptgründe, warum sich Verzeichnisdienste wie ADS und OpenLDAP nicht einfach zur Zusammenarbeit überreden lassen: Einer der beiden hält sich eben oft genug nicht an genau diese standardisierten Definitionen, der andere schon. Wer wer ist, dürfte dabei außer Frage stehen. Fakt bleibt unter dem Strich, dass durch diese Alleingänge jede Interoperabilität von vornherein zum Scheitern verurteilt ist, es sei denn, es finden sich Entwickler (wie z.B. die Samba-Crew), die die teilweise arg verbogenen Semantiken des ADS nachbildet. Im Folgenden betrachten wir zunächst die konventionellen Schema-Varianten mit den darin enthaltenen Attributen und Objektklassen, später sehen wir uns dann ihre Online-Gegenparts an und welche Vorteile sie uns gegenüber ihren »statischen« Brüdern bieten.
356
1198.book Seite 357 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
3.9.1
Attribute
Attributtypen definieren zum Beispiel, welche Syntax ein bestimmtes Attribut haben muss und wie die Zeichenketten miteinander verglichen werden können. Schauen wir uns zunächst einmal die offizielle Definition eines Attributtyps nach RFC 2252 an (whsp steht im folgenden Listing für Whitespace, also Leerzeichen): AttributeTypeDescription = "(" whsp # whsp=whitepace [Leerzeichen] numericoid whsp # AttributeType Identifier. z.B. 1.1.2.1.1 [ "NAME" qdescrs ] # menschenlesbarer Name des Attributs [ "DESC" qdstring ] # menschenlesbare Kurzbeschr. des Attributs [ "OBSOLETE" whsp ] # Indikator, ob das Attribut obsolet ist [ "SUP" woid ] # (Superior)->enthält OID eines anderen At# tributs von dem der zu definierende Attri# buttyp erben soll [ "EQUALITY" woid # Art des Gleichheitstests [ "ORDERING" woid # Anzuwendende Vergleichsregel [ "SUBSTR" woid ] # Vergleichsregel für Teilstrings [ "SYNTAX" whsp noidlen whsp ] # OID der verwendeten Syntax [ "SINGLE-VALUE" whsp ] # Nur 1 Wert zulässig, default # (LDAPv3)ist multi-valued [ "COLLECTIVE" whsp ] # default not collective [ "NO-USER-MODIFICATION" whsp ] # “ro”-Attribut, keine mod. durch # Benutzer möglich. [ "USAGE" whsp AttributeUsage ] # default: userApplications, # weitere Werte: directoryOpera# tions, distributedOperations, # dsaOperations whsp ")"
Verdeutlichen wir nun einige der vorgenannten Direktiven an einem einfachen Attribut, das wir bereits kennen: description, ehemals Bestandteil des core. schema, nun hartverdrahtet im System wie z.B. auch »name«. Die Nummerierung im folgenden Beispiel dient nur der späteren Beschreibung: 1) attributetype ( 2.5.4.13 NAME 'description' 2) DESC 'RFC2256: descriptive information' 3) EQUALITY caseIgnoreMatch 4) SUBSTR caseIgnoreSubstringsMatch 5) SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
1) Definition des Attributtyps über eindeutige OID (2.5.4.13) und einen menschenlesbaren Namen (NAME 'description'), der als Alias für die OID fungiert. Das erste Zeichen im Alias-String sollte keine Zahl enthalten. OIDs finden sich nicht nur im Zusammenhang mit Verzeichnisdiensten, sondern typischerweise in allen ASN1 (Abstract Syntax Notation 1)-basierten Protokollen; ein anderes, typisches Einsatzgebiet für OIDs ist der SNMP (Simple Network Management Protocol)-Bereich.
357
3.9
1198.book Seite 358 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
2) enthält die Beschreibung des Attributs ('RFC2256: descriptive information').
3) Die Vergleichsregel (caseIgnoreMatch) bedeutet, dass Klein-/Großschreibung und Leerzeichen beim Vergleich ignoriert werden. 4) Die Vergleichsregel für die Teilstrings (caseIgnoreSubstringsMatch) ignoriert ebenfalls Klein-/Großschreibung und Leerzeichen. 5) Die Attributsyntax (1.3.6.1.4.1.1466.115.121.1.15{1024}) beschreibt durch seine OID, dass es sich um einen directoryString mit UTF-8-Encodierung handelt, dessen Längenempfehlung auf 1024 Byte lautet (was aber keine Größenlimitierung darstellt, da zumindest unser slapd Größenlimitierungen ignoriert).
3.9.2
Attribut-Syntax und Matching Rules
Damit hätten wir nun eine eindeutige Beschreibung des Attributs description vorliegen. Bevor wir aber einen genaueren Blick auf die Zeilen 3–5 werfen (da sie die Eigenschaften des Attributs entscheidend beeinflussen), betrachten wir zunächst einen Auszug der gebräuchlichsten Syntaxdefinitionen (SYNTAX), die per OID wie folgt beschrieben werden. Tabelle: Auszug Syntaxdefinitionen nach RFC 2252/4517: Syntax
OID des Syntax
Boolean
1.3.6.1.4.1.1466.115.121.1.7
Binary
1.3.6.1.4.1.1466.115.121.1.5
Bit String
1.3.6.1.4.1.1466.115.121.1.6
Certificate
1.3.6.1.4.1.1466.115.121.1.8
Distinguished Name
1.3.6.1.4.1.1466.115.121.1.12
Directory String
1.3.6.1.4.1.1466.115.121.1.15
IA5 String
1.3.6.1.4.1.1466.115.121.1.26
Integer
1.3.6.1.4.1.1466.115.121.1.27
JPG
1.3.6.1.4.1.1466.115.121.1.28
Name and Optional UID
1.3.6.1.4.1.1466.115.121.1.34
Numeric String
1.3.6.1.4.1.1466.115.121.1.36
OID
1.3.6.1.4.1.1466.115.121.1.38
Octet String
1.3.6.1.4.1.1466.115.121.1.40
Postal Address
1.3.6.1.4.1.1466.115.121.1.41
Printable String
1.3.6.1.4.1.1466.115.121.1.44
Telephone Number
1.3.6.1.4.1.1466.115.121.1.50
UTC Time
1.3.6.1.4.1.1466.115.121.1.53
358
1198.book Seite 359 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
Auch wenn der Integer-Bezeichner in dieser Tabelle irreführend sein könnte: es handelt sich tatsächlich um die String-Repräsentation eines numerischen Wertes (siehe hierzu auch RFC 4517, Punkt 3.3.16, »INTEGER«). Die Integerzahl 1234 wird durch den Zeichenkette »1234« repräsentiert. Die Herkunft der LDAPv3-Syntax-OIDs leitet sich bis OID 1.3.6.1.4.1 gemäß den Erläuterungen auf der vorletzten Seite ab, danach geht es wie folgt weiter: 1.3.6.1.4.1.1466 - Mark Wahl (Critical Angle) 1.3.6.1.4.1.1466.115 - LDAPv3 Schema Framework (Syntaxes) 1.3.6.1.4.1.1466.115.121(.1) - LDAPv3 Syntaxes
Sehen wir uns nun ein Listing der gebräuchlichsten Vergleichsregeln (Matching Rules) an: Name der Regel
Typ
Art des Vergleichs
booleanMatch
EQUALITY
boolean
caseIgnoreMatch
EQUALITY
case insensitive, space insensitive
caseIgnoreOrderingMatch
ORDERING
case insensitive, space insensitive
caseIgnoreSubstringsMatch
SUBSTRINGS
case insensitive, space insensitive
caseExactMatch
EQUALITY
case sensitive, space insensitive
caseExactOrderingMatch
ORDERING
case sensitive, space insensitive
caseExactSubstringsMatch
SUBSTRINGS
case sensitive, space insensitive
distinguishedNameMatch
EQUALITY
distinguished name
integerMatch
EQUALITY
integer
integerOrderingMatch
ORDERING
integer
numericStringMatch
EQUALITY
numerical (String)
numericStringOrderingMatch
ORDERING
numerical (String)
numericStringSubstringsMatch
SUBSTRINGS
numerical (String)
octetStringMatch
EQUALITY
octet string
octetStringOrderingStringMatch
ORDERING
octet string
octetStringSubstringsStringMatch
ORDERING
octet string
objectIdentiferMatch
EQUALITY
object identifier
Der Vergleichstyp (EQUALITY,SUBSTRINGS,ORDERING) in der Attributdefinition überprüft den übermittelten String auf Gleichheit: EQUALITY den ganzen String ohne Wildcards, bei Verwendung von Wildcards greift SUBSTRINGS, und für <= bzw. >= Suchfilter greift das selten vorhandene ORDERING.
359
3.9
1198.book Seite 360 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Welche Gleichheitsregel Verwendung findet, definiert der Regelname in der ersten Spalte, die Art des Vergleichs (integer, boolean, *string) wird in der dritten Spalte beschrieben. Kleine Anmerkung hierzu: Die Vergleichsparameter numerical und integer unterscheiden sich dahingehend, dass numerical (string) eine Zeichenkette definiert, die aus numerischen Werten und Leerzeichen bestehen kann, ein integer-Wert besteht per Definition immer aus der Stringrepräsentation einer ganzen Zahl unbeschränkter Größe. Mehr Informationen hierzu finden sich in RFC 4517. Eine Übersicht der tatsächlich vorhandenen Matching Rules liefert uns ein: #> ldapsearch -x -s base -b "cn=subschema" \ "(objectClass=*)" matchingrules
und zeigt uns ebenfalls die den Matching Rules zugehörigen Syntaxdefinitionen. Da die Vergleiche wie bereits erwähnt über Strings erfolgen, schauen wir uns nun einige der LDAP-Strings und ihre zugehörigen MatchingRules genauer an: Der countryString (1.3.6.1.4.1.1466.115.121.1.11) verwendet den eingeschränkten IA5-Charset (siehe unten) und ist nach ISO 3166 auf zwei Zeichen limitiert. Erlaubte Matching Rules sind caseIgnoreMatch und caseIgnoreSubstringsMatch. Der directoryString (1.3.6.1.4.1.1466.115.121.1.15) verwendet UTF-8-Encodierung und bietet damit gegenüber IA5 einen erweiterten Zeichensatz mit Sonderzeichen wie z.B. dem Durchmesser-Symbol »Ø« oder länderspezifischen Umlauten wie »å« oder »é«. Erlaubte Matching Rules sind caseIgnoreMatch und caseIgnoreSubstringsMatch. Beim Vergleich werden führende und anhängende Leerzeichen entfernt. Mehrere Leerzeichen innerhalb des Strings werden durch ein einzelnes ersetzt. Der IA5String (1.3.6.1.4.1.1466.115.121.1.26) ist ein 7-Bit-Charset und ähnelt ASCII, erlaubt jedoch keine Sonderzeichen wie die UTF-8-Encodierung (siehe oben). Er wird z.B. für das Mail-Attribut im core.schema verwendet. Erlaubte Matching Rules sind caseIgnoreIA5Match und caseIgnoreIA5SubstringsMatch. Der numericString (1.3.6.1.4.1.1466.115.121.1.36) verwendet gemäß RFC 2252 ein numerisches Subset des IA5-Strings (0–9), Leerzeichen innerhalb des Strings sind zulässig. Erlaubte Matching Rules sind numericStringMatch und numericStringSubstringsMatch. Der printableString (1.3.6.1.4.1.1466.115.121.1.44) basiert auf dem IA5-String, ist allerdings auf einen beschränkten Zeichensatz limitiert, der in RFC 2252, Sektion 4.1. p, definiert ist, wie z.B.: / + , .: ? -. Erlaubte Matching Rules sind caseIgnoreMatch und caseIgnoreSubstringsMatch.
360
1198.book Seite 361 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
Der octetString (1.3.6.1.4.1.1466.115.121.1.40) wird üblicherweise immer encodiert. Die Encodierung erfolgt gemäß RFC 3641, »Generic String Encoding Rules for ASN.1 Types«, und ist (mehr oder weniger) menschenlesbar. Er wird üblicherweise bei Passwortattributen verwendet: attributetype (2.5.4.35 NAME 'userPassword' ...). Erlaubte Matching Rules sind octetStringMatch und octetStringOrderingMatch. Der Stringtyp postalAddress (1.3.6.1.4.1.1466.115.121.1.41) bedient sich ebenfalls des UTF-8-Formats, die Zeilen werden für Druckformate durch »$«-Zeichen umbrochen. Erlaubte Matching Rules sind caseIgnoreListMatch und caseIgnoreListSubstringsMatch. Weitere Syntaxformate mit jeweils spezifischen Matching Rules wären unter anderen noch: telephoneNumber, OID: 1.3.6.1.4.1.1466.115.121.1.50, matchingRules: telephoneNumberMatch / telephoneNumberSubstringsMatch generalizedTime, OID:1.3.6.1.4.1.1466.115.121.1.24, matchingRules: generalizedTimeMatch / generalizedTimeOrderingMatch
Eine Übersicht über die tatsächlich vorhandenen matchingRules, ldapSyntaxes, matchingRuleUse (bei Attributen x,y,z) sowie von effektiv vorhandenen Attributen und Objektklassen kann man sich wie folgt verschaffen: #> ldapsearch -x -s base -b "cn=subschema" \ "(objectclass=subschema)" + | less
Eine umfassende Übersicht der Syntaxdefinitionen findet sich z.B. unter: http://www.alvestrand.no/objectid/1.3.6.1.4.1.1466.115.121.1.html und http://ldap.akbkhome.com/index.php/syntax.html und natürlich in den bereits genannten RFCs. Bevor wir nun unser eigenes Schema entwerfen, schauen wir uns noch einmal kurz die Objektklassenhierarchie für eine Organisations- OID 1.1 an: 1.1 1.1.3 1.1.3.5 1.1.3.5.1 1.1.3.7 1.1.3.7.1
OID der Firma LDAP-Elemente Attributtypen meine Attribute Objektklassen meine Objektklassen
Das Schema, das wir auf dieser OID 1.1.*-Basis erstellen wollen (und das ebenfalls in den Beispieldateien zu diesem Abschnitt zu finden ist), nennen wir local-
361
3.9
1198.book Seite 362 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
site.schema. Als Erstes erstellen wir ein ganz einfaches Attribut, das sich aus dem Attribut uidNumber des nis.schema ableitet. attributetype ( 1.1.3.5.1 NAME 'myCMNumber' DESC 'unique Number of ClubMember' SUP uidNumber )
Der Attributname erhält den Wert »myCMNumber« als menschenlesbarer Alias für seine OID, 1.1.3.5.1 also gemäß vorab getroffener Definition die erste OID aus dem Bereich für »meine Attribute«. Die Syntax entfällt in diesem einfachen Beispiel, da wir das Attribut von dem vorhandenen Attribut uidNumber ableiten (SUP uidNumber), wodurch es all seine Eigenschaften automatisch erbt: (EQUALITY integerMatch, SYNTAX 1.3.6.1.4.1.1466.115.121.1.27, SINGLE-VALUE ) Nun erstellen wir ein zweites Attribut mit dem Alias »myCMDescription«; jedoch leiten wir es in diesem Fall nicht ab, sondern definieren explizite Eigenschaften für dieses Attribut: attributetype ( 1.1.3.5.2 NAME 'myCMDescription' DESC 'Description of ClubMember' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
Die Syntax 1.3.6.1.4.1.1466.115.121.1.15 entspricht der ebenfalls bereits bekannten Syntax directoryString mit UTF-8-Codierung. Allerdings erlauben wir in diesem Fall per SINGLE-VALUE explizit nur einen Attributwert für myCMDescription. Erlaubte Matching Rules gemäß Syntaxdefinition sind caseIgnoreMatch und caseIgnoreSubstringsMatch. Als Dritten im Bunde erstellen wir das Attribut myCMPhoto. Entsprechend des Alias könnten wir also z.B. folgendes Format für einen JPG Image String durch Vererbung definieren: attributetype ( 1.1.3.5.3 NAME 'myCMPhoto' DESC 'JPEG-Photo of ClubMember' SUP jpegPhoto )
Die Attributsyntax ist vom SUPerior-Attribut jpegPhoto der Objektklasse inetOrgPerson abgeleitet, deren OID (1.3.6.1.4.1.1466.115.121.1.28) den Attributtyp als jpg-image-string definiert. Alternativ könnten wir auch direkt die Syntax für octetString verwenden (1.3.6.1.4.1.1466.115.121.1.40) oder per LDAP-URL bzw. directoryString (OID 1.3.6.1.4.1.1466.115.121.1.15) auf den Ablageort des Fotos verweisen. In diesem Fall ist natürlich ein caseExactMatch zwingende Vorgabe:
362
1198.book Seite 363 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
attributetype ( 1.1.3.5.3 NAME 'myCMPhoto' EQUALITY caseExactMatch DESC 'Path to Photo of ClubMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
Eine weitere Alternative wäre die Ableitung vom Attribut labeledURI: attributetype ( 1.1.3.5.3 NAME 'myCMPhoto' DESC 'Path to Photo of ClubMember' SUP labeledURI )
Allerdings kann es vorkommen, dass einige LDAP-Clients das Foto nur dann anzeigen, wenn es im Attribut selbst gespeichert ist. Nun generieren wir noch ein Boolean-Attribut: attributetype ( 1.1.3.5.4 NAME 'myCMVIP' DESC 'Is this ClubMember VIP – TRUE or FALSE' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
Und um ganz sicher zu gehen, dass unser ClubMember auch zertifiziert ist, hängen wir noch das Attribut myCMcertificate an, das vom Attribut userCertificate aus dem core.schema abgeleitet ist. Und wie wir das Zertifikat in das Objekt bekommen, schauen wir uns gleich an: attributetype ( 1.1.3.5.5 NAME 'myCMcertificate' DESC 'Certificate of ClubMember' SUP userCertificate )
3.9.3
Objektklassen
Damit hätten wir bereits fünf Attribute definiert. Was fehlt, ist nun eine entsprechende Objektklasse, die diese Attribute beinhaltet. Betrachten wir zunächst die allgemeine Objektklassendefinition: ObjectClassDescription = "(" whsp # Leerzeichen numericoid whsp # OID [ "NAME" qdescrs ] # menschenlesbarer OID-Alias [ "DESC" qdstring ] # Beschreibung der Objektklasse [ "OBSOLETE" whsp ] # Objektklasse mittlerweile obsolet? [ "SUP" oids ] # abgeleitet von Klasse ...? [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ] # Objektklassen-TYP:(default structural) [ "MUST" oids ] # erforderliche AttributeTypen [ "MAY" oids ] # optionale AttributeTypen whsp ")"
363
3.9
1198.book Seite 364 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Die Kommentare sollten selbsterklärend sein. Erstellen wir nun auf Basis dieser Definition und unserer vorhandenen Attribute unsere Objektklasse myClubMember: objectclass ( 1.1.3.7.1 NAME 'myClubMember' SUP top STRUCTURAL DESC 'Objektklasse myClubMember aus schema localsite' MUST ( cn $ myCMNumber $ myCMDescription ) MAY ( myCMPhoto $ myCMVIP $ myCMcertificate ) )
Die Objektklasse myClubMember fügt nun unsere zuvor definierten Attribute zusammen. Das nicht zuvor definierte Attribut cn ist, wie wir wissen, ein Standardattribut und unserem LDAP bereits geläufig. Durch unsere Definition als STRUCTURAL können wir die Objektklasse myClubMember standalone nutzen, d.h., mit dem folgenden LDIF können wir also ein völlig neues Objekt im DIT erstellen, das allein auf dieser Objektklasse basiert. Bevor wir loslegen bitte an folgendes denken: Unser frisch erstelltes localsite.schema muß (als letzter Include-Eintrag) in die slapd.conf eingebunden werden, anschließend müssen wir unseren slapd restarten. Die ou=clubmember muss bei Verwendung des u.a. DNs natürlich bereits existieren, ebenso das Zertifikat in dem angegebenen Pfad: dn: cn=snoopy,ou=clubmember,dc=local,dc=site objectClass: myClubMember cn: snoopy myCMDescription: "Dieser Beagle ist Mitglied" myCMNumber: 1 myCMVIP: TRUE myCMcertificate;binary:< file:///usercerts/snoopyscert.der
Wäre die Objektklasse myClubMember vom Typ AUXILIARY, könnte sie nur wie z.B. posixAccount dazu dienen, ein bestehendes Objekt um zusätzliche Attribute zu erweitern. Ein Hinweis zum Attribut myCMcertificate, in dem wir das UserZertifikat abspeichern: Um ein Zertifikat innerhalb eines Objekts abspeichern zu können, müssen wir dem Attribut die Zusatzdefinition ;binary mit auf den Weg geben, und das Zertifikat selbst sollte im DER-Format vorliegen. Haben wir bereits ein entsprechendes User-Zertifikat im PEM-Format vorliegen (gemäß unseren Beispielen aus Abschnitt 3.4.5, »Eine Frage der Zertifizierung«), können wir es einfach per openssl in das entsprechende Format konvertieren, z.B.: #> openssl x509 -inform PEM -in newcert.pem \ -outform DER -out newcert.der
Andernfalls ernten wir beim Import des Userobjekts nur folgenden Fehler: additional info: myCMcertificate;binary: value #0 invalid per syntax
364
1198.book Seite 365 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
Die Kapabilitäten und Verfahren zum Auslesen des Zertifikat-Attributwertes obliegen natürlich der jeweiligen Client-Applikation. Eine andere, effektive Variante, Objektklassen zu konstruieren, besteht natürlich darin, diese von übergeordneten Objektklassen abzuleiten. Die Grundlagen dazu haben wir bereits im Abschnitt 1.7, »Nicht nach Schema F«, kennen gelernt. Im konkreten Fall könnten wir zum Beispiel eine eigenständige Objektklasse myPerson konstruieren. Für unser Beispiel leiten wir diese Objektklasse von der Objektklasse person (STRUCTURAL) ab, die ihrerseits von top (ABSTRACT) abgeleitet ist. Dadurch können wir direkt auf die in person bereits definierten Attribute zurückgreifen: objectclass ( 1.1.3.7.2 NAME 'myperson' DESC 'Objektklasse myPerson' SUP person MUST ( cn $ sn $ myCMNumber $ myCMDescription ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description $ myCMPhoto $ myCMVIP $ myCMcertificate ) )
3.9.4
Geht nicht – gibt’s nicht ...
So viel zu einfachen Ergänzungen der Standard-Schemas mit eigendefinierten Schemas. Was aber, wenn wir vor einer Aufgabe stehen, die auf den ersten Blick gar nicht umsetzbar scheint? Hier heißt es nicht die Flinte sonst wohin schmeißen, sondern erst mal überlegen und schauen, wie wir auf der Basis von Standard-Objektklassen unsere eigene Speziallösung umsetzen können. Wie schon im Abschnitt über das Overlay dynlist versprochen, schauen wir uns jetzt die Konversion einer statischen posixGroup in eine semidynamische Gruppe an. Als Beispiel nehmen wir wieder an, wir müssten eine Gruppe abbilden, die sowohl dynamische als auch statische Einträge von Mitgliedern führen soll, Vorgabe für das member-Attribut sei dieses mal jedoch das posixGroup-konfirme memberUID, wie es für Samba-Gruppen benötigt wird. So könnte z.B. ein »fester Stamm« von Mitgliedern in dieser Gruppe statisch enthalten sein, und andere könnten bei Bedarf einfach dynamisch per AttributÄnderung im Objekt (siehe Abschnitt 3.1.1, »Gruppentherapie«) hinzugefügt werden. Und im Gegensatz zu kernig klingenden, aber oft mit niedrigem Wahrheitsgehalt behafteten Werbesprüchen aus der TV-Box, frei nach dem Motto »Geht nicht, gibt’s nicht«, gilt dieses Motto in unserem Fall sehr wohl.
365
3.9
1198.book Seite 366 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Da wir idealerweise schon ein Schema unser eigen nennen können, definieren wir dort fix eine Gruppe, die wir – nur vom Aufbau(!) her – an posixGroup anlehnen, aber einige wichtige Änderungen vornehmen : objectclass (1.1.3.7.3 NAME 'myposixGroup' DESC 'myposixGroup' SUP top AUXILIARY MUST ( cn $ gidNumber ) MAY ( userPassword $ memberUid $ description ) )
Die wichtigste Änderung: Wir definieren unsere Gruppe myposixGroup als AUXILIARY (statt STRUCTURAL in der Original-posixGroup), da sonst Probleme mit der strukturellen Hierarchie in Verbindung mit groupOfURLs (STRUCTURAL) auftreten. Nachdem wir das dynlist-Overlay in unserer slapd-Konfiguration aktiviert haben, fügen wir das folgende Hybrid-Objekt in unseren DIT ein, wobei skiu und pparker bereits als statische Mitglieder der Gruppe angehören: dn: cn=dynposgroup,dc=local,dc=site objectClass: myposixGroup objectClass: groupOfURLs cn: dynposgroup gidNumber: 99999 memberUid: skiu memberUid: pparker memberURL: ldap:///dc=local,dc=site?memberUID?sub?(title=admin)
Das Einzige, was wir nun noch benötigen, ist ein zusätzliches memberUID-Attribut, das die dynamischen User mit sich führen müssen, damit es über die LDAPURL der dynamischen Liste zurückgegeben werden kann. Dazu können wir im einfachsten Fall eine neue, ergänzende Objektklasse erzeugen, die von posixAccount abgeleitet ist und nur das Attribut memberUID auf Ebene eines Userobjekts optional zur Verfügung stellt: objectclass (1.1.3.7.4 NAME 'myposixAccount' SUP posixAccount AUXILIARY DESC 'myposixAccount' MAY ( memberUid ))
Nachdem wir z.B. ckent und rdeckard noch um die erforderliche Objektklasse myposixAccount und die Attribute memberUID und title erweitert haben, sieht der Rückgabewert unseres posixGroup-Hybrids genauso aus, wie erwartet (die Kommentare sind nicht Teil der Ausgabe): #> ldapsearch -x cn=dynposgroup dn: cn=dynposgroup,dc=local,dc=site objectClass: myposixGroup objectClass: groupOfURLs
366
1198.book Seite 367 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
cn: dynposgroup gidNumber: 99999 memberUid: skiu # statisch memberUid: pparker # statisch memberUid: ckent # dynamisch memberUid: rdeckard # dynamisch memberURL: ldap:///dc=local,dc=site?memberUID?sub?(title=admin)
Die nachträgliche »Umrüstung« der User fällt nicht mehr ins Gewicht, wenn die User direkt über entsprechende Templates in der gewünschten Form angelegt werden (uid=memberUID). Anschließend kann der Hybrid genauso problemlos verwaltet werden wie eine normale, dynamische Gruppe. Die ACL-Auswertung muss in diesem Fall natürlich über entsprechende sets erfolgen (siehe Abschnitt 3.7.3), da memberUID allein nicht die erforderliche DN-Syntax mitbringt. Für alle Anwendungsfälle, in denen normale posixGroups ihren Dienst tun, kann dieser dynamische Ersatz eine sinnvolle Ergänzung sein. So weit, so gut. Das bisher gezeigte war natürlich nur ein sehr kleiner Bereich von dem, was sich auf der Basis von Standard-Objektklassen und -Attributen alles realisieren lässt. Bereits hier sollte sich aber schon unschwer erkennen lassen, welche Möglichkeiten uns zur Verfügung stehen. Fassen wir bis hierher kurz zusammen: Grundsätzlich ist bei der Erstellung/Einbindung eigener Attribute/Objekte/Schemas immer auf folgende Punkte zu achten: Attribute werden innerhalb eines Schemas vor den Objektklassen definiert. Vor Erstellung eines Attributs sollte immer erst überprüft werden, ob dieses gegebenenfalls nicht bereits existiert. Gutes Hilfsmittel hierfür: Schema-Discovery (siehe oben) per #> ldapsearch -x -s base -b "cn=subschema" \ "(objectclass=subschema)" + | less # oder grep <Suchbegriff>
oder über die GUI eines aktuellen LDAP-Browsers (siehe Abschnitt 4.7, »Auf den Schirm!«). Eigene Attribute und Objektklassen lassen sich von bestehenden Objekten ableiten und übernehmen ihre Eigenschaften bzw. Attribute. Sollen Attribute/Objektklassen von bestehenden Objekten für ein eigenes Schema abgeleitet werden, muss das Schema, das diese Objekte beinhaltet, vor dem eigenen Schema geladen werden. Objektklassen vom Typ AUXILIARY können dazu verwendet werden, bestehende Objekte zu erweitern, z.B.: Erweiterung von inetOrgPerson (STRUCTURAL) mit posixAccount (AUXILIARY).
367
3.9
1198.book Seite 368 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Eigene Objektklassen vom Typ STRUCTURAL können nur dann zu bestehenden Objekten hinzugefügt werden, wenn bereits eine übergeordnete Objektklasse Bestandteil des Objekts ist. Beispiel: Das Hinzufügen der Klasse inetOrgPerson zu einem Objekt, das bereits die Objektklassen person hat, ist möglich. Hinzufügen der Objektklasse account zu einem Objekt, das auf der Objektklasse inetOrgPerson basiert, ist nicht möglich. Damit würde versucht, eine zweite strukturelle Objektklassenhierarchie zu etablieren, die vererbungstechnisch nicht zu inetOrgPerson passt.
3.9.5
OID-Makros
Und noch etwas für Leute mit OID-»Allergie«: OID-Makros Im Prinzip handelt es sich nicht um Makros im herkömmlichen Sinn. Die Funktion ähnelt vielmehr einem namentlichen Alias, der für eine bestimmte OID gesetzt wird. Aufgerufen wird die Funktionalität über die Direktive objectIdentifier. Die Syntax sieht wie folgt aus: objectIdentifier { | [:<suffix>] }
Schauen wir uns dazu folgendes Beispiel an (die Kommentare dienen nur der Übersichtlichkeit und sind nicht Bestandteil der Definitionen): objectIdentifier myOID 1.1 objectIdentifier myLDAP myOID:3 # ergibt 1.1.3 für myLDAP –> nehme # und hänge .3 an objectIdentifier myAttributeType # ergibt 1.1.3.5 -> myLDAP (1.1.3) objectIdentifier myObjectClass # ergibt 1.1.3.7 -> myLDAP (1.1.3)
myOID (1.1) myLDAP:5 + .5 myLDAP:7 + .7
In der Praxis könnte das wie folgt aussehen (ohne Kommentar): attributetype ( myAttributeType:1 NAME 'myUniqueTESTName' # ergibt OID 1.1.3.5.1 für myAttributeType:1 DESC 'My unique TEST name in my organization' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
Der endgültige »Alias« für die OID von myUniqueTESTName beinhaltet also alle vorab getroffenen »Alias«-Definitionen, von myOID bis zu myAttributeName.
368
1198.book Seite 369 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
Wir entwickeln also eine Hierarchie aus OID-Aliasen, aus der wir letztlich allein per Textdefinition die gewünschte OID namentlich ableiten können. Hier noch einmal analog für eine Objektklasse (Kommentar dient nur dem Verständnis): objectclass ( myObjectClass:2 NAME 'myTESTPerson' # ergibt 1.1.3.7.2 DESC 'my TEST person' SUP top AUXILIARY MUST ( myUniqueTESTName $ myTESTdescription ) MAY ( myTESTPhoto ))
Die Verwendung dieser OID-Makros mag Geschmackssache sein. Die einen präferieren die eindeutige OID-, die anderen die Makro-Schreibweise. Welches Verfahren letztlich gewählt wird, hat keinen Einfluss auf die eigentliche Funktionalität der Attribut- oder Objektdefinitionen.
3.9.6
Rein Schematisch – Replikation der Schemas
Jetzt geht’s wie versprochen an die Schema-Modifikation und -Replikation, denn nun steht uns endlich unser eigenes Schema zum »Verbiegen« zur Verfügung. Und wie bereits oft genug, ausdrücklich und mit allen erdenklichen Gründen erwähnt: Modifikation an Standard-Schemas? Definitiv: NEIN! Testen können wir die Modifikations-Funktionalität zunächst an der Beschreibung des myCMNumber-Attributs aus unserem localsite.schema. Hierzu konvertieren wir als zwingende Voraussetzung natürlich wieder in die Online-Konfiguration. Um das Attribut (oder die Objektklasse) eines Schemas online zu ändern, müssen wir jedoch etwas differenzierter vorgehen, als wir es von einem einfachen ldapmodify eines »normalen« Objekts kennen. Um das zu verstehen, müssen wir zunächst das zugrunde liegende Schema betrachten (Ausgabelisting ist umbrochen). #> ldapsearch -xWD cn=config -b \ cn={3}localsite,cn=schema,cn=config
olcAttributeTypes -LLL
Enter LDAP Password: dn: cn={4}localsite,cn=schema,cn=config olcAttributeTypes: {0}( 1.1.3.5.1 NAME 'myCMNumber' DESC 'unique Number of ClubMember' SUP uidNumber ) olcAttributeTypes: {1}( 1.1.3.5.2 NAME 'myCMDescription' DESC 'Description of ClubMember' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) olcAttributeTypes: {2}( 1.1.3.5.3 NAME 'myCMPhoto' DESC 'JPEG-Photo of ClubMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 ) ...und hier folgt der Rest der olcAttributeTypes von unserem localsite-schema
369
3.9
1198.book Seite 370 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Wie wir anhand der kompletten Ausgabe unschwer erkennen können, besitzt unser Schema 5 olcAttributeTypes. Das übliche changetype: modify mit anschließendem replace: olcAttributeType im LDIF für genau das eine, gewünschte Attribut würde uns im schlimmsten Fall nur eines bescheren: ein »zerschossenes« Schema, da im Extremfall alle(!) olcAttributeTypes durch das eine mit der gewünschten Änderung überschrieben werden würden. Daher auch Finger weg von grafischen Tools für solche Operationen, sie können mit dieser speziellen Anforderung in der Regel (noch) nicht umgehen. Die einfachste und effektivste Vorgehensweise besteht daher darin, mit dem zuletzt benutzten ldapsearch-Filter alle Objekte des Typs olcAttributeTypes in ein LDIF zu extrahieren, das entsprechende Objekt anzupassen und das LDIF anschließend per ldapmodify wieder einzulesen. Zugegeben, im Ganzen etwas unökonomisch. Aber schließlich werkelt man auch nicht ständig an den Schemas herum, und auf diese Art lässt sich die Problematik sauber lösen. Zunächst erstellen wir auf dem Provider das LDIF per #> ldapsearch -xWD cn=config -b \ cn={4}localsite,cn=schema,cn=config \ olcAttributeTypes -LLL > localsite.ldif
und bearbeiten anschließend den gewünschten Eintrag (DESC ’unique Number of ClubMember NEU und frisch geaendert!’) im nächsten Listing, alle anderen lassen wir unverändert! Natürlich darf auch die Anpassung des Headers nicht vergessen werden (Zeilen sind umbrochen): dn: cn={4}localsite,cn=schema,cn=config changetype: modify replace: olcAttributeTypes olcAttributeTypes: {0}( 1.1.3.5.1 NAME 'myCMNumber' DESC 'unique Number of ClubMember NEU und frisch geaendert!' SUP uidNumber ) olcAttributeTypes: {1}( 1.1.3.5.2 NAME 'myCMDescription' DESC 'Description of ClubMember' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX ... usw.
Nun können wir unseren Consumer »from the scratch« mit der LDIF-Seed-Datei olcbase-consumer.ldif aus Abschnitt 3.2.10, »Replikation der Online-Konfiguration«, Variante 2 in der dort beschriebenen Vorgehensweise starten. Nach dem Initial Content Load vom Provider sollten – unter anderem – alle Schemas nebst unserem localsite-Schema auf dem Consumer gelandet sein. Im nächsten Schritt importieren wir das geänderte LDIF unseres localsite-Schemas auf dem Provider:
370
1198.book Seite 371 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
#> ldapmodify –xWD cn=config –f localsite.ldif
Nach erfolgreicher Änderung sollten wir im Log des Consumers folgende DebugMeldungen sehen (Zeilen zum Teil gekürzt), die die Replikation des modifizierten Schemas auf den Consumer zeigen: syncrepl_entry: rid=001 cn={4}localsite,cn=schema,cn=config slap_queue_csn: queing 0xb8072b08 20081124224430.487553Z#000000#000#000000 slap_graduate_commit_csn: removing 0xb806fbe8 20081124224430.487553Z#0000... syncrepl_entry: rid=001 be_modify (0) slap_queue_csn: queing 0xb8072b08 20081124224430.487553Z#000000#000#000000 slap_graduate_commit_csn: removing 0xb806fc18 20081124224430.487553Z#000... ...
An dieser Stelle noch einmal der wichtiger Hinweis: Bei Änderungen an den Attributen oder Objektklassen über grafische Tools (z.B. per JXplorer/ApacheDS) kann es aufgrund der Mehrdeutigkeit (siehe unten) der Modifikations-Operationen im vorgenannten Schema-Beispiel im schlimmsten Fall zu einem Segmentation-Fault kommen. Eine typische Abbruchmeldung des slapd im detaillierten Debug-Mode könnte in etwa folgendermaßen aussehen: olcAttributeTypes: value #0 olcAttributeTypes: Duplicate attributeType: "1.3.6.1.1.1.1.2" Segmentation fault
Aus diesem Grund sollten wir Modifikationen an der Online-Konfiguration – zumindest was Schemas betrifft – immer mit den Kommandozeilen-Tools vornehmen. Primäre Anwendung für die Schema-Replikation wäre z.B. das Hinzufügen kompletter, eigendefinierter Schemas zur Laufzeit oder das Hinzufügen, Ändern und Löschen bestimmter Attribute innerhalb des eigenen Schemas. Tipp: Eine effektive Möglichkeit, um vorhandene Schemas zu einem beliebigen Zeitpunkt der Online-Konfiguration hinzuzufügen, besteht in der Konvertierung per slapd/ slaptest, und zwar vom Ansatz her genau so, wie wir das Verfahren bereits kennen. Noch ein kleiner Hinweis: Zu den statischen Standard-Schemas liefert OpenLDAP im Unterordner ../schema die jeweiligen LDIF-Gegenparts gleich mit.
Nehmen wir an, wir würden nachträglich das samba(3).schema (wird in Verbindung mit Samba zur Verwaltung der Samba-Benutzeraccounts über OpenLDAP benötigt; dazu gleich mehr im Abschnitt »Meister der Domäne«) zur Laufzeit hinzufügen wollen, könnten wir wie folgt vorgehen: Wir erstellen eine abgespeckte slapd.conf.temp, die lediglich Include-Statements auf die entsprechenden Schema-Dateien beinhaltet (die Hierarchie ist in diesem
371
3.9
1198.book Seite 372 Donnerstag, 5. Februar 2009 3:02 15
3
OpenLDAP im Einsatz
Fall vererbungstechnisch notwendig; die alleinige Konvertierung des sambaSchemas würde zu Abhängigkeitsfehlern führen): Include Include Include Include Include
/etc/openldap/schema/core.schema /etc/openldap/schema/cosine.schema /etc/openldap/schema/nis.schema /etc/openldap/schema/inetorgperson.schema /etc/openldap/schema/samba(3).schema
Anschließend erstellen wir einen temporären Ordner, z.B. temp.d/, und starten die Konvertierung (Pfadangaben sind im folgenden Befehl zu ergänzen). Durch die Verwendung des slaptest-Befehls konvertieren wir offline und vermeiden es, mit einer gegebenenfalls im Hintergrund laufenden Instanz unseres slapd zu kollidieren: #> slaptest –f slapd.conf.temp –F temp.d/ –d 1
Nach Beendigung der Konvertierung schauen wir im temp.d/-Ordner nach der konvertierten Schema-Datei, die wir genau hier finden (die Backslashes dienen nur zur Maskierung der Sonderzeichen): ../temp.d/cn\=config/cn\=schema/cn\=\{4\}samba.ldif
Nachdem wir den Header des LDIFs (samba.ldif) wie folgt angepasst haben: Alter Header: dn: cn={4}samba objectClass: olcSchemaConfig cn: {4}samba
Neuer Header: dn: cn=samba,cn=schema,cn=config objectClass: olcSchemaConfig cn: samba
sind wir fast startklar, um das neue Schema während der Laufzeit zu importieren. Um den numerischen Wert in den geschweiften Klammern kümmert sich unser slapd automatisch, d.h. er hängt dieses Schema beim Import in der Reihenfolge an die bereits vorhandenen an. Zudem müssen die operational Attributes am Ende der Datei unbedingt gelöscht oder auskommentiert werden, da diese beim Import in den Konfigurationskontext neu erzeugt werden: # # # #
structuralObjectClass: olcSchemaConfig entryUUID: 646faad0-4ecb-102d-99b6-7386c59e41a2 creatorsName: cn=config ... usw.
372
1198.book Seite 373 Donnerstag, 5. Februar 2009 3:02 15
Selbst ist der Admin – das eigendefinierte Schema
Nachdem wir das LDIF in gewohnter Manier per ldapadd unserem config-Tree hinzugefügt haben: #> ldapadd -xWD cn=config -f samba.ldif
sollten uns folgende Debug-Meldungen auf dem Consumer belohnen. syncrepl_entry: rid=002 cn={4}samba,cn=schema,cn=config slap_queue_csn: queing 0xb80ac5b0 20081124233636.672321Z#000000#000#000000 ... syncrepl_entry: rid=001 be_add (0)
So – das war unser kleiner Exkurs in die Welt der Schemas. Und da wir gerade rein zufällig das Samba-Schema konvertiert haben: Scheint so, als würden wir das Ding ebenfalls rein zufällig im nächsten Kapitel schon gebrauchen können. Sein Name: Samba. Und sein Job ...
373
3.9
1198.book Seite 374 Donnerstag, 5. Februar 2009 3:02 15
1198.book Seite 375 Donnerstag, 5. Februar 2009 3:02 15
Bug for bug, feature for feature, we will implement the SMB(CIFS) protocol. Jeremy Allison, SambaXP 2006
4
OpenLDAP und Applikationen
4.1
Die Meister der Domäne: OpenLDAP und Samba
Der Spruch oben trifft es im Kern. Und jeder, der sich zwangsläufig tiefer mit den MS-Protokollen herumschlagen muss – wie das Samba-Team durch Reverse-Engineering (... und: ja, auch die »Offenlegungen« einiger Spezifikationen von der MS-Seite in letzter Zeit haben da nicht sonderlich viel geändert ...) weiß, das Jerry Allisons Spruch leider tödlicher Ernst sein muss, damit die XP- und VistaBüchsen auch unter Samba ihre gewohnt verbogene Umgebung zumindest größtenteils wiederfinden. Viele Open-Source-Entwickler sind bis heute gleichermaßen erschreckt und fasziniert zugleich über die Windows-Protokollwelt. Zum einen erschreckt darüber, dass so fehlerbehaftete Implementationen, von denen bisweilen nicht einmal mehr die ursprünglichen Entwickler alle Bugs kennen, bis heute gepatcht und durchgeschleift werden – es lebe die Kompatibilität zu Win 3.11. Andererseits fasziniert darüber, dass solche Dinge anscheinend trotz aller Fehler nahezu uneingeschränkt von einem Großteil der Anwender akzeptiert werden – solange mit genügend Eye-Candy von Instabilitäten und Designfehlern abgelenkt wird. Aber hieß es nicht schon im alten Rom: panem et circenses1 – und alles war gut? Oder nicht?
4.1.1
Die wunderbare Welt der MS-Protokolle
SMB – oder völlig BAF? Fakt ist: SMB steht nicht für Support Microsofts Business, auch wenn die Vermutung nahe liegen könnte. Der Protokollstandard wurde 1983 von IBM unter dem Begriff SMB (= Server Message Block) vorgestellt. Und was es mit BAF auf sich hat, lässt sich auch schnell erklären: SMB sollte ursprünglich BAF heißen, da BAF 1 lat. (frei übersetzt:) »Brot und Spiele«
375
1198.book Seite 376 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
für die Initialen eines seiner geistigen Urväter, Dr. Barry Alan Feigenbaum, steht. Der gute Mann war in den frühen 80ern für IBM in Florida tätig, als er die Grundsteine für die Entwicklung von SMB legte. Später überlegte er es sich dann doch anders und benannte SMB so, wie wir es nun letztlich kennen. Wer meint, dass BAF die Sache vielleicht besser beschrieben hätte, steht sicherlich nicht allein da. SMB war somit zwar eine Entwicklung von IBM, die man dann aber mit Microsoft gemeinsam weiter entwickelte. Eigentlich waren zwischenzeitig auch noch SCO und Apple beteiligt, aber eher für eine Schrecksekunde. Leider war zu jener Goldgräberzeit des Silicon Valley eine methodische Dokumentation der eigenen Arbeit bestenfalls eine nette Idee. In der Tat finden die Entwickler des SambaTeams bis heute Schalter und Optionen im SMB, die weder bei IBM noch Microsoft irgendjemand kennt. Oder aus guten Gründen nicht mehr kennen will. Es war für Bill Gates zu dieser Zeit natürlich unerträglich, dass eine Client/ServerArchitektur mit OS/2-Servern laufen musste, weil Microsoft noch kein funktionierendes Server-Betriebssystem zur Hand hatte. Also begann mit Hochdruck die Arbeit an Windows NT, der eine weitere Flut von Protokollerweiterungen des SMB folgte. Auch hier wurde mehr schlecht als recht dokumentiert, es wurden Entwicklungsideen und Konzepte, die nie produktionsreif wurden, mit in das Protokoll aufgenommen oder dort belassen, so dass die Reverse-Engineerer des Samba-Teams bis heute sehr viel Spaß haben. Außerdem blieb weiterhin das Problem der nicht vorhandenen Routing–Fähigkeit für das Netzwerkmodell von Microsoft bestehen. Auch hier musste etwas geschehen – und das führte zu … CIFS – Das Common? Internet? FileSystem? Das 1996 von Microsoft eingeführte Common Internet File System erheitert uns bis heute allein schon aufgrund seiner Namensgebung, denn 왘 es ist Microsoft-spezifisch, und daher bis heute weder ein komplett dokumentierter oder gar fertiger, allgemeingültiger (engl. common) Standard, 왘 was es in direkter Verbindung mit dem Internet zu tun haben soll, weiß Big Bill allein; 왘 es ist im eigentlichen Sinne gar kein File-System, sondern ein Protokoll. Nun denn, shiet drauf, Internet klingt natürlich immer verdammt gut, auch wenn damit gerade mal die Routingfähigkeit eines Protokolls beschrieben wird. Der Begriff Internet in der CIFS-Namensgebung resultierte wohl am ehesten aus dem Bestreben von Microsoft, ihre Defizite aus den Boom-Jahren des Internets wieder wettzumachen.
376
1198.book Seite 377 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
Ursprünglich sollte es – schon eher passend – Direct Hosted TCP heißen und entspricht fast in allen Details SMB. Seine Crux war die Einstellung von NetBIOS mit all seinen Mängeln und die Etablierung von SMB als selbstständigem Anwendungsprotokoll über Port 445, direkt über TCP/IP. Die Namensauflösung über WINS wurde (Gott sei Dank) aufgegeben und durch DNS ersetzt bzw. NBT (NetBIOS über TCP/IP), wenn DNS nicht verfügbar ist. Mit der Namensauflösung per DNS war zumindest ein weiteres Feature vorhanden, das eine gewisse »Internettauglichkeit« attestiert. CIFS funktioniert, vereinfacht ausgedrückt, als eine Erweiterung für SMB, die es über TCP/IP routingfähig macht, also eine Kommunikation über routingfähige Netze ermöglicht. Der Begriff File System für CIFS ist (wie bereits weiter oben angeführt) gelinde ausgedrückt »etwas neben der Spur«, denn genau genommen ist CIFS kein Dateisystem im herkömmlichen Sinne, sondern nur die Microsoft-spezifische Idee und Implementation einer Datei-/Ressourcenverwaltung über ein Netzwerk. So weit die MS-Theorie. Samba Die von Andrew Tridgell und seinem Team entwickelte und seit vielen Jahren sehr populäre Samba-Suite bietet Windows-Nutzern die Alternative, Linux-Server als kostenlosen Open-Source-»Ersatz« für Windows-Fileserver zu verwenden. In früheren Versionen (2.x) beschränkte sich der Einsatz primär auf die Abbildung von Workgroup-Servern. Mittlerweile ist Samba in Version 3.x in Verbindung mit OpenLDAP imstande, die Funktionalitäten von Windows NT-Domain Controllern eingeschränkt nachzuahmen, aber auch nicht mehr. Samba 4 schlägt ein ganz neues Kapitel auf, einen echten »ADS« DC, der von den Win-Clients auch als solcher erkannt wird. Dazu später mehr in diesem Abschnitt. Fakt ist: der über Ewigkeiten geflickte, gepatchte und zu Lebzeiten selbst von einigen Samba-Entwicklern immer zu Recht als Hack bezeichnete Samba 3 ist längst am Ende seiner Leistungsfähigkeit angelangt. Auch die zahllosen Nachbesserungen und Erweiterungen können nicht verbergen, dass das Grundkonzept von Samba 3 völlig überaltert ist: Einige der Kernfunktionalitäten von Samba 3 basieren zum Teil immer noch auf Codestrukturen aus dem Jahr 1992, und trotz aller Nachbesserungen konnten bis heute kaum alle smb-Messages geparst werden. Gerade im Bereich der Remote Procedure Calls (RPCs) – die einen großen Anteil der MS-Server-Funktionalität ausmachen, wie z.B. Domänen- oder Druckdienste, wurde heftigst improvisiert. Und wer denkt, dass soll Kritik an den Samba-Entwicklern sein, liegt voll daneben, denn das genaue Gegenteil ist der Fall. Jeder, der einmal in seinem Leben Reverse-Engineering betrieben hat, weiß, welche Spitzenarbeit die Samba-Truppe leistet.
377
4.1
1198.book Seite 378 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Seit Mitte 2008 wird Version 3.2 in den meisten Distributionen eingesetzt. Diese Version enthält noch mehr Backports aus der komplett neu entwickelten Version 4 als die vormalige Version 3.0.x. Leider, muss man sagen, denn Version 4 dient traurigerweise schon seit Längerem eher als Kiste mit Tuningteilen für Samba 3. Der Grund dahinter liegt auf der Hand. Einige kommerzielle Dienstleister, die zum Teil auch die Samba-Entwickler stellen und auf ihrer Lohnliste führen, haben ihren Support vornehmlich auf Samba 3 aufgebaut. Was prinzipiell nicht verkehrt ist – nur wird hier schon viel zu lange das eben beschriebene Verfahren praktiziert, den ausgelaugten 3er-Gaul bis zum letzten Support-Cent auszureizen und mit etlichen Samba-4-Backports aufzumotzen, insbesondere im WinbindBereich; eine der zahllosen Pseudo-ADS-Anbindungs-Sackgassen. Und dies eben leider auf Kosten der Entwicklungsdauer von Samba 4. Die Kopplung von Samba 3 an OpenLDAP und Kerberos, die zwar hinreichend funktioniert, aber letztlich definitiv nicht als eigenständiger ADS-DC fungieren (und vor allem so bezeichnet werden) kann, macht bis heute niemanden wirklich glücklich, der einen vollständigen, funktionellen Ersatz für einen Windows-2KXServer benötigt. Besonders niedlich sind insbesondere jene Spezialisten, die das Samba 3/OpenLDAP/Kerberos-Dreigestirn bis heute als vollwertigen ADS-Ersatz anpreisen. Nun ja, vielleicht liegt es auch einfach nur – wie so oft in diesem Business – in der mit Sicherheit völlig flexiblen Interpretierbarkeit des Begriffes Ersatz selbst. Samba 4 geht einen anderen, besseren Weg: Es wurde analysiert, was benötigt wird, um einen Active Directory DC so nachzubilden, dass er von den WindowsWorkstations auch als genau solcher erkannt – und vor allem genutzt werden kann. Die notwendigen Schritte waren schnell klar, denn es wurden genau drei Komponenten benötigt, die in der richtigen Art und Weise miteinander verzahnt werden müssen: Samba, ein LDAP-kompatibler Verzeichnisdienst (zunächst über die Samba-interne LDAP-DB) und Kerberos. Nach den ersten TP (Technical Previews) erkannten allerdings auch die Samba-Entwickler die zwingende Notwendigkeit, einen standardisierten LDAP-Server (im konkreten Fall OpenLDAP bzw. Fedora DS) optional als Datenbank-Backend einzubinden (der Begriff Backend sei uns an dieser Stelle verziehen, aber er wird in der Samba 4 –Terminologie in diesem Kontext verwendet). Und diese Variante werden wir im Zusammenspiel Samba 4 und OpenLDAP im Folgenden ebenfalls vorstellen. Zunächst werfen wir jedoch ein Blick auf Samba 3 mit OpenLDAP. Oft heißt es ja, Totgesagte leben länger. Wir lassen uns überraschen – und hoffen auf ein baldiges Release der V4.
378
1198.book Seite 379 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
4.1.2
Samba 3 mit OpenLDAP einsetzen
Wir wollen zunächst erreichen, dass wir die Accounts der Windows-Benutzer auf unserem Samba-DC (Domain Controller) bzw. PDC (Primary Domain Controller nach NT4-Terminologie) direkt per LDAP pflegen können. Im zweiten Schritt erstellen wir eine fehlertolerante Konfiguration: Dabei ist unser ldapmaster – und Samba PDC – redundant mit unserem ldapslave verbunden, der den Samba BDC (Backup Domain Controller) beherbergt. Zur Abrundung verfeinern wir das Ganze noch mit einer Prise TLS. Und wer nach dem Hauptgang immer noch Hunger hat, der erhält im nächsten Abschnitt als Nachtisch ein Single-Sign-On-Dessert aus LDAP, Samba und einem kräftigen Schuss Kerberos. Aber nun erst einmal zu den Basics. Nach der Installation der Samba-Pakete (siehe Anhang) binden wir die Dienste nmbd und smbd in die gewünschten bzw. vorgegebenen Run-Level ein (bei Debian nach erfolgter Installation der Pakete bereits geschehen). Der nmbd(8) übernimmt den Part des NetBIOS-Name-Servers und dient zur Auflösung von NetBIOS-Namen über TCP/IP. Der eigentliche Samba-Daemon ist der smbd(8), der die SMB/CIFS-Fileservices zur Verfügung stellt. Den ebenfalls zum Samba-Paket gehörenden winbindd(8)-Daemon werden wir im Folgenden im Rahmen der LDAP-Kopplung per ldapsam:editposix behandeln. Er ist für die Umsetzung von Windows SIDs (Security IDentifiern) auf Linux-UIDs bzw. -GIDs zuständig. Wer Samba unbedingt als Member-Server einer ADSDomäne betreiben will (es findet hierbei keine Replikation der LDAP-DB statt, nur ein ID-Mapping per winbind), ist leider ebenfalls auf diesen Vertreter angewiesen. Vorab noch einmal etwas zum Rahmen dieses Abschnitts: Samba ist ein derart umfassendes Produkt, so dass wir nur schwerlich mehr als eine kurze Einführung geben können. Zweifler mögen sich kurz per #> testparm --show-all-parameters
von der Mannigfaltigkeit der möglichen Konfigurationsoptionen überzeugen. Wir weisen auch nochmals darauf hin, dass wir die Bezeichner DC/PDC bzw. BDC unter Vorbehalt verwenden. Die Verwendung dieser Bezeichner impliziert definitiv nicht, dass Samba die Fähigkeiten eines Domain Controllers unter Windows NT, 2000, 2003 oder gar 2008 komplett abbilden kann. Eine recht deutliche Ansage hierzu ist im deutschsprachigen Samba-HowTo nachzulesen. Jedem Samba-Interessierten sei ohnehin vorab auf jeden Fall schon einmal das Studium des Official Samba HowTo sowie Using Samba ans Herz gelegt, in dem umfassende Hintergrundinformationen und Beispielkonfigurationen zu finden
379
4.1
1198.book Seite 380 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
sind. Beides ist unter www.samba.org zu finden. Deutsche Übersetzungen zu Samba finden sich unter http://gertranssmb3.berlios.de/.
4.1.3
Grundlegendes Setup: ldapmaster als PDC
Das Konfigurations-Herzstück unseres Samba liegt üblicherweise unter /etc/ samba, in der Datei smb.conf, von der wir gleich zu Beginn ein Backup erstellen. Alle dort nicht gesetzten Optionen werden mit ihren Standardeinstellungen verwendet. Einen Überblick über alle verfügbaren Optionen und ihre momentanen Einstellungen verschafft testparm –v, weitere Hilfe liefert smb.conf(5). Um nun unseren ldapmaster als (P)DC einzurichten, setzen wir folgende (LDAP-) relevanten Direktiven in der smb.conf (die Kommentare dienen nur der Beschreibung und sind nicht Teil der Datei): [global] workgroup = LOCAL # Domain-Name / Workgroup netbios name = ldapmaster # default=Hostname domain logons = yes # PDC-relevant domain master = yes # PDC-relevant local master = yes # PDC-relevant preferred master = yes # PDC-relevant os level = 65 # PDC-relevant ### ab hier: ldap – Settings ### passdb backend = ldapsam:ldap://ldapmaster.local.site # LDAP ldap admin dn = cn=ldapadmin,dc=local,dc=site # LDAP ldap suffix = dc=local,dc=site # LDAP ldap passwd sync = Yes # LDAP # ldap machine suffix = ou=computers # ldap User suffix = ou=users # ldap Group Suffix = ou=groups ldap ssl = off # LDAP idmap backend = ldap:ldap://ldapmaster.local.site idmap uid = 10000-20000 idmap gid = 10000-20000 [samba] path=/samba readonly=no
Und nun ein paar kurze Erläuterungen zu den wichtigsten Direktiven: Da unsere Maschine als PDC konfiguriert ist, wird mit Hilfe des angegebenen workgroup-Parameters automatisch eine eindeutige Netzwerk-SID für den von uns gewählten Domänennamen im DIT generiert. Alternativ lässt sich diese auch manuell auf der Konsole per
380
1198.book Seite 381 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
#> net getlocalsid
oder etwas ausführlicher mit #> net rpc info
auslesen. Sicherheitshalber können wir per testparm –v | grep prüfen, ob die Settings security = user (in dieser Standardeinstellung erfolgt die Authentifizierung über die Kombination Benutzername/Passwort) und encrypt passwords = yes gesetzt sind, was default der Fall sein sollte. Der optionale netbios name legt den selbigen für unseren Domain-Master-Browser fest. Lokale Master-Browser, wie später z.B. unser BDC, beziehen von ihm eine Kopie der Browse List. Als passdb backend wird statt der standardmäßig verwendeten Textdatei /etc/ samba/smbpasswd (in ihrer Funktion etwa vergleichbar mit der /etc/passwd und /etc/shadow) der Parameter ldapsam angegeben. Durch die Angabe der LDAPURL (es sollte immer der FQHN angegeben werden, da sonst später Fehler bei der Verwendung mit TLS auftreten können) zeigen wir auf den/die Host(s) mit der LDAP-Datenbank, die Samba anstelle der Textdatei smbpasswd (5) – nicht zu verwechseln mit der gleichnamigen Binary – verwenden soll. Die Direktiven domain logons = yes, domain master = yes, local master = yes und preferred master = yes sorgen dafür, dass Samba auf unserem ldap-
master als PDC arbeitet. Auf dem BDC muss zumindest die Direktive domain master unbedingt auf no und der os level – siehe nächster Punkt – auf einen niedrigeren Wert gesetzt werden. Als os-level kann für einen PDC der Wert von 65 gewählt werden, damit hat er beim Browsing-Wettbewerb innerhalb eines MSNetzes in jedem Fall die Nase vorn. Allerdings kann dieser Wert auch dazu führen, dass unser Samba bereits existierende MS-Server (W2K3: default-OS-Level 32) locker »niederbrüllt« und den Masterbrowser-Wettbewerb gewinnt, obwohl ihm diese Rolle gar nicht zugedacht ist. Okay, wir werden uns spätestens dann an die Tatsache erinnern, wenn der Mob wütender XP-User, die sich nicht einloggen können, gegen die Tür unseres Admin-Büros hämmert, nachdem wir unseren Samba auf das ahnungslose Rudel W2Kx-Server mit viel zu hohem OS-Level losgelassen haben ... Fazit: Daher sollte in Netzwerktopologien mit bereits existierenden MS-Servern dieser Parameter immer mit Bedacht gewählt werden; eher zu niedrig. Der Samba-BDC sollte zudem immer einen niedrigeren os-level-Wert als der SambaPDC haben. Die logon-Parameter dienen zur Festlegung pfadspezifischer Einstellungen bei der Anmeldung und stellen in Verbindung mit der domain logons = yes-Direktive den für einen PDC erforderlichen NETLOGON-Service zur Verfügung. Eben-
381
4.1
1198.book Seite 382 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
falls sollte eine Netlogon-Freigabe in der smb.conf existieren. In dieser Freigabe (Share) würden z.B. Login-Skripte und Richtliniendateien (Policy-Files) hinterlegt. Ergänzt wird dies meist noch durch eine profile-Share, in dem die Benutzerprofile netzwerkweit hinterlegt werden. Die von uns gesetzten ldap *-Parameter legen unter anderem Folgendes fest: 왘 den Verwaltungsaccount ldap admin dn. Wir haben der Einfachheit halber unseren bestehenden Account cn=ldapadmin genommen, alternativ kann auch jederzeit ein spezieller Account mit expliziten Zugriffberechtigungen für diese Funktionalität verwendet werden, z.B. cn=samba-admin. Auf jeden Fall muss das Passwort des gewählten Administrator-DNs per #> smbpasswd –w in der Datei secrets.tdb hinterlegt werden. Die korrekte Rückmeldung sollte in unserem Fall (cn=ldapadmin) lauten: Setting stored password for "cn=ldapadmin,dc=local,dc=site" in secrets.tdb
왘 ldap passwd sync legt fest, ob und wie Samba das LDAP-Passwort des jeweiligen Accounts – bei einer Passwortänderung auf der Samba-Seite- mit dem Hash-Wert des sambaLMPassword synchronisiert. 왘 Die idmap* Statements dienen dem Mapping von Windows SIDs und Linux UIDs/GIDs. 왘 Die optionalen Parameter ldap (group/user/machine) suffix erlauben die Festlegung bestimmter Ordner innerhalb unseres DIT, in denen die SambaUser, Gruppen oder Maschinen-Accounts standardmäßig angelegt werden. Falls diese Parameter nicht angegeben werden, wird alles unterhalb des in ldap suffix angegebenen Parameters angelegt. Bei sehr großen Installationen mit vielen Accounts sollten diese separaten Unterordner aus Performancegründen stets Verwendung finden. Gleichfalls wird die Übersicht innerhalb des DIT verbessert, und die ACLs können effektiver gestaltet werden. Falls in den Settings der smb.conf der Wert obey pam restrictions = yes
gesetzt sein sollte (prüfen per testparm –v | grep obey), sollte dieser auf No umgestellt werden, da es sonst zu Fehlern beim Anmeldevorgang kommen kann. Über die Share-Sektion [samba] definieren wir eine einfache Freigabe, deren physikalischer Pfad natürlich vorhanden sein sollte. Bevor wir nun das OpenLDAP-Samba-Konstrukt einem ersten Funktionstest unterziehen können, müssen wir OpenLDAP auf jeden Fall noch das entsprechende Schema mit auf den Weg geben, damit die für Samba erforderlichen Objekte und Attribute zur Verfügung stehen. Der Name des Schemas lautet übli-
382
1198.book Seite 383 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
cherweise samba3.schema (oder auch samba.schema). Wir binden es in bekannter Weise hinter der letzten Schema-Direktive unserer slapd.conf ein: include
Falls sich die Schemadatei nicht unterhalb des Schema-Ordners befindet, hilft ein locate samba.schema bzw. samba3.schema, um die Datei zu finden. Im Tarball liegt die Datei üblicherweise unterhalb des Ordners ~/examples/LDAP/. Bei Debian findet sich das gepackte Schema z.B. unter /usr/share/doc/samba-doc/ examples/LDAP/samba.schema.gz. Die Datei sollte aus Gründen der Übersichtlichkeit im selben Schema-Ordner liegen wie die anderen verwendeten Schemadateien. Jetzt starten wir sowohl ldap als auch smbd und nmbd. Nach dem Start der Services müsste uns nmap die zusätzlichen Ports 139 (NetBIOS) und 445 (MicrosoftDirectory-Services) zeigen, über die die Kommunikation mit den Clients erfolgt. In der Log-Datei /var/log/samba/log.nmbd sollten wir nun folgende Meldungen finden: „Samba is now a logon server for workgroup LOCAL on subnet 192.168.198.11” „Samba server LDAPMASTER is now a domain master browser for workgroup LOCAL on subnet 192.168.198.11” „Samba server LDAPMASTER is now a local master browser for workgroup LOCAL on subnet 192.168.198.11”
Danach kann – und sollte – noch die Log-Datei log.smbd im gleichen Log-Ordner auf etwaige Fehler geprüft werden. Um den Detailgrad zu erhöhen, können wir in der smb.conf den Parameter log level = setzen, wobei n für numerische Integer-Werte, angefangen bei 0, steht. Ungleich zu OpenLDAP steht hier ein höherer Wert einfach für einen höheren Detailgrad. Zusätzlich können selektiv debug classes angegeben werden. Mehr Infos dazu liefert smb.conf(5). #> ldapsearch -x sambaDomainName=*
sollte uns nun das frisch generierte Domänenobjekt im DIT zeigen: dn: sambaDomainName=LOCAL,dc=local,dc=site sambaDomainName: LOCAL sambaSID: S-1-5-21-482047378-3892580850-923572024 ... usw.
Mit dem Samba Client-Tool smbclient können wir uns auf der Konsole die aktuell vorhandenen Freigaben unseres Samba-Servers anzeigen lassen. Die Passworteingabe kann für einen anonymen Zugriff einfach mit [Enter] bestätigt werden: #> smbclient -L localhost Anonymous login successful Domain=[LOCAL] OS=[Unix] Server=[Samba 3.2.3]
383
4.1
1198.book Seite 384 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Sharename Type Comment -----------------samba Disk IPC$ IPC IPC Service (Samba 3.2.3) Anonymous login successful Domain=[LOCAL] OS=[Unix] Server=[Samba 3.2.3] Server Comment --------------LDAPMASTER Samba 3.2.3 Workgroup Master --------------LOCAL LDAPMASTER
Der Befehl testparm sollte Server role: ROLE_DOMAIN_PDC
als korrekt definierte Rolle unseres PDC ausspucken. Damit wäre das grundlegende Setup unseres DC vorerst abgeschlossen, und der NetBIOS-Name ldapmaster sollte beim Durchforsten des Netzwerks erscheinen. Ein Rechtsklick auf den Karteireiter »Eigenschaften« sollte ihn auf einem Windows XP-Arbeitsplatz als »NT 4.9-Primär«-Server ausweisen. So weit, so gut. Nur bringt uns das Setup unseres Samba-PDC bisher noch nicht wirklich etwas, denn um die Client-Funktionalität testen zu können, müssen wir entweder neue Samba-Benutzerkonten anlegen oder unsere bereits bestehenden Accounts um Samba-Attribute erweitern. Dazu existieren – wie so oft im Land des Pinguins – etliche Möglichkeiten, von denen (fast) jede bestimmte Vorzüge hat.
4.1.4
Tools zur User-Verwaltung
pdbedit Die einfachste Variante, um einen bestehenden Benutzeraccount manuell um die erforderlichen Samba-Attribute zu erweitern, bietet das Tool pdbedit, das Bestandteil der Samba-Suite ist. Mit #> pdbedit –a –u <username>
werden dem angegebenen Account nach Eingabe des Samba-Passworts (das nicht identisch mit dem Linux-Passwort sein muss, mit ldap passwd sync = yes wird es jedoch bei der nächsten Samba-seitigen Änderung gesynct) die erforderlichen Samba-Attribute zugewiesen. Durch die Anbindung per ldapsam an unsere LDAP-DB werden alle neu gesetzten Attribute des Userobjekts direkt im DIT
384
1198.book Seite 385 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
gespeichert. Der LDAP-Account unseres Users ckent sieht daher nach der Erweiterung per pdbedit wie folgt aus (Listing gekürzt): dn: uid=ckent,ou=verkauf,dc=local,dc=site objectClass: posixAccount objectClass: inetOrgPerson objectClass: sambaSamAccount uid: ckent ... sambaSID: S-1-5-21-482047378-3892580850-923572024-1004 displayName: Clark Kent sambaNTPassword: F0873F3268072C7B1150B15670291137 sambaPasswordHistory: 000000000000000000000000000000000000000000 (...) sambaPwdLastSet: 1227607077 sambaAcctFlags: [U ]
pdbedit bietet natürlich noch viele weitere nützliche Optionen, wie z.B. das Auflisten existierender Samba-User (-Lv), Modifizieren bestehender Samba-Attribute wie Profilpfad oder Laufwerks-Mapping. Als einfaches Beispiel sei hier das Setzen eines Profilpfades für Server-gespeicherte User-Profile angeführt. Hierfür würden wir auf unserem PDC einen entsprechenden Profilpfad mit den entsprechenden Berechtigungen benötigen, z.B. \\ldapmaster\samba\profiles. Setzen wir nun beim Erweitern eines LDAP-Userobjekts (hier skiu) per pdbedit den zusätzlichen Parameter: #> pdbedit –a –u user \ --profile="\\\ldapmaster\samba\profiles\skiu"
würde das Profil unserer kleinen Susie nach erfolgreichem Domain-Join und dem Ende der nächsten Session serverseitig gespeichert. Arbeiten wir später mit den srvtools, kann der entsprechende Pfad beim Anlegen eines Users direkt mit angegeben werden. Über pdbedit –x <user> können wir (in der smb.conf-Standard-Einstellung ldap delete dn = no) die samba-spezifischen Attribute unserer Userobjekte wieder
löschen. Eine Options-Übersicht liefert pdbedit --help, ausführliche Informationen die zugehörige Manpage (pdbedit (8)). smbldap-tools Eine weitere Variante zur OpenLDAP/Samba-Benutzerverwaltung bieten die smbldap-tools. Ursprünglich wurde die Perl-Skript-Sammlung von der Firma IDEALX (www.idealx.org) entwickelt, nun werden sie von Jerome Tournier weiter gepflegt (www.iallanis.info oder https://gna.org/projects/smbldap-tools/ ). Das Paket kann bei Debian über die Repositories in der Version 0.9.4 bezogen wer-
385
4.1
1198.book Seite 386 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
den, ebenso bei SUSE, allerdings dort in der aktuellen Version, die sich zum Zeitpunkt der Erstellung dieses Buches auf dem Versionsstand 0.9.5 befindet. Da die smbldap-tools umfangreiche Konfigurationsoptionen enthalten, verweisen wir an diesem Punkt auf die zugehörigen Dokumentationen und Beispiele. Alternativ kann man sich auch mit perldoc eine Kurzbeschreibung des jeweiligen Skripts mit allen Optionen im Manpage-Stil aufrufen. Die Einbindung der smbldap-tools gestaltet sich recht einfach. Wollen wir z.B. die Tools vorrangig manuell einsetzen, benötigen wir in der Regel nur einen Eintrag in der globalen Sektion der smb.conf, der sich um die automatische Erstellung eines Maschinen-Accounts beim Domain-Join selbiger kümmert: add machine script = /etc/smbldap-tools/smbldap-useradd -t 0 -w "%u"
Wollen wir jedoch die srvtools von Microsoft als Verwaltungswerkzeug für die Samba-Benutzer- und Gruppenaccounts abwickeln, stehen uns zwei Varianten zur Verfügung: die Integration der smbldap-tools oder die Anwendung von ldapsam:editposix, wobei Letzteres den weitaus geringeren Aufwand bereitet, und zudem integraler Bestandteil von Samba ist, was einen gewaltigen Vorteil darstellt. Zunächst zu den smbldap-tools: Für die Anwendung in Verbindung mit den MSsrvtools müssen wir die smbldap-tools in der nachfolgend beschriebenen Art in unsere smb.conf einfügen. Die smbldap-Skripte können selbstverständlich auch komplett »standalone« (ohne irgendeine Integration in die smb.conf) auf der Konsole verwendet werden, oder als Basis für eigen-entwickelte Administrationstools dienen. Nach der Installation der Pakete befinden sich die smbldap-*Perl-Skripte unter / usr/sbin, ebenso sollte der Ordner /etc/smbldap-tools/ bereits vorhanden sein. Zunächst müssen wir ein paar kleinere Anpassungen an unserer smb.conf vornehmen, die die Container für User, Gruppen und Maschinen betreffen. Mit Hilfe dieser Container erzeugt der Befehl smbldap-populate später eine NT4-ähnliche Baumstruktur. Hierfür entfernen wir einfach die Kommentarzeichen vor den folgenden Zeilen: ldap machine suffix = ou=computers ldap user suffix = ou=users ldap group suffix = ou=groups
Danach tragen wir mit Hilfe des configure-Skripts (/usr/share/doc/packages/ smbldap-tools/configure.pl bei SUSE) die Parameter in der zentralen smbldapKonfigurationsdatei smbldap.conf ein, die für unser Setup Verwendung finden
386
1198.book Seite 387 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
sollen. Viele Einstellungen werden direkt aus der smb.conf ausgelesen und können daher meist in der vorgeschlagenen Form übernommen werden, eine korrekt konfigurierte smb.conf vorausgesetzt. Relevant sind vorrangig der Ort der Samba-Konfigurationsdatei (/etc/samba/smb.conf), der Ablage-Ordner für die smbldap-Skripte (/usr/sbin/) und weitere Parameter, wie z.B. der NetBIOS-Name unseres PDC. Weiterhin muss das korrekte Passwort für unseren ldapadmin-DN angegeben werden. Die Konfiguration für einen optionalen LDAP-Slave wird gleich mit abgefragt, kann aber später auch noch komplettiert werden. Die Einstellung für das TLS-Setup belassen wir zunächst auf »0« (deaktiviert), die verschlüsselungsrelevanten Direktiven sollten erst nach Sicherstellung der Basisfunktionalität aktiviert werden. Hierfür setzen wir später folgende Direktiven: ldapTLS="1" verify="allow" cafile="" clientcert="" clientkey=""
wodurch alle smbldap-tool-Operationen TLS-verschlüsselt durchgeführt werden. Zurück zum configure-Skript: Nach Abschluss des Setups sollte eine Meldung über erfolgreiche Konfiguration der Datei smbldap.conf erscheinen, und dass die alten *.conf-Dateien gesichert wurden. Der binddn und die zugehörigen credentials für die Konnektivität mit unserem LDAP finden sich nach erfolgreichem Setup in der Datei smbldap_bind.conf. Im nächsten Schritt kümmern wir uns um die Einbindung der smbldap-Skripte in unsere smb.conf – zwingende Voraussetzung, um die Domänenbenutzer mit den MS-Tools administrieren zu können. Beispielkonfigurationen hierzu finden sich ebenfalls im Unterordner ../doc der smbldap-Sourcen: # Integration der smbldap–tools ([global]-Sektion smb.conf) add user script = /usr/sbin/smbldap-useradd -m "%u" delete user script = /usr/sbin/smbldap-userdel "%u" add machine script = /usr/sbin/smbldap-useradd -t 0 -w "%u" add group script = /usr/sbin/smbldap-groupadd -p "%g" delete group script = /usr/sbin/smbldap-groupdel "%g" add user to group script = /usr/sbin/smbldap-groupmod -m "%u" "%g" delete user from group script = /usr/sbin/smbldap-groupmod -x "%u" "%g" set primary group script = /usr/sbin/smbldap-usermod -g "%g" "%u"
Um die MS-srvtools nutzen zu können, müssen wir im nächsten Schritt unseren DIT mit MS-kompatiblen (posix-)Gruppen und Usern bevölkern. Hierzu dient das Skript smbldap-populate, das ohne weitere Parameter aufgerufen wird.
387
4.1
1198.book Seite 388 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Da es sich bei den smbldap-tools wie bereits erwähnt um perl-Skripte handelt, werden zur Interaktion mit unserem LDAP zusätzlich die Pakete z.B. perl-ldap, perl-ldap-ssl, perl-Unicode-Map8 und einige andere benötigt (siehe Anhang). Wir können etwaige fehlende Perl-Module auch relativ elegant direkt auf der Kommandozeile über cpan(1) oder cpanp(1), die üblicherweise Bestandteile des Perl-Basispaketes sind, nachinstallieren. Nach dem relativ selbsterklärenden und zum großen Teil automatisierten Setup beim ersten Aufruf von cpan kann z.B. das fehlende Modul Unicode::MapUTF8 durch den Aufruf von: # cpan> install Unicode::MapUTF8
am cpan-Prompt installiert werden. Der Vorteil: cpan kümmert sich um alle notwendigen Abhängigkeiten weiterer, gegebenenfalls erforderlicher Module. Voraussetzung für dieses Prozedere sind natürlich die Pakete gcc und make. Anschließend sollte das smbldap-populate-Skript problemlos seinen Dienst verrichten und die entsprechende Ordnerstruktur erzeugen. Am Ende des SkriptDurchlaufs wird noch das Passwort für den Administrator-Account (root) gesetzt, der z.B. benötigt wird, um Maschinen der Domäne hinzuzufügen. Der smbldapAdministrator-Account root kann auch im Nachhinein z.B. in »Administrator« umbenannt werden, um Verwechslungen mit dem root-Account des Systems zu vermeiden. Dabei aber nicht vergessen, den Account auch in der Mitgliedschaft der Gruppen »Administrators« und »Domain Admins« anzupassen bzw. hinzuzufügen. Mit einem einfachen Test überprüfen wir nun die Funktion eines der Skripte, indem wir einen komplett neuen User mit der uid=testuser anlegen: #> smbldap-useradd –a –P testuser
Der Parameter -a legt einen neuen User unterhalb der ou=users an, -P erwartet direkt die Angabe eines Passworts für den neuen Account. Alle weiteren Einstellungen werden entsprechend der in smbldap.conf eingetragenen Parameter gesetzt. Nach Bestätigung mit [Enter] wird das neue Passwort für diesen User zwei Mal abgefragt, bevor der Benutzer mit den erforderlichen Samba-Attributen im DIT angelegt wird. ldapsam:editposix Die smbldap-tools liefern zweifelsohne ein solide funktionierendes UnterbauKonstrukt zur Verwaltung der Samba-User- und Gruppenaccounts mit den srvtools, jedoch ist das relativ aufwändige Setup der smbldap-tools (und die für aktuelle Belange eher ungelenke Verquickung von Skripten, zusätzlichen Konfigurationsdateien mit Klartext-Kennwörten und diversen zusätzlichen Perl-Modulen)
388
1198.book Seite 389 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
sowohl vom Aufwand, als auch unter sicherheitstechnischen Aspekten nicht mehr ganz zeitgemäß. Samba wurde daher ab Version 3.0.25 von den Entwicklern um eine -vom Setup her deutlich transparentere- Variante ergänzt, die es ebenfalls ermöglicht, einen PDC im Windows-NT-Style so aufzusetzen, dass er direkt über die srvtools administriert werden kann. Durch die Verwendung von internen Funktionalitäten kommt das Setup komplett ohne Tools von Drittanbietern auf der Linux-Seite aus, zusätzlich wird jedoch (aufgrund des ID-Mappings) der winbind-Daemon benötigt. Das Setup wird in der smb.conf primär über zwei Direktiven initiiert: ldapsam:trusted = yes und ldapsam:editposix = yes. Hinzu kommen noch einige Subdirektiven, die wir uns im folgenden Beispiel-Setup natürlich genauer anschauen werden. Fakt ist jedoch: das Setup ist insgesamt deutlich übersichtlicher, und benötigt keine zusätzlichen Skripte, um die Funktionalität bereitzustellen. Im Detail: ldapsam:editposix greift dabei direkt auf die LDAP-Datenbank zu. Zwingende Voraussetzung für ein funktionierendes Setup sind, wie gerade erwähnt, ein aktivierter winbind-Daemon, der sich um das Mapping der uids und gids auf die Samba-SIDs kümmert, und -in logischer Verbindung- die Verwendung des winbind-idmap_ldap-Backends mit präkonfiguriertem bzw. -alloziertem ID-Range. Bevor wir mit dem Setup beginnen, sollten wir alle Spuren – falls vorhanden – eines zuvor durchgeführten smbldap-tool-Setups bereinigen. Im Klartext: Über das Backup der originalen smb.conf stellen wir den Default-Zustand wieder her bzw. verwenden die entsprechende smb.conf aus den Beispieldateien zu diesem Abschnitt (http://www.galileocomputing.de/1801) und löschen die Datei /etc/ samba/secrets.tdb, die das Passwort unseres ldapadmin-Accounts aus dem letzten Setup enthält. Apropos: Falls das vorherige Setup übersprungen wurde, in jedem Fall zuvor noch einmal sicherstellen, dass das samba(3).schema in unseren slapd inkludiert wurde! Ebenso müssen wir alle Gruppen und User aus unserem DIT entfernen, die per smbldap-Setup generiert wurden, sicherheitshalber kann auch das sambaDomainName-Objekt entfernt werden. Um ldapsam:editposix verwenden zu können, benötigen wir zunächst eine Basisstruktur, die jener ähnelt, die die smbldap-tools per smbldap-populate enthalten. Für uns kein Problem, das LDIF hierzu (samba-base.ldif, ist auch in den Beispieldaten zu diesem Abschnitt enthalten) ist fix erstellt und sollte die folgenden vier ou’s generieren (Darstellung gekürzt):
389
4.1
1198.book Seite 390 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
dn: ou=users,dc=local,dc=site objectClass: organizationalUnit ou: users dn: ou=groups,dc=local,dc=site ... dn: ou=idmap,dc=local,dc=site ... dn: ou=computers,dc=local,dc=site ...
Nachdem wir die Datei per ldapadd in unseren DIT eingelesen haben, modifizieren wir unsere smb.conf wie folgt (die globalen Settings sind identisch mit denen aus Abschnitt 4.1.3, »Grundlegendes Setup: ldapmaster als PDC«, bis zu dem Punkt, an dem die ldap-relevanten Settings beginnen): [global] ... ### ldapsam:editposix ### passdb backend = ldapsam:ldap://ldapmaster.local.site ldapsam:trusted = yes ldapsam:editposix = yes ldap admin dn = cn=ldapadmin,dc=local,dc=site ldap user suffix = ou=users ldap group suffix = ou=groups ldap idmap suffix = ou=idmap ldap machine suffix = ou=computers ldap passwd sync = Yes ldap suffix = dc=local,dc=site log level = 3 idmap domains = LOCAL idmap config LOCAL:default = yes idmap config LOCAL:backend = ldap idmap config LOCAL:ldap_base_dn = ou=idmap,dc=local,dc=site idmap config LOCAL:ldap_user_dn = cn=ldapadmin,dc=local,dc=site idmap config LOCAL:ldap_url = ldap://ldapmaster.local.site/ idmap config LOCAL:range = 10000 - 50000 # -idmap alloc backend = ldap idmap alloc config:ldap_base_dn = ou=idmap,dc=local,dc=site idmap alloc config:ldap_user_dn = cn=ldapadmin,dc=local,dc=site idmap alloc config:ldap_url = ldap://ldapmaster.local.site/ idmap alloc config:range = 10000 - 50000
390
1198.book Seite 391 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
Im nächsten Schritt hinterlegen wir das Passwort »linux« für den ldap admin dn in der Datei secrets.tdb in der bekannten Weise: #> smbpasswd –w
<password>
Über die net-Befehle #> net idmap secret LOCAL <password> #> net idmap secret alloc <password>
speichern wir das Passwort des winbind-idmap_ldap-Backends für die in unserem Fall spezifizierte Domain LOCAL. Diese Vorgehensweise wird – wie in unserem Fall – typischerweise für Samba-Domains verwendet, die mit idmap_ldap(8) als winbind-Backend zur Allozierung bzw. dem Mapping der SIDs auf die uids/ gids arbeiten. Für die beiden vorgenannten net idmap -Befehle verwenden wir das Passwort des ldap admin dn, mit dem wir Samba an unseren ldap binden, also »linux«; welches ebenfalls in der Datei /etc/samba/secrets.tdb hinterlegt wird. Hat alles reibungslos funktioniert, wird es Zeit, den winbind-Daemon zu starten. #> /etc/init.d/winbind start
Im nächsten Schritt führen wir das Basis-Provisioning durch; es sollte die ou’s domadmins, domguests und domusers unterhalb der Unit groups anlegen sowie die beiden User nobody und Administrator unterhalb der Unit users: #> net sam provision Checking for Domain Users group. Adding the Domain Users group. Checking for Domain Admins group. ... Adding the Domain Guests group.
Eine komplette Übersicht der zur Verfügung stehenden net sam-Subkommandos liefert uns net(8). Anschließend setzen wir das Passwort im DIT für den SambaAdministrator-Account mit dem smbpasswd-Kommando, das dank unserer Einstellungen in der smb.conf direkt mit unserem LDAP parlieren kann: #> smbpasswd Administrator
Nachdem wir die beiden Samba-Daemons gestartet haben, #> /etc/init.d/nmb start && etc/init.d/smb start
müssen wir den Administrator-Account noch mit den entsprechenden Privilegien ausstatten, die ihn dazu befähigen, User- und Maschinen-Accounts im DIT zu verwalten (hierzu muss das folgende Setting in der smb.conf aktiviert sein: enable privileges = Yes # entspricht dem Defaultwert):
391
4.1
1198.book Seite 392 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
#> net rpc rights grant Administrator SeAddUsersPrivilege \ -U Administrator #> net rpc rights grant Administrator SeMachineAccountPrivilege \ -U Administrator
In beiden Fällen sollten wir nach der Passworteingabe die Rückmeldung Successfully granted rights.
erhalten. Sollten bis zu diesem Punkt Probleme aufgetreten sein, geht’s wie üblich ans Debugging. Checkpunkte wären: 왘 Alle erforderlichen Direktiven in der smb.conf korrekt gesetzt? 왘 Samba(3).schema in die slapd.conf eingebunden? 왘 Alle Dienste in der entsprechenden Reihenfolge gestartet? 왘 nscd testweise deaktiviert? 왘 Passwort für cn=ldadadmin,dc=... in secrets.tdb gesetzt? 왘 Logs auf Fehlermeldungen geprüft/log level hochgeschraubt? 왘 smbldap-tools: 왘 Stimmen alle Pfadangaben für die smbldap-tools in der smb.conf? 왘 Wurden alle Parameter in smbldap.conf korrekt gesetzt? 왘 Wurde das Passwort für den Windows-Admin-DN (root) der smbldap-tools gesetzt? 왘 Ist der Windows-Admin-DN Mitglied der Gruppen-Administratoren und Domain-Admins? 왘 ldapsam:editposix: 왘 Wurden alle Schritte in der richtigen Reihenfolge durchgeführt/die Dienste beim Setup in der richtigen Reihenfolge gestartet? 왘 Funktioniert das Provisioning? 왘 Wurde der Admin mit den entsprechenden Privilegien versehen? 왘 Allgemein gilt: 왘 Timeouts berücksichtigt? Samba/Windows benötigen oft etwas Zeit, bis sich alle getätigten Änderungen per smb-Message-Exchange bei allen Maschinen »herumgesprochen« haben. 왘 Vor allem bei schwer reproduzierbaren Fehlern, sollte dass das Setup im Zweifelsfall noch einmal »from the scratch« neu hochgezogen werden. Bei VMs bietet sich hierfür ein Snapshot an, zu dem revertiert werden kann.
392
1198.book Seite 393 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
Damit haben wir alle Vorbereitungen erledigt und kommen zum nächsten Schritt auf dem Tanzparkett: dem Domain-Join einer XP-Workstation. Domain Join eines XP-Clients Beide vorab gezeigten Verfahren – die smbldap-tools und ldapsam:editposix (Ersteres, insofern smbldap-useradd als add machine script in die smb.conf eingebunden wurde) – kümmern sich in der Regel automatisch um das Anlegen eines neuen Maschinen-Accounts. Genau dieser Account wird für die Vertrauensstellung innerhalb der Domäne benötigt; ohne ihn kann der Windows-Client der Domäne nicht beitreten, und Letzeres ist wiederum zwingende Vorgabe, um z.B. mit den MS-srvtools die User und Gruppen der Domäne verwalten zu können. Auf der Windows-Seite läuft die Einbindung einer Windows XP-Pro-Workstation in den Sicherheitskontext der Domäne in der üblichen Weise über das Kontextmenü Arbeitsplatz 폷 Eigenschaften 폷 Computername 폷 Ändern; hierzu wird natürlich ein Account mit der entsprechenden Berechtigung benötigt, um der Domäne beizutreten (je nach Setup z.B. root oder Administrator). Hat alles geklappt, existiert kurz darauf unterhalb der ou=computers ein neuer Eintrag für die hinzugefügte Maschine, bestehend aus dem Maschinennamen mit einem »$«-Zeichen am Ende des Namens:
Abbildung 4.1 Join
Automatisch erzeugter Maschinen-Account nach einem erfolgreichen Domain-
Das manuelle Hinzufügen eines Maschinen-Accounts erfolgt mit der gleichen Syntax, wie sie z.B. im smbldap-useradd -Kommando in der smb.conf angewendet wird (hier ohne Pfadangabe): #> smbldap-useradd -w myMachine001$
Kleiner Tipp: Soll beim Einbinden einer Maschine auf der Windows-Seite gleichzeitig ein User-Account für die gewählte Domäne angelegt werden, kann es – je
393
4.1
1198.book Seite 394 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
nach Version und SP-Level – gegebenenfalls zu folgender oder ähnlicher Fehlermeldung kommen: »Die Vertrauensstellung zwischen dieser Arbeitsstation und der primären Domäne konnte nicht hergestellt werden«
In diesem Fall kann folgender Parameter in der Registry geändert werden, um einer Nicht-W2K-Domäne beizutreten: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\requiresignorseal [0]
Domänenverwaltung mit srvtools.exe Um nun die smbldap-tools und ldapsam:editposix in Verbindung mit einem grafischen Frontend nutzen zu können, bietet sich wie bereits vorab erwähnt die Verwendung der Tools srvmgr.exe und usrmgr.exe an, die im Paket srvtools.exe enthalten sind. Das Paket kann von der Microsoft-Website heruntergeladen werden: http://support.microsoft.com/kb/173673/en-us/ Dabei handelt es sich um NT4-Domänen-Management-Werkzeuge, die auch für den Einsatz unter Windows 2000 und XP geeignet sind. Über die Menüs können nun unter anderem neue Benutzer oder Gruppen hinzugefügt, gelöscht oder modifiziert werden. Auch Maschinenkonten können mit den Tools verwaltet werden. Achtung: Bei den verwendeten Gruppen handelt es sich standardmäßig um posixGroups, die ACL-technisch nur per sets ausgewertet werden können (siehe hierzu Abschnitt 3.7.3 und http://www.openldap.org/faq/data/cache/ 1133.html). Um nun die Samba-Domäne mit den srvtools verwalten zu können, müssen zwei Voraussetzungen erfüllt sein: Die Maschine, von der aus die Verwaltung erfolgt, muss der Domäne beigetreten sein, und die Modifikationen müssen von einem User durchgeführt werden, der die entsprechenden Rechte/Privilegien besitzt (z.B. root bei den smbldap-tools oder Administrator im ldapsam:editposixSetup). Kleiner Tipp: Beim nachträglichen Aufbohren von Usern, die nicht per srvtools angelegt wurden, aber über ldapsam:editposix »betrieben« und verwaltet werden sollen: uid/gidNumber gegebenenfalls in den idmap-Range des von editposix verwalteten Bereichs hieven und die Userobjekte in die Unit ou=users verlegen.
394
1198.book Seite 395 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
Abbildung 4.2
Samba- Domänen-Administration mit den MS-srvtools
Webmin/SWAT Ein weiteres Tool zur Verwaltung von Samba- und LDAP-Accounts stellt Webmin dar, das wir zusammen mit einigen anderen Tools in Abschnitt 4.7 über grafische LDAP-Frontends, »Auf den Schirm!«, später kurz vorstellen werden. Das webbasierte, Samba(-eigene) Admin-Tool SWAT werden wir in diesem Zug nicht behandeln, da es definitiv nicht zur Verwendung von Samba in Verbindung mit OpenLDAP geeignet ist.
4.1.5
Redundantes Setup: ldapslave als BDC
Im Folgenden werden wir unseren ldapslave als BDC einrichten. Durch dieses Setup erreichen wir eine fehlerredundante Konfiguration: Fällt der (P)DC oder BDC komplett aus, soll dennoch weiterhin eine Anmeldung für die WindowsArbeitsplätze an dem verbliebenen Server möglich sein. Was die Kombinationsmöglichkeiten LDAP-Provider/LDAP-Consumer und PDC/ BDC angeht, sollte stets die Kombination LDAP-Provider/PDC in Verbindung mit LDAP-Consumer/BDC Verwendung finden. Würde man einen Samba-PDC auf einem LDAP-Consumer installieren (was rein technisch durchaus machbar wäre), würde diese Konfiguration schon an der ersten automatischen Erstellung eines Maschinen-Accounts scheitern. Der Grund:
395
4.1
1198.book Seite 396 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Der Windows-Client, welcher der Domäne beitreten will, muss dies üblicherweise auf dem schreibbaren LDAP-Provider tun. Der neu generierte Account wird aber im Regelfall nicht schnell genug (auf den LDAP-Consumer und PDC) repliziert, so dass die Anfrage des PDC ins Leere läuft. Auf dem Client erscheint die Fehlermeldung, dass die Account-Daten nicht generiert werden konnten. Praktisch kann es nun sein, dass zwar Teile des Accounts generiert wurden, der Account selbst ist aber aufgrund dessen faktisch unbrauchbar. Ein eindeutiges Statement hierzu findet sich auch im offiziellen Samba-HowTo. Ein Workaround ist seit Samba 3.0.1 mit dem Parameter ldap replication sleep möglich. Dennoch raten wir von der LDAP-Consumer/PDC-Kombination ab. Die von uns verwendete Konfiguration LDAP-Provider/PDC → LDAP-Consumer/ BDC gestaltet sich – zumindest auf der Samba-Seite – recht einfach. Wie bereits in den Erläuterungen zum PDC angeführt, sind es primär zwei Direktiven, die auf dem BDC keinesfalls identisch sein dürfen: zum einen der os level, der aufgrund des Browsing-Wettbewerbs zwingend einen niedrigeren Wert haben muss als der des PDC, zum anderen muss mindestens die Direktive domain master zwingend auf no gesetzt sein. Natürlich wählen wir (analog zum NetBIOS-Namen des PDC) ldapslave für unseren BDC. Für die Replikation unserer LDAP-Server untereinander können wir alle »normalen«, verschlüsselten Replikationsverfahren verwenden. Vorzugsweise bietet sich (delta-)syncrepl per TLS und SASLMech EXTERNAL an. Die Prozeduren haben wir bereits ausführlich in den Abschnitten 3.2 und folgende über Replikation und in Abschnitt 3.4, »OpenLDAP mit SSL und TLS«, erläutert und werden sie daher an dieser Stelle nicht weiter erörtern. Eine fehlerredundante Anmeldung am Linux-System selbst sollte vorab getestet werden und ohne Probleme funktionieren (siehe hierzu auch Abschnitt 3.6.6, »Authentifikation am System mit aktiviertem TLS«). Wir betrachten im Folgenden nur die LDAP-relevanten Direktiven aus der smb.conf unseres ldapslave, die sowohl für das Setup mit den smbldap-tools als auch für das Setup per ldapsam:editposix in ähnlicher Form (redundante Angabe der LDAP-Server in den relevanten Direktiven) angewendet werden können (die passdb backend-Zeile ist aus Platzgründen umbrochen, zwischen den beiden LDAP-URLs befindet sich ein Leerzeichen): [global] ... netbios name = ldapslave passdb backend = ldapsam:"ldap://ldapslave.local.site ldap://ldapmaster.local.site" # BDC - Settings
396
1198.book Seite 397 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
domain logons = yes preferred master = no domain master = no local master = no os level = 32 ...
Durch die Angabe zweier LDAP-Server als Backend (passdb backend = ...) ist Samba in der Lage, beim Ausfall eines der passdb-Backends auf das verbliebene zurückzugreifen. Nachdem wir die smb.conf wie oben beschrieben angepasst haben, setzen wir – genau wie für unseren ldapmaster – mit smbpasswd das rootdn-Passwort in der Datei secrets.tdb. Falls ldapsam:editposix zum Einsatz kommt, nicht vergessen, per net idmap secret LOCAL|alloc <passwort> die idmap_ldap-Passwörter ebenfalls in der secrets.tdb abzulegen und winbind zu starten. Eine weitere zwingende Vorgabe ist eine identische Netzwerk-SID auf Provider und Consumer bzw. PDC und BDC. Um die SID auszulesen und zu vergleichen, gibt es die bereits bekannten Konsolen-Befehle: #> net getlocalsid oder auch #> net rpc info
Stimmen die Netzwerk-SIDs nicht überein, führen wir auf dem BDC/Consumer den folgenden Befehl aus: #> net rpc getsid
Dieser Befehl speichert die ausgelesene Netzwerk-SID der Domäne in seiner Datei secrets.tdb. Eine andere Variante ist das manuelle Setzen per net setlocalsid. Ein einfaches Kopieren der Datei secrets.tdb vom PDC zum BDC ist nicht anzuraten, da der BDC die SID in diesem Fall beim nächsten Restart einfach mit seiner eigenen wieder überschreibt. Auf unserem ldapmaster ergänzen wir nun analog zum Beispiel des BDC in der smb.conf die passdb backend -Direktive für ein redundantes Setup. Nach dem Neustart aller Services sollte in den Logs zu lesen sein, dass ldapslave nun ein Logon-Server für die Domäne LOCAL geworden ist; der Befehl testparm sollte »Server role: ROLE_DOMAIN_BDC« für unseren ldapslave ausgeben. Als Funktionstest können wird den slapd auf unserem ldapmaster/PDC deaktivieren; ein beliebiger Client müsste sich nun immer noch an der Domäne anmelden können.
397
4.1
1198.book Seite 398 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
TLS-Setup Dieser Punkt erfordert keinen größeren Aufwand, natürlich vorausgesetzt, dass die bestehende OpenLDAP/Samba-Konfiguration ohne Probleme läuft und das OpenLDAP-spezifische SSL/TLS-Setup ebenfalls reibungslos arbeitet. In der smb.conf wird zur Aktivierung von TLS lediglich der Parameter ldap ssl = start_tls
gesetzt. Standardmäßig ist dieser Parameter deaktiviert (wenn nicht gesetzt). Weitere mögliche Parameter sind Off (explizit deaktiviert) und On (SSL aktiviert, NICHT TLS! -> Port 636 benötigt dann logischerweise ldaps:// in der passdb backend-Direktive). Die Direktive sollte natürlich gleichermaßen auf PDC und BDC gesetzt werden. Sobald TLS aktiviert wurde, läuft die Kommunikation zwischen Samba und LDAP-Server verschlüsselt ab. Um uns dessen zu vergewissern, können wir z.B. den slapd auf unserem ldapmaster deaktivieren und die passdb backend-Direktive der smb.conf des ldapmasters auf ldap://ldapslave.local.site zeigen lassen. Dadurch sind die beiden gezwungen, über das Netz miteinander zu kommunizieren. Danach überwachen wir in bekannter Weise (z.B. per tcpdump) den über das Netz-Device auf Port 389 ausgehenden Traffic am ldapmaster, während wir uns mit einem Windows-Client am ldapmaster anmelden. Als aussagekräftige Gegenprobe kann – und sollte – man die Konfiguration mit explizit gesetztem ldap ssl = off testen. Um die smbldap-tools mit TLS verwenden zu können, muss dort ebenfalls die TLS-Unterstützung aktiviert werden. Das geschieht über die Konfigurationsdatei smbldap.conf. Hier wird zunächst per TLS=1 (statt vorher 0) TLS aktiviert. In den darauf folgenden Statements müssen die entsprechenden Zertifikatspfade eingetragen werden. Der Einfachheit halber wählen wir für unser Beispiel die bereits erstellten Zertifikate des ldapmaster.local.site. ldapTLS="1" cafile="/etc/openldap/certs/cacert.pem" clientcert="/etc/openldap/certs/newcert.pem" clientkey="/etc/openldap/certs/ldapkey.pem"
Damit die Perl-Skripte in Verbindung mit TLS genutzt werden können, wird das Perl-Modul IO::Socket::SSL benötigt. Bei SUSE befindet es sich im Paket perl-IOSocket-SSL, bei Debian im Paket libio-socket-ssl-perl. Alternativ kann es direkt über die CPAN-Website (http://search.cpan.org/dist/IO-Socket-SSL/) bezogen werden.
398
1198.book Seite 399 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
Nun steht uns ein robustes, redundant und verschlüsselt arbeitendes Konstrukt zur Verfügung, das uns sowohl Samba- als auch LDAP-Services in einer ausfallsicheren Konfiguration bereitstellt. Sollten Fehler aufgetreten sein, geht’s wie üblich ans Debuggung. Checken wir noch einmal die Auflistung möglicher Fehler für Provider und Consumer bzw. PDC und BDC analog zum letzten Abschnitt: 왘 Laufen alle erforderlichen Dienste auf Provider und Consumer? 왘 Wurde das Passwort für den rootdn in der Datei secrets.tdb gesetzt? 왘 Wurde das samba(3).schema korrekt eingebunden? 왘 Sind alle Parameter in der smb.conf auf beiden Servern korrekt gesetzt? 왘 Funktioniert die Replikation standalone? 왘 Wurde das Passwort für den Windows Admin-DN gesetzt? 왘 TLS-Direktiven in der smbldap.conf (nur Provider) korrekt gesetzt? 왘 Stimmt die Netzwerk-SID auf PDC und BDC überein? 왘 Schlägt die Authentifizierung fehl, sollten der Log-Level für slapd und samba erhöht werden, danach eingehende Prüfung der Logs. 왘 Ist das Login auf Systemebene möglich? Scheitert dies bereits, könnte der Fehler innerhalb der PAM/NSS-Konfiguration liegen. 왘 Sind die Einträge in der /etc/hosts korrekt bzw. funktioniert die Namensauflösung? 왘 ** Existieren auf PDC und BDC identische Home-Verzeichnisse für alle existierenden Samba-User? Existiert die Datei .ldaprc in jedem der Home-Ordner mit einem Verweis auf die entsprechenden Zertifikate? 왘 Sind in der host-Direktive in /etc/ldap.conf (bzw. /etc/libnss-ldap.conf und / etc/pam_ldap.conf) beide LDAP-Server eingetragen? Zum Punkt »identische Home-Verzeichnisse«: hier stehen uns natürlich wie immer im Linux-Universum verschiedene Möglichkeiten zur Verfügung. Die einfachste, allerdings nicht zeitkritische Variante wäre ein automatischer, cron-gesteuerter Abgleich der Verzeichnisse auf beiden Servern, z.B. per rsync. Die weitaus elegantere Variante wäre natürlich ein Server-übergreifender shared-Storage, auf das beide Samba-Server zugreifen und auf dem sich die gemounteten Home-Verzeichnisse und Daten der User befinden.
Noch ein kurzer Hinweis zu einigen bdb-Indizes, die bei Verwendung von OpenLDAP mit Samba berücksichtigt werden sollten, um die Performance zu verbes-
399
4.1
1198.book Seite 400 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
sern. Die Liste sollte natürlich je nach Anforderung entsprechend erweitert werden: index sambaSID eq index sambaPrimaryGroupSID eq index sambaDomainName eq
4.1.6
The new Dance – Samba 4 und OpenLDAP
Und damit wären wir fast am Ende dieses Abschnitts. Bevor wir zum nächsten schreiten, dem Kerberos-Setup, werfen wir wie versprochen noch einen Ausblick auf die Dinge, die da kommen werden. Und das wäre: ein Samba 4-DC mit OpenLDAP. Und wem das noch nicht reicht, der kann ein Preview auf eine Samba 4Multi-Master-Replikation mit 2-n-DCs werfen. Und das ist insbesondere unter folgendem Aspekt ziemlich interessant: Samba 4 funktioniert bereits im -zur Erstellung des Buches aktuellen- Alpha-Stadium (pre-Alpha 6) hervorragend als Standalone-DC, was die reinen LDAP/ Kerberos-Funktionalitäten angeht. Eine größere Baustelle bildet jedoch nach wie vor die Implementierung von Microsofts Replikations-Protokoll (DRSUAPI), das Samba letztendlich benötigen wird, um sich gegen echte ADS-DCs zeitkritisch replizieren zu können. Über dem Ob, Wann und Wie der Umsetzung steht noch – wie üblich, dank zukünftiger MS-spezifischer Neuerungen/Erweiterungen/Features(!), um Kompatibilitäten mit anderen DS in jedem Fall zu vermeiden – ein mächtig großes Fragezeichen. Aber das interessiert uns OpenLDAPer herzlich wenig. Denn wer braucht schon Replikations-Protokolle, die eher nach Gonorrhoe oder einer Nervenerkrankung klingen und die man beim intensiven Studium ihrer Funktionsweise vielleicht auch unweigerlich bekommt? Niemand, denn wir können bereits zwei Samba 4DCs dank OpenLDAP’s MMR gegeneinander replizieren ... Exkurs: ldapi:// – Internal Affairs Hier geht’s weniger um die Truppe, die korrupten Bullen auf die Finger haut, aber ldapi kümmert sich tatsächlich auch nur um interne Dinge. Wie wir wissen, können wir unserem slapd per -h-Option die LDAP-URL(s) angeben, für die er sich zuständig fühlen soll. Wir kennen bereits ldap://:Port/ und auch seinen veralteten Bruder ldaps://. Aber ldapi:// unterscheidet sich gewaltig von den beiden, da er üblicherweise wie ein Eremit herzlich wenig von externer Kommunikation hält. Er wickelt alles über einen Unix-Domain-Socket ab, den wir ihm statt einer normalen URL übergeben, und das könnte in etwa so aussehen:
400
1198.book Seite 401 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
-h ldapi://%2Fusr%2Flocal%2Fvar%2Frun%2Fldapi
(Nein, kein Tippfehler: Die %2F entsprechen dabei einfach nur der EscapeSequenz für »/« und sind zwingend erforderlich, sonst wird der Socket evtl. falsch angesprochen.) Zum Samba-Background: Als Datenbank-»Backend« für Samba 4 werden in unserem Setup nicht die LDAP-artigen ldb-Datenbanken von Samba 4 verwendet, sondern alle Daten werden mit Hilfe unseres guten alten slapd direkt in einem echten LDAP-Server angelegt. Die Vorteile liegen auf der Hand – denn wer braucht schon zwei LDAP-Server in einem Netz, von denen einer dank MS-Kompatibilität so verbogen ist, dass man ihn kaum mit gängigen Schemas und Funktionalitäten erweitern kann? Wir mit Sicherheit nicht. Die Kommunikation zwischen Samba und OpenLDAP kann im einfachsten Fall, wenn Samba und OpenLDAP auf einem Server liegen, über einen Unix Domain Socket laufen. Diese Interprozesskommunikation (kurz IPC) sorgt dafür, dass kein TCP Overhead anfällt und die Kommunikation noch performanter wird. Im OpenLDAP-Fall wird für solche Aufgaben der eben erläuterte ldapi://-Socket verwendet (siehe hierzu auch draft-chu-ldap-ldapi-00/xx.txt). Die Kommunikation stellt sich in diesem Anwendungsfall stark vereinfacht und rein schematisch ungefähr so dar:
OpenLDAP ldapi:/// ldb-mapper
Samba
Anfrage auf Port 389 (Samba)
Client
Abbildung 4.3 Einsatz von ldapi:// in Verbindung mit Samba 4 und OpenLDAP
Der Vorteil des Szenarios für Samba: Die Kommunikation läuft ungestört und fern von jedem LDAP-Netzwerktraffic ab. Und genau daher wurde dieses Konstrukt von Andrew Bartlett auch als primäre Kommunikation zwischen OpenLDAP und Samba 4 angedacht. Allerdings stößt diese Variante auch schnell an ihre Grenzen, insbesondere replikationstechnisch. In diesem Fall muss die Kommunikation zwischen Samba und OpenLDAP über einen dedizierten Port erfolgen (z.B. 9000). Nun zum Setup.
401
4.1
1198.book Seite 402 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
4.1.7
Setup eines Standalone Samba 4 DC mit OpenLDAP-Backend
Installationstechnisch haben wir die Wahl zwischen einem konventionellen Tarball (Stand November 2008: bis Alpha 5 verfügbar, der jedoch z.T. einige fehlerhafte Implementierungen des OpenLDAP-Backends aufweist) oder der aktuellsten Version via GIT oder rsync. Die Verfahren hierzu sind unter http:// wiki.samba.org/index.php/Samba4/HOWTO ausführlich beschrieben. Im Folgenden beziehen wir uns aufgrund der oben genannten Problematik und der MMRKapabilitäten auf die aktuellste Entwicklerversion (pre-Alpha 6). Kleine Anmerkung: Bei den Tests hat sich Samba 4 (pre-Alpha 6 GIT) mit frisch kompiliertem OpenLDAP >= 2.4.12 (./configure --enable-overlays=yes --with-tls=yes --with-cyrus-sasl=yes) in der Regel als problemloseste Setup-Variante erwiesen.
Nachdem wir die Sourcen heruntergeladen und entpackt haben, sollten wir vor einer Kompilierung überprüfen, ob zumindest folgende Pakete (Namen hier bezogen auf SUSE) auf unserem System vorhanden sind: gcc, make, python, python-devel, libgnutls-devel, libacl-devel, libattr-devel, libtalloc-devel, readlinedevel, libblkid-devel, pkg-config, cyrus-sasl-devel, libopenssl-devel, (b)db-(4_5)devel und einige andere mehr. Das komplette Paketlisting zu diesem Abschnitt findet sich im Anhang. Die Kompilation starten wir (bei Verwendung der GITVersion nach einem ./autogen.sh) im Unterordner ./source4 in der üblichen Weise: #> ./configure && make && make install
Sollten Probleme beim Kompilieren (oder beim späteren Provisioning) auftreten, kann gegebenenfalls ein etwas geändertes configure (s.u.) Abhilfe schaffen. In dem Fall sollten wir zuvor jedoch erst per make distclean wieder etwas aufräumen: #> ./configure.nodebug.developer --enable-automatic-dependencies \ && make && make install Achtung: Alle folgenden Prozedere beziehen sich auf eine pre-Alpha 6, und können von den tatsächlich benötigten Parametern der aktuellsten Version abweichen. Daher sollte in jedem Fall immer ein Blick in die README’s und HowTos des Tarballs geworfen werden; die --help–Parameter des jeweiligen Provision-Scripts liefern ebenfalls Hilfen zu den verfügbaren Direktiven!
Anschließend finden sich die Samba 4-Binaries, Konfigurationsdateien und Bibliotheken unter /usr/local/samba/*, und kollidieren auf diese Art nicht mit unserer ggf. noch vorhandenen 3er Installation. Natürlich müssen wir darauf achten, das keine Samba 3- und LDAP- Instanzen (nmbd, smbd, winbindd, slapd) mehr laufen,
402
1198.book Seite 403 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
und das alle Befehle über den kompletten Pfad angesprochen werden, damit es keinesfalls zu Verwechslungen mit Samba 3-Tools und Binaries kommt. Backend-Provisioning Das Provisioning entspricht im weitesten Sinne dem Befehl dcpromo unter Windows und sorgt für die Erstellung der Verzeichnisstruktur sowie eine Erstbefüllung des Verzeichnisbaums mit Standardobjekten. Bei Verwendung von OpenLDAP als Samba-Backend müssen wir jedoch zunächst ein Backend-Provisioning durchführen, das Samba 4 für die Verwendung mit OpenLDAP als StandaloneDC vorbereitet. Als Kerberos-Realm (vereinfacht: der Bereich, für den sich Kerberos zuständig fühlt – ausführliche Erläuterungen im nächsten Abschnitt) und DNS-Domain wählen wir ldap.local.site, als Workgroup die Domain LDAP. Wir starten das Provisioning vom Unterordner source4/ aus (Zeile ist umbrochen): #> setup/provision-backend --realm=ldap.local.site \ --domain=LDAP --ldap-admin-pass="linux" \ --ldap-backend-type=openldap --server-role='domain controller' Converted 536 records (skipped 13) with 0 failures
Your openldap Backend for Samba4 is now configured, and is ready to be started Server Role: domain controller Hostname: ldapmaster DNS Domain: ldap.local.site Base DN: DC=ldap,DC=local,DC=site LDAP admin user: samba-admin LDAP admin password: linux Start slapd with: slapd -f /usr/local/samba/private/ldap/slapd.conf -h ldapi://%2Fusr%2Flocal%2Fsamba%2Fprivate%2Fldap%2Fldapi Run provision with: --ldap-backend=ldapi --ldap-backend-type=openldap --password=linux --username=samba-admin
ACHTUNG: Die Direktiven können aufgrund des pre-Alpha6-Status durchaus zu denen späterer Versionen differieren. Für den exakten Syntax jeweils provision(-backend) --help aufrufen!
Die automatisch vom Backend-Provisioning generierte slapd.conf (zu finden unter /usr/local/samba/private/ldap/) macht extensiven Gebrauch der uns bereits gut bekannten Overlays memberOf und refint, ebenso ist bereits Overlay syncprov als Vorbereitung für die Multi-Master-Replikation implementiert. Aufgrund etlicher Modifikationen von memberof in den letzten OpenLDAP-MinorReleases sollte unbedingt die aktuellste OpenLDAP-Version verwendet werden. Ebenso wird beim Backend-Provisioning eine rudimentäre smb.conf generiert, die – bezogen auf unsere Einstellungen – die folgenden Abschnitte enthält: [globals] netbios name = LDAPMASTER
403
4.1
1198.book Seite 404 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
workgroup = LDAP realm = ldap.local.site server role = domain controller # tls enabled = no # ggf. noch manuell hinzufuegen [netlogon] path = /usr/local/samba/var/locks/sysvol/ldap.local.site/scripts read only = no [sysvol] path = /usr/local/samba/var/locks/sysvol read only = no
Um nun unseren OpenLDAP mit dem Samba 4-DIT befüllen zu können, starten wir ihn mit dem weiter oben angegebenen Syntax. Als kleine Vorbereitung auf unsere 2 DC-Multi-Master-Replikation verwenden wir jedoch nicht den ldapi://Socket, sondern eine LDAP-URL mit dediziertem Port; letzterer sollte sich natürlich nicht mit dem später von Samba 4 belegten LDAP-Port 389 beißen. Wir wählen daher in unserem Beispiel Portnummer 9000, natürlich sollte zuvor auf dem jeweiligen System unbedingt geprüft werden, ob der verwendete Port frei ist und nicht mit einer anderen Applikation kollidiert: #> /usr/local/libexec/slapd \ -f /usr/local/samba/private/ldap/slapd.conf \ -h "ldap://ldapmaster.local.site:9000/" -d 1
Ist unser OpenLDAP sauber hochgefahren, starten wir nun auf einer zweiten Konsole das eigentliche, finale Provisioning zur Befüllung des Samba-DITs (Zeile ist umbrochen): #> setup/provision --realm=ldap.local.site --domain=LDAP \ --server-role='domain controller' \ --ldap-backend="ldap://ldapmaster.local.site:9000/" \ --ldap-backend-type=openldap --password=linux \ --username=samba-admin --adminpass=linux Achtung: Der ebenfalls vorhandene Provision-Parameter --simple-bind-dn="cn=sambaadmin,cn=samba" sollte nicht verwendet werden, da sonst später beim Start von samba ggf. der SASL-bind (Samba->LDAP) fehlschlägt!
Die Ausgabe sollte –stark gekürzt- in etwa so aussehen: Setting up share.ldb ... Pre-loading the Samba 4 and AD schema Adding DomainDN: DC=ldap,DC=local,DC=site (permitted to fail) Modifying DomainDN: DC=ldap,DC=local,DC=site ... Server Role: domain controller Hostname: ldapmaster
404
1198.book Seite 405 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
NetBIOS Domain: LDAP DNS Domain: ldap.local.site DOMAIN SID: S-1-5-21-2459713200-4066685742-144458070 Admin password: linux
Noch einmal der Hinweis: die verwendeten Parameter entsprechen -sowohl für das Backend-Provisioning als auch für das finale Provisioning- dem Stand einer pre-Alpha 6. Daher in neueren Versionen immer per provision(-backend) --help die jeweils aktuell verfügbaren Optionen prüfen!
Prinzipiell sollte ebenfalls immer darauf geachtet werden, das die verwendeten Optionen (z.B. realm, domain, server-role usw.) bei beiden Provisionings identisch gewählt werden müssen. So entspricht das beim provision-backend gesetzte --ldapadmin-pass="linux" dem --password="linux" im finalen Provisioning; die Option -adminpass setzt z.B. das Passwort für den Account cn=Administrator, cn=users, dc=ldap, dc=local, dc=site.
Und noch ein Hinweis: In einer der letzten getesteten pre-Alpha 6 trat beim finalen Provisioning folgender Fehler auf: ldb.LdbError: (21, 'LDAP error 21 LDAP_INVALID_ATTRIBUTE_SYNTAX – <wellKnownObjects: value #0 invalid per syntax> <>')
Das Problem ist auf ein fehlerhaftes, Samba-internes Mapping des 'DN+Binary' Syntaxes -der für etliche Objekte verwendet wird- zurückzuführen. Der Attributwert muß dabei auf einen arbitrary String gemappt werden, damit OpenLDAP ihn korrekt interpretieren kann. Bis zum Erscheinen dieses Buches dürfte der Fehler behoben sein. Apropos finales Provisioning: Das kümmert sich neben der Befüllung des DIT unter anderem um die Erstellung einer entsprechenden Zonendatei (in unserem Fall: /usr/local/samba/private/ldap.local.site.zone), die in den Nameserver (typischerweise bind) eingebunden werden muß. Andernfalls könnten Win-Clients etwas orientierungslos durch die Gegend irren, und Probleme bei der Lokalisierung der von Samba 4 angebotenen ADS-DC kompatiblen Services (LDAP/ CLDAP/Kerberos) haben. Das Kerberos Konfigurationsfile findet sich unter /usr/ local/samba/private/krb5.conf und muß nach /etc kopiert werden. In den ebenfalls beim Provisioning generierten Dateien /usr/local/samba/private/named.conf|.txt finden wir alle weiteren Hinweise zur Integration der DNSZonendatei und weitere, benötigte Punkte wie den Kerberos-relevanten Export der dns.keytab. Hier einige der Punkte in der Kurz-Übersicht, die –je nach Entwicklungsstand- natürlich z.T. noch variieren können: 왘 Integration der beim Provisioning erstellten Zonendatei in die named.conf und ggf. Anpassung erforderlicher Direktiven 왘 /etc/resolv.conf gegebenenfalls anpassen
405
4.1
1198.book Seite 406 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
왘 Anpassung von Owner und Rechten der dns.keytab 왘 Einbindung der Variablen KEYTAB_FILE und KRB5_KTNAME in das Bind-StartSkript (siehe hierzu die Anleitung in named.txt) 왘 Kopieren der beim Provisioning erstellten krb5.conf nach /etc 왘 Nameserver bind starten, auf Fehlermeldungen kontrollieren, Test z.B. per ’dig _ldap._tcp.dc._msdcs.ldap.local.site SRV @ldapmaster.local.site’ 왘 Zeitsynchro auf allen beteiligten Maschinen (DC(s) und Win-Clients) kontrollieren! Nun sind wir bereit für den ersten Start unseres Samba 4-Daemons. Vorher noch einmal kurz auf alte Instanzen von nmbd, smbd und winbind prüfen, dann geht’s los. Per: #> /usr/local/samba/sbin/samba –i –d 4 –-debug-stderr
starten wir den Samba-Daemon interaktiv (-i) im Debug-Level 4, die Ausgaben werden per --debug-stderr direkt auf der Konsole ausgegeben. Ein nmbd wird nicht mehr benötigt; seine Funktionalitäten wurden in den Samba-Daemon integriert, der -wie wir unschwer erkennen können- nun auch einen neuen Namen bekommen hat: samba. Sollte uns folgende Fehlermeldung beim Domain-Join einer XP-Station beglücken: dcesrv_init_context: failed to find endpoint server = 'epmapper'
starten wir den samba-Daemon testhalber zusätzlich im Single-Process-Mode (-M single). Standardmäßig werden beim ersten Start des samba-Daemons TLS-Zertifikate generiert, was unter Umständen 1-n Minuten dauern kann. Als einfachen Workaround können wir uns damit behelfen, das wir entweder a) die Zertifikate selbst kreieren (für uns mittlerweile eine leichte Übung) und unterhalb von /usr/ local/samba/private/tls/ ablegen, oder b) wir setzen einfach die Direktive tls enabled = no in unserer /usr/local/samba/etc/smb.conf. Für ein einfaches Preview der Samba 4 –Funktionalitäten sollte letzteres völlig ausreichend sein. Für den direkten Connect zu unserem OpenLDAP-»Backend« für Samba 4 verwenden wir nun im JXplorer oder Apache DS die folgenden Settings: Server: , Port: 9000 BaseDN: dc=ldap,dc=local,dc=site Admin-DN: cn=samba-admin,cn=samba , Passwort: linux.
Die Struktur unseres Samba 4- DIT sollte sich -in etwa- wie in der nächsten Abbildung gezeigt (JXplorer, s.u.) darstellen. Allerdings sollten wir von unseren poten-
406
1198.book Seite 407 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
tiellen Schreibrechten im DIT vorerst keinen Gebrauch machen; zumindest nicht mit unseren »normalen« und standardisierten LDAP-Tools. Ein Blick auf einige der dort gezeigten Attributwerte (z.B. nTSecurityDescriptor oder objectSID) des ADS-kompatiblen DIT sollte auch sofort klarmachen, warum. Wir können mit unseren LDAP-Tools zwar auf den DIT zugreifen, Objekt-Manipulationen sind jedoch nur in beschränktem Rahmen möglich: aufgrund ihrer strikten Einhaltung der X.500-Standards können unsere LDAP-Tools einige der wunderbaren MS-spezifischen Attribute nicht »sauber« darstellen. Fazit: Zum Anzeigen okay, Modifikation auf der Kommandozeile sollten jedoch ausschließlich über die ldb* -Tools, die Bestandteil der Samba4-Suite sind, erfolgen (liegen alle unter /usr/local/samba/bin/*).
Abbildung 4.4 Samba4- DIT im OpenLDAP-Backend, betrachtet im JXplorer
Eine weitere, im Fall von Samba 4 auch recht elegante Variante der Administration bietet die MMC (Microsoft-Management-Console), die jeder W2Kx-Server
407
4.1
1198.book Seite 408 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
besitzt, und die auch nachträglich auf XP-Pro Clients installiert werden kann. Entsprechende Downloads-Links finden sich auf den Microsoft-Seiten, Stichwort: adminpak.exe. Damit kann unser Samba 4 DC im Stil eines W2K3 Servers administriert werden. Voraussetzung für die Anwendung der MMC ist -wie bei der Administration von Samba3 per Win-Client- ein zuvor erfolgter Domain-Join der Station, was im Fall von Samba 4 eine einfache Übung ist. Hierbei sollte zuvor darauf geachtet werden, das der DNS-Server unserer Samba 4-Maschine in die Netzwerkkonfiguration des Win-Clients eingetragen wurde, und die Zeitsynchro des Clients -Kerberos-bedingt- natürlich ebenfalls in Ordnung zu sein hat. Nach erfolgtem Join können wir unseren Samba 4 DC bequem per MMC managen:
Abbildung 4.5 Samba 4 DC über MMC verwaltet
Aber schließlich fühlt sich ein einzelner Samba 4-DC auch einsam und allein auf weiter Flur, also stellen wir ihm fix einen Kollegen zur Seite.
408
1198.book Seite 409 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
4.1.8
Staffelflug: Zwei Samba 4-DCs mit OpenLDAP in Multi-Master-Replikation
Seit Sommer 2008 bietet Samba 4 in der Entwicklerversion (GIT) eine Erweiterung des OpenLDAP-Backend-Provisionings an, die von Andrew Bartlett und Oliver Liebel entwickelt wurde, um Multi-Master-Setups mit OpenLDAP-Backends für zukünftige Releases zu automatisieren. Die wichtigste Neuerung in dieser Hinsicht, die auch Bestandteil der aktuellen pre-Alpha 6 ist, ist der Parameter --ol-mmr-urls="<>". Über ihn kann eine Liste potentieller OpenLDAP-Server in der Form ldap://<server>:<port> [Leerzeichen] ldap://<server>:<port> ... usw. angegeben werden, die als Backends für die Multi-Master-Replikation zwischen multiplen Samba 4-DCs genutzt werden können. Dadurch werden die entsprechenden Subkontexte cn=user/config/ schema -in der uns nun hinreichend bekannten Vorgehensweise- via syncrepl-, ServerID- und MirrorMode-Direktiven auf die Replikation mit ihren DC-Artgenossen vorbereitet: #> setup/provision-backend --realm=ldap.local.site --domain=LDAP \ --host-name=LDAPMASTER --ldap-admin-pass="linux" \ --ldap-backend-type=openldap --server-role='domain controller' \ --ol-mmr-urls="ldap://ldapmaster.local.site:9000 \ ldap://ldapslave.local.site:9000"
Nach erfolgtem Backend-Provisioning und Start des slapd auf ldapmaster können wir das finale Provisioning des ersten DCs (ldapmaster) in der bereits beschriebenen Vorgehensweise -analog zu einem Standalone-DC mit OpenLDAP-Backendstarten. Zwingend ist natürlich die korrekte Vorgabe der LDAP-URL und des Ports. Wichtig dabei: Die am Ende des finalen Provisionings ausgegebene Domain-SID benötigen wir natürlich für das Provisioning unseres zweiten DC: DOMAIN SID:
S-1-5-21-4286536947-1969703804-385546026
Alternativ können wir uns die SID unserer Domain auch per ldbsearch aus dem DIT unseres ersten DC holen (der samba-Daemon muss dabei aktiv sein): #> /usr/local/samba/bin/ldbsearch -H ldap://localhost objectClass=domainDNS | grep -i objectsid objectSid: S-1-5-21-4286536947-1969703804-385546026
\
Oder wir setzen die Domain-SID, was noch einfacher ist, beim finalen Provisioning selbst über die zusätzliche Direktive: --domain-sid=S-1-5-4444 Für unseren zweiten DC (ldapslave) können wir nun wie folgt vorgehen:
409
4.1
1198.book Seite 410 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Zunächst fügen wir unseren 2.DC der Domain LDAP hinzu; hierzu müssen slapd und samba auf DC1 (ldapmaster) gestartet sein. Ebenfalls muss sichergestellt sein, das die krb5.conf von ldapslave (DC2) auf das Samba-KDC (KDC: Kerberos Key Distribution Center, mehr dazu im nächsten Abschnitt) von ldapmaster (DC1) zeigt, ebenso muss der DNS auf ldapmaster aktiv sein, und in die Konfiguration (/etc/resolv.conf) von ldapslave (DC2) eingetragen sein. Kurz gefasst: Das KDC auf ldapmaster muss via DNS für ldapslave auflösbar/sichtbar sein. Ein Test in der vorgestellten Weise -per dig von DC2 (ldapslave) aus- sollte hier schnell Klarheit bringen: #> dig _ldap._tcp.dc._msdcs.ldap.local.site SRV \ @ldapmaster.local.site
Nun fügen wir (samba und slapd auf ldapmaster aktiv, auf ldapslave nicht) per: #> /usr/local/samba/bin/net join LDAP BDC -U administrator%linux
(auf der Konsole von ldapslave ausgeführt) unseren 2. Samba 4-DC (ldapslave) der Domain hinzu. Sollte alles gut gegangen sein, sieht der Output i.e. so aus: We still need to perform a DsAddEntry() so that we can create the CN=NTDS Settings container. Joined domain LDAP (S-1-5-21-4286536947-1969703804-385546026)
Der erste der beiden Einträge ist der relevante Part: Wir müssen unterhalb von cn=configuration,dc=ldap,dc=local,dc=site noch manuell ein Objekt für den frisch gejointen ldapslave generieren. Das entsprechende LDIF finden wir in den Beispieldaten zu diesem Abschnitt, und fügen es (Zeile umbrochen) per: #> /usr/local/samba/bin/ldbadd -H ldap://localhost \ -U administrator ntds-dc2.ldif
in den DIT unseres (noch) aktiven DC1 (ldapmaster) ein, die Rückmeldung sollte: Added 1 records with 0 failures
lauten. Nun stoppen wir slapd und samba auf DC1 (ldapmaster); anschließend führen wir zuerst das Backend-Provisioning auf unserem DC2 (ldapslave) analog zur eben für ldapmaster (DC1) beschriebenen Vorgehensweise durch. Danach starten wir slapd auf DC2 (ldapslave), und führen das finale Provisioning durch – natürlich mit der gleichen Domain-SID, wie auf DC1: #> setup/provision --realm=ldap.local.site --domain=LDAP \ --server-role='domain controller' \ --ldap-backend="ldap://ldapslave.local.site:9000/" \ --ldap-backend-type=openldap --password=linux \
410
1198.book Seite 411 Donnerstag, 5. Februar 2009 3:02 15
Die Meister der Domäne: OpenLDAP und Samba
--username=samba-admin --adminpass=linux \ --domain-sid="S-1-5-21-4286536947-1969703804-385546026"
Nach Abschluß des finalen Provisionings auf DC2 stoppen wir unseren slapd auf DC2 (ldapslave); anschließend starten wir zunächst slapd und samba auf DC1, dann in gleicher Reihenfolge beide Dienste auf DC2. Stark abstrahiert stellt sich unser Konstrukt dann – bezogen auf unsere 2 DCs – etwa wie folgt dar: Direkte Replikation zwischen den LDAP-Backends
(Port 9000)
(Port 9000)
OpenLDAP
OpenLDAP
ldb-mapper
ldb-mapper
Samba
Samba
DC1 (»LDAP«-Port 389/636)
DC2 (»LDAP«-Port 389/636)
Client
Client
Client
Abbildung 4.6 Schematische Darstellung von 2 Samba4 DC’s in Multi-Master-Replikation mit OpenLDAP-Backend
Die Struktur des Samba 4 –»ADS«-DIT gliedert sich dabei in verschiedene Subkontexte (cn=users/cn=config/cn=schema) auf; wir haben nun die Wahl, welche Settings/Container wir auf unseren zweiten DC replizieren möchten bzw. müssen. Aktuell wird »nur« die statische Konfigurationsvariante (über slapd.conf) unterstützt; eine automatisierte olc-Konversion wurde von Andrew Bartlett und Oliver Liebel konzeptionell schon erörtert und steht bereits auf der To-Do-Liste. Bis hierher haben wir den OpenLDAP-seitigen Part der Samba 4-MMR-Konfiguration komplett erschlagen. Was die komplette, Samba-seitige Implementierung und Umsetzung der Multi-Master-Replikation angeht, stehen noch ein paar Punkte auf der To-Do Liste der Entwickler (z.B. keytab-Synchro, Administrierbarkeit des DIT nach Ausfall eines DCs), deren Lösungsansätze jedoch schon recht bald klare Konturen zeigen dürften. Das folgende Bild zeigt 2 Samba 4/OpenLDAP DCs in der MMC, die sich gegeneinander replizieren und in weiten Teilen bereits »normal« administrierbar sind:
411
4.1
1198.book Seite 412 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Abbildung 4.7 2 Samba4/OpenLDAP DCs in der MMC
Der kleine Einblick in Samba 4 mit OpenLDAP-Backend hat hoffentlich Lust auf mehr gemacht. Weitere Informationen rund um Samba 4 finden sich natürlich unter www.samba.org, sowie FAQs und (leider nicht immer ganz aktuelle) HowTos unter wiki.samba.org.
4.2
Für die Furchtlosen: OpenLDAP und Kerberos
Auch den Kerberos sah ich, mit bissigen Zähnen bewaffnet Böse rollt er die Augen, den Schlund des Hades bewachend. Wagt es einer der Toten an ihm vorbei sich zu schleichen, So schlägt er die Zähne tief und schmerzhaft ins Fleisch der Entfliehenden. Und schleppt sie zurück unter Qualen, Der böse, der bissige Wächter. Aus den Gesängen des Homer – Odysseus Was »zur Hölle« ist Kerberos? Im geschichtlichen Kontext eigentlich schnell erklärt: die dreiköpfige, meist schwer übel gelaunte Töle aus der griechischen Mythologie, die das Portal zur Unterwelt bewacht. Klingt in jedem Fall bissig. Das ist unser Kerberos auch, denn unser Höllenhund soll vor allem eines tun: bewachen. Und diese Aufgabe meistert der binäre Gegenpart der Bestie sehr gut.
412
1198.book Seite 413 Donnerstag, 5. Februar 2009 3:02 15
Für die Furchtlosen: OpenLDAP und Kerberos
Kerberos bietet per Definition die Möglichkeit einer ticket-basierten, sicheren Authentifizierung von »sicheren« Hostrechnern innerhalb eines unsicheren TCP/ IP-Netzes. (By the way – welches Netz ist wirklich sicher? Aber das ist Thema eines anderen Buches.) Die eigentliche Authentifizierung wird dabei über einen Dritten im Bunde abgewickelt, der eine Vertrauensstellung genießt: Kerberos. Daher wird dieses Verfahren auch oft »Trusted Third Party« genannt. Der Kerberos-Dienst sollte aus Sicherheitsgründen immer nur auf einem dedizierten Server laufen, auf dem sonst keine weiteren Dienste installiert sind, da sie potenzielle Intrusions-Möglichkeiten bieten könnten. Physikalisch und über das Netzwerk sollte nur der Admin Zugang zu diesem Rechner haben. Betrachten wir zunächst die prinzipielle Funktionsweise des Verfahrens, bei der sich – vereinfacht ausgedrückt – jeder gegenüber jedem authentifiziert: der Client gegenüber dem Applikationsserver, der Applikationsserver gegenüber dem Client, und der Kerberos-Server schließlich verifiziert seine Identität sowohl gegenüber Client als auch Server, sehr frei nach Arthur Schnitzlers »Der Reigen«. Bevor wir uns das Verfahren an sich anschauen, sollten wir einen Blick auf die Kerberos-Terminologie werfen, denn sie bringt eine Reihe applikationsspezifischer Definitionen mit sich: 왘 Authenticator: wird bei der Authentifizierung eines Clients vom Client zusammen mit einem Ticket präsentiert, um die Identität des Clients zu verifizieren. Authentikatoren werden nur einmal verwendet. 왘 AS: Der Authentifizierungsserver ist Teil des KDC und nimmt die erste TicketAnfrage des Clients entgegen. 왘 Credentials: Berechtigungsnachweise, die den Client berechtigen, Dienste anzufordern. In der Kerberos-Terminologie sind das Tickets und Authentikatoren. 왘 KDC: das Key Distribution Center, der eigentliche Kerberos-Server. 왘 Kerberos: bezeichnet zum einen das Netzwerkprotokoll, über das die Kommunikation zwischen Client, Applikationsserver und KDC abläuft. Zum anderen ist damit auch der eigentliche Server-Dienst gemeint, der die Identitäten der Principals verwaltet, verifiziert und Tickets vergibt. 왘 Key: geheimer oder privater Schlüssel. Der geheime Schlüssel – das Benutzerpasswort – ist zwei Instanzen bekannt: dem Benutzer und dem Kerberos-Server. Der private Schlüssel ist üblicherweise immer nur einer Instanz bekannt, dem Benutzer, und wird in PKI in Verbindung mit einem öffentlichen Schlüssel verwendet.
413
4.2
1198.book Seite 414 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
왘 Principal: Kann ein Benutzer, ein Host oder ein Dienst sein. Die eindeutigen Principals werden in der Kerberos-Datenbank verwaltet und besitzen üblicherweise folgende dreiteilige Struktur: testuser/[email protected] Der erste, auch primary genannte Teil (in unserem Beispiel der User testuser) bezeichnet den User-, Host- oder Dienstnamen. Der zweite, optionale Teil (instance genannt) definiert die Rolle (/admin), der dritte Teil schließlich den so genannten Realm (@LOCAL.SITE). 왘 TGT: Das Ticket Granting-Ticket ist das erste angeforderte Ticket innerhalb einer Session. Es wird vom AS für die weitere Authentifizierung ausgestellt. 왘 TGS: der Ticket Granting Server; stellt dem Client nach Vorlage des TGT die Tickets für den vom Client angeforderten Service aus. 왘 Ticket: Credential, das ein Client benutzt, um sich bei einem Server zu authentifizieren, von dem er Services anfordern möchte. 왘 Realm: wörtlich übersetzt etwa so viel wie »Gebiet« oder auch »Bereich«. Üblicherweise entspricht der Realm dem Domänennamen in Großbuchstaben, in unserem Beispiel also LOCAL.SITE. Jeder Realm besitzt einen eigenen AS und TGS, bei dem sich die dem Realm zugehörigen Hosts authentifizieren und Tickets anfordern. 왘 SessionKey: temporärer Schlüssel (pro Session) zur Verschlüsselung der Kommunikation zwischen Server und Client. Betrachten wir nun das Verfahren selbst: Wir gehen dabei zunächst von einem beliebigen Principal aus, der in unserer Kerberos-Datenbank bereits existiert. Ein Principal kann, wie bereits erläutert, in der Kerberos-Terminologie sowohl ein User, ein Host oder auch ein Service sein (wie z.B. unser alter Bekannter ldap/slapd). Nehmen wir für unseren Fall weiter an, es handelt sich um den User ckent, der sich anmelden will. Er gibt seinen Benutzernamen (ckent) zur Authentifizierung ein. Dieser Benutzername geht nun über das Netz zum Kerberos- Server, dem so genannten KDC (Key Distribution Center). Der KDC besteht aus zwei Teilen: dem TGS (Ticket Granting Server) und dem AS (Authentification Server). Der Principal und sein Passwort sind dem AS bekannt; er generiert einen zufälligen Session Key, der nur während der aktuellen Session gültig ist. Dieser Session Key wird für die Kommunikation zwischen dem Principal und dem TGS benötigt. Der AS erstellt nun ein Ticket, das für den TGS bestimmt ist und ebenfalls mit einem Session Key verschlüsselt wird. Diesen Session Key kennen nur der TGS und der AS. Danach wird das Ticket – zusammen mit dem Session Key – mit einem persönlichen Schlüssel codiert, der vom Benutzerpasswort abgeleitet ist, und vom AS zurück an den Principal gesendet. Daraufhin erscheint die Eingabeaufforderung
414
1198.book Seite 415 Donnerstag, 5. Februar 2009 3:02 15
Für die Furchtlosen: OpenLDAP und Kerberos
für das Benutzerpasswort. Der Principal (ckent) gibt sein Benutzerpasswort ein. Das eingegebene Passwort wird in einen Schlüssel konvertiert, der das vom AS an den Principal gesendete Paket decodiert. Nach der Decodierung des Pakets erfolgt die umgehende Löschung von Schlüssel und Passwort aus dem RAM des Principals. So wird potenziellen Angreifern keine Möglichkeit gegeben, dieses im Nachhinein noch auslesen zu können. Hierbei ist auch zu beachten, dass zu keinem Zeitpunkt ein Passwort über das (potenziell unsichere) Netz verschickt wird. Nun ist unser Principal im Besitz eines TGT (Ticket-Granting-Tickets). Das TGT bescheinigt ihm netzwerkweit seine Identität bis zum vorgegebenen Zeitpunkt der Löschung. Nun möchte Clark Kent die Autorisierung erhalten, einen »kerberisierten« Dienst auf dem Applikationsserver zu nutzen. Nehmen wir an, er startet z.B. seinen FTPClient, um die Verbindung mit dem FTP-Server auf dem Applikationsserver aufzunehmen. Nun passiert Folgendes: Der FTP-Client generiert einen so genannten »Authenticator« (der die Identität der Client-Applikation verifiziert) und bittet den TGS (unter Vorlage des TGT, das der Principal bereits erhalten hat) um ein neues Ticket für den gewünschten FTP-Serverdienst. Der TGS erstellt der anfragenden Client-Applikation ein Service-Granting-Ticket (SGT). Der FTP-Client legt es zusammen mit dem Authenticator dem FTP-Server vor. Daraufhin erhält der FTP-Client (und damit letztlich auch der Principal) die Autorisation, den FTP-Serverdienst zu nutzen. Zugegeben, das Verfahren klingt nicht ganz einfach – und das ist es auch. Daher sehen wir uns das Zusammenspiel der Komponenten noch einmal schematisch in der folgenden – stark abstrahierten – grafischen Darstellung an: Anfrage für TGT (1) Kerberos-Client (Principal)
(5) Client fordert kerberisierten Dienst an
Anfrage für SGT (3) Client erhält SGT (4) Client erhält TGT (2)
Kerberos-Server KDC (AS/TGS)
(6) Antwort des Dienstes an Client
Applikationsserver LDAP, FTP ...
Abbildung 4.8
Vereinfachte Darstellung einer Kerberos-Authentifizierung
415
4.2
1198.book Seite 416 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Die Sicherheit des Verfahrens ist recht hoch; hierzu tragen die folgenden Aspekte bei: Zu keinem Zeitpunkt wird – wie bereits erwähnt – über das Netzwerk ein Passwort versendet, das mitgesnifft werden könnte. Die Tickets haben nur eine beschränkte Lebensdauer und sind an die IP des anfragenden Clients gebunden. Durch die Sessionkeys, Timestamps und die gegenseitige Authentifizierung (Mutual Authentification) ist die Gefahr einer Man-in-the-Middle-Attacke deutlich vermindert. Eine Replay-Attacke (Capture des Tickets, Verschicken mit neuer ID) wird durch die Timestamps und das mögliche Zeitfenster für gültige Tickets erschwert. Daher ist eine perfekt abgestimmte und abgesicherte Zeitsynchronisation eine grundlegende Voraussetzung für die Sicherheit des Kerberos-Systems. Durch unsere intensiven NTP-Vorarbeiten im Kapitel über Replikation sollten wir hier eindeutig auf der sicheren Seite sein. Dennoch ist eine regelmäßige Kontrolle unabdingbar. Zu bedenken ist aber, dass auch Kerberos nicht gefeit gegen Dictionary Attacks (Wörterbuchattacken zum Erraten von Passwörtern von Tickets, die abgefangen wurden) ist, sowie gegen Angriffe von kompromittierten Clients innerhalb des Realm, die administrative Kerberos-Tools auf dem KDC mit Root-Rechten ausführen könnten. Unser Ziel Ganz einfach: Wir wollen zunächst Kerberos als primären Authentifizierungsdienst einrichten. Danach werden wir als User über den SASLMech GSSAPI verschlüsselt auf die Datenbestände in unserem LDAP zugreifen. Zum Leidwesen aller Datenschnüffler werden wir dann per syncrepl, TLS und SASLMech GSSAPI eine »kugelsichere«, kerberisierte Replikation zwischen Provider und Consumer einrichten. Ebenfalls werden wir den kerberisierten Zugriff von Clients auf eine Samba-Domäne demonstrieren, sowohl von einem Linux- als auch von einem Windows-XP-Client aus. Und als Krönung des Ganzen schauen wir uns außerdem an, wie wir den Hund sogar auf (bzw. im LDAP-Fall besser gesagt: in) den Baum bekommen. Klingt komisch? Abwarten und lesen ... Die wunderbare Welt der Abkürzungen – SSO, SPoF und SPoA Eine kurze Bemerkung zu den vorgenannten Kürzeln ist an dieser Stelle wohl angebracht. Unter SSO versteht man im üblichen IT-Sprachgebrauch das so genannte Single-Sign-On-Verfahren. Zu gut Deutsch – einmal authentifiziert – Zugriff auf alle Dienste. Klingt so weit schon mal prima, und das ist es im Kern auch. Kerberos bietet hierfür mit Sicherheit einen der besten Ansätze, da viele Services auf kerberisierte Authentifizierung ein- bzw. umgestellt werden können. Im Zusammenspiel mit PAM ist die ganze Geschichte zudem noch relativ einfach
416
1198.book Seite 417 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
konfigurierbar. Und die ewig nörgelnden User – allen voran der Chef –, die sich auf gar keinen Fall mehr als einmal am System authentifizieren möchten, damit die Finger bloß nicht wund werden, können eventuell das Zünglein an der Waage sein. Eine Sache sollte man dabei stets im Hinterkopf behalten: Ein SSO ist nicht nur ein SSO, sondern kann auch ganz schnell ein SPoF – ein Single Point of Failure – sein. Denn sollte es einem Angreifer gelingen, das kerberisierte Authentifizierungssystem zu kompromittieren, hat er mit einem Schlag auch direkten Zugriff auf sämtliche Services, auf die der User-Account Zugriff hat. Mit all seinen Rechten.
Was wir im Folgenden beschreiben, kann sicherlich als Ausgangsbasis für ein SSO-System dienen. Die letztendliche Entscheidung hierfür trifft natürlich immer der Admin, sowohl im Hinblick auf Sicherheitskriterien als auch auf die verwendeten Applikationen. Was wir aber nach Durcharbeitung dieses Buches haben werden, ist in jedem Fall ein SPoA – ein Single Point of Administration. Zumindest, was die User, unseren OpenLDAP und die auf ihn zugreifenden Dienste angeht. Nun aber genug der Vorrede und ans Werk, sprich – ans Setup.
4.3
Setup von Kerberos V5
Kümmern wir uns nun um den Schlüsselmeister: die Einrichtung unseres KDC, des Key Distribution Centers. Wir betrachten im Folgenden das Setup beispielhaft anhand des MIT-Kerberos. Eine kurze Anmerkung zu Heimdal an dieser Stelle: Seit OpenSUSE 10 ist das Heimdal-Kerberos-Paket nicht mehr Bestandteil dieser Distribution, Debian bietet die Heimdal-Implementation zwar noch an, verfügt aber nun auch über den MIT-Kerberos. Daher werden wir im Folgenden nur einige grundsätzliche Punkte der Heimdal-Variante kurz anreißen. Da wir (genau wie z.B. bei Heartbeat oder Samba) nur einen kurzen Einstieg in diese sehr komplexe Applikation geben können, verweisen wir auf die umfangreichen Dokumentationen unter http://web.mit.edu/kerberos (MIT-Kerberos) und http://www.h5l.org/ (Heimdal-Kerberos). Wir installieren zunächst die erforderlichen Pakete (siehe Anhang: Paketlisting, Sektion Kerberos). Für unser Beispiel haben wir den KDC der Einfachheit halber auf unserem ldapmaster.local.site installiert, was sicherheitstechnisch in einer Produktivumgebung nicht unbedingt die optimale Lösung ist. Daher weisen wir an dieser Stelle noch einmal darauf hin, den KDC gemäß den vorab genannten Sicherheitskriterien möglichst immer auf einer dedizierten Maschine zu installieren, die besonders abgesichert
417
4.3
1198.book Seite 418 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
ist, oder zumindest dafür zu sorgen, dass alle neuralgischen Dateien (wie z.B. die Host-/Service-Keytab) besonders sorgsam abgesichert werden. Kernstück bilden die Konfigurationsdateien kdc.conf und /etc/krb5.conf. Die Konfigurationsdatei des KDC (Key Distribution Centers) kdc.conf befindet sich unter /var/lib/kerberos/krb5kdc/ (SUSE) bzw. /etc/krb5kdc/ (Debian). Heimdal verwendet /var/lib/heimdal-kdc/. Die clientseitige Kerberos-Konfiguration nehmen wir über die /etc/krb5.conf vor. Zunächst setzen wir einige Parameter in den beiden Konfigurationsdateien für unseren Realm (die Pfade können je nach Distribution abweichen): krb5.conf [libdefaults] default_realm = LOCAL.SITE [realms] LOCAL.SITE = { kdc = ldapmaster.local.site admin_server = ldapmaster.local.site } [logging] kdc = FILE:/var/log/krb5/krb5kdc.log admin_server = FILE:/var/log/krb5/kadmind.log default = SYSLOG:NOTICE:DAEMON
kdc.conf [kdcdefaults] kdc_ports = 750,88 [realms] LOCAL.SITE = { database_name = /var/lib/kerberos/krb5kdc/principal admin_keytab = FILE:/var/lib/kerberos/krb5kdc/kadm5.keytab dict_file = /var/lib/kerberos/krb5kdc/kadm5.dict acl_file = /var/lib/kerberos/krb5kdc/kadm5.acl key_stash_file = /var/lib/kerberos/krb5kdc/.k5.LOCAL.SITE kdc_ports = 750,88 max_life = 10h 0m 0s max_renewable_life = 7d 0h 0m 0s } [logging] kdc = FILE:/var/log/krb5/kdc.log admin_server = FILE:/var/log/krb5/kadmin.log [appdefaults] pam = {
418
1198.book Seite 419 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
ticket_lifetime = 1d renew_lifetime = 1d forwardable = true proxiable = false retain_after_close = false minimum_uid = 0 try_first_pass = true }
Mit dem Befehl: #> kdb5_util create -r LOCAL.SITE -s
erzeugen wir die eigentliche Kerberos-Datenbank für unseren Realm (-r) LOCAL.SITE, und zusätzlich über den Parameter (-s) die stash-Datei (.k5.LOCAL.SITE), in welcher der Master-Schlüssel (unsere Passworteingabe) verschlüsselt abgelegt wird. Loading random data Initializing database '/var/lib/kerberos/krb5kdc/principal' for realm 'LOCAL.SITE', master key name 'K/[email protected]' You will be prompted for the database Master Password. It is important that you NOT FORGET this password. Enter KDC database master key: Re-enter KDC database master key to verify:
Beim Heimdal-Kerberos wird der Realm nach Aufruf des kadmin-Tools im local (-l)-Modus per init LOCAL.SITE, der Schlüssel mit dem Befehl kstash angelegt. Der Schlüssel findet sich unter /var/lib/heimdal-kdc/m-key. Im nächsten Schritt erstellen wir ein paar grundlegende Kerberos-ACLs. Sie werden in der Datei .. /krb5kdc/kadm5.acl (Heimdal: kadmind.acl) wie folgt eingetragen: */[email protected] * *@LOCAL.SITE cil */*@LOCAL.SITE i
Die Reihenfolge der Einträge ist wichtig. Genau wie bei den LDAP-ACLS wird die Suche nach dem ersten passenden Eintrag abgebrochen. Die erste Spalte gibt das Muster vor; die Berechtigungen ergeben sich aus den in der zweiten Spalte angegebenen Parametern: * bedeutet Vollzugriff, cil erlaubt z.B. Passwortänderungen (c=change), Auslesen der Principals und (l=list) und Datenbankabfragen (i=info). Die Admin-Principals haben in unserer Konfiguration Vollzugriff, User haben cil, und Services bzw. Hosts nur i. Die Syntax der ACL-Datei unter Heimdal weicht von der oben genannten Darstellung ab, daher lohnt ein Blick in die entsprechenden Sektionen beider Dokus bzw. in kadmind(8).
419
4.3
1198.book Seite 420 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Nun zu den wichtigsten Tools, um unseren Kerberos-Server zu verwalten. Nachdem wir unseren Realm angelegt und die wichtigsten ACLs generiert haben, geht es nun an das Erstellen der eigentlichen Principals. Dazu verwenden wir zunächst das Admin-Tool kadmin.local. Die Tools kadmin und kadmin.local sind von der Funktionalität her identisch; allerdings greift kadmin.local direkt auf die KDCDatenbank zu und benötigt selbst keine Kerberos-Authentifizierung (die zu diesem Zeitpunkt ja auch noch gar nicht in Funktion ist). Zur späteren, netzwerkweiten Verwaltung sollte kadmin verwendet werden. Wir rufen also kadmin.local (Heimdal: kadmin -l) auf und legen am Prompt (kadmin.local:) des kadmin-Interfaces nun einige Principals an. Eine Übersicht der zur Verfügung stehenden Direktiven im kadmin(.local)-Interface liefert die Eingabe von »?«. Achtung: Die Principals sind stets Case-Sensitive. Daher vor allem auch bei Host- und Service-Principals immer auf den exakten Namen achten! Nach der Eingabe von: addprinc root/admin
und der Eingabe (und Bestätigung) des Passworts erscheint folgende Ausgabe: WARNING: no policy specified for root/[email protected]; defaulting to no policy Enter password for principal "root/[email protected]": Re-enter password for principal "root/[email protected]": Principal "root/[email protected]" created.
Nun existiert (dank administrativer Rolle: */admin) ein User-Principal für Verwaltung unserer Kerberos-Datenbank. Der Realm wird dabei automatisch angehängt. Der adäquate Heimdal-Befehl lautet einfach add <principal>. Mit dem Befehl getprincs (Heimdal: list *) können wir uns die bereits bestehenden Accounts (inklusive der bereits vorhandenen Kerberos-Standard-Accounts) listen lassen. Danach legen wir analog zum oberen Beispiel Accounts für unsere User an; allerdings erhalten sie keine administrative Rolle, es fehlt also der /admin-Teil des Principals. Als Passwörter vergeben wir überall »linux«, analog zu den bestehenden Passwörtern im LDAP: addprinc ckent ... addprinc hcallahan
usw. Wie bereits erwähnt, werden Principals auch zur Host- und Service-Authentifizierung benötigt. Um unseren LDAP in Verbindung mit SASLMech GSSAPI nutzen zu können, müssen wir Principals für die Hosts und die Services anlegen: addprinc –randkey ldapmaster.local.site
420
1198.book Seite 421 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
Hier erfolgt keine Passwortabfrage, stattdessen wird ein Zufallsschlüssel (-randkey) generiert. Im Heimdal-Kerberos lautet das entsprechende Kommando add – r <principal>. Analog zum Host-Principal für ldapmaster generieren wir einen weiteren für ldapslave. Um nun einen Service-Principal anzulegen (in unserem Fall natürlich ldap), müssen wir auch den Host angeben, auf dem er läuft, also: addprinc –randkey ldap/ldapmaster.local.site
In der gleichen Weise gehen wir vor für ldap/ldapslave, bevor wir kadmin.local per exit-Kommando verlassen. Damit wäre das Gröbste schon fast geschafft. Um den KDC für die Hosts und Services nutzen zu können, müssen wir noch eine krb5.keytab unter /etc anlegen. Die Keytab für unsere beiden Hosts (ldapmaster und ldapslave) erstellen wir im kadmin-Interface mit dem Kommando ktadd: ktadd ldapmaster.local.site ldapslave.local.site
bzw. mit ktutil bei Heimdal: ktutil get <principal1 principal2 ...>
Die Ausgabe für den MIT-Kerberos sollte in etwa so aussehen: Entry for principal ldapmaster.local.site with kvno 3, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/etc/krb5.keytab. Entry for principal ldapmaster.local.site with kvno 3, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/etc/krb5.keytab.Entry for principal ldap/ ldapmaster.local.site with kvno 3, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/etc/krb5.keytab. ...
Der Inhalt der neuralgischen Keytab-Datei /etc/krb5.keytab lässt sich mit dem Kommando ktutil rkt /etc/krb5.keytab einlesen und auflisten, bei Heimdal direkt mit ktutil list. Per delprinc und ktremove (MIT) lassen sich die Principals und deren zugehörige Keytab-Einträge innerhalb des kadmin-Interface löschen. Heimdal verwendet das ktutil-Kommando remove für die Entfernung der Keytab-Einträge. Aber Moment mal – wieso »neuralgische« Keytab? Der Schlüssel zu allem Warum die krb5.keytab so wichtig ist: in ihr befinden sich die lokalen Kopien der Schlüssel, den die Hosts/Services anstelle eines Passworts benötigen, um ihre Tickets verwalten zu können. Daher ist diese Datei auch potenzielles Angriffsziel. Sie sollte nur auf dem KDC bzw. Host zu finden sein, der sie benötigt. Sie sollte mit zusätzlichen Schutzmaßnahmen per Backup gesichert werden und nur minimale Zugriffsrechte haben.
421
4.3
1198.book Seite 422 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Genau aus diesem Grund sollten die Service-Principals für die LDAP-Dienste auf Provider und Consumer auch in einer separaten Keytab gespeichert werden, die nur für die Gruppe lesbar ist, mit deren Rechten unser slapd läuft, und die in dem jeweiligen Applikationsordner liegt (z.B. /etc/(open)ldap/ldap.keytab). Auf die separate Keytab wird im MIT-Kerberos mit der Variablen KRB5_KTNAME="FILE:// etc/ldap/ldap.keytab" verwiesen, die exportiert und per Startskript eingebunden werden sollte. Das Verfahren ist in der LDAP-Faq-O-Matic sehr gut beschrieben, daher gehen wir an dieser Stelle nicht weiter darauf ein. Heimdal-Anwender können alternativ über die applikationsspezifische Cyrus-SASL-Konfigurationsdatei (z.B. /usr/lib/sasl2/slapd.conf) mit dem Eintrag keytab:
auf die Datei verweisen, die der Mech GSSAPI als Keytab verwenden soll. Alternativ kann zum Testen als Quick & Dirty-Variante auch die Standard-Keytab /etc/ krb5.keytab für alle Host- und Service-Keys verwendet werden. Dazu muss sie aber für die Gruppe ldap bzw. die GID, mit welcher der LDAP-Dienst läuft, lesbar gemacht werden, was sicherheitstechnisch natürlich bedenklich ist. Bei SUSE kann z.B. über die Datei /etc/sysconfig/openldap eine separate Keytab eingestellt werden: OPENLDAP_KRB5_KEYTAB="<path-to-keytabfile>" Als Nächstes starten wir die Dienste krb5kdc und kadmind (bei Debian schon geschehen), anschließend sollte uns nmap den Port 749 als neu hinzugekommenen Port für kadmin anzeigen. Auf den Ports 88 und 750 (udp) lauscht das KDC – wie in der kdc.conf eingestellt – auf ankommende Anfragen. Und nun ab an den Schalter, und schnell ein Ticket geholt. Als angemeldeter Benutzer geben wir einfach: #> kinit root/admin
ein. Nach Angabe des Kennworts für seinen Principal erhält der User sein erstes Ticket (TGT), dessen Vorhandensein wir uns mit klist schnell bestätigen lassen können: Ticket cache: FILE:/tmp/krb5cc_0 Default principal: root/[email protected] Valid starting Expires Service principal 11/25/08 21:22:44 11/26/08 07:22:44 krbtgt/[email protected] renew until 11/26/08 21:22:44 Kerberos 4 ticket cache: /tmp/tkt0 klist: You have no tickets cached
Resümieren wir: Was bringt´s uns bisher? Noch nicht wirklich viel. Was aber auch nicht weiter verwunderlich ist, denn wir haben uns auch noch nicht mit den kerberisierten Diensten und automatischer TGT-Erstellung, die im Rahmen eines Single-Sign-On-Verfahrens Sinn ergeben, beschäftigt. Das werden wir jetzt nach-
422
1198.book Seite 423 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
holen. Beginnen wir logischerweise mit dem ersten Dienst, mit dem der Benutzer in Berührung kommt: dem Login am System.
4.3.1
Was diese Frau so alles treibt: Schon wieder PAM …
Rufen wir uns zunächst in Erinnerung, dass der binäre, namentliche Gegenpart unserer mittlerweile etwas in die Jahre gekommenen Stripperella modular konzipiert ist. Also suchen wir als Erstes nach einem entsprechenden Kerberos-Modul für PAM, das wir »hinzupluggen« können, und werden schnell fündig. Die Pakete finden sich unter den Bezeichnern pam_krb5 (SUSE) bzw. libpam-krb5 (Debian), für Heimdal wird unter Debian das Paket libpam-heimdal benötigt. Die Pakete enthalten das PAM-Modul pam_krb5.so, dass nach der Installation unter /lib/security/ zu finden ist. Das Modul selbst können wir in der bereits aus dem Abschnitt 3.6, »Hör mal, wer da hämmert«, bekannten Vorgehensweise implantieren. Ansatzpunkt hierbei bilden wie üblich die Dateien unter /etc/pam.d/*. Idealerweise verwenden wir die Dateien common-*, da sie als Includes in alle applikationsspezifischen PAM-Konfigurationsdateien eingebunden sind, so auch bei dem für uns an erster Stelle interessanten login. In der common-auth sind, wie wir wissen, die globalen PAM-Module hinterlegt, die sich um die Authentifizierung kümmern. Hier fügen wir das pam_krb5Modul ein; sufficient sorgt dafür, dass pam_ldap.so bei Erfolg des krb5-Moduls nicht mehr involviert wird: auth auth auth auth
required sufficient sufficient required
pam_env.so pam_unix2.so pam_krb5.so pam_ldap.so
use_first_pass debug use_first_pass debug
Vorab an dieser Stelle noch einmal der Sicherheitshinweis, den wir bereits im Abschnitt 3.6, »Hör mal, wer da hämmert«, über Authentifizierung angesprochen haben: Bei allen Änderungen an den Konfigurationsdateien, die in irgend einer Form mit der Authentifizierung am System zu tun haben, sollten eine oder mehrere weitere Konsolen geöffnet sein, auf denen wir mit Root-Rechten eingeloggt sind. Durch diese Hintertür können wir im Fall der Fälle fehlerhafte Konfigurationen im Bedarfsfall wieder zurechtbiegeben.
Durch unsere Konfigurationsvorgabe wird primär der Einsatz des PAM-KerberosModuls zur Authentifizierung gefordert; existiert kein User-Principal, greift pam_ ldap als Fallback. Die debug-Parameter dienen der Fehlersuche und können nach Sicherstellung der Funktionalität wieder entfernt werden. Debian loggt in die
423
4.3
1198.book Seite 424 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Datei /var/log/auth.log. SUSE schiebt (mal wieder) alles in die /var/log/messages, daher bringt dort ein #> tail –f /var/log/messages | grep pam
eindeutig mehr Übersicht, und hilft später – dank aktiviertem pam_krb5-debugMode –, fehlerhafte Konfigurationen schneller aufzuspüren. Danach passen wir die entsprechenden Sektionen der anderen common-*-Dateien analog an. Durch die Integration des pam_krb5-Moduls in die jeweiligen Sektionen kann der User nun in gewohnter Manier sein Passwort ändern, ohne sich um Kerberos-spezifische Belange kümmern zu müssen. Melden wir nun einen »normalen« User am System an, so passiert Folgendes: Wenn für den User bereits ein Principal existiert, greift pam_krb5.so, und die Authentifizierung inklusive TGT-Erstellung wird durchgeführt. Existiert kein Principal für den User, so erfolgt der Fallback auf das Modul pam_ldap.so, damit sich der Benutzer überhaupt anmelden kann. Nun testen wir die ganze Mimik anhand eines Benutzerwechsels. Da pam_krb5 in common-auth liegt, wird es in diesem Fall von su ebenfalls angesprochen. Wir wechseln hierzu einfach per su -<user> von einem »normalen« Benutzeraccount in einen anderen, für den wir noch kein Ticket angefordert haben und für den natürlich ein entsprechender Principal existieren muss. (Alternativ können wir ein vorhandenes Ticket auch mit kdestroy löschen.) Nach erfolgter Ummeldung per su sollte uns klist mit folgender Ausgabe beglücken (in unserem Beispiel muss der alte Harry Callahan herhalten): ckent@ldapmaster> su – hcallahan Passwort:
hcallahan@ldapmaster:~> klist Ticket cache: FILE:/tmp/krb5cc_902_dski7N Default principal: [email protected] Valid starting Expires Service principal 11/25/08 21:43:10 11/26/08 07:43:10 krbtgt/[email protected] renew until 11/26/08 21:43:10 Kerberos 4 ticket cache: /tmp/tkt902 klist: You have no tickets cached
Das Log sollte bei einer korrekten Anmeldung mit aktiviertem debug-Mode für pam_krb5.so in etwa folgende (stark gekürzte) Ausgabe liefern; hier für ein login von ckent über putty und ssh: called to authenticate 'ckent', realm 'LOCAL.SITE' ldapmaster sshd[3527]: pam_krb5[3527]: authenticating '[email protected]' ldapmaster sshd[3527]: pam_krb5[3527]: checking for externally-obtained v5 credentials ldapmaster sshd[3527]: pam_krb5[3527]: KRB5CCNAME is not set, none found ldapmaster sshd[3527]: pam_krb5[3527]: trying previously-entered password for 'ckent',
424
1198.book Seite 425 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
allowing libkrb5 to prompt for more ldapmaster sshd[3527]: pam_krb5[3527]: authenticating '[email protected]' to 'krbtgt/[email protected]' ... ldapmaster sshd[3527]: pam_krb5[3527]: account management succeeds for 'ckent' ldapmaster sshd[3527]: pam_krb5[3527]: '[email protected]' passes .k5login check for 'ckent' ldapmaster sshd[3525]: Accepted keyboard-interactive/pam for ckent from 192.168.31.44 port 2951 ssh2 ldapmaster sshd[3525]: pam_krb5[3525]: configured realm 'LOCAL.SITE' ... ldapmaster sshd[3525]: pam_krb5[3525]: creating v5 ccache for 'ckent', uid=901, gid=100 Nov 25 21:48:54 ldapmaster sshd[3525]: pam_krb5[3525]: saving v5 credentials to 'MEMORY:[email protected]' for internal use ldapmaster sshd[3525]: pam_krb5[3525]: copied credentials from "MEMORY:[email protected]" to "FILE:/tmp/krb5cc_901_5sbvhp" for the user, destroying "MEMORY:[email protected]" ldapmaster sshd[3525]: pam_krb5[3525]: created v5 ccache 'FILE:/tmp/krb5cc_901_ghl0Rd' for 'ckent' ldapmaster sshd[3525]: pam_krb5[3525]: pam_open_session returning 0 (Success)
Sollte die automatische TGT-Erstellung fehlschlagen, obwohl das login bzw. su und die Ticket-Erstellung per kinit problemlos funktionieren, kann die Ursache in der jeweiligen Binary liegen, die diese Funktion gegebenenfalls nicht unterstützt. In einigen Fällen lassen sich entsprechende Binaries des MIT- oder Heimdal-Kerberos einbinden, die dies unterstützen. Wir empfehlen, hierzu auf jeden Fall vorab die jeweilige Dokumentation intensiv zu studieren, eine Sicherheitskopie der originalen Binary anzulegen und das System erst dann wirklich in Betrieb zu nehmen, wenn alle authentifizierungstechnischen Vorgänge absolut reibungslos ablaufen. In jedem Fall gilt: Vor dem nächsten Reboot auf jeden Fall noch einmal sicherstellen, dass zumindest der root-Account sich ohne Probleme per Login am System anmelden kann!
So – die Anmeldung unserer LDAP-User mit automatischer Ticketerzeugung haben wir nun erschlagen. Das heißt konkret, wir haben ein TGT, aber was fangen wir der Service-Freikarte nun an? Na logisch – wir fordern einen Service an ...
4.3.2
SASL, die Zweite: GSSAPI
Wie schon in Abschnitt 3.4.3 über Cyrus-SASL und seine Mechs erwähnt, findet der SASLMech GSSAPI vorrangig in Verbindung mit Kerberos Verwendung. Das Kürzel GSSAPI steht für Generic Security Services Application Programming Interface und stellt entsprechend seiner Bezeichnung ein generisches API zur Verfü-
425
4.3
1198.book Seite 426 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
gung, das zur Client-Server-Authentifizierung verwendet wird. Kerberos V5 bringt zu diesem Zweck eine entsprechende GSSAPI-Bibliothek (libgssapi_ krb5.so) mit. Bevor wir loslegen, sollten wir natürlich noch prüfen, ob der entsprechende SASLMech auf unserer Maschine auch installiert ist (SUSE: cyrus-sasl-gssapi, Debian: libsasl2-modules-gssapi-mit), und unseren slapd gegebenenfalls neu starten, damit er die krb5.keytab einlesen kann. Führen wir nun als ckent, dessen Principal ja beim Login ein TGT erhalten hat, ein ldapsearch durch (alternativ explizit mit -Y GSSAPI), sollte die Ausgabe in etwa wie folgt aussehen: ckent@ldapmaster:~> ldapsearch uid=skiu -LLL SASL/GSSAPI authentication started SASL username: [email protected] SASL SSF: 56 SASL data security layer installed. dn: uid=skiu,ou=forschung,dc=local,dc=site ...
(Sollte die Rückmeldung des Systems ein fehlendes Ticket monieren, erzeugen wir per kinit einfach ein neues.) Wie wir erkennen können, ist nun keine weitere Authentifizierung am System mehr nötig, da der Zugriff auf den LDAPDienst mit Hilfe unseres Kerberos-Tickets erfolgt ist. Werfen wir dazu einen Blick auf die vorliegenden Tickets, so wird dies deutlich, denn nun liegt ebenfalls ein SGT für den LDAP-Dienst vor: hcallahan@ldapmaster:~>
klist
Ticket cache: FILE:/tmp/krb5cc_901_H9KvBo Default principal: [email protected] Valid starting Expires Service principal 11/25/08 22:13:21 11/26/08 08:13:21 krbtgt/[email protected] renew until 11/26/08 22:13:21
11/25/08 22:13:27
11/26/08 08:13:21
ldap/[email protected]
renew until 11/26/08 22:13:21
So könnte unser »kerberisierter« Clarkie nun ohne jede weitere Authentifikation – entsprechende ACLs vorausgesetzt – schreibend auf den DIT zugreifen. Aber genau da liegt der Haken. Denn um dem Principal Zugriff auf den DIT zu gewähren, müssen wir die ankommende Anfrage entsprechend umsetzen. Das erledigen wir mit der bereits bekannten Direktive authz-regexp, die wir entsprechend anpassen müssen. Als Erstes müssen wir uns dazu natürlich anschauen, wie der übermittelte String des Principals überhaupt aussieht, durch den die Anfrage erfolgt. Wie immer hilft uns der Debug-Mode unseres guten alten slapd auch hier weiter.
426
1198.book Seite 427 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
Betrachten wir eine Änderungsanfrage des Principals [email protected]; hierzu muss der Principal natürlich existieren, und wir müssen uns bereits ein entsprechendes TGT per kinit besorgt haben. Testen wir nun eine einfache Modifikation (z.B. Änderung des description-Attributwertes von ckent) auf der Konsole: #> ldapmodify -f kent.ldif SASL/GSSAPI authentication started SASL username: [email protected] SASL SSF: 56 SASL installing layers modifying entry "uid=ckent,ou=verkauf,dc=local,dc=site" ldap_modify: Insufficient access (50)
und beobachten unseren slapd im Debug-Mode (gekürzte Ausgabe): slap_sasl_getdn: u:id converted to uid=ldapadmin,cn=GSSAPI,cn=auth
==>slap_sasl2dn: converting SASL name uid=ldapadmin,cn=gssapi,cn=auth to a DN <==slap_sasl2dn: Converted SASL name to <nothing> SASL Authorize [conn=0]: proxy authorization allowed authzDN=""
do_bind: SASL/GSSAPI bind: dn="uid=ldapadmin,cn=gssapi,cn=auth" sasl_ssf=56
Wie wir anhand der Ausgabe unschwer erkennen können, muss die Änderungsanfrage scheitern, weil keine entsprechende Ersetzungsregel greift. Also wird versucht, die Änderung mit dem DN des Principals (uid=ldapadmin, cn=gssapi,cn=auth) durchzuführen, die logischerweise keine entsprechende Berechtigung in unseren ACLs hat. Da wir aber bereits wissen, was wir umsetzen müssen, erstellen wir eine simple authz-regexp-Direktive mit einer entsprechenden Ersetzungsregel in der slapd.conf: authz-regexp "uid=(.+),cn=GSSAPI,cn=auth" "cn=$1,dc=local,dc=site"
Hierbei wird der gefundene uid-String in der Ersetzungsregel über die Variable $1 abgebildet und erzeugt damit den gewünschten DN, der auch sauber per ACL ausgewertet werden kann. Führen wir nun noch einmal die gleiche Anfrage durch und betrachten erneut die Debug-Ausgabe des slapd: ==>slap_sasl2dn: converting SASL name uid=ldapadmin,cn=gssapi,cn=auth to a DN ==> rewrite_context_apply [depth=1] string='uid=ldapadmin,cn=gssapi,cn=auth' ==> rewrite_rule_apply rule='uid=(.+),cn=GSSAPI,cn=auth$' string='uid=ldapadmin,cn=gssapi,cn=auth' [1 pass(es)] ==> rewrite_context_apply [depth=1] res={0,'cn=ldapadmin,dc=local,dc=site'} <==slap_sasl2dn: Converted SASL name to cn=ldapadmin,dc=local,dc=site do_bind: SASL/GSSAPI bind: dn="cn=ldapadmin,dc=local,dc=site" sasl_ssf=56
427
4.3
1198.book Seite 428 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Wie wir anhand der Ausgabe erkennen können, benötigen wir – zumindest für den ldapadmin-Principal – noch keine zusätzliche ACL, da er ja ohnehin schreibberechtigt ist. Weitaus wichtiger bei dem oben verwendeten *-regexp-Konstrukt ist, dass der jeweilige User-Name des verwendeten Principals korrekt eingefügt wird und zu einem kompletten, existenten DN vervollständigt wird. Dadurch können wir die ACLs in der bekannten Syntax verwenden; zugleich können wir durch die zusätzliche ACL-Option ssf den übermittelten Security Strength Factor abfragen und auswerten. Wie das geht, wissen wir bereits aus unserem Kapitel über ACLs. Um nun »normale« User-Principals auszuwerten, die sich unterhalb einer ou im DIT befinden, benötigen wir dreierlei: erstens einen entsprechend ausgelegten Principal, zweitens eine adäquate authz-regexp-Direktive und drittens die zugehörige ACL. Das Format der *-regexp-Direktive hängt primär davon ab, wie unsere User-Principals aufgebaut sind bzw. ob ergänzend die Direktive saslrealm in der slapd.conf Verwendung findet. Eine authz-regexp-Direktive für einen User-Principal in der Form <user>_ (Unterstrich als Separator, also: ckent_verkauf ) könnte z.B. so aussehen: authz-regexp "uid=(.+)\_(.+),cn=GSSAPI,cn=auth$" "uid=$1,ou=$2,dc=local,dc=site"
Dann würde der DN der Authentifizierungsanfrage des User-Principal ckent_verkauf (User ckent aus der ou verkauf) aus der Sicht unseres slapd so aussehen: uid=ckent,ou=verkauf,cn=GSSAPI,cn=auth
Allerdings ist dabei zu berücksichtigen, dass die automatische Ticket-Generierung beim Login in diesem Fall nicht greift, da der Login-Account-Name (uid) in dem Fall ungleich dem Namen des verwendeten Principals wäre. Ein sehr simpler Workaround könnte darin bestehen, den Usernamen dem des Principals anzugleichen; weitere Informationen zum Mapping von Usernamen und Principals liefert der Kerberos Admin-Guide. Verwenden wir dagegen einen »normalen« User-Principal und die Direktive sasl-realm verkauf in der slapd.conf, würde der DN der Authentifizierungsanfrage so aussehen: uid=ckent,cn=verkauf,cn=GSSAPI,cn=auth
Eine weitere Variante von authz-regexp könnte unter Verwendung der LDAPURL-Syntax so aussehen:
428
1198.book Seite 429 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
authz-regexp "uid=(.+),cn=GSSAPI,cn=auth" "ldap:///ou=verkauf,dc=local,dc=site??sub?(uid=$1)"
Das gezeigte URL-Format entspricht dabei dem in RFC 2255 spezifizierten »The LDAP URL Format«. Egal, welches der Beispiele wir verwenden; wir nehmen nun an, der umgesetzte DN sieht letztlich so aus, dass jeder kerberisierte User auf seinen »normalen« DN gemappt wird. Nun erstellen wir noch eine passende ACL, die z.B. nur für alle User mit einem ssf=56 greift und ihnen Zugriff auf ihr eigenes Attribut description gewährt: access to attrs=description by ssf=56 self write by * break
4.3.3
Bullet-Proof: OpenLDAP-Replikation per syncrepl, TLS und Kerberos
Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren. Benjamin Franklin, 1706 – 1790 Klingt abwegig? Vielleicht ja, vielleicht nein – das muss wohl jeder für sich selbst entscheiden. Nach Ansicht etlicher unserer Volksvertreter scheint die totale Überwachung in Orwellscher Tradition der richtige Weg zu sein; eine Ansicht, die wir in Anbetracht von ständig steigenden Datenmissbrauchsfällen und sonstigen Schwachsinns-Aktionen durch Politik, Unternehmen und dank Lobbyisten immer noch butterweicher Datenschutzgesetze wohl kaum kommentieren müssen. Wir wollen an dieser Stelle jedenfalls dafür sorgen, dass sich auch die kleinsten Paranoia-Anfälle des stressgeplagten Admins ganz schnell wieder verflüchtigen, wenn er an die Sicherheit seiner replizierten Daten denkt, denn mit diesem Setup versauen wir den »normalen« bösen Buben (und den bösen Buben in ihren Maßanzügen, die uns ständig in allen Medien verklickern wollen, sie wären die Guten) endgültig den Tag: Wir setzen die Replikation zwischen Master und Slave per Kerberos/GSSAPI und TLS-verschlüsselt auf. Im Klartext (von bei diesem Setup niemand mehr etwas sehen sollte) heißt das: Wir haben als erste Sicherheitsstufe den verifizierten TLSHandshake mit dem Abgleich der Zertifikats-DNs, und authentifizieren uns anschließend zusätzlich noch per Kerberos-Principal durch den in diesem
429
4.3
1198.book Seite 430 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Moment bereits TLS-verschlüsselten Tunnel. Wer noch einen oben drauf setzen will, kann auch zusätzlich noch den SSF und die IP der Gegenstelle in die Replikator-ACL mit einbauen. Und genau das machen wir auch. Wie wir bereits wissen, benötigen wir beim Einsatz von Kerberos außer für die User-Principals auch noch die Service- und Host-Principals, die wir ja bereits generiert haben. Als da wären: ldap/ldapmaster.local.site ldap/ldapslave.local.site ldapmaster.local.site ldapslave.local.site
Als Nächstes stellen wir sicher, dass auf unserem ldapslave die krb5-Client-Bibliotheken installiert sind. Sämtliche relevanten Dateien werden analog zum Master auf Kerberos-Authentifizierung umgestellt, als KDC in der krb5.conf von ldapslave wird unser ldapmaster.local.site eingestellt. Um die Replikation per syncrepl in Verbindung mit GSSAPI und Kerberos aufzusetzen, benötigen wir auf der Provider-Seite keine zusätzlichen Anpassungen, es reichen die bereits in den Abschnitten über Replikation besprochenen Direktiven zum Overlay syncprov. Auf unserem Consumer muss natürlich Mech GSSAPI verfügbar sein. Was die TLS-relevanten Direktiven angeht, werden wir diese hier nicht mehr explizit erläutern. Das Setup erfolgt analog zu dem in Abschnitt 3.5, »Replikation und Chaining auf Nummer sicher«, beschriebenen. Auf der Consumer-Seite stellen sich die syncrepl-Direktiven wie folgt dar (auch hier wieder die Einrückungen beachten): syncrepl
rid=1 provider="ldap://ldapmaster.local.site" searchbase="dc=local,dc=site" type=refreshAndPersist retry="10 +" starttls="critical" bindmethod=sasl saslmech=GSSAPI authcId="[email protected]"
Die wichtigsten Modifikationen fallen sofort auf: Als SASLMech wird in Verbindung mit Kerberos natürlich GSSAPI gewählt, als neuer Parameter kommt authcId hinzu. authcId wird in Verbindung mit Kerberos verwendet, um eine Identität anzugeben, mit welcher sich unser SASLMech GSSAPI gegenüber der Gegenstelle – in diesem Fall also dem Provider – per Ticket authentifiziert (Wei-
430
1198.book Seite 431 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
tere Infos zu authcId liefert auch slapd.conf(5)). Wir können für diesen Anwendungsfall einen separaten Principal namens replicator erstellen, oder – viel einfacher – auf den bestehenden Host-Principal des Consumers zurückgreifen. Per authcId legen wir in der letzten Direktive also den Principal fest, mit dem sich unser Consumer gegenüber dem Provider authentifiziert. Dazu verwenden wir in diesem Fall den bereits vorhandenen Host-Principal ldapslave.local.site@ LOCAL.SITE. Der Principal selbst besitzt, wie jeder Host- oder Service-Principal, statt eines Passworts einen Schlüssel, der per Random Key (-randkey) generiert wurde und in der /etc/krb5.keytab hinterlegt ist. Wie das funktioniert, wissen wir aus dem letzten Abschnitt. Wichtig ist vor allem, dass der verwendete Principal auf beiden Maschinen in der krb5.keytab existiert. Weil unser ldapslave-slapd als KerberosClient agiert, muss er logischerweise eine entsprechende /etc/krb5.conf besitzen, die auf das KDC unseres ldapmasters zeigt. Im einfachsten Fall verwenden wir eine Kopie der krb5.conf von unserem ldapmaster. Die Verschlüsselung per TLS setzen wir auf critical, womit die Verbindung beim geringsten Fehlschlag des Handshakes abgebrochen würde. Dass die Zeitsynchro zwischen beiden Maschinen ebenfalls perfekt arbeiten muss, sollte in jedem Fall klar sein. Der nächste, wichtige Schritt ist das Kopieren der Datei /etc/krb5.keytab bzw. der entsprechenden Keytab-Datei, in der die Keys für die Host- und Service-Principals hinterlegt sind, auf die zweite Maschine (siehe oben). Natürlich auch hier wieder darauf achten, dass die Datei für die Gruppe ldap bzw. die Gruppe, mit deren Rechten der LDAP-Daemon läuft, lesbar ist. Dies sollte für Testzwecke ausreichen, für einen späteren Produktiveinsatz empfiehlt sich die Verwendung einer separaten Keytab, wie bereits im letzten Abschnitt beschrieben. Würden wir an dieser Stelle bereits versuchen zu replizieren, würden wir alles mögliche sehen, aber keinen funktionierenden SASL-bind. Unserem ldapslave fehlt schließlich im Moment noch vor allem eines: na klar, ein Ticket! Denn der authcId benötigt ein Ticket, mit dem er sich gegenüber dem Provider authentifizieren kann. Der per -randkey generierte Host-Principal für ldapslave in der /etc/krb5.keytab macht zwar die Eingabe eines Passworts bei der Ticketanforderung überflüssig, aber: Hat der Replikations-Principal ([email protected]) dadurch bereits ein Ticket? No way. Und da wir wohl kaum in regelmäßigen Abständen unseren wohlverdienten Schönheitsschlaf unterbrechen möchten, um das Ding manuell zu generieren, bietet sich eine automatische Ticketgenerierung als praktikable Lösung an, die wie folgt aussehen könnte: Wir erzeugen ein kleines Skript, das diesen
431
4.3
1198.book Seite 432 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Job per cron in regelmäßigen Abständen, die logischerweise kleiner als die maximale Ticket-Lifetime sind, für uns erledigt. Die Ticket-Lifetime können wir schnell per #> kadmin.local -q "getprinc ldapslave.local.site" | grep –i \ ^maximum\ ticket
abgreifen. Das Ergebnis ist in unserem Fall 10 Stunden. Maximum ticket life: 0 days 10:00:00
Ans Werk: Im ersten Schritt müssen wir eine Systemvariable setzen, in der die Ablage des Ticket-Caches definiert wird. Das kann im Dauereinsatz praktischerweise z.B. über eine Integration der nachfolgenden Direktiven in das LDAPStartskript des Slaves geschehen oder zum manuellen Test zunächst auf der Kommandozeile desselbigen: KRB5CCNAME="/var/run/syncrepl.krb5cache" export KRB5CCNAME
Weiterhin muss sichergestellt sein, dass das Ticket-Cache-File (/var/run/syncrepl.krb5cache) für den User und die Gruppe lesbar ist, mit deren Rechten unser LDAP läuft. Das Skript selbst läuft dabei mit root-Rechten. In unserem Fall setzen wir den Owner des Ticket-Cache-Files auf ldap, die Dateirechte bleiben aus Sicherheitsgründen auf 600: #!/bin/bash # script syncreplticket.sh REPLICA=`grep ^syncrepl /etc/openldap/slapd.conf` if [ ! -z "$REPLICA" ]; then kinit -k -t /etc/krb5.keytab ldapslave.local.site chown ldap /var/run/syncrepl.krb5cache fi
Nach dem ersten Replikationsvorgang sollte die Ausgabe von klist für unser Ticket-Cache-File in etwa so aussehen: Ticket cache: FILE:/var/run/syncrepl.krb5cache Default principal: [email protected] Valid starting Expires Service principal 08/14/08 14:56:43 08/15/08 14:56:43 krbtgt/[email protected] 08/14/08 14:57:23 08/15/08 14:56:43 ldap/[email protected]
Nun muss das Skript nur noch automatisch bei jedem Neustart und periodisch per cron angestoßen werden, wobei das Zeitintervall in unserem Fall kleiner die maximale Ticket-Lifetime von 10 Stunden gewählt werden sollte.
432
1198.book Seite 433 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
Schlägt die Replikation z.B. fehl, weil kein gültiges Ticket vorliegt, erscheint in der /var/log/messages oder der entsprechenden slapd-Log-Datei eine Meldung dieser oder ähnlicher Art: GSSAPI Error: Miscellaneous failure (No credentials cache found)
Zum Schluss können wir noch auf der Provider-Seite eine entsprechende ACL einsetzen, die den Lesezugriff auf den DIT regelt. Wer will, kann natürlich den »GSSAPI«-DN uid=ldapslave.local.site,cn=GSSAPI,cn=auth
per authz-regexp noch auf einen anderen Account umbiegen. Bei der Kürze des Strings spielt das jedoch eher eine untergeordnete Rolle. Im folgenden Beispiel beziehen wir als zusätzliche Sicherheit noch den SSF und die IP des Remote-Peers mit ein (Zeile 2 wurde umbrochen): access to * by dn="uid=ldapslave.local.site,cn=GSSAPI,cn=auth" \ peername.ip=”192.168.0.1” ssf=56 read by * break
Das ganze Setup funktioniert übrigens auch hervorragend, wenn die KerberosDB komplett in unserem LDAP-Tree untergebracht ist. Wie das funktioniert, lesen wir im nächsten Abschnitt, »Der Hund im Baum«. Einer perfekt verschlüsselten, ticketbasierten Replikation zwischen Provider und Consumer(n) sollte nun nichts mehr im Weg stehen. Wir können beruhigt schlafen, und die Freunde des Lauschangriffs können sich den Hintern weiter plattsitzen. Sollten Fehler aufgetreten sein, geht’s wie üblich ans Debugging. Checkliste: 왘 krb5.keytab und krb5.conf auf Consumer kopiert? Rechte der Dateien? 왘 Mech GSSAPI auf Consumer installiert? 왘 kdc aktiv auf Provider? 왘 Ticket-Initiierung (auf Consumer) per Script okay? 왘 KRB5-Variable exportiert (Consumer)? 왘 Klappt der reine Connect per TLS?
4.3.4
Der Hund im Baum – MIT-Kerberos-Datenbank im LDAP
Bis hierher war ja alles schon ganz nett: kerberisiertes login dank pam_krb5, kerberisierter Zugriff per GSSAPI auf unseren DIT, Replikation per TLS und Kerberos-Ticket, und so weiter und so fort.
433
4.3
1198.book Seite 434 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Aber ein Punkt sollte uns eindeutig noch nerven ... die separate Kerberos-Datenbank, in der die Principals abgelegt sind. Schließlich soll ein SPoA unser erklärtes Ziel sein, oder nicht? Das dachten sich die Jungs vom MIT auch und gaben ihrem Kerberos ein paar Tools und ein nettes, kleines Schema namens kerberos.schema mit dazu. Und nun schauen wir uns an, wie wir den (Höllen-)Hund auf bzw. in den Baum kriegen. Okay, im realen Leben wär’s wohl eher andersherum ... Vorab noch ein paar Hinweise zum Thema Sicherheit: Natürlich besteht auch bei diesem Setup eine Kommunikation zwischen OpenLDAP und Kerberos, die (je nach Standort des KDC) über das Netz geht. In Produktivumgebungen sollte diese Kommunikation daher immer in der hinlänglich bekannten Art über ldaps:// (SSL) abgesichert werden. Eine weitere Alternative wäre die Kommunikation zwischen OpenLDAP und Kerberos per ldapi://-Socket (siehe Abschnitt 4.1.6, »The new Dance«), was sich jedoch nicht wirklich mit den Kerberos-Sicherheitsprinzipien deckt (mehrere Services auf dem KDC). In unserem Test-Setup richten wir Kerberos und OpenLDAP zwar auf demselben Host ein (ldapmaster), dabei verwenden wir jedoch für die Kommunikation die Netzvariante per SSL; so, wie es im Produktivumfeld eingesetzt werden würde. TLS wird derzeit leider nicht unterstützt. Warum sich einige Institutionen (und nicht nur was dieses spezifische Produkt/Setup angeht) mit der TLS-Implementation in ihren Produkten immer noch schwer tun, steht mit Sicherheit in den Sternen. Anscheinend aber nicht in unserem Sonnensystem. Und noch eine generelle Anmerkung zur Thematik »Hund im Baum«: In einigen Mailinglisten tauchen immer wieder Kommentare auf, die die Sicherheit von Kerberos-Daten im LDAP anmeckern. Hier hilft, wie so oft im Leben – einfach mal vorher nachdenken, denn: 1. LDAP und X.500 sind unter anderem genau zu dem Zweck designt worden, um authentifizierungs-relevante Daten im DIT abzuspeichern. 2. LDAP besitzt aufgrund seines Designs wesentlich effizientere Zugriffskontrollmechanismen (ACLs), die sensitiven Daten einen besseren Schutz bieten als die relativ primitiven Zugriffskontrollen eines nackten KDCs. 3. Aus Sicht des KDC macht es für ihn nicht den geringsten sicherheitstechnischen Unterschied, ob er seine Daten aus der bdb unseres slapd holt oder aus seiner eigenen bdb(!). Zudem bietet die Hund-im-Baum-Variante Vorteile wie transparente Replikation der Credentials via syncrepl, feine Zugriffskontrolle per ACLs, und last but not least befinden sich alle Kerberos-relevanten Attribute im DIT bzw. sind Bestandteil des jeweiligen Objekts. SPoA ...
434
1198.book Seite 435 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
Und nun zur Hundedressur: Um einen Status quo herzustellen, sollte ein etwaiges, vorhandenes KerberosSetup komplett rückgängig gemacht bzw. bei Verwendung einer VM auf einen früheren Snapshot zugegriffen werden, in dem noch kein Kerberos-Setup durchgeführt wurde. Die Services krb5kdc und kadmind sollten nicht gestartet sein. Im ersten Schritt installieren wir alle benötigten Kerberos-Pakete (siehe Listing im Anhang zu diesem Abschnitt) sowie das zusätzlich erforderliche LDAP-spezifische Paket (SUSE: krb5-plugin-kdb-ldap, Debian: krb5-kdc-ldap). Im ersten Schritt nach seiner Installation kopieren wir das kerberos.schema aus dem Unterordner (hier die Pfadangabe für eine OSS 11) /usr/share/doc/packages/krb5/ in den Schema-Unterordner unseres OpenLDAP und fügen es hinter dem letzten Include-Statement in unserer slapd.conf ein, z.B.: ... include include
/etc/openldap/schema/nis.schema /etc/openldap/schema/kerberos.schema
Das neue Schema enthält die für die Integration benötigten Attribute und Objektklassen wie z.B. krbPrincipalAux und krbTicketPolicyAux. Zusätzlich enthält das oben genannte Paket das Kerberos-Schema auch im LDIF-Format, sodass einem Import zur Laufzeit ebenfalls nichts im Wege steht. Ein wichtiger Punkt: Damit wir (zumindest für das Setup) problemlosen Zugriff auf das kadmin.local-Interface erhalten, erzeugen wir unter Verwendung der »alten« /etc/ krb5.conf aus Abschnitt 4.3, »Setup von Kerberos V5«, per #> kdb5_util create -s
die für die lokale Authentifizierung (kadmin.local, via root/admin-Principal ohne Passwort) benötigten Dateien (bei SUSE unterhalb von /var/lib/kerberos/krb5kdc/). Alternativ kann der Schritt auch noch später unter Verwendung der »alten« krb5.conf erfolgen.
Im nächsten Schritt müssen wir die Konfigurationsdatei /etc/krb5.conf wie folgt anpassen (Zeile ldap_kadmin_dn gekürzt, Kommentare sind nicht Bestandteil der Datei): [libdefaults] default_realm = LOCAL.SITE [realms] LOCAL.SITE = { kdc = ldapmaster.local.site admin_server = ldapmaster.local.site database_module = LDAP # neu } [logging]
435
4.3
1198.book Seite 436 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
# ... (default-werte belassen) [dbdefaults] # ab hier neu ldap_kerberos_container_dn = cn=krbcontainer,dc=local,dc=site [dbmodules] LDAP = { db_library = kldap ldap_kerberos_container_dn = cn=krbcontainer,dc=local,dc=site ldap_kdc_dn = "cn=kdc-service,cn=krbcontainer,dc=local,dc=site" ldap_kadmind_dn = "cn=kadmin-service,cn=krbcontainer,dc=local..." ldap_service_password_file = /etc/kerberos/service.keyfile ldap_servers = ldap://ldapmaster.local.site ldap_conns_per_server = 5 }
Kurze Erklärung zu den Parametern: Als Subdirektive zu den vorhandenen realms-Definitionen für LOCAL.SITE wird ein database_module mit dem frei gewählten Namen LDAP definiert. Dieses Modul wird anschließend in der neu erstellten Sektion [dbmodules] konfiguriert. Dort werden die Settings für die Kommunikation und einige andere Parameter festgelegt, die Kerberos sagen, welche Units er auf unserem LDAP-Server zu welchem Zweck verwenden soll. Schauen wir sie uns kurz an: db_library
Gibt den Namen der loadable database library an. Der Wert kann hier z.B. db2 für eine DB2-Datenbank sein, oder (wie in unserem Fall) kldap für eine LDAP Datenbank. ldap_kerberos_container_dn
Hierüber wird der DN des Container-Objekts angegeben, in dem die REALMObjekte abgelegt werden (cn=krbcontainer,dc=local,dc=site). ldap_kdc_dn
Mit dieser Direktive wird der Service-DN für die Anmeldung des KDC am DIT angegeben. Per ACL muss sichergestellt sein, dass das Objekt ausreichende Rechte besitzt, um die Kerberos-bezogenen Daten im DIT lesen zu können. Um die ACLs kümmern wir uns gleich. ldap_kadmind_dn
Mit dieser Direktive wird der Service-DN für die Anmeldung des AdministrationServers (kadmind) im DIT angegeben. Per ACL muss sichergestellt sein, dass dieses Objekt ausreichende Rechte besitzt, um die Kerberos-bezogenen Daten im DIT lesen – und vor allem schreiben zu können.
436
1198.book Seite 437 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
ldap_service_password_file
Hier wird die Datei angegeben, in der sich die »ge-stashed-en« Passwörter der beiden vorgenannten Objekte (ldap_kdc_dn, ldap_kadmin_dn) bzw. der korrespondierenden Service-DNs befinden, mit denen sie sich am DIT anmelden. Der eingeschränkte Zugriff auf die Datei muss unbedingt sichergestellt werden, wenn wir keinen SPoF haben wollen. ldap_server
Enthält eine Liste von LDAP-Servern, mit denen sich der Kerberos-Server konnektieren kann. Die Server werden per LDAP-URL angegegeben, mehrere werden einfach durch Leerzeichen getrennt angegeben. Die Konnektierung kann wie bereits erwähnt per ldapi:// erfolgen, wenn sich KDC und LDAP auf dem gleichen Rechner befinden. ldap_conns_per_server
Gibt die Anzahl der gleichzeitigen Verbindungen an, die pro LDAP-Server maximal gehandelt werden sollen (Minimum zwei). Wichtig: In der kdc.conf für unser LDAP-spezifische Setup finden sich keine Realm-bezogenen Direktiven wie z.b. database_name; die entsprechende Datei findet sich in den Beispieldaten zu diesem Abschnitt http://www.galileocomputing.de/1801. Nun implementieren wir in unserer slapd.conf die bereits erwähnten, zusätzlichen ACLs (Zeilen im folgenden Listing z.T. umbrochen), die den Zugriff auf die Kerberos-relevanten Attribute/Objekte ausschließlich auf die Service-DNs und die User selbst limitieren. Wir platzieren sie oberhalb der letzten globalen ACLDirektive (... to * by * read): ### Zugriff auf cn=krbcontainer auf die Service-DNs limitieren access to dn.subtree="cn=krbcontainer,dc=local,dc=site" by dn.exact="cn=kdc-service,cn=krbcontainer,dc=local,dc=site" read by dn.exact="cn=kadmin-service,cn=krbcontainer,dc=local,dc=site" write by * none ### Zugriff auf die kerberos-relevanten Attribute access to attrs=krbPrincipalName,krbPrincipalKey, krbLastPwdChange,krbExtraData by dn.exact="cn=kdc-service,cn=krbcontainer, dc=local,dc=site" read by dn.exact="cn=kadmin-service,cn=krbcontainer, dc=local,dc=site" write
437
4.3
1198.book Seite 438 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
by self read by * auth
Damit die ACL by self read für »normale« Userobjekte korrekt ausgewertet werden kann, sollte gegebenenfalls noch in der globalen Sektion der slapd.conf per authz-regexp eine entsprechende Umsetzung des Authentifizierungs-DNs stattfinden. Die letzte Default-ACL (jeder darf alles lesen) ergänzen wir ebenfalls um eine Zeile, damit das kadmin-Service-Objekt bestehende Accounts, die nicht unterhalb des Subtrees krbcontainer liegen, um die Kerberos-relevanten Objektklassen und Attribute erweitern kann (2.Zeile wurde umbrochen): access to * by dn.exact="cn=kadmin-service,cn=krbcontainer, dc=local,dc=site" write by * read
Anschließend nicht vergessen, unseren slapd zu restarten, damit das neue Schema und die ACLs geparst werden. Nun geht’s ans Werk: Mit dem neuen Tool kdb5_ldap_util(8) in unserem Werkzeugkasten erzeugen wir die Struktur und einen Teil der benötigten Objekte für unseren Realm im DIT. Dabei sollten wir darauf achten, dass unser slapd wie im Produktiveinsatz mit den korrekten Parametern gestartet ist; z.B.: #> slapd -d 1 -u ldap -g ldap -h "ldap:/// ldaps:///"
Nun erzeugen wir die Kerberos-Struktur im DIT: #> kdb5_ldap_util -D cn=ldapadmin,dc=local,dc=site -w linux \ create -subtrees dc=local,dc=site -r LOCAL.SITE \ -H ldaps://ldapmaster.local.site Initializing database for realm 'LOCAL.SITE' You will be prompted for the database Master Password. It is important that you NOT FORGET this password. Enter KDC database master key: Re-enter KDC database master key to verify: Kerberos container is missing. Creating now...
Der Parameter -D gibt, wie bei vielen LDAP-spezifischen Befehlen üblich, den BindDN an (-w gibt optional das zugehörige Passwort gleich mit auf den Weg), per create -subtrees wird angegeben, wo die Kerberos-spezifische Struktur angelegt werden soll. Per -r wird der zu erzeugende Realm angegeben, und hinter dem Parameter -H verbirgt sich wie üblich die LDAP-URL des LDAP-Hosts, in diesem Fall per ldaps://, also unter Verwendung von SSL. Umfangreiche Informationen zur Anwendungssyntax liefert kdb5_ldap_util(8).
438
1198.book Seite 439 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
Anschließend kontrollieren wir kurz, ob die Struktur korrekt angelegt wurde (Ausgabe gekürzt): #> ldapsearch -xWD cn=ldapadmin,dc=local,dc=site \ -b cn=krbcontainer,dc=local,dc=site |grep ^dn Enter LDAP Password: dn: cn=krbcontainer,dc=local,dc=site dn: cn=LOCAL.SITE,cn=krbcontainer,dc=local,dc=site dn: krbPrincipalName=K/[email protected],cn=LOCAL.SITE,cn=krbcontainer,dc=local... ...
Und so weiter und so fort. So weit, so gut. Wie wir unschwer erkennen können, wurden unser Realm-Objekt (cn=LOCAL.SITE) und die Standard-Principals unterhalb des Subtrees cn=krbcontainer angelegt. Im nächsten Schritt müssen wir noch die beiden Service-Objekte für den KDCund Admin-Server innerhalb unseres DIT erzeugen, denn hierüber erfolgt der Bind zu unserem LDAP-Server. Die DNs der Objekte sollten natürlich denen entsprechen, die wir in der krb5.conf (ldap_kdc_dn und ldap_kadmind_dn) definiert haben. Für die Service-Objekte wählen wir – wie beim Account unseres ldapadmin – eine organizationalRole, ergänzt durch die Objektklasse simpleSecurityObject, die uns das Attribut userPassword zur Verfügung stellt. Als SSHA-gecryptetes Passwort wählen wir »linux«: dn: cn=kdc-service,cn=krbcontainer,dc=local,dc=site objectClass: organizationalRole objectClass: simpleSecurityObject cn: kdc-service userPassword: {SSHA}+Ee419m6Ndxa4/3b7V1d2w9sqOKlMZHJ dn: cn=kadmin-service,cn=krbcontainer,dc=local,dc=site # ... bis auf den cn-Attributwert analog zum oberen Beispiel
Nun müssen wir noch Stash-Passwörter für die vorgenannten Accounts generieren, welche dann in der Datei »service.keyfile« abgelegt werden; Als korrespondierendes Passwort wählen wir hier natürlich ebenfalls ‚linux’. Den Ordner /etc/ kerberos, der die Datei mit den Stash-Passwörtern aufnimmt, müssen wir gegebenenfalls noch anlegen: #> kdb5_ldap_util stashsrvpw \ "cn=kadmin-service,cn=krbcontainer,dc=local,dc=site" \ -H ldaps://ldapmaster.local.site Password for "cn=kadmin-service,cn=krbcontainer,dc=local,dc=site":
Re-enter password for " cn=kadmin-service,cn=krbcontainer,dc=local,dc=site":
439
4.3
1198.book Seite 440 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
und analog dazu das Gleiche noch einmal für den Service-DN cn=kdc-service. Anschließend überprüfen wir kurz den Inhalt des Service-Keyfiles: #> cat /etc/kerberos/service.keyfile cn=kdc-service,cn=krbcontainer,dc=local,dc=site#{HEX}6c696e7578 cn=kadmin-service,cn=krbcontainer,dc=local,dc=site#{HEX}6c696e7578
Ebenfalls dürfen wir die Konfiguration der kadm5.acl, in der wir die ACLs analog zum Abschnitt 4.3, »Setup von Kerberos V5«, setzen, nicht vergessen – andernfalls fehlen uns später die nötigen Berechtigungen, um unsere User-Objekte um die Kerberos-spezifischen Attribute zu erweitern. Jetzt wird’s langsam ernst, denn der erste Funktionstest steht bevor: Wir rufen das bekannte kadmin.local auf (krb5kdc und kadmind bleiben weiterhin im Tiefschlaf, also nicht gestartet) und erzeugen einen Principal für den Systembenutzer root mit Admin-Privilegien (root/admin). #> kadmin.local Authenticating as principal root/[email protected] with password. kadmin.local: addprinc root/admin ... Enter password for principal "root/[email protected]": Re-enter password for principal "root/[email protected]": Principal "root/[email protected]" created. kadmin.local: listprincs K/[email protected] ... root/[email protected]
Kontrollieren wir nun, ob der Principal auch sauber in unserem Tree abgelegt wurde (Ausgabe gekürzt): #> ldapsearch -xWD \ cn=kdc-service,cn=krbcontainer,dc=local,dc=site \ krbPrincipalName=root/admin* Enter LDAP Password: # root/[email protected], LOCAL.SITE, krbcontainer, local.site
dn: krbPrincipalName=root/[email protected],cn=LOCAL.SITE,cn=krbcontainer... krbPrincipalName: root/[email protected]
krbPrincipalKey:: MIGSoAMCAQGhAwIBAaIDAgEBowMCAQCkfDB6MEOhQTA/oAMCA... ... und so weiter und so fort
Nun ist es soweit, wir können die Services krb5kdc und kadmind starten. Zwingende Voraussetzung ist natürlich jetzt, dass unser slapd ebenfalls gestartet ist!
Anschließend kümmern wir uns darum, eines unserer vorhandenen UserObjekte um die Kerberos-relevanten Attribute zu erweitern. Allerdings gestaltet
440
1198.book Seite 441 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
sich das Vorgehen beim Erstellen eines User-Principals in diesem Fall etwas anders als das »nackte« Erstellen eines Principals im DIT; zumindest wenn wir möchten, dass die Kerberos-relevanten Daten innerhalb des Objekts gespeichert werden (was schließlich ebenfalls Ziel unserer Unternehmung sein soll). Zunächst starten wir das kadmin Interface; sollten wir hier eine Fehlermeldung erhalten: kadmin: GSS-API (or Kerberos) error while initializing kadmin interface
überprüfen wir noch einmal die Rechte der Keytab und starten unseren slapd gegebenenfalls neu. Mit dem Befehl addprinc –x <principal-Name> innerhalb des kadmin-Interfaces wird das bestehende Objekt einfach um die erforderlichen Objektklassen und Attribute erweitert. Wichtig dabei: der Name des Principals als letzter Befehlsparameter: #> kadmin Authenticating as principal root/[email protected] with password. Password for root/[email protected]:
kadmin:addprinc -x dn=uid=skiu,ou=forschung,dc=local,dc=site skiu WARNING: no policy specified for [email protected]; defaulting to no policy Enter password for principal "[email protected]": Re-enter password for principal "[email protected]": Principal "[email protected]" created.
Der Erfolg lässt sich per ldapsearch schnell überprüfen: dn: uid=skiu,ou=forschung,dc=local,dc=site ... objectClass: krbPrincipalAux objectClass: krbTicketPolicyAux ... krbPrincipalName: [email protected] krbPrincipalKey:: MIGSoAMCAQGhAwIBAaIDAgEBowMCAQCkfDB6MEOhQTA... krbLastPwdChange: 20080813121612Z krbExtraData:: AAKM0KJIcm9vdC9hZG1pbkBMT0NBTC5TSVRFAA==
Et voilà, alles so, wie es sein sollte – zentrale Ablage und Administration unserer Kerberos-Daten im Tree, wie in der folgenden Abbildung per JXplorer noch einmal dargestellt. Zum guten Schluss nicht vergessen, die in diesem Zusammenhang häufig verwendeten Attribute wie z.B. krbPrincipalName zu indexieren.
441
4.3
1198.book Seite 442 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Abbildung 4.9
Integration der Kerberos-relevanten Objekte in unseren DIT
Betrachten wir noch einmal kurz die Vorteile dieses Setups gegenüber der »normalen« Variante mit einer separaten KDC-Datenbank: 왘 Alle Kerberos-relevanten Attribute bzw. die Principals sind direkter Bestandteil der Objekte im DIT. 왘 Die Replikation der Kerberos-»DB« (im LDAP) findet über ldap statt, eine separate Replikation über Kerberos entfällt. Gegebenenfalls müssen nur noch Keytabs repliziert/kopiert werden. 왘 Fein granulierbare Zugriffskontrolle auf krb-relevante Objekte durch ACLs 왘 Dem steht als Nachteil gegenüber, dass die Rechte der Keytab angepasst werden müssen, da unser slapd nach wie vor Zugriff darauf haben muss. Aber das gilt schließlich auch für die »normale« Kerberos-Variante. Nun wie üblich zum Debugging, falls etwas nicht geklappt haben sollte: 왘 Host und Service-Principals per kadmin.local erzeugt und in die Keytab exportiert? (krb5.conf ohne LDAP-Direktiven) 왘 Keytab für den User, mit dessen Rechten slapd läuft, lesbar? 왘 kerberos.schema in die slapd.conf eingebunden? 왘 krb5.conf (ldap) und ACLs in der slapd.conf korrekt eingerichtet? 왘 kadm5.acl konfiguriert? 왘 krb5kdc und kadmind gestartet? (benötigen slapd) 왘 kdc.conf korrekt konfiguriert? (keine Realm-Angaben) 442
1198.book Seite 443 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
Ansonsten gilt wie üblich: Loglevel aller involvierten Services hochdrehen, Fehlermeldungen genau lesen(!), Ärmel aufkrempeln und gegebenenfalls noch einmal from the scratch anfangen.
4.3.5
Kurz und gut: XP-Client an kerberisierter Samba-Domäne
In diesem Abschnitt werfen wir zu guter Letzt noch einen kurzen Blick auf das Zusammenspiel von XP-Clients mit einem Linux KDC. Der verwendete Windows-Client PC benötigt zunächst einen entsprechenden Maschinen-Account in der Samba-/LDAP-Domäne. Die Vorgehensweise haben wir bereits im Abschnitt über Samba beschrieben. Weiterhin muss die Namensauflösung sowohl auf der Win-Client- als auch auf der Linux-Seite funktionieren. Als Erstes sollte darauf geachtet werden, dass der Samba-Workgroup-/Domänenname – wie in unserem Fall – äquivalent zum Kerberos Realm ist: Windows-Clients reagieren unter Umständen zickig auf einen Domänennamen, der ungleich dem des Kerberos-Realm ist (Nachstehend Auszug der smb.conf): workgroup = LOCAL.SITE realm = LOCAL.SITE password server = ldapmaster.local.site client use spnego = yes use kerberos keytab = yes # ...hier folgen die ldap-relevanten Direktiven und shares
Zusätzlich geben wir unseren KDC (password server) sowie unseren realm an und aktivieren mit client use spnego (Default) die eigentliche Kerberos-Authentifizierung. Ausführliche Beschreibungen zu den verschiedenen Security-Leveln finden sich im Samba-HowTo. Der Parameter use kerberos keytab sollte keiner weiteren Erläuterung bedürfen. Auf der Kerberos-Seite müssen wir einen Host-Principal für den Windows-Client und einen Service-Principal für Samba (cifs) anlegen. Das geschieht in bekannter Weise per kadmin: addprinc –randkey winclient.local.site addprinc –randkey cifs/ldapmaster.local.site
Anschließend nicht vergessen, die Schlüssel in der bekannten Vorgehensweise die Keytab zu exportieren. Natürlich muss auch für den Windows-User auf der XP-Clientseite ein entsprechender LDAP-Account und User-Principal vorliegen. Nun können wir einen ersten Test vornehmen, zunächst von der Linux-Seite aus, indem wir als Client für unseren eigenen Samba-Server fungieren: Wir melden uns mit dem Account eines Linux-Users (ckent) an, der bereits die entsprechenden Samba-Attribute besitzt. Dann kurz prüfen, ob ein TGT vorliegt; 443
4.3
1198.book Seite 444 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
wenn nicht, ein neues Ticket per kinit holen. Nun starten wir den Samba-ClientAufruf an unserem eigenen Samba-Server: ckent@ldapmaster:~> smbclient //ldapmaster/samba \ -W LOCAL.SITE -k -d 3
Der gewählte User muss natürlich als Samba-User existieren, und Samba muss ebenfalls problemlos mit unserem slapd kommunizieren können; siehe hierzu Abschnitt 4.1, »Die Meister der Domäne: OpenLDAP und Samba«. Zum Befehl selbst: Der Parameter -k startet die Kerberos-Authentifizierung, -W gibt die Domäne an, und -d 3 erhöht den Debug-Output. Nach erfolgreichem Login (ohne Passworteingabe!) sollten wir am smb-Prompt der Freigabe angelangt sein: lp_load_ex: refreshing parameters Initialising global parameters
params.c:pm_process() - Processing configuration file "/etc/samba/smb.conf" Processing section "[global]" ... resolve_lmhosts: Attempting lmhosts lookup for name ldapmaster<0x20> ... Connecting to 192.168.198.11 at port 445 Doing spnego session setup (blob length=113) got OID=1 2 840 113554 1 2 2 ... got principal=cifs/[email protected] Doing kerberos session setup ads_cleanup_expired_creds: Ticket in ccache[FILE:/tmp/krb5cc_901] expiration Do, 27 Nov 2008 15:59:27 CET OS=[Unix] Server=[Samba 3.2.3-0.1-1882-SUSE-SL11.0] dos_clean_name [(null)] smb: \>
Per ? können wir uns die verfügbaren Befehle auflisten lassen und anschließend noch etwas auf der Share herumstöbern, danach verlassen wir per exit oder [Strg] + [C] die Samba-Client-Kommandozeile wieder. Anschließend werfen mit klist einen Blick auf das cifs-Service-Ticket, das wir erhalten haben: ckent@ldapmaster:~> klist icket cache: FILE:/tmp/krb5cc_901 Default principal: [email protected] Valid starting Expires Service principal 11/26/08 15:59:29 11/27/08 15:59:27 krbtgt/[email protected] 11/26/08 15:59:41 11/27/08 15:59:27 cifs/[email protected]
So weit, so gut. Nun schauen wir uns noch die Kerberisierung des Windows-Clients an. Eine einfache und schnelle Variante, die wir hier vorstellen, ist die Installation der KfW, der MIT-Kerberos-Tools für Windows in der Version 3.2.*. Die andere Variante wäre die direkte Eingabe von Parametern über ksetup.exe (üblicherweise Bestandteil der jeweiligen Windows-Supporttools) oder das direkte Editieren der Registry.
444
1198.book Seite 445 Donnerstag, 5. Februar 2009 3:02 15
Setup von Kerberos V5
Das KfW-Paket selbst kann unter http://web.mit.edu/kerberos/ heruntergeladen werden. Nach dem Setup, in dem sich das Paket standardmäßig in C:\Programme\ MIT\Kerberos\ installiert, finden wir auch eine Datei unterhalb des Windows-Systemordners (z.B. C:\Windows\) mit dem Namen krb5.conf. Klingt bekannt? Absolut. Und genau wie beim Kerberos-Client-Setup auf der Linux-Seite können wir auch hier einige Default-Parameter, die wir bereits kennen, setzen: [libdefaults] dns_lookup_kdc = false noaddresses = false default_realm = LOCAL.SITE [realms] LOCAL.SITE = { kdc = ldapmaster.local.site admin_server = ldapmaster.local.site default_domain = local.site } [domain_realm] .local.site = LOCAL.SITE .site = LOCAL.SITE
Das ganze Setup lässt sich natürlich auch über die KfW-GUI erledigen. Hierzu rufen wir einfach den Network Identity Manager auf, der sich im Untermenü »Programme/Kerberos for Windows/« verbirgt. Hierüber können wir alle Settings einstellen und uns mit frischen Tickets versorgen.
Abbildung 4.10
netidmgr der KfW-Tools
445
4.3
1198.book Seite 446 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Was Kerberos angeht, so sind seine Fähigkeiten und »kerberisierbaren« Applikationen keinesfalls schon am Ende, denn das war nur ein kleines Intro zu diesem mächtigen Paket. Im nächsten Abschnitt werden wir den Typen treffen, der immer zwei Mal klingelt: der Postmann. Und wenn sein Name nicht Jack Nicholson, sondern Cyrus ist, versteht er sich ebenfalls gut mit Kerberos.
4.4
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Eigentlich sollte sich nur derjenige als echter Administrator bezeichnen dürfen, der eine sendmail.cf schon einmal manuell erstellt hat. Und er sollte vielleicht seinen Analytiker aufsuchen, wenn er es mit Freude ein zweites Mal wieder tun würde. Geläufiger Spruch zur sendmail-Konfiguration Okay, einen Spruch zur sendmail.cf hatten wir schon in Abschnitt 3.1, »Völlig überlagert«. Ist auch nichts Persönliches gegen sendmail, denn auch wir haben uns mit sendmail-Konfigurationen die ersten Sporen im Mailserver-Segment erarbeitet. Aber das gute alte sendmail ist nun einmal leider ein monolithisches Fossil aus Unix-Urzeiten und daher in manchen Belangen genauso sperrig zu handhaben wie der schwarze Klotz aus Stanley Kubricks ’2001’. Uns persönlich fiel daher der Umstieg auf Postfix nicht allzu schwer, da es zum einen modular konzipiert und zum anderen – zumindest unserer Meinung nach – erheblich einfacher zu konfigurieren ist. Aber letztlich geht es hier nicht um die Vorliebe für ein bestimmtes Mailsystem, sondern primär um seine Integration in unseren LDAP. Und das lässt sich – wie im nachfolgenden Beispiel – mit Postfix hervorragend bewerkstelligen. Neben Postfix bieten auch etliche andere MTA’s (=Mail Transport Agent) LDAP-Unterstützung; Debian präferiert z.B. Exim, das auch gern per ldap parliert. Unser Ziel Wir werden Postfix in der von den Distributionen verwendeten Version 2.5.* so konfigurieren, dass es unseren DIT als zentrale Adressdatenquelle verwenden kann. Der Postfix-Mailserver empfängt und versendet dabei die Mails für unsere Subdomains (forschung, verkauf) und bezieht die Objektdaten der User – und damit z.B. Attribute wie lokale und externe Mailadressen – direkt aus unserem LDAP-Verzeichnis. Womit ein weiterer Dienst dem SPoA (Single Point of Administration) hinzugefügt wäre. Den Zugriff selbst lassen wir zunächst noch unverschlüsselt erfolgen, später per TLS. Danach werden wir noch einen IMAP-Mailserver integrieren und einige gängige Mailclients als Frontend für das ganze
446
1198.book Seite 447 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Päckchen vorstellen. Natürlich erfolgt die Kommunikation später ebenfalls verschlüsselt. Das in SUSE enthaltene Postfix-Paket ist bereits mit LDAP- und TLS-Unterstützung kompiliert, Debian bringt hierfür zwei separate Pakete mit: postfix-ldap und postfix-tls. Um Postfix manuell mit LDAP- und TLS-Unterstützung zu kompilieren, werden die jeweiligen Bibliotheken für OpenLDAP, Cyrus-SASL und OpenSSL benötigt. Die erforderlichen Compiler-Schalter sind im Anhang gelistet. Per postconf –m lässt sich schnell herausfinden, ob die vorliegende Postfix-Version LDAP unterstützt oder nicht. Per nmap oder ps sollte kurz geprüft werden, ob der SMTP-Service von Postfix auf Port 25 bereits läuft. Falls nicht, den Dienst in die Run-Level einbinden und starten. Zusätzliche Eingriffe in die LDAP-Konfiguration sind nicht vonnöten, es sollte lediglich sichergestellt sein, dass – wie in den von uns bisher verwendeten Beispielen – das inetOrgPerson-Schema eingebunden ist und wir die entsprechenden Mail-Attribute für unsere User-Objekte gesetzt haben.
4.4.1
Setup der Postfix-Dateien main.cf/ldap-aliases.cf
Betrachten wir als Erstes die Konfigurationsdatei, in der fast alle Postfix-Konfigurationsdirektiven abgelegt sind; die Datei main.cf, die sich üblicherweise unter /etc/postfix/ befindet. Logischerweise können wir auch hier keine vollständige Postfix-Konfiguration erläutern, da dies den Rahmen komplett sprengen würde, sondern beschränken uns auf die LDAP-relevanten Konfigurationseinstellungen. Hilfe zum grundlegenden Postfix-Setup bieten die gut kommentierte Datei main.cf selbst, die Postfix-Manpages (insbesondere postconf(5)) sowie Dokumentationen und HowTos unter www.postfix.org. Einen Überblick über die aktuell gesetzten Einstellungen bietet postconf ohne Angabe weiterer Parameter. Der erste wichtige Eintrag bezieht sich auf die alias_maps. Über diese Direktive wird Postfix mitgeteilt, wo er Information darüber finden kann, welche User – vereinfacht ausgedrückt – auf dem System existieren und damit als potenzielle Kandidaten für die Mailauslieferung zur Verfügung stehen. Standardmäßig zeigt alias_maps auf die Datei /etc/aliases. Diese Einstellung belassen wir und ergänzen sie einfach um eine weitere Konfigurationsdatei (ldap-aliases.cf), in der wir unsere LDAP-relevanten Einstellungen hinterlegen. Die Datei verwendet – ähnlich wie ein Include-File – die gleiche Konfigurationssyntax wie die main.cf: alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf
447
4.4
1198.book Seite 448 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Eine kurze Anmerkung zur Syntax der Direktiven: Postfix interpretiert (wie unser guter alter slapd) eingerückte Zeilen als Folgezeilen einer vorab gesetzten Direktive. Weiter im Text: Durch die Ergänzung um ldap-aliases.cf bleibt der Zugriff auf die Postfix-Standardkonfiguration auch bei einem nicht laufenden LDAP funktionsfähig; vom Funktionsprinzip etwa vergleichbar mit den files ldap-Einträgen in der /etc/nsswitch.conf. Alle folgenden Einstellungen treffen wir in der ldap-aliases.cf und definieren damit zunächst den eigentlichen LDAP-Server sowie die Searchbase: server_host = ldap://ldapmaster.local.site
Zusätzlich zur server_host- kann die server_port-Direktive (optional) angegeben werden. Um LDAP per SSL zu nutzen, kann ldaps:// angegeben werden, für die direkte Verbindung per Socket (Postfix und LDAP auf einem Host) kann die Verbindung via ldapi:// verwendet werden. Über die optionale Direktive timeout kann die maximale Wartezeit in Sekunden angegeben werden, die Postfix auf eine Rückmeldung vom LDAP-Server wartet. Der nächste Eintrag ist zwingend erforderlich und gibt den DN der Searchbase an – logischerweise kann so auch schon eine Prä-Selektion, z.B. für eine bestimmte Unit getroffen werden. search_base = dc=local,dc=site
Der folgende Parameter query_filter folgt den Syntaxregeln nach RFC 4515 (»The String Representation of LDAP Search Filters«) und definiert das SuchfilterKonstrukt für das von Postfix auszuwertende Attribut, z.B. also: query_filter = (|(mail=%u@%d)(mail=%u)(mail=%s)(uid=%u))
Die %-Parameter definieren dabei die Interpretation des eingegebenen Suchbegriffs: %s wertet den kompletten String aus, etwa user@domain, %u nur den UserAnteil, %d den Domain-Anteil der Mailadresse. Eine komplette Übersicht der verfügbaren %-Parameter liefert ldap_table(5). Über result_attribute = mail
wird das zurückzugebende Attribut festgelegt. Der Parameter version = 3
legt die LDAP-Protokollversion fest. Version 3 sollte in jedem Fall verwendet werden, da Postfix sonst aus Gründen der Abwärtskompatibilität Protokollversion 2 annimmt. Wie wir wissen, ist’s dann Essig mit TLS.
448
1198.book Seite 449 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Weitere interessante Direktiven wären z.B. chase_referrals (Verfolgung von Referrals), debuglevel oder auch size_limit (adäquat zur slapd-sizelimit-Direktive). Einen kompletten Überblick über alle korrespondierenden Direktiven hierzu bietet ebenfalls ldap_table(5). Kommen wir nun zu einem ersten einfachen Funktionstest, bei dem wir folgende Konfiguration in unserer ldap-aliases.cf mit den bereits erläuterten Settings annehmen: # ldap-aliases.cf server_host = ldap://ldapmaster.local.site search_base = dc=local,dc=site version = 3 query_filter = (|(mail=%u)(mail=%s)(uid=%u)(cn=%u)) result_attribute = mail
Nun setzen wir folgenden postmap-Befehl ab, der den DIT nach dem String eripley durchsuchen soll. Rückgabewert wird gemäß oben getroffener Definition die vollständige Mailadresse sein: #> postmap -q eripley ldap:/etc/postfix/ldap-aliases.cf
Die (hier umbrochene) Ausgabe sollte wie folgt aussehen: [email protected],[email protected],eripley@marketing. local.site
Wie wir sehen, werden bei dieser Konfiguration des query_filter und der search_base alle im DIT vorhandenen Einträge für eripley zurückgegeben. Im konkreten Fall würde dies bedeuten, dass eine Mail, die an eripley adressiert ist, an sie selbst und ihre beiden Klone verschickt wird, da der erste Teil der MailAdresse vor dem »@« bei allen gleich ist. Alternativ können wir auch die exaktere Variante: query_filter = (mail=%s)
zur kompletten Stringauswertung wählen, denn Peter Müller aus der Buchhaltung ist vielleicht doch nicht identisch mit Peter Müller aus dem Verkauf. So weit, so gut. Vor dem nächsten Schritt muss sichergestellt sein, dass die Postfix-Konfiguration in sehr vereinfachter Form zumindest so weit angepasst ist, dass Mails für unsere lokalen Domains und Subdomains von Postfix akzeptiert werden. Hier ein Auszug der Direktiven aus der main.cf: mydomain = local.site myhostname = ldapmaster.local.site inet_interfaces = all
449
4.4
1198.book Seite 450 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain, verkauf.$mydomain, forschung.$mydomain disable_dns_lookups = yes
Über myhostname und mydomain werden der Hostname und die Domain als Variablen gesetzt, die von Postfix ausgewertet werden. mydestination gibt an, für welche Domains und Subdomains Postfix sich zuständig fühlen soll. Alle dort nicht gelisteten werden von Postfix ignoriert bzw. an den externen SMTP-Server weitergeleitet, der (optional) in der Direktive relayhost = gesetzt werden kann. Der Parameter inet_interfaces = all sorgt dafür, dass Postfix auf allen vorhandenen Netz-Devices lauscht. Per Default ist dort nur das Loopback-Device aktiv. Der Parameter disable_dnslookups = yes kann bei Problemen mit der Namensauflösung hilfreich sein. Nach einem restart/reload des Postfix-Daemons verschicken wir – als ckent – nun eine Mail auf der Kommandozeile. Hierzu wird z.B. bei SUSE das Programm nail(1), bei Debian üblicherweise das BSD-Mailprogramm mail(1) verwendet. Da wir uns jedoch auf eine sehr einfache Syntax beschränken, fallen die Unterschiede in den Kommandozeilenoptionen nicht ins Gewicht: ckent@ldapmaster:~> mail [email protected] Subject: test testmail
Die Eingaben beenden wir mit [Strg] + [D], danach checken wir das Mail-Log unter /var/log/. Dort sollte folgende Ausgabe zu finden sein: postfix/pickup[5633]: 072E556CEC: uid=901 from= postfix/cleanup[5705]: 072E556CEC: messageid=<[email protected]> postfix/qmgr[5635]: 072E556CEC: from=, size=461, nrcpt=1 (queue active)postfix/local[5707]: 072E556CEC: to=<[email protected]>, orig_to=<skiu>, relay=local, delay=0.61, delays=0.51/0.07/0/0.03, dsn=2.0.0, status=sent (delivered to mailbox)postfix/qmgr[5635]: 072E556CEC: removed
Wie wir erkennen können, wurde unser LDAP-User ckent automatisch um den FQHN ergänzt. Das ist insofern zweitrangig, als der FQHN als myhostname ebenfalls zur Liste der Domains gehört, für die sich Postfix zuständig fühlt. Allerdings können wir diese Mailadresse kaum für externe Belange verwenden. Um diese Problematik zu lösen, bietet Postfix mit der Datei /etc/postfix/sender_canonical die Möglichkeit, »manuell« lokale auf »echte« Mailadressen abzubilden. Ein Eintrag für ckent könnte in dieser Datei etwa so aussehen: ckent
450
[email protected]
1198.book Seite 451 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Danach müsste die Datei noch per postmap /etc/postfix/sender_canonical in das gewünschte db-Format gebracht werden, und der korrekten Namensauflösung steht beim nächsten Mailing nichts mehr im Wege: postfix/qmgr[5635]: 01E6856CEC: from=, size=460, nrcpt=1 (queue active) postfix/local[5753]: 01E6856CEC: to=<[email protected]>, orig_to=<skiu>, relay=local, delay=0.3...
Allerdings wäre diese Vorgehensweise auch nicht sonderlich hilfreich, schließlich geht es darum, einen SPoA aufzusetzen. Wozu also wiederum in separaten Konfigs herumfingern, wenn wir das Mail-Mapping elegant per LDAP erschlagen können? Wie das geht, schauen wir uns sofort an. Debugging Aber zunächst muss dafür sichergestellt sein, dass bis zu diesem Punkt alles korrekt funktioniert hat. Sollte bis zu dieser Stelle etwas fehlschlagen sein, überprüfen wir als Erstes, ob unser LDAP-Server erreichbar ist. Danach am besten noch einmal die grundlegende Postfix-Konfiguration und die in der ldap-aliases.cf gesetzten Einstellungen überprüfen: Funktioniert der lokale Mailversand für nicht im LDAP abgelegte User? Haben die verwendeten LDAP-User-Accounts eine gültige Mail-Adresse im mail-Attribut gesetzt? Sind die Variablen für myhostname, mydomain und mydestination in der /etc/postfix/main.cf korrekt gesetzt? Stimmt der query_filter in der ldap-aliases.cf?
4.4.2
Adress-Umsetzung per LDAP
Wie eben schon erwähnt, ist die Mail-Adressenumsetzung per sender_canonical zwar funktionell, würde aber im konkreten Fall wieder Arbeit an zwei verschiedenen Stellen für ein Mailsystem bedeuten. Daher ist unsere LDAP-basierte Lösung in jedem Fall eleganter. Schauen wir uns nun einen möglichen Lösungsansatz an. Zunächst benötigen wir ein zusätzliches Mail-Attribut, und zwar für die »öffentliche« Mailadresse. Postfix bringt von Haus aus kein eigenes Schema mit, daher haben wir den Beispieldateien dieses Abschnitts ein eigendefiniertes postfix.schema hinzugefügt (http://www.galileocomputing.de/1801). Eines der dort verwendeten Attribute ist rewMailAddress: attributetype ( 1.3.6.1.4.1.24373.1.5 NAME ( 'rewMailAddress' ) DESC 'Rewritten MailAddress' SUP mail )
Das rewMailAddress-Attribut ist aus dem mail-Attribut des core.schema abgeleitet und verwendet damit die gleiche IA5-String-Syntax (die OID 1.3.6.1.4.1.24373
451
4.4
1198.book Seite 452 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
wurde bei der IANA für die Autoren registriert). Um das Attribut verwenden zu können, fügen wir das neue Schema per include /<path-to-schema>/postfix.schema
unserem slapd hinzu und ergänzen nach einem Restart die User-Objekte ckent und skiu um die neue Objektklasse postfixMailUser, die das rewMailAddressAttribut bereitstellt: dn: uid=ckent,ou=verkauf,dc=local,dc=site changetype: modify add: objectClass objectClass: postfixMailUser add: rewMailAddress rewMailAddress: [email protected] dn: uid=skiu,ou=forschung,dc=local,dc=site changetype: modify add: objectClass ... usw ....
Die intern verwendete Mail-Adresse, also z.B. [email protected], kann nun über das Attribut rewMailaddress in die »öffentliche« Mail-Adresse [email protected] umgeschrieben werden. Allein mit dem Hinzufügen der Objektklasse und dem Setzen des neuen Attributs ist unser aktuelles Setup jedoch noch nicht abgeschlossen; wir müssen Postfix in der main.cf noch einen Verweis mit auf den Weg geben, mit Hilfe welcher LDAP-spezifischen Datei er die Umsetzungsregeln anwenden kann. Hierfür verwenden wir die vorhandene Postfix-Direktive (main.cf) sender_ canonical_maps, die wir um den LDAP-relevanten Part ergänzen: sender_canonical_maps = hash:/etc/postfix/sender_canonical, ldap:/etc/postfix/ldap-sender_canonical.cf
Den Eintrag für die nun nicht mehr benötigte /etc/postfix/sender_canonical-Datei können wir optional entfernen. Die Datei /etc/postfix/ldap-sender_canonical.cf entspricht vom Aufbau her weitestgehend der ldap-aliases.cf, doch wird anstelle des Attributs mail nun rewMailAddress zurückgegeben: # ldap-sender_canonical.cf server_host = ldap://ldapmaster.local.site search_base = dc=local,dc=site version = 3 query_filter = (|(mail=%u@%d)(mail=%u)(mail=%s)(uid=%u)) result_attribute = rewMailAddress
452
1198.book Seite 453 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Über query_filter werden dabei die lokale Mail-Adresse bzw. Teile davon abgefragt, der Rückgabewert ist rewMailAddress. Überprüfen wir also die Funktionalität in der bereits bekannten Weise per postmap: #> postmap -q ckent@* ldap:/etc/postfix/ldap-sender_canonical.cf
Wir sollten als Ergebnis [email protected] und in den Logs beim Versenden einer Mail folgende Ausgabe erhalten, die uns zeigt, dass die Umsetzung korrekt funktioniert (zuvor restart/reload von Postfix nicht vergessen): CEDE856CEC: uid=901 from= postfix/qmgr[7162]: CEDE856CEC: from=, size=465, nrcpt=1 (queue active) postfix/local[7202]: CEDE856CEC: to=<[email protected]>, orig_to=<skiu>, relay=local, delay=0.4, delays=0.35/0.02/0/0.03, dsn=2.0.0, status=sent (delivered to mailbox)
Das hier gezeigte Verfahren stellt nur einen kleinen Teil der vielfältigen Möglichkeiten dar, die die Verknüpfung von Postfix und LDAP bietet. Weitere sinnvolle Umsetzungen wären z.B. Recipient-(Datei: ldap-recipient_canonical.cf in den Beispieldateien zu diesem Abschnitt) oder globale Mappings von Mail-Adressen:
4.4.3
Gruppentherapie für Postboten
Durch die im postfix.schema enthaltene Objektklasse postfixMailGroup können wir z.B. eine Gruppe von Mail-Usern definieren, die über eine gemeinsame Sammel-Mail-Adresse angesprochen werden kann (Datei ldap-mailgroup.cf in den Beispieldateien), z.B. für Rundmailings an eine ganze Abteilung. Der Eintrag der Gruppe mailuser im DIT könnte so aussehen: dn: cn=mailuser,dc=local,dc=site objectClass: postfixMailGroup objectClass: top cn: mailuser mail: [email protected] member: uid=ckent,ou=verkauf,dc=local,dc=site member: uid=skiu,ou=forschung,dc=local,dc=site
Im nächsten Schritt ergänzen wir die folgenden Direktiven in der main.cf: virtual_alias_maps = hash:/etc/postfix/virtual, ldap:/etc/postfix/ldap-mailgroup.cf alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf, ldap:/etc/postfix/ldap-mailgroup.cf
453
4.4
1198.book Seite 454 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
In der Datei ldap-mailgroup.cf verwenden wir folgende Settings: server_host = ldap://ldapmaster.local.site search_base = dc=local,dc=site version = 3 query_filter = (&(mail=%s)(objectClass=postfixMailGroup)) leaf_result_attribute = mail special_result_attribute = member
Der query_filter verwendet zur Suche die Objektklasse postfixMailGroup und die komplette Mail-Adresse der Gruppe. Die Direktive special_result_attribute wird zusammen mit leaf_result_attribute verwendet, um die zu den im member-Attribut gespeicherten DNs zugehörigen Mail-Adressen zurückgeben zu können. Ein Test per #> postmap -q [email protected] \ -f ldap:/etc/postfix/ldap-mailgroup.cf
sollte uns wie gewünscht die Mitglieder der Gruppe mailuser auflisten: [email protected],[email protected]
Eine kurze Testmail per mail -s test [email protected] sollte nun problemlos an skiu und ckent herausgehen.
4.4.4
Der unsichtbare Dritte: Postfix, TLS und saslauthd
Den Nutzwert einer verschlüsselten Verbindung haben wir bereits in den vorangegangenen Kapiteln eingehend beleuchtet. Bezogen auf Postfix – bzw. einen Mailserver – liegt der Hauptnutzen in Verbindung mit der Authentifizierung in zwei Punkten: Zum einen kann so sichergestellt werden, dass nicht authentifizierte Benutzer keine Möglichkeit bekommen, den Mailserver als Relay zu missbrauchen. Zum anderen finden Vorgänge wie Authentifizierung und Versand von Mails nur noch verschlüsselt statt. Der Ablauf erfolgt in der bekannten Reihenfolge: Zuerst wird die Verbindung per TLS verschlüsselt, im Anschluss daran erfolgen erst die Authentifizierung und dann der Versand der Mails. Benötigt wird – bei serverseitiger Verschlüsselung – zumindest ein Server-Zertifikat, das den SMTP-Clients bei der Anmeldung präsentiert wird. Wir können zum Test der Einfachheit halber die bereits für unseren ldapmaster.local.site erstellten Zertifikatsdateien verwenden oder optional neue erstellen. Diese Dateien (cacert.pem, newcert.pem und ldapkey.pem) kopieren wir anschließend in den Ordner /etc/postfix/certs/, den wir zuvor noch erstellen müssen.
454
1198.book Seite 455 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Nachstehend sind die Postfix-Direktiven der main.cf gelistet, die wir für die TLSKonfiguration benötigen. (Die Nummerierung dient nur der späteren Erläuterung und ist nicht Bestandteil der Datei.) 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
smtpd_tls_CAfile = /etc/postfix/certs/cacert.pem smtpd_tls_cert_file = /etc/postfix/certs/newcert.pem smtpd_tls_key_file = /etc/postfix/certs/ldapkey.pem # smtp_tls_CAfile = /etc/postfix/certs/cacert.pem smtpd_tls_security_level = may smtpd_tls_loglevel = 3 smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_tls_session_cache smtpd_sasl_auth_enable = yes broken_sasl_auth_clients = yes smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, check_recipient_maps, reject_unauth_destination, permit_auth_destination
Die Zeilen 1–3 binden die Zertifikatsdateien ein. Zeile 4 (optional) gibt den smtpClients die CA bekannt. Zeile 5 aktiviert opportunistisches TLS (auf diese Art [may] können auch unverschlüsselt arbeitende Clients nach wie vor Mails versenden). Wer TLS-verschlüsselte Verbindungen in jedem Fall erzwingen will, stellt statt may den wert [encrypt] ein. Zeile 6 stellt einen höheren Debug-Level für TLS ein, der nach sichergestellter Funktionalität wieder auf einen niedrigeren Wert geschraubt werden sollte. Zeile 7 gibt den Pfad zur B-Tree-Datenbank für den Sessioncache des tlsmgr(8) an. Zeile 8 aktiviert schließlich den Daemon saslauthd, den wir als »Vermittler« für die Authentifikation benötigen, hierzu gleich mehr. Zeile 9 wird benötigt für ältere Outlook-Express- und Exchange-Clients, da sich diese nicht an das in RFC 4954 (»SMTP Service Extension for Authentication«) spezifizierte AUTH-Format halten. Zeile 10 verhindert anonyme Verbindungen. Die leere smtpd_sasl_ local_domain-Direktive in Zeile 11 sorgt dafür, dass der Benutzer nicht den vollständigen Domänennamen an seinen Usernamen anhängen muss. Zeile 12 gestattet dem authentifizierten Benutzer, Postfix als Mail-Relay zu verwenden. Zur Erhöhung der Sicherheit kann z.B. die Option permit_tls_clientcerts über die smtpd_*_restrictions-Direktiven eingebunden werden (*=client, helo, sender, recipient). Bei Verwendung der Option permit_tls_clientcerts wird in /etc/postfix/ eine Datei relay_clientcerts angelegt. In dieser Datei wird dann für jeden berechtigten Client die MD5-Prüfsumme seines Zertifikats in Verbindung mit seinem FQ-Hostname gespeichert:
455
4.4
1198.book Seite 456 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
#> openssl x509 -in usercert.pem -fingerprint –noout SHA1 Fingerprint=12:33:DA:D0:A5:FB:B4:84:52:F3:40:27:D0:ED:5B:A8:B4:BA:1A:BE
In der Datei relay_clientcerts wird das Ganze dann in der Form <Wert des SHAFingerprints> <mailuser>.<domain> eingetragen: 12:33:DA:..........: BA:1A:BE
ckent.verkauf.local.site
Das postfix.schema stellt uns ein entsprechendes Attribut (relayClientcert) zur Verfügung, in dem wir die Attributwerte der gerade beschriebenen relay_clientcerts-Daten bei Bedarf ablegen können. Ist in der main.cf die Direktive smtpd_tls_received_header = yes gesetzt, können wir uns zusätzliche, verschlüsselungsrelevante Informationen im MessageHeader »received:« anzeigen lassen (im Thunderbird z.B. per [Strg] + [U]): ... Return-Path: X-Original-To: [email protected] Delivered-To: [email protected] Received: from ldapmaster.local.site (ldapmaster.local.site [192.168.198.11]) (using SSLv3 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ldapmaster.local.site (Postfix) with ESMTPSA id 0D73456CEC for <[email protected]>; Wed, 20 Nov 2008 14:02:21 ...
Sehr ausführliche Informationen zu diesen und allen weiteren Direktiven und Konfigurationsmöglichkeiten bieten die Datei TLS_README der Postfix-Dokumentation und postconf(5). Mit den TLS-Settings in der main.cf ist es leider noch nicht getan; wir müssen nun noch in der Konfigurationsdatei /etc/postfix/master.cf des »zentralen« Postfix-master(8)-Prozesses die Direktive für den tlsmgr(8) aktivieren. Der tlsmgr verwaltet den TLS Session Cache (den wir zuvor über die korrespondierende Direktive smtpd_tls_session_cache_database in die main.cf eingebunden hatten). Schematisch betrachtet, befindet er sich zwischen SMTPD (Server) und SMTP (Client) und kommuniziert mit beiden während der Session. tlsmgr
unix
-
-
n
1000?
1
tlsmgr
Weitere Informationen hierzu bieten man 5 master und man 8 tlsmgr. Bevor wir jedoch mit unserer verschlüsselten Mail-Kommunikation loslegen können, benötigen wir noch einen Dritten im Bunde: den Daemon saslauthd, der im Folgenden für uns als Vermittler zwischen Postfix und LDAP interagiert. Der SASL-Authentifizierungsdaemon saslauthd ist Bestandteil des Cyrus-SASLPaketes (SUSE: cyrus-sasl-saslauthd, Debian: sasl2-bin). Seine Aufgabe ist es, den vom Mail-Client übergebenen Benutzernamen und das zugehörige Passwort mit
456
1198.book Seite 457 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
der Benutzerdatenbank des Systems zu vergleichen, in unserem Fall also LDAP. Wie funktioniert das Ganze nun im Detail? Betrachten wir den Ablauf zunächst in stark vereinfachter, schematischer Darstellung:
TLS-Handshake
UserAuthentifikation
Zugriff auf smtp-Service
Postfix Zugriff über Socket
saslauthd
PAM
LDAP Abbildung 4.11
Postfix, saslauthd und LDAP
Exkurs: SASL-Soup – ein bisschen von diesem , ein bisschen von jenem ... Bei der oben stehenden Darstellung ist ein wichtiger Punkt zu beachten. Im Normalfall nimmt uns die Zwischenschaltung von PAM (pam_-/nss_ldap) einige Konfigurations-Arbeiten ab, da es – eben im Normalfall – problemlos für die entsprechende Kommunikation zwischen unserem LDAP-Server und saslauthd sorgt. Allerdings kann es auch in bestimmten Anwendungsfällen erforderlich sein, die Authentifizierung so umzustellen, dass eine direkte Kommunikation zwischen saslauthd und LDAP stattfindet. Das kann z.B. der Fall sein, wenn wir replizierte Cyrus-Mailserver aufsetzen möchten. Wie das funktioniert, schauen wir uns im Abschnitt 4.5.3, »Geklonter Briefkasten«, an. Zunächst werfen wir jedoch einen Blick auf drei mögliche Smalltalk-Varianten zwischen saslauthd bzw. ldapdb und unserem LDAP: 왘 saslauthd → PAM → LDAP 왘 saslauthd → LDAP 왘 auxprop ldapdb → LDAP Aber der Reihe nach: saslauthd und PAM(-LDAP) Zunächst schauen wir uns die in der letzten Grafik gezeigte Variante an, welche PAM zur Authentifizierung zwischenschaltet, und die im Normalfall für fast alle
457
4.4
1198.book Seite 458 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Anwendungsfälle funktionieren sollte. Zudem stellt sie konfigurationstechnisch die einfachste Variante dar, und sicherheitstechnisch (keine Klartext-Bind-Daten/ Passwörter) hat sie gegenüber den beiden anderen ebenfalls die Nase vorn (ausgenommen ldapdb, dazu später mehr). Nun zur Konfiguration selbst: Zunächst werden über die SASL-spezifische Konfigurationsdatei der jeweiligen Applikation (/etc/sasl2/smtpd.conf für postfix bei SUSE, alternativ /usr/lib/sasl2/smtpd.conf) die Methode und Mechs festgelegt, die dem Mail-Client zur Authentifizierung zur Verfügung stehen. Ist die Datei nicht vorhanden, muss sie angelegt werden: # saslauthd_path: /var/run/sasl2/ pwcheck_method: saslauthd mech_list: plain login
Über pwcheck_method wird die zu verwendende Methode (per saslauthd) angegeben, mit der Postfix die über das AUTH-Kommando eingegebenen Passwörter überprüfen soll. Der Daemon saslauthd, der in der »PAM«-Variante mit dem Schalter -a pam gestartet wird, kommuniziert dabei über einen Unix-Socket mit Postfix. Der Socket selbst findet sich nach dem Start von saslauthd üblicherweise im Verzeichnis /var/run/sasl2/ (OSS11). Der Pfad kann natürlich auch anders gewählt werden; siehe die auskommentierte saslauthd_path-Zeile, allerdings ohne den Socket selbst anzugeben! Die Pfadangabe spielt insbesondere dann eine Rolle, wenn Postfix in einer chroot-Umgebung arbeitet. In diesem Fall müssen besondere Anpassungen vorgenommen werden, dazu gleich mehr. Als Mechs stehen in diesem Beispiel login und plain zur Verfügung. Ersterer ist kein Standard und wird z.B. von Winzigweichs Mailclients Outlook und Outlook Express verwendet. Eine weitere wichtige Datei ist /etc/default/saslauthd (Debian) bzw. /etc/sysconfig/saslauthd (SUSE). Dort wird mit dem Parameter MECHANISMS bzw. SASLAUTHD_AUTHMECH der zu verwendende Mechanismus festgelegt, mit dem saslauthd die Authentifizierung durchführen soll. Wir verwenden hierfür wie eben beschrieben PAM, da wir so über das Modul pam_ldap problemlos auf unsere LDAP-Datenbank zugreifen können (saslauthd-Schalter: -a pam): SASLAUTHD_AUTHMECH="pam"
Kleiner Tipp: Per saslauthd –v lässt sich schnell feststellen, mit welchen Mechanismen der verwendete saslauthd kompiliert wurde: authentication mechanisms: getpwent kerberos5 pam rimap shadow ldap
In der Debian-Variante der Konfigurationsdatei wird der saslauthd über den zusätzlichen Parameter START="yes" als Service aktiviert. Bei SUSE muss der
458
1198.book Seite 459 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Dienst in üblicher Manier über insserv bzw. chkconfig in die Runlevel eingebunden werden. Nun zum Test der Kommunikation: Hierfür können wir das Zusatztool testsaslauthd des Cyrus-SASL-Paketes einsetzen: #> testsaslauthd -u ckent -p linux -s smtp -f /var/run/sasl2/mux
Der letzte Parameter (-f ) ist optional, insofern er bereits in der sasl-spezifischen smtpd.conf gesetzt wurde. Das Ergebnis sollte in jedem Fall 0: OK "Success." sein. Eine Gegenprobe mit nicht existentem Usernamen sollte stattdessen 0: NO "authentication failed" zurückliefern. Sicherheitshalber sollte der Kollege nscd in Tiefschlaf versetzt werden, denn er kann sich auch hier (mal wieder) kontraproduktiv auswirken. Smalltalk – saslauthd und LDAP im direkten Zwiegespräch Die zweite Variante zur Kopplung von saslauthd und LDAP besteht darin, saslauthd zur direkten Kommunikation mit unserem slapd zu bewegen. Dazu muss in der applikationsspezifischen saslauthd-Konfigurationsdatei (/etc/sysconfig/saslauthd bei SUSE) der Authmech von pam auf ldap umgestellt werden: SASLAUTHD_AUTHMECH="ldap"
Voraussetzung ist natürlich, dass saslauthd diese Schnittstelle zur Verfügung stellt (Test wie eben beschrieben per saslauthd -v). Da PAM von diesem Moment an für alle saslauthd-spezifischen Authentifizierungsvorgänge nicht mehr zur Verfügung steht, benötigen wir im nächsten Schritt eine separate Konfigurationsdatei für saslauthd, und zwar /etc/saslauthd.conf. Über sie legen wir die kommunikationsspezifischen Parameter zum Smalltalk mit unserem LDAP-Server fest: ldap_servers: ldap://ldapmaster.local.site/ ldap_bind_dn: cn=sasluser,dc=local,dc=site ldap_bind_pw: linux ldap_version: 3 ldap_search_base: dc=local,dc=site ldap_verbose: on ldap_debug: 3
Der Aufbau ist recht einfach, und deswegen hier wird auch schnell klar, warum diese Lösung nicht unbedingt zu den optimalsten gehört – denn wir haben ein Klartextkennwort und den zugehörigen BindDN in unserer Konfigurationsdatei. Auch wenn der verwendete (Beispiel-)Benutzer nur Leserechte auf den ganzen DIT besitzen sollte, sollte jeder, der diese Lösung verwendet, den Owner/die
459
4.4
1198.book Seite 460 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Dateirechte der saslauthd.conf auf das minimal Mögliche beschränken. Zum anderen sollte die Kommunikation zwischen saslauthd und unserem ldap außerhalb einer Testumgebung entweder per ldapi://-Socket abgewickelt werden, oder zumindest per ldaps:// (Direktive: ldap_servers) verschlüsselt werden. Verschlüsselungstechnisch noch besser wäre hier natürlich die Verwendung der TLSrelevanten Settings, da wir auf diese Art Port 636 erst gar nicht benötigen (hier der Einfachheit halber unter Verwendung unserer existierenden LDAP-Zertifikate): ldap_tls_cert: /etc/openldap/certs/newcert.pem ldap_tls_key: /etc/openldap/certs/ldapkey.pem ldap_tls_cacert: /etc/openldap/certs/cacert.pem
Ein Test in der bekannten Form per #> testsaslauthd -u ckent -p linux –s smtp
sollte uns bei erfolgreicher Rückmeldung (0: OK "Success.") in den Logs Folgendes (oder Ähnliches) präsentieren (Ausgabe ist stark gekürzt): STARTTLS slapd[396]: conn=5 op=0 RESULT oid= err=0 text= slapd[396]: conn=5 fd=14 TLS established tls_ssf=256 ssf=256 ... conn=6 op=0 BIND dn="cn=sasluser,dc=local,dc=site" method=128 slapd[396]: conn=6 op=0 BIND dn="cn= sasluser,dc=local,dc=site" mech=SIMPLE ssf=0 slapd[396]: conn=6 op=1 SRCH base="dc=local,dc=site" scope=2 deref=0 filter="(uid=ckent)" slapd[396]: conn=6 op=2 BIND anonymous mech=implicit ssf=0 slapd[396]: conn=6 op=2 BIND dn="uid=ckent,ou=verkauf,dc=local,dc=site" method=128 ...
Sieht unser Output in etwa so aus, ist die verschlüsselte Kommunikation geglückt. Falls nicht, alle involvierten Konfigurationsdateien auf Typos, und sicherheitshalber auch noch einmal den Kollegen saslauthd auf seine Kapabilitäten prüfen. auxprop ldapdb – LDAP-Plugin für Services Auxprop steht für auxiliary properties (zusätzliche Eigenschaften). Über diese Schnittstelle können SASL-spezifische Plugins für bestimmte Services eingebunden werden, die es dem Service – im Fall von ldapdb – ermöglichen, direkt mit unserem slapd zu kommunizieren, vornehmlich über einen separaten Proxy-User. Benötigt wird dazu bei SUSE das zusätzliche Paket cyrus-sasl-ldap-auxprop, bei Debian libsasl2-modules-ldap. Allerdings entbindet uns auch dieses Verfahren in der Regel nicht davon, separate und applikationsspezifische Konfigurationsdateien mit bind- und sonstigen kommunikationstechnischen Daten zu pflegen.
460
1198.book Seite 461 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Hierzu greifen wir üblicherweise auf die applikationsspezifische SASL-Datei, im smtpd-Fall also dementsprechend /etc/sasl2/smtpd.conf (OSS 11-Pfad), zurück. Der saslauthd wird in dieser Konfiguration nicht mehr benötigt und kann daher deaktiviert werden. Schauen wir uns den Aufbau der Datei am Beispiel der SASLspezifischen smtpd.conf kurz an, die ebenfalls in den Beispieldaten zu diesem Abschnitt hinterlegt ist (wie die ebenfalls nachstehend gelistete Datei .ldaprc): # /etc/sasl2/smtpd.conf pwcheck_method: auxprop auxprop_plugin: ldapdb mech_list: PLAIN LOGIN ldapdb_uri: ldap://ldapmaster.local.site ldapdb_mech: EXTERNAL ldapdb_starttls: demand ldapdb_rc: /etc/openldap/certs/.ldaprc log_level: 7 # /etc/openldap/certs/.ldaprc TLS_CERT /etc/openldap/certs/newcert.pem TLS_KEY /etc/openldap/certs/ldapkey.pem TLS_CACERT /etc/openldap/certs/cacert.pem TLS_REQCERT demand
Wir haben in unserer Konfiguration statt eines BindDN plus zugehörigem Klartext-Kennwort die hinlänglich bekannte Variante der Authentifizierung per SASLMech EXTERNAL gewählt; hierbei ist natürlich zu beachten, dass die Datei .ldaprc tatsächlich existiert, auf die korrekten Zertifikate zeigt, diese für die ClientApplikation lesbar sind und eine entsprechende Umsetzung des Zertifikats-DNs in der slapd-Konfiguration stattfindet. In unserem simplen Beispiel mit dem Zertifikats-DN unseres ldapmaster-Servers, umgesetzt auf den ldapadmin-Account, könnte das – zu Testzwecken sehr einfach gehalten – so aussehen: authz-regexp
cn=ldapmaster(.+) cn=ldapadmin,dc=local,dc=site
Um das Ganze nun anhand eines kleinen Tests zu demonstrieren, testen wir die Konnektivität und Authentifizierung per authcId mit dem bereits bekannten ldapwhoami-Befehl: #> ldapwhoami -Y EXTERNAL -ZZ -X u:ckent SASL/EXTERNAL authentication started SASL username: u:ckent SASL SSF: 0 dn:uid=ckent,cn=external,cn=auth
(Log-Ausgabe, teilweise gekürzt:)
461
4.4
1198.book Seite 462 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
conn=1 op=0 STARTTLS slapd[4739]: conn=1 fd=13 TLS established tls_ssf=256 ssf=256 slapd[4739]: conn=1 op=1 BIND dn="" method=163 slapd[4739]: conn=1 op=1 BIND authcid="cn=ldapmaster.local.site,o=brainstorm,..." authzid="u:ckent" ldapmaster slapd[4739]: conn=1 op=1 BIND dn="cn=ldapadmin,dc=local,dc=site" mech=EXTERNAL sasl_ssf=0 ssf=256 slapd[4739]: conn=1 op=2 WHOAMI
Wie wir unschwer erkennen können, klappt die Verbindungsaufnahme per Zertifikats-DN und authz-regexp problemlos. Damit haben wir einen funktionierenden Einstieg; für einen produktiven Einsatz des ldapdb auxprop-Plugins würde noch eine adäquate Umsetzung des übermittelten User-DNs (in unserem Beispiel in der Form: uid=*,cn=external,cn=auth) benötigt bzw. gegebenenfalls ein Mapping über einen separaten Proxy-User per authzTo/authzFrom (slapd.conf(5)). Noch ein Hinweis: Von der Klartext-Variante (Direktiven: ldapdb_id / ldapdb_ pw) ist in Produktivumfeldern eindeutig abzuraten. Hierzu müssten die Passwortdaten im Objekt des (Proxy-)Users im Klartext gespeichert werden. Zudem müsste das Attribut userPassword dieses Users nicht nur Authentifizierungsrechte besitzen, sondern auch noch per ACL für den Proxy-User lesbar sein. Wir gehen an dieser Stelle nicht weiter auf alle Service-spezifischen Details ein, das würde unseren kleinen Ausflug in die Welt der Mailservices etwas sprengen. Wer ldapdb nutzen will, sollte einen Blick in die applikationsspezifischen Settings der jeweiligen Applikations-Dokumentation werfen; einen guten Einstieg bietet das Mini-HowTo der SASL-Dokumentation, bei SUSE z.B. unter: /usr/share/doc/packages/cyrus-sasl/LDAP_SASLAUTHD Im Netz finden sich hierzu ebenfalls Infos, z.B. unter: http://www.sendmail.org/~ca/email/cyrus2/options.html Fassen wir kurz zusammen: Im »Normal«-Betrieb stellt die saslauthd -> PAMVariante die einfachste, effektivste und sicherste dar. Wer aus funktionellen Gründen ein anderes, einfach aufzusetzendes und (per TLS oder ldapi:// auch sicheres) Verfahren verwenden muss, sollte saslauthd -> ldap per saslauthd.conf den Vorzug geben. Wer ein relativ sicheres, aber deutlich aufwändiger zu konfigurierendes Setup, evtl. in Verbindung mit einer Proxy-User-Umsetzung, wünscht, der sollte einen Blick auf auxprop ldapdb werfen. Ergänzend hierzu sei ein Blick in slapd.conf(5), Stichwort authzTo bzw. authzFrom empfohlen. Weitere Infos zum saslauthd finden sich in saslauthd(8).
462
1198.book Seite 463 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Über Sockel und Käfige Nun zurück zu Postfix und weiter mit unserer spezifischen Vorarbeit an saslauthd – den wir (in der im letzten Abschnitt erläuterten) PAM-Variante betreiben – und Postfix. Wir hatten eben gesagt, dass saslauthd über einen Unix-Socket mit Postfix kommuniziert. Dieser Socket findet sich ohne weitere Angabe von Parametern bei SUSE z.B. unter /var/run/sasl2/mux, was im Normalfall völlig in Ordnung ist. Allerdings kann es bei der Wahl dieses Pfades und dem Einsatz einer Postfix-chroot-Umgebung wie z.B. bei Debian zu Problemen kommen. Ob Postfix im Käfig hin- und hertapert, lässt sich schnell anhand der Datei /etc/ postfix/master.cf kontrollieren (siehe unten). Eine typische Fehlermeldung in der entsprechenden Mail-Logdatei für einen nicht angepassten saslauthd-Socket-Pfad in Verbindung mit Postfix im chroot-Jail könnte dann so aussehen: postfix/smtpd: warning: SASL authentication failure: cannot connect to saslauthd server: No such file or directory
Ist dies der Fall, muss das saslauthd-Startskript unter /etc/init.d/ der Postfixchroot-Umgebung angepasst werden. Das könnte mit dem zusätzlichen Parameter PARAMS="-m /var/spool/postfix/var/run/saslauthd"
erfolgen. Allerdings empfiehlt sogar die Postfix-Dokumentation, den Dienst besonders in Verbindung mit SASL nicht in einer chroot-Umgebung laufen zu lassen, da dies die Installation extrem verkompliziert. Das Ganze potenziert sich dann noch im Zusammenspiel mit Cyrus-IMAP, da dieser auch mit saslauthd kommunizieren muss. Also: Kein Käfig für den Master – in unserem Beispiel konfigurieren wir den SMTP-Service in der /etc/postfix/master.cf ohne chroot-Umgebung (Spalte 5): # service type private unpriv chroot wakeup maxproc command+args # (yes) (yes) (yes) (never) (100) # ============================================================================= smtp inet n n smtpd -v
Zurück zu saslauthd. Vor unserem nächsten Testdurchlauf prüfen wir noch einmal per testsaslauthd die Kommunikation zwischen saslauthd und LDAP: #> testsaslauthd -u ckent -p linux –s smtp
Das Ergebnis sollte 0: OK "Success." sein. Je nach Distribution kann es gegebenenfalls erforderlich sein, den Postfix-Systemuser derjenigen Gruppe zuzuordnen, die Schreibberechtigung für den Socket des saslauthd hat, um mit ihm kommunizieren zu können. Bei Debian würde man etwa den User postfix der Gruppe sasl zuordnen:
463
4.4
1198.book Seite 464 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
#> usermod –G sasl postfix
Nun sollte unserem ersten Test auf der Kommandozeile nichts mehr im Wege stehen. Zuerst prüfen wir, ob uns der SMTP-Server das STARTTLS-Kommando meldet. #> telnet localhost 25
sollte uns folgende Ausgabe bringen: Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 ldapmaster.local.site ESMTP Postfix
Nun tippen wir das Kommando ehlo localhost am Telnet-Prompt ein. ehlo steht für »extended hello«. Über dieses Kommando wird die Client-Verbindung zum SMTP-Service ausgebaut. ehlo produziert dabei eine etwas geschwätzigere Ausgabe als das ebenfalls verwendbare helo. Die Antwort des Servers sollte so aussehen: 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN
Beenden können wir die Ausgabe durch die Eingabe und anschließende Bestätigung des Kommandos quit. Besonders wichtig hierbei ist, dass uns –wie im oberen Listing- das STARTTLS-Kommando angezeigt wird. Das AUTH-Kommando darf an dieser Stelle keinesfalls auftauchen, denn wir wollen die Authentifizierung ja erst nach erfolgreich gestarteter Verschlüsselung zulassen. Fall das doch der Fall sein sollte, kurz überprüfen, ob in der main.cf folgende Direktive gesetzt ist; wenn nicht, muss sie ergänzt werden. smtpd_tls_auth_only = yes
Jetzt starten wir den zweiten Teil unseres Tests, indem wir eine verschlüsselte Sitzung initiieren. Wir öffnen dazu eine zweite Konsole, auf der wir uns als User ckent einloggen. Dort setzen wir den Befehl #> openssl s_client -starttls smtp -host \ ldapmaster.local.site -port 25
ab, der uns über eine verschlüsselte Verbindung mit dem auf Port 25 laufenden SMTP-Dienst (Postfix) verbindet. Nach Abschicken des Befehls sollten als Erstes
464
1198.book Seite 465 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
die Daten des TLS-Handshakes inklusive Zertifikat über den Bildschirm flimmern. Fehlermeldungen über etwaige selbst signierte Zertifikate können wir getrost ignorieren, denn schließlich wissen wir ja, wer sie signiert hat. Nun schicken wir auf genau dieser Konsole wiederum ein ehlo-Kommando ab: ehlo ldapmaster.local.site
Die Antwort des Servers sollte in etwa so aussehen: 250-ldapmaster.local.site 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-AUTH LOGIN PLAIN 250-AUTH=LOGIN PLAIN 250 8BITMIME
Erscheint diese Ausgabe direkt nach Abschicken des vorletzten Befehls (openssl s_client ...), hängt dies sehr wahrscheinlich mit den Einstellungen der Direk-
tiven smtp_always_send_ehlo/smtp_never_send_ehlo zusammen. Die zweite 250-AUTH=LOGIN PLAIN Zeile taucht nur dann auf, wenn die Direktive broken_ sasl_auth_clients = yes gesetzt wurde. Weiter im Text, oder besser: Test. Wir erzeugen auf der ersten Konsole mit Perl ein Base64-codiertes Passwort für den User ckent, dessen erfolgreich per TLS verschlüsselte SMTP-Client-Session auf der anderen Konsole im Gange ist (Zeile ist umbrochen): #> perl -MMIME\:\:Base64 -e 'print \ encode_base64("ckent\0ckent\0linux");'
oder alternativ: #> printf '\0ckent\0linux' | mmencode
Das dort gewonnene, Base64-codierte Passwort kopieren wir per Cut & Paste an das AUTH PLAIN-Kommando auf der zweiten Konsole, unserer SMTP-Client-Session, um uns am SMTP-Server zu authentifizieren: AUTH PLAIN Y2tlbnQAY2tlbnQAbGludXg=
Als Rückgabe sollten wir »235 Authentication successful« erhalten. Auch wenn das Passwort »nur« Base64-codiert – also eigentlich PLAIN ist –, stellt das kein Problem dar, da wir ja innerhalb der TLS-Session arbeiten. Um nun eine Mail auf der Kommandozeile zu verschicken, gehen wir wie folgt vor (die mit * markierten Zeilen sind die Kommandos, die wir eingeben):
465
4.4
1198.book Seite 466 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
* mail from:ckent 250 Ok * rcpt to:skiu 250 Ok * data 354 End data with . * Test mit TLS * . 250 Ok: queued as F03C856CEC * quit 221 2.0.0 Bye read:errno=0
Sollte bis zu diesem Punkt alles geklappt haben, besitzen wir bereits eine solide Ausgangskonfiguration für einen per TLS verschlüsselt arbeitenden Mailserver, die wir im nächsten Abschnitt im Zusammenspiel mit regulären E-Mail-Clients wie Thunderbird und Outlook Express testen werden, bevor wir uns Cyrus-IMAP ansehen. Hat etwas nicht in der beschriebenen Form funktioniert, geht es wie üblich ans Debugging: 왘 Alle Direktiven in der main.cf (und in allen Includes) und master.cf korrekt gesetzt? 왘 saslauthd korrekt konfiguriert und gestartet? 왘 nscd abgeschaltet? 왘 tlsmgr aktiviert (master.cf)? 왘 Postfix in chroot-Umgebung? 왘 Wurde saslauthd entsprechend angepasst? 왘 Was ergibt der Test per testsaslauthd? 왘 Wurde der Systemuser-Postfix der entsprechenden Gruppe zugeordnet? 왘 Alle sonstigen involvierten Konfigurationsdateien korrekt konfiguriert? 왘 Funktioniert TLS an sich? 왘 Wurden die Zertifikate korrekt erstellt und eingebunden? 왘 Log-Level für Postfix-TLS hoch genug? Taucht in den Logs folgende Fehlermeldung auf: smtpd: warning: problem talking to server private/tlsmgr: Connection refused,
so wurde vergessen, den tlsmgr(8) in der Datei /etc/postfix/master.cf zu aktivieren. Weiterführende Informationen, Dokumentationen und Beispiele rund um Postfix (und auch Cyrus-SASL, und einiges andere mehr) finden sich unter www.postfix.org.
466
1198.book Seite 467 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Nachdem wir uns nun eingehend mit dem LDAP-optimierten Postamt beschäftigt haben, wird es Zeit nachzuschauen, wie wir die Post auf dem letzten Stück sicher zum User bekommen.
4.4.5
Setup der Mailclients für LDAP und TLS
Betrachten wir die relevanten Einstellungen am Beispiel der gängigsten Mailclients Outlook Express und Thunderbird. Kurze Anmerkung vorab: Zum Testen der kompletten Mailclient-Funktionalität kann es erforderlich sein, den POP3Service auf Port 110 zur Verfügung zu stellen. Da wir noch keinen IMAP-Server installiert haben, der diese Funktionalität bereitstellt, können die Ungeduldigen dies bei Bedarf recht einfach und schnell über das Paket qpopper bewerkstelligen. Die Integration erfolgt recht simpel über xinetd und die Datei /etc/xinet.d/qpopper. Anschließend nicht vergessen, den xinetd-Service zu starten. Die andere Variante: bis zum nächsten Abschnitt zu warten. Denn dort setzen wir den IMAPMailserver Cyrus-IMAP auf, und der kümmert sich gleich mit um Port 110. Outlook Express Um auf das Adressenverzeichnis unseres LDAP zugreifen zu können, muss im OE-Menü über Extras 폷 Konten zunächst ein entsprechender Eintrag für den Verzeichnisdienst eingerichtet werden:
Abbildung 4.12
LDAP-Einrichtung in Outlook Express
467
4.4
1198.book Seite 468 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Im Karteireiter »Erweitert« müssen zusätzlich der Port (389) und die Searchbase angegeben werden, in unserem Fall also dc=local,dc=site. Die Bindung kann, sofern keine Einschränkungen durch ACLs für anonyme Verbindungen gesetzt wurden, ohne Anmeldung erfolgen. Nun können bei der Suche von Adressen bzw. Personen die Daten aus unserem DIT mit einbezogen werden. Das Setup für TLS ist ebenfalls schnell erledigt; hierfür muss in den erweiterten Einstellungen des jeweiligen Mailkontos nur der Haken bei SSL (für smtp) gesetzt werden. Erhalten wir nun eine Mail, können wir uns den Header mit den verschlüsselungsrelevanten Informationen einfach über Rechtsklick auf die Mail (Eigenschaften 폷 Details) aufrufen:
Abbildung 4.13
TLS-Infos im Mail-Header (Outlook Express)
Der Donnervogel: Thunderbird Betrachten wir nun noch kurz die Einstellungen für Thunderbird, wo für die LDAP-Anbindung im Menü Extras 폷 Einstellungen 폷 Verfassen der Haken für einen LDAP-Verzeichnisserver gesetzt sein muss. Dann müssen wir die Einstellungen für den LDAP-Server wie folgt bearbeiten:
468
1198.book Seite 469 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Abbildung 4.14
LDAP-Einrichtung im Thunderbird
Die Aktivierung von TLS erfolgt beim Thunderbird über das Menü Extras 폷 Konten 폷 Postausgang-Server (SMTP). Dort aktivieren wir die Einstellungen für TLS:
Abbildung 4.15
TLS-Einrichtung im Thunderbird
469
4.4
1198.book Seite 470 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Beim nächsten Versand einer Mail präsentiert uns unser Postfix-Server dann das eingebundene Zertifikat (aufgrund unserer eigens signierten Zertifikate üblicherweise mit der Meldung, dass das Zertifikat einer unbekannten Zertifizierungsstelle entstammt – ein Import der CA kann hier für Ruhe sorgen), das den gelungenen Verbindungsaufbau per TLS signalisiert. Die Verschlüsselung zwischen Postfix und Mailclient kann auch noch für die zusätzliche Verwendung von Client-Zertifikaten aufgebohrt werden. Dazu müssen natürlich die entsprechenden Client-Zertifikate generiert sowie die relevanten smtp_*-Client -Direktiven in der main.cf gesetzt werden. Wir hofften zwar schon bei der Erstellung der letzten Ausgabe auf einen schreibenden Zugriff via Thunderbird 2.x auf den DIT, aber leider ist nichts daraus geworden. Also ist –leider- Warten auf Release 3.x angesagt. Ein schreibender Zugriff auf die Objektdaten im DIT lässt sich momentan nur mit unserem nächsten Kunden, Evolution, realisieren, wobei gegebenenfalls die hinterlegten Attribute bzw. Objekte angepasst werden müssen. Dies kann durch Einbinden des evolutionperson.schema, das vom Evolution-Paket mitgebracht wird, in die LDAP-Konfiguration erreicht werden.
Alles eine Frage der Evolution Der PIM unter Linux, ohne Frage. Das LDAP-Setup von Evolution lässt sich ziemlich einfach bewerkstelligen. Nach der Installation der erforderlichen Pakete (siehe Anhang) starten wir Evolution und klinken uns in unser LDAP-Adressverzeichnis ein. Dazu wählen wir den Menüpunkt Datei 폷 Neu 폷 Adressbuch 폷 Auf LDAP-Server. Danach bietet sich uns ein Konfigurationsdialog, in dem wir Server, Port und die Art der Authentifizierung angeben. Wahlweise können wir anonym, per Mail-Adresse oder per DN authentifizieren. Im zweiten Karteireiter, »Details«, geben wir searchbase, scope und limit der angezeigten Entries an. Das Mail-Setup lässt sich ebenfalls schnell einrichten. Über Bearbeiten 폷 Einstellungen 폷 E-Mail-Konten 폷 Hinzufügen werden wir über diverse selbsterläuternde Fenster zur Einrichtung unserer Mailbox geführt, die verschiedene Varianten bietet, unter anderem natürlich POP3 und IMAP. Beim Einrichten kann auch direkt die Konnektivität per verschlüsselter Verbindung getestet werden. Damit Evolution optimal unterstützt wird, sollten wir das eben bereits erwähnte evolutionperson.schema mit einbinden, das Bestandteil des Evolution-Paketes ist. Es findet sich bei SUSE z.B. unter /usr/share/evolution-data-server-2.22/evolutionperson.schema.
470
1198.book Seite 471 Donnerstag, 5. Februar 2009 3:02 15
Wenn der Postmann zwei Mal klingelt: OpenLDAP und E-Mail
Abbildung 4.16
LDAP-Einbindung unter Evolution
Legen wir über das Adressbuch-Interface von Evolution einen neuen Eintrag an, sieht das neu erstellte Objekt im DIT so aus: # Lois Lane, local.site dn: cn=Lois Lane,dc=local,dc=site cn: Lois Lane sn: Lane fileAs: Lane, Lois objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson objectClass: evolutionPerson
Voraussetzung ist natürlich die Einbindung des evolutionperson.schema in unsere slapd-Konfiguration sowie ein DN, der über die entsprechenden Rechte bzw. die passenden ACLs verfügt. Noch ein kleiner, allgemeiner Tipp am Rande: Man kann auch im Browser (Firefox/IE) per LDAP-URL eine Suche im Adressbuch ausführen: Einfach in die Adresszeile einen Search-Request der folgenden Form eingeben (Zeile umbrochen): ldap://ldapmaster.local.site/dc=local,dc=site?mail?sub?objectClass= inetOrgPerson
471
4.4
1198.book Seite 472 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Nun zu einer weiteren, interessanten Erweiterung des Mailsystems: dem IMAPMailserver. Er ermöglicht es, Mails zentral auf dem Mailserver zu verwalten, so wie man es von vielen Freemailern im Web kennt. Und das Beste daran – wir ahnen es bereits wieder: Er spricht auch mit unserem LDAP.
4.5
Cyrus-IMAP
Wie sein Name bereits unschwer erahnen lässt, handelt es sich auch beim CyrusIMAP um ein Produkt aus derselben Entwicklerschmiede wie das Cyrus-SASLPaket: der Carnegie Mellon University (CMU). Neben dem Cyrus-IMAP existieren weitere bekannte IMAP-Mailserver wie z.B. der UW-IMAP der University of Washington (den Debian standardmäßig vorschlägt), Dovecot oder CourierIMAP. Wir haben uns -wie in der letzten Ausgabe- für Cyrus-IMAP entschieden, da er im Vergleich zu seinen Mitstreitern einige Vorteile bietet. Die wichtigsten wären: sehr umfangreiche Konfigurierbarkeit, sehr gute Skalierbarkeit und Performance (hierzu müssen allerdings die Standardsettings gegebenenfalls etwas optimiert werden), insbesondere bei vielen Usern: Kommt es zu Engpässen, kann mit Hilfe des Projekts Cyrus Murder die Last auch auf verschiedene Cyrus-Server verteilt werden, die nach außen hin als ein System erscheinen. Zudem erstellt CyrusIMAP für sich wiederholende Aktionen Caches und Indizes, wodurch die I/OOperationen minimiert werden. Die Benutzer-Authentifikation erschlägt er naheliegenderweise über das Cyrus-SASL-Framework respektive durch unseren bereits bekannten Kollegen saslauthd. Ein Nachteil steht jedoch noch im Raum: Die Dokumentation des Projekts ist leider nach wie vor nicht unbedingt üppig, im Gegensatz zu früheren Zeiten ist jedoch langsam Besserung zu spüren. Im Wiki http://cyrusimap.web.cmu.edu/twiki/bin/view/Cyrus/WebHome finden sich kleine Dokus zu Cyrus, Murder, eine kleine FAQ und einiges andere. Der in der Vergangenheit oft als Manko gesehene Punkt, dass Cyrus nicht das Standard-Mailbox-Format verwendet, ist mittlerweile haltlos. Alle MailserverEntwickler stimmen nunmehr darin überein, dass das traditionelle mbox-Format für moderne Mailbox-Server nicht mehr adäquat ist, insbesondere unter dem Aspekt der Geschwindigkeit, denn der Server muss bei jedem Zugriff auf eine Mail die komplette mbox-Datei mit n enthaltenen Mails öffnen. Was den Rahmen des Setups angeht, so beschränken wir uns natürlich auch in diesem Fall hauptsächlich auf die für uns relevanten LDAP-technischen Punkte und verweisen an den entsprechenden Stellen auf die vorhandenen Dokumentationen bzw. Manpages.
472
1198.book Seite 473 Donnerstag, 5. Februar 2009 3:02 15
Cyrus-IMAP
Unser Ziel Im Folgenden werden wir Cyrus-IMAP in der Version 2.3.11 (Debian verwendet out of the box eine betagtere 2.2.13) zunächst grundlegend konfigurieren. Dabei stellen wir genau wie bei Postfix über den bereits hinlänglich bekannten saslauthd die Verbindung zu unserem LDAP her. Zusätzlich werden wir die Verschlüsselung per TLS einrichten und noch kurz die Anbindung an die E-Mail-Clients erläutern, bevor wir uns eine Replikation von zwei Cyrus-IMAP Servern anschauen. Die von uns verwendeten Pakete zu diesem Abschnitt sind im Anhang gelistet.
4.5.1
Setup
Hierbei sind primär zwei Punkte zu beachten: zum einen natürlich das Setup des Cyrus-IMAP selbst, zum anderen seine Integration in Postfix, denn schließlich soll Postfix die Mails nicht mehr direkt ausliefern, sondern an Cyrus-IMAP übergeben. Die erste Konfigurationsdatei, die wir hierzu bearbeiten, ist die /etc/imapd.conf. Dort definieren wir einige IMAP-spezifische Parameter wie Quota-Einstellungen, Verzeichnisse und den Admin des Cyrus-IMAP. Daneben werden ebenfalls der Authentifizierungsmechanismus (sasl_pwcheck_method) und die tls_*-relevanten Direktiven zur Verschlüsselung festgelegt. Dabei werden wir der Einfachheit halber wieder die für unseren LDAP generierten Zertifikate verwenden. Das folgende Listing entstammt der SUSE-/etc/imapd.conf: # /etc/imapd.conf – SUSE configdirectory: /var/lib/imap partition-default: /var/spool/imap sievedir: /var/lib/sieve admins: cyrus allowanonymouslogin: no autocreatequota: 10000 reject8bit: no quotawarn: 90 timeout: 30 poptimeout: 10 dracinterval: 0 drachost: localhost sasl_pwcheck_method: saslauthd lmtp_overquota_perm_failure: no lmtp_downcase_rcpt: yes ldap_version: 3 # TLS-Settings tls_cert_file: /etc/openldap/certs/newcert.pem
473
4.5
1198.book Seite 474 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
tls_key_file: /etc/openldap/certs/key.pem tls_ca_file: /etc/openldap/certs/cacert.pem
Bei Debian müssen gegebenenfalls noch die Direktiven sasl_mech_list: PLAIN LOGIN, sasl_minimum_layer, sasl_maximum_layer gesetzt bzw. einkommentiert werden, ebenso wie admins: cyrus. Nun zur /etc/postfix/main.cf. Dort fügen wir die folgende Zeile ein: mailbox_transport = lmtp:unix:/var/lib/imap/socket/lmtp
Das LMTP (Local Mail Transfer Protocol) ist eine Ableitung des Mailprotokolls SMTP. Letzteres wurde primär für die Mailzustellung zwischen Servern konzipiert, LMTP hingegen ist für eine endgültige lokale Zustellung gedacht. LMTP wird unter anderem von Cyrus-IMAP unterstützt. Die Direktive mailbox_transport = lmtp:... – sorgt daher – vereinfacht ausgedrückt – für die Weiterleitung der Mail von Postfix zu Cyrus-IMAP, wobei die Prozesskommunikation wiederum über einen Unix-Socket erfolgt. Der angegebene Socket-Pfad bezieht sich auf SUSE, Debian verwendet den Pfad /var/run/cyrus/socket/lmtp. Taucht in den mail-Logs folgender oder ähnlicher Fehler auf: connect to ldapmaster.local.site [/var/lib/imap/socket/lmtp]: Permission denied
müssen wir gegebenenfalls die Zugriffsrechte auf den Socket bzw. die übergeordneten Ordner kontrollieren und anpassen; bei SUSE z.B. im einfachsten Fall: #> chmod a+x /var/lib/imap/ #> chmod a+x /var/lib/imap/socket
Anschließend müssen natürlich die Services neu gestartet werden. In der /etc/cyrus.conf überprüfen wir, ob die folgende lmtpunix-Zeile vorhanden ist, und passen den Socket-Pfad (siehe oben) für die jeweilige Distribution gegebenenfalls entsprechend an (Zeile ist umbrochen): lmtpunix cmd= "lmtpd" listen="/var/lib/imap/socket/lmtp" prefork=0
Der prefork-Parameter beschreibt hierbei die Anzahl der geforkten Prozesse, die in »Reserve« stehen, und ist daher für die Performance relevant (default 0). lmtpunix definiert auf der Cyrus-Seite den Unix-Socket, über den er mit Postfix kommuniziert. Es sollte unbedingt sichergestellt sein, dass sowohl der Postfix- als auch der Cyrus-Systemuser lesenden und schreibenden Zugriff auf diesen Socket haben! Im Mail-Log äußert sich ein solcher Zuordnungsfehler (und damit auch Berechtigungsfehler) meist in folgender Form:
474
1198.book Seite 475 Donnerstag, 5. Februar 2009 3:02 15
Cyrus-IMAP
status=deferred (connect to […/socket /lmtp]: Permission denied)
Bringt die Gruppenzuordnung noch keinen Erfolg, lohnt es sich, einen genaueren Blick auf die Rechte und Eigentümer der entsprechenden Ordner zu werfen, unter denen der Socket liegt. Apropos Log: Während des Setups -und bei Bedarf auch zur späteren Log-Auswertungkann es sich lohnen, Cyrus etwas geschwätziger einzustellen. Das können wir über die Variable CYRUS_VERBOSE=1 erledigen. Bei Debian findet sich der Parameter z.B. unter / etc/default/cyrus. Manuell können wir die Variable genauso gut temporär setzen oder auch permanent in das Cyrus-Start-Skript integrieren. Dabei den Export nicht vergessen.
Um die verschlüsselten Mail-Services imaps und pop3s auf Port 993 bzw. 995 zu aktivieren, müssen wir die mit imaps bzw. pop3s beginnenden Zeilen in der /etc/ cyrus.conf einfügen bzw. entkommentieren, hier beispielhaft für imaps: imaps cmd="imapd -s" listen="imaps" prefork=0
Im nächsten Schritt muss dem Cyrus-Administrator (cyrus), der bei der Installation des Paketes üblicherweise mit angelegt wird, ein Passwort gegeben werden. Der User cyrus wird regulär in den System-Passwort-Dateien /etc/passwd /etc/ shadow angelegt, ein Test mit grep cyrus /etc/passwd bringt schnell Klarheit. Alternativ können wir den Account auch in unseren LDAP transferieren und dort verwalten. Wir wählen als Passwort für den User cyrus hier ebenfalls »linux«. First Contact Bevor wir unseren Cyrus-Imap starten (Restart von Postfix nicht vergessen, damit die neue mailbox_transport-Direktive aktiviert wird), bitte sicherstellen, dass der POP3Daemon qpopper aus unserem letzten Beispielsetup nicht (mehr) läuft, da cyrus uns diese Funktion mit zur Verfügung stellt. Ebenfalls sicherstellen, dass saslauthd im Gegenzug aktiv ist.
Nun nehmen wir ersten Kontakt mit dem Cyrus über das Tool imtest auf. Es ist Bestandteil des Cyrus-IMAP-Paketes und liefert umfangreiche Informationen über die Funktionalität. Zuvor kontrollieren wir per nmap, ob der Cyrus-Dienst läuft und uns die Ports 143 (imap), 993 (imaps), 110 (pop3) und 995 (pop3s) zur Verfügung stellt. Ist alles okay, starten wir imtest mit dem User-Account Cyrus und den Parametern -s (imaps) und -v (verbose): #> imtest -m login -a cyrus localhost –s -v
Die Ausgabe sollte (stark gekürzt) so aussehen:
475
4.5
1198.book Seite 476 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
starting TLS engine setting up TLS connection SSL_connect:before/connect initialization ... SSL_connect:SSLv3 write client hello A SSL_connect:SSLv3 read server hello A... Peer cert verify depth=0 /DC=site/DC=local/ST=Deutschland/L=Dortmund/ O=Brainstorm/CN=ldapmaster.local.site ... TLS connection established: TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits) ... S: * CAPABILITY IMAP4 IMAP4rev1 LITERAL+ ID AUTH=GSSAPI AUTH=LOGIN AUTH=PLAIN AUTH=CRAM-MD5 AUTH=DIGEST-MD5 SASL-IR ...<snip>... URLAUTH S: C01 OK Completed Please enter your password: C: L01 LOGIN cyrus {5} S: + go ahead C: S: L01 OK [CAPABILITY IMAP4 IMAP4rev1 LITERAL+ ID LOGINDISABLED ACL RIGHTS=kxte QUOTA ...<snip>... URLAUTH] User loggedin Authenticated. Security strength factor: 256
Per [Strg] + [C] (SIGINT, kill -2) können wir die Verbindung beenden. In den ersten beiden Zeilen erkennen wir die starttls-Kommandos, die den verschlüsselten Verbindungsaufbau einleiten. Am Ende der Ausgabe finden wir den ssf 256, der uns zusammen mit der Meldung Authenticated die erfolgreich stattgefundene, verschlüsselte Authentifizierung signalisiert. Im nächsten Schritt legen wir eine Mailbox für unsere User ckent und skiu im Cyrus-IMAP an. Über das cyradm-Kommando initiieren wir zunächst eine interaktive Sitzung mit Cyrus-IMAP: #> cyradm --auth login localhost --user cyrus
Das Kommando erwartet die Eingabe des Passworts für den User cyrus, also »linux«. Hat alles geklappt, befinden wir uns im Kommandozeilen-Interface des Cyrus-IMAP. Taucht stattdessen z.B. folgende Fehlermeldung auf: IMAP Password: Login failed: generic failure at /usr/lib/perl5/Cyrus/IMAP/Admin.pm
so kann dies mit der Tatsache zusammenhängen, dass der User cyrus nicht zu der Gruppe gehört, die entsprechende Rechte auf den saslauthd-Socket hat, z.B. der Gruppe sasl (Debian) oder mail (SUSE). Weiter im Text: Mit den folgenden Befehlen legen wir im Kommandozeilen-Interface die Mailboxen der User an und geben ihnen entsprechende Berechtigungen. Hilfe zu den verfügbaren Befehlen im Interface des Cyrus-IMAP gibt das Kommando »?«:
476
1198.book Seite 477 Donnerstag, 5. Februar 2009 3:02 15
Cyrus-IMAP
localhost> cm user.ckent localhost> cm user.skiu localhost> lm user.ckent (\HasNoChildren) user.skiu (\HasNoChildren)
localhost> setacl user.* cyrus lrswipcda Setting ACL on user.ckent...OK. Setting ACL on user.skiu...OK.
localhost> lam user.* user.ckent: ckent lrswipkxtecda cyrus lrswipkxtecda user.skiu: skiu lrswipkxtecda cyrus lrswipkxtecda
localhost> exit
Schauen wir uns kurz an, was die Befehle im Einzelnen bedeuten: Zuerst haben wir die Mailboxen für ckent und skiu angelegt (cm=create mailbox). Der Parameter »user.« vor dem jeweiligen Namen ist dabei erforderlich. lm listet die vorhandenen Mailboxen. Per setacl haben wir den Usern selbst sowie dem CyrusAdmin (ja, das muss explizit gemacht werden ...) die entsprechenden Zugriffsrechte gewährt und per lam überprüft. Eine ausführliche Beschreibung der Berechtigungen und aller Kommandos findet sich in cyradm(8). Nun sollten wir so weit sein, mit den Mailclients auf unseren frisch aufgesetzten IMAP-Mailserver zuzugreifen, der sich seine Authentifizierungsdaten per saslauthd aus unserem LDAP-DIT holt.
4.5.2
Clients
Mail-Clients gibt es für IMAP-Mailserver zuhauf. Auch Mozilla/Thunderbird, Evolution, OE, Outlook und viele andere kommen mit IMAP-Mailservern klar, wobei der Umfang der Unterstützung je nach Produkt variiert. Allerdings muss die Verwendung als IMAP-Client üblicherweise bereits bei der Erstellung des Mailkontos entsprechend gesetzt werden. Dabei auch nicht vergessen, die Einstellungen für verschlüsselte Verbindung und die entsprechenden Ports zu setzen! Startet nun User ckent von einem Mailclient aus die Kontaktaufnahme über Port 993 (imaps), sollten in den Logs die folgenden Meldungen auftauchen: imaps[9493]: SSL_accept() succeeded -> done imaps[9493]: starttls: TLSv1 with cipher DHE-RSA-AES256-SHA ... imaps[9493]: login: [192.168.198.250] ckent plain+TLS User logged in
Nun zum Debugging: 왘 Wurde der Debug-Level höher gesetzt? (CYRUS_VERBOSE) 왘 Alle Direktiven in den entsprechenden Konfigurationsdateien gesetzt?
477
4.5
1198.book Seite 478 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
왘 Was sagen die Log-Dateien? Tauchen dort einige der in diesem Abschnitt beschriebenen Fehlermeldungen auf? 왘 Läuft saslauthd? 왘 nscd abgeschaltet? 왘 lmtp-Socket für alle beteiligten Dienste erreichbar/lesbar? 왘 Läuft Postfix gegebenenfalls in einer chroot-Umgebung? 왘 Wurden alle Konfigurationsparameter in den entsprechenden Dateien gesetzt? 왘 Haben Postfix und Cyrus-IMAP entsprechende Berechtigungen für den gemeinsam genutzten lmtp-Socket? Hierbei auch darauf achten, dass die Gruppe, mit deren Rechten Postfix läuft, auch Zugriff auf den Ordner hat, in dem der lmtp-Socket liegt. 왘 Hat Cyrus-IMAP entsprechende Berechtigungen für den saslauthd-socket? 왘 Was sagt id postfix bzw. id cyrus? Auf unseren Testsystemen (bezogen auf den letzten Punkt): Debian uid=112(cyrus) gid=8(mail) Gruppen=8(mail),45(sasl) uid=111(postfix) gid=119(postfix) Gruppen=119(postfix),8(mail),45(sasl)
SUSE uid=96(cyrus) gid=12(mail) groups=12(mail) uid=51(postfix) gid=51(postfix) groups=51(postfix),12(mail)
Taucht beim Mailclient ein Fehler beim Verschieben der Mail in den Ordner Sent/Gesendet auf? Dann gegebenenfalls für den Postausgangsserver die Abfrage von Benutzername und Passwort deaktivieren.
4.5.3
Geklonter Briefkasten – replizierte Cyrus-IMAP-Mailboxen
Das Thema gehört zwar nicht direkt zu LDAP – weil wir uns jedoch extensiv mit replizierten LDAP-Servern beschäftigen, auf denen zum Teil auch die LDAP-relevanten Services (wie Samba, oder in diesem Fall auch Cyrus-IMAP) redundant angelegt werden können, werden wir zumindest eine kleine Einleitung zu diesem Thema geben. Cyrus-IMAP bietet seit einiger Zeit die Möglichkeit, Mailboxen von einem Master auf einen Slave zu replizieren. Klingt bekannt? Richtig. Und daher harmoniert es auch gut mit den typischen Consumer/Provider -Setups
478
1198.book Seite 479 Donnerstag, 5. Februar 2009 3:02 15
Cyrus-IMAP
unseres LDAP. Zur Aktivierung muss Cyrus-IMAP mit der Option --enable-replication kompiliert sein; hierdurch werden unter anderem die benötigten
Tools wie z.B. sync_server(8) und sync_client(8) erstellt. Bei SUSE finden sich die Tools z.B. unter /usr/lib/cyrus/bin/*. Das Funktionsprinzip ähnelt entfernt dem refreshAndPersist-Mode der sync-Replikation unseres LDAP-Servers, denn der jeweils aktive Cyrus-Master kümmert sich mit Hilfe des Tools sync_client(8) um den aktiven Part der Replikation, bei der Änderungen vom Master auf den Slave, auf dem der sync_server(8) läuft, gepusht werden. Der Cyrus-Slave seinerseits horcht auf Synchronisationsnachrichten des Masters. Auf beiden Cyrus-Servern, dem Cyrus-Master und dem ReplicaServer (Slave), sollte jeweils in der /etc/services ein Eintrag für den Service csync vorgenommen werden. In unserem Beispiel nehmen wir dazu TCP-Port 2003. Die Portnummer selbst ist dabei nebensächlich, sie muss nur zwei Kriterien erfüllen: sie darf noch nicht belegt sein und muss logischerweise auf Master und Slave identisch sein. Kümmern wir uns zunächst um die /etc/cyrus.conf von Master- und Slave (Replica)-Server. Auf dem Master wird zusätzlich in der Sektion »SERVICES« folgender Eintrag benötigt (Zeile umbrochen): syncclient cmd="/usr/lib/cyrus/bin/sync_client -r" listen="csync" prefork=0
Und auf dem Slave (Replica-)Server dieser Eintrag: syncserver cmd="/usr/lib/cyrus/bin/sync_server" listen="csync
Wobei die Pfade zu den Binaries natürlich je nach Distribution anzupassen sind. Der zusätzliche sync_client Parameter (-r) sorgt für eine so genannte »rolling replication« in festen Intervallen. In der imapd.conf des Masters muss noch angegeben werden, wie er (der Master) sich am Replica-Server anmeldet. Dies geschieht über die folgenden, relativ selbsterklärenden Direktiven: sync_log: 1 sync_host: ldapslave.local.site sync_authname: cyrus sync_password: linux sync_machineid: 1 sync_repeat_interval: 10
Der sync_host spezifiziert per IP/Hostname den Slave, auf den per sync_clientKommando repliziert wird, und der unter sync_authname angegebene Account
479
4.5
1198.book Seite 480 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
muss auf dem Slave der Administrator des Cyrus-IMAP sein, also üblicherweise ebenfalls der User cyrus. Das Aktivieren der Universally Unique Identifiers (UUIDs) optimiert den Replikationstraffic erheblich, deswegen sollte dieser Punkt in jedem Fall aktiviert werden. Hierfür wird in der imapd.conf des Masters die Direktive sync_machineid:
gesetzt, wobei die ID ein Wert von 0-255 sein kann. Zusätzlich wird in der cyrus.conf des Masters die Zeile imap
cmd="imapd" listen="imap" prefork=5 provide_uuid=1
eingefügt. Per sync_repeat_interval: <sec>
in der imapd.conf des Master wird das Intervall angegeben, in dem die »rolling«Synchro durchgeführt wird; zusätzlich sollte hierzu – ebenfalls in der imapd.conf – die sync_log: 1 Direktive aktiviert werden. Hierdurch können die imapd, pop3d, nntpd, und lmtpd-Dienste ihre synchronisationsrelevanten Aktionen loggen, die wiederum periodisch vom sync_client auf den Slave gepusht werden. Nun zum Test: Wir starten unseren Cyrus-IMAP auf Master und Slave neu und beobachten die Log-Ausgaben des Cyrus-Slaves unter /var/log/messages. Auf dem Master rufen wir das Kommando: #> /usr/lib/cyrus/bin/sync_client -vloC /etc/imapd.conf -u ckent
das im Single-Shot-Modus die Mailbox des Users ckent auf den Slave pusht: USER ckent ADDSUB ckent INBOX.Sent ADDSUB ckent INBOX.Trash
Auf dem Slave sollten wir in etwa folgende (gekürzte) Log-Ausgabe sehen: ldapslave master[8176]: about to exec /usr/lib/cyrus/bin/sync_server ... ldapslave syncserver[8176]: cmdloop(): startup ldapslave slapd[4998]: conn=1508 fd=18 ACCEPT from IP=192.168.198.12:43570 (IP=0.0.0.0:389) ldapslave slapd[4998]: conn=1508 op=0 STARTTLS ldapslave slapd[4998]: conn=1508 fd=18 TLS established tls_ssf=256 ssf=256 ldapslave slapd[4998]: conn=1508 op=2 SRCH base="dc=local,dc=site" scope=2 deref=0 filter="(&(objectClass=posixAccount)(uid=cyrus))" ... ldapslave syncserver[8176]: login: ldapmaster.local.site [192.168.198.11] cyrus DIGEST-MD5 User logged in
480
1198.book Seite 481 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Anschließend sollte die Mailbox des Users ckent auf dem Cyrus-Slave synchronisiert sein. Zickt PAM allerdings herum, und es treten authentifizierungsspezifische Fehler auf, können wir das Setup alternativ auch auf die bereits vorgestellte saslauthd -> ldap-Variante umstellen. Hierzu legen wir (nur auf dem Slave) eine entsprechende /etc/saslauthd.conf an, transferieren den User cyrus mit identischer uid, gid und Passwort in unseren DIT und stellen die SASL-Authentifizierung (auf dem Slave) von PAM auf ldap um (bei SUSE: /etc/sysconfig/saslauthd). Anschließend sollte die Authentifizierung problemlos arbeiten: ldapslave syncserver[11435]: login: ldapmaster.local.site [192.168.198.11] cyrus LOGIN+TLS User logged in
Wie eingangs erwähnt, handelt es sich hier natürlich nur um einen kurzen Anriss und Einstieg ins Thema; weiterführende Informationen liefern http://cyrusimap.web.cmu.edu/imapd/install-replication.html sowie die im Paket enthaltene Dokumentation replication_examples und replication_protocol. Weitere Infos zu den verfügbaren Direktiven bieten auch die Manpages von imapd.conf(5) und cyrus.conf(5). Kleine Tierkunde: Das fleißige Eichhörnchen Um über ein Web-Frontend auf den Cyrus-IMAP (und viele andere IMAP-Server) zuzugreifen, bietet sich auch die Verwendung des Pakets squirrelmail an (www.squirrelmail.org). Das Paket ist Bestandteil der meisten Distributionen, leider oft nicht in der aktuellsten Version. Die Installation ist sehr simpel, das Setup erfolgt über ein geführtes Konfigurationsskript. Zum Betrieb des fleißigen Eichhörnchens wird ein Webserver benötigt, der mit PHP umgehen kann. Und was liegt da näher als der freundliche Indianer von nebenan.
4.6
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Es war damals eine wirklich harte Zeit … Wir hatten nichts. Nicht mal Bandbreite.
4.6.1
Apache und OpenLDAP
Der erste Webbrowser, den die Autoren 1993 zu Gesicht bekamen, hieß Spry Mosaic und war von einem Studenten der Uni Stanford geschrieben worden: dem späteren Netscape-Begründer Marc Andreesen. Den kennen wir ja schon
481
4.6
1198.book Seite 482 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
aus dem Intro. Zu diesem frühen Browser mit seiner sich wichtig drehenden Erdkugel im Fenster rechts oben gehörte selbstverständlich auch ein Webserver, denn die Existenz von Client-Software ist ja schließlich kein Selbstzweck. Zusammen mit den von Sir Berner-Lee entwickelten Formaten http und HTML stellten sie das Rüstzeug für das »frühe« Web dar. Das Internet an sich war zu diesem Zeitpunkt schon biblische 15 Jahre alt und an den Universitäten der Welt ein wichtiges Informationsmedium – besonders E-Mail und die so genannten Usergroups, in denen alle wichtigen Debatten jener Zeit stattfanden: »Ist Arnold Schwarzenegger ein Alien oder doch ein Gen-Experiment? War Luke Skywalker wirklich der uneheliche Sohn von Yoda’s Cousine und Chewbacca? Hatte Sharon Stone ihren MTV-Movie-Award für Basic Instinct tatsächlich den Lobbyisten der Pelzindustrie zu verdanken?« Es war eine liebe Zeit, aber dann kam das Web und dann kamen all diese Menschen ins Web, und ehe man sich’s versah, war das Postfach voller Spam. Was wollten wir noch erklären? Ach ja, der Webserver. Der hieß NCSA httpd (National Center for Supercomputing Applications hyper text transfer protocol daemon – wobei daemon für Disk and Environment Monitor steht). Nein, wir werden das nicht kommentieren. Der hieß eben so, basta. Der NCSA-Server erwies sich schnell als Heimsuchung, die überstürzt in einem Prä-Prä-Alpha-Stadium publiziert worden war, weil – siehe den Anleser zu diesem Abschnitt: Es gab ja nix anderes. Während Marc Andreesen vorzog, Netscape zu gründen und seinen eigenen Server zu entwickeln, produzierte die Entwicklercrew des NCSA-Projekts fleißig immer neue Patches für immer neue Teillösungen und Sicherheitslecks. Endlich kam jemand aus dem Team auf die einzig rettende Idee, dieses Ding, das so unrund lief wie ein V8 auf fünf Töpfen, zu entsorgen und aus den unzähligen Patches ein völlig neues System zu generieren. So geschah es dann, und siehe … das Produkt bekam – ob seiner windigen und geflickten Herkunft den Namen »a-patch-e« Webserver. Also anders gesagt: der Apache Webserver, seit Langem einer der populärsten Webserver weltweit. Gerüchte ob des Zusammenhangs der Namensfindung mit dem Respekt vor einer amerikanischen Volksgruppe sind allesamt jüngeren Datums und wohl eher romantisch geprägt. Apache ist seit über 2 Jahren bei der Version 2.2 angelangt und aufgrund seiner Vielseitigkeit und feinen Skalierbarkeit der Spitzenreiter unter den Webservern, auch wenn er derzeit mit einem aktuellen Marktanteil von etwa 50 Prozent deutlich unter seinem Höchststand von 70 Prozent im November 2005 liegt. Die IISKonkurrenz aus Redmond folgt derzeit auf Platz 2 mit etwa 35 Prozent. Den Apa-
482
1198.book Seite 483 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
che-Einbruch führen die Statistiker auf mehrere Ursachen zurück. Zum einen war Apache in den vergangenen Jahren der mit Abstand am weitesten verbreitete Webserver im Netz und somit logischerweise primäres Angriffsziel für Attacken. Zum anderen wurden laut Studien in vielen Installationen – ob auf firmeneigenen Webservern, gemieteten Root-Servern von Providern oder auf privaten Installation – viel zu oft viel zu lasche Passwörter verwendet, die entsprechend leicht gehackt werden konnten. Ein gewaltiges Problem, insbesondere, wenn man einen Bereich des typischen Webserver-Einsatzes betrachtet: das Bereitstellen geschützter Bereiche für authentifizierte User. Ein Bereich, den wir daher gleich in Verbindung mit unserem LDAP sehr genau unter die Lupe nehmen werden. Mit dem verstärkten Aufkommen der Webserver verspürten auch Geschäftsleute aus allen Bereichen den starken Drang, ihre Services über das Internet anzubieten; je nach Legalitätsgrad der jeweiligen Branche mit einem erstaunlichen Grad an Sicherheitsvorkehrungen auf der Serverseite (wobei einige legale Anbieter bisweilen auch heute noch einigen ihrer eher zwielichtigen Mitstreiter hinterherhinken, was die reine Einbruchssicherheit der eingesetzten Serversysteme angeht). Jedenfalls kam mit den Geschäften per Web das Verlangen nach gesicherten Bereichen, in die nur die User eintreten dürfen, die sich erfolgreich authentifizieren können. Der erste Schritt in diese Richtung war die Authentifizierung über die Apache-spezifische Datei .htaccess, die allerdings ohne Kombination mit LDAP – mal wieder – einer separaten Datenbank für Benutzerkonten und Passwörter bedarf. Für den unbe-ldap-ten Admin also dezentrale Baustelle Nummer neunhundertneunzig. Zudem eine eher unsichere Methode, da die Konten mitsamt Passwörtern in Klartextdateien abgelegt werden. Nach allerlei Selbstversuchen der Webgemeinde entstand schließlich und endlich das Modul mod_auth_ldap (aus dem in der aktuellen Version mod_auhtnz_ldap wurde), mit dem die sichere Überprüfung der Client-Identität via LDAP möglich wurde. Im Übrigen – die Kürzel n und z in den neuen Modulnamen lassen sich recht einfach herleiten: Alle Module mit einem zusätzlichen n am Ende ihres Namens haben in irgendeiner Form mit Authentification zu tun, alle z-Module mit Authorization. Module wie authnz_ldap kümmern sich folglich um beides. Im Folgenden werden wir die Module in der Regel bei ihrem üblichen Kurznamen (ohne führendes mod_) nennen.
483
4.6
1198.book Seite 484 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Wir werden uns in diesem Abschnitt mit Apache in der aktuellen Version 2.2 beschäftigen. Zunächst erst einmal eine kurze, stark gekürzte und vereinfachte Liste der grundlegendsten Veränderungen zwischen Apache 2.0 und 2.2: 왘 Eine ganze Reihe authentifikationsrelevanter Module wurden zum Teil drastisch überarbeitet bzw. komplett neu erstellt, so auch die LDAP-relevanten Module, die etliche neue Features und Filter besitzen. 왘 Es wurden neue Caching-Module hinzugefügt. 왘 Per mod_proxy* lassen sich mehrere Apache- in Load-Balancing-Szenarien relativ einfach aufsetzen. 왘 Über mod_filter lassen sich Ausgabefilter definieren. 왘 mod_ssl unterstützt endlich TLS. Ausführliche Infos über alle Änderungen finden sich auf der Apache-Homepage, z.B. unter http://httpd.apache.org/docs/2.2/new_features_2_2.html. Leider hat sich ein wichtiger Punkt seit Version 2.0 nicht geändert: Die Konfiguration von Apache 2.2 ist noch immer dezentralisiert. Die vormals überragend klar strukturierte httpd.conf spielt weiterhin nur eine Statistenrolle als Verteiler von Include-Verweisen auf eine mittlerweile horrende Anzahl untergeordneter Konfigurationsdateien. Leider. Denn auch wenn das Include-Konzept mit Sicherheit in bestimmten Bereichen absolut Sinn ergibt (wie z.B. separate Konfigs für vhost-, dav- oder mpm-spezifische Settings, wie sie auch in der Sourcen zu finden sind), ist es wirklich nötig und vor allem sinnvoll, für jede noch so kleine Mickymaus-Direktive eine eigene Include zu kreieren? Unter der Distributoren-Prämisse, jede noch so kleine Änderung über ihre Konfigurations-Frontends wie z.B. YaST erschlagen zu können, anscheinend schon. Aus rein logischer Sicht mit Sicherheit nicht, und so wird sich uns wohl auch zukünftig der Sinn einer listen.conf oder gar uid.conf eher nicht erschließen. Der Admin, der keine Lust mehr auf solche distributionsspezifischen Spielereien hat, sollte zu den Sourcen greifen und sich Apache per Hand kompilieren. Die Settings hierzu finden sich im Anhang. Apropos Kompilierung: Apache bietet bei der Kompilierung natürlich auch die Möglichkeit, Module statisch mit einzukompilieren. Eingebürgert hat sich allerdings die deutlich flexiblere Variante, bei der die Module separat kompiliert und beim Start des Apache je nach Anforderungsfall selektiv geladen werden. Wir erläutern hier nur kurz die entsprechenden Vorgehensweisen zur ModulEinbindung für Debian und SUSE. Im Anschluss daran behandeln wir die »reguläre« Standalone-Variante.
484
1198.book Seite 485 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Unser Ziel: Wir setzen einen SSL-gesicherten Webserver auf, auf dessen geschützten Bereich wir OpenLDAP-authentifiziert zugreifen. Nicht nur die Kommunikation zwischen Browser und Webserver erfolgt hierbei (SSL-)verschlüsselt, sondern auch die Kommunikation zwischen Apache und OpenLDAP während des Authentifizierungsvorgangs, und zwar per TLS. Setup Bei Debian können z.B. einfach die *.load-Dateien mit der entsprechenden Funktionalität von /etc/apache2/mods-available/ in den /etc/apache2/mods-enabledOrdner kopiert oder verlinkt werden. Das wären in unserem Fall die Dateien ssl.load und auth_ldap.load. Beim nächsten Restart des Apache wird dieser Ordner geparst, und so werden die Module entsprechend den LoadModule-Direktiven in den ausgewählten *.load-Dateien geladen. Im Falle von SSL muss bei Debian noch die ssl.conf-Datei aus dem Ordner mods-avilable hinzugefügt werden. Bei SUSE kann die Konfiguration z.B. per /etc/sysconfig/apache2 erfolgen. Dort müssen die Zeilen APACHE_MODULES und APACHE_SERVER_FLAGS um die LDAP- und SSL-Module angepasst werden. Wie schon bei den Versionsunterschieden angemerkt, hat sich gerade im Bereich der authentifizierungs-relevanten Module einiges getan. Statt des ehemals in Version 2.0 eingesetzten Moduls auth_ldap wird nun authnz_ldap verwendet, das neben der Möglichkeit einer TLS-verschlüsselten Kommunikation erheblich mehr Flexibilität im Bereich der LDAP-Filter mitbringt. Details hierzu liefert http://httpd.apache.org/docs/2.2/mod/mod_authnz_ldap.html Das ldap-Modul ist dabei für die Performance zuständig, da es Daten aus dem DIT für schnelleren Zugriff cached. (Dieses Modul wird bei Debian über die auth_ldap.load-Datei mitgeladen.) Der Einsatz des SSL-Moduls erlaubt es, in Verbindung mit den Zertifikaten eine einseitig (serverseitig) verschlüsselte Verbindung zwischen Client (Browser) und Applikation (Apache) aufzubauen, wie wir es alle von den stets vertrauenswürdigen Online-Portalen unserer favorisierten Hausbanken her kennen. Die Apache_Server_Flags-Direktive macht nichts anderes, als den httpd auf der Kommandozeile mit den entsprechenden Schaltern (Kommandozeilenparameter: -D) zu starten, um die jeweiligen Module zu aktivieren: APACHE_MODULES="...ldap authnz_ldap ssl..." APACHE_SERVER_FLAGS="SSL LDAP"
Nach der Anpassung muss Apache neu gestartet werden, damit die Änderungen wirksam und die entsprechenden Settings in den jeweiligen Includes gesetzt werden.
485
4.6
1198.book Seite 486 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Deutlich transparenter gestaltet sich die manuelle Methode, bei der die gewünschten Module einfach beim Start des httpd auf der Kommandozeile bzw. per Startskript mit angegeben werden. Zuvor sollte geprüft werden, ob die entsprechenden Module im Ordner /usr/lib/apache2<-(mpm-Name)>/ (oder dem bei der Installation gewählten Modulpfad) vorhanden sind: mod_ldap.so, mod_ authnz_ldap.so und mod_ssl.so. Ihre Einbindung erfolgt über die httpd.conf (Source) oder die entsprechende distributionsspezifische Include-Datei. Bei SUSE wäre das z.B. die Datei /etc/apache2/sysconfig.d/loadmodule.conf. Aber Achtung, hier ist Vorsicht angesagt. Eine manuelle Änderung der Datei wird beim nächsten Restart des Apache von den in /etc/sysconfig/apache2 getroffenen Konfigurationseinstellungen wieder überschrieben. Hier die Direktiven zum Laden der jeweiligen Apache-Module: LoadModule ssl_module /<Modulpfad>/mod_ssl.so LoadModule ldap_module /<Modulpfad>/mod_ldap.so LoadModule authnz_ldap_module /<Modulpfad>/mod_authnz_ldap.so
Zusätzlich kann es erforderlich sein, dass wir noch explizit die Listen-Direktive für Port 443 in der entsprechenden Konfigurationsdatei setzen müssen. Die Befehlszeile zum Starten des Apache könnte (je nach verwendeter Binary oder Startskript) z.B. so oder ähnlich aussehen: #> /usr/sbin/apache2 -f /etc/apache2/httpd.conf \ –D LDAP –D SSL
Wichtig hierbei sind vor allem die -D-Flags, mit denen die zu ladenden Module angegeben werden. Der Parameter -f verweist dabei auf die zentrale Konfigurationsdatei. Bevor Apache jedoch mit aktiviertem SSL-Modul gestartet werden kann, benötigt er natürlich noch Verweise auf die entsprechenden Zertifikatspfade. Wir verwenden auch in diesem Fall der Einfachheit halber die bereits für unseren ldapmaster generierten Zertifikate, die wir in den Ordner /etc/apache2/ certs kopieren. Im ersten Schritt setzen wir einen virtuellen, SSL-verschlüsselten Host auf, in dem sich unser Web-Content befindet. Okay, genau genommen besteht unser »Web-Content« nur aus einem bereits vorhandenen Systemordner, was jedoch für unsere Zwecke allemal ausreichend ist. Dreh- und Ansatzpunkt sind dabei primär zwei Dateien: 왘 eine vhost(-ssl).conf-Datei, die unseren SSL-verschlüsselten VirtualHost kreiert 왘 eine .htaccess-Datei, in der wir die LDAP- und authentifizierungs-relevanten Settings vornehmen
486
1198.book Seite 487 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Der Reihe nach: Zunächst kümmern wir uns um das zentrale Setup eines SSL-verschlüsselten vhosts, der auf den Systemordner /etc zeigt. Hierfür verwenden wir folgende Konfiguration, die aus der vhost-ssl.template-Datei einer OSS11 abgeleitet ist: # vhost-ssl-etc.conf # alternativ : DocumentRoot "/etc" ErrorLog /var/log/apache2/ssl-error_log TransferLog /var/log/apache2/ssl-access_log SSLEngine on SSLCipherSuite ALL:!ADH:!EXPORT56:RC4 ... <snip> ... :+eNULL SSLCertificateFile /etc/apache2/certs/newcert.pem SSLCertificateKeyFile /etc/apache2/certs/ldapkey.pem SSLCACertificateFile /etc/apache2/certs/cacert.pem CustomLog /var/log/apache2/ssl_request_log ssl_combined Options Indexes FollowSymlinks AllowOverride All Order allow,deny allow from all
Gegebenenfalls müssen wir per Include-Statement noch dafür sorgen, dass die neu erstellte vhost-Konfigurationsdatei (die Datei findet sich auch in den Beispieldaten zu diesem Abschnitt: http://www.galileocomputing.de/1801) beim (Re-)Start des Apache automatisch mit eingebunden wird, z.B. per Include /etc/apache2/vhosts.d/*.conf
in der httpd.conf (Default bei SUSE, Pfade gegebenenfalls anpassen). Nun noch kurz zu den allerwichtigsten vhost-Settings. Leider können wir aufgrund der Komplexität des Apache Webservers an dieser Stelle kaum eine unfassende Apache-Konfiguration erläutern. Wer mehr zu dem Thema wissen möchte: Apache bietet eines der besten Online-Manuals, das nahezu jede Direktive und Konfigurationseinstellung übersichtlich und umfangreich erläutert.
487
4.6
1198.book Seite 488 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Als DocumentRoot für unser Testsystem haben wir den Systemordner /etc gewählt, weil wir so aufgrund der vorhandenen Datenstruktur sehr einfach einen hierarchisch gestaffelten Zugriff auf geschützte Inhalte demonstrieren können. Im Produktivumfeld ist von einer Freigabe von echten Systemordnern wie /etc (selbst wenn zugriffsgeschützt) eher abzusehen. Was ebenfalls nicht vergessen werden sollte: Bei der Verwendung von mehreren SSLgeschützten vhosts muss für jeden virtuellen SSLHost eine separate IP existieren, über die er angesprochen werden kann, denn der Einsatz von namensbasierten vhosts ist in diesem Fall nicht möglich! Warum? Ganz einfach: das typische Henne/Ei-Problem, oder, noch besser, Catch 22: Bei einem Apache mit mehreren namensbasierten vhosts (eine IP, auf der mehrere unverschlüsselte(!) vhosts arbeiten) kümmert sich die Applikation (Apache) intern anhand des im Client-Header (Browser) angefragten Namens (URL) um die Zuordnung zu dem entsprechenden vhost. Bei einer SSL-verschlüsselten Sitzung geht der eigentliche Host-Request mit der URL erst nach dem geglückten Handshake (und somit nach der Zuordnung zur IP) über die Leitung. Dumm gelaufen.
In unserem Fall jedoch kein Widerspruch, da wir zwar zwei »Hosts« auf einer IP laufen haben, doch nur einer von beiden SSL-verschlüsselt arbeitet. Regulär würden wir natürlich jedem SSL-vhost eine separate IP zuordnen, was sich selbst mit nur einem »echten« Netzwerkinterface – mit Hilfe virtueller IP-Adressen auf demselben Interface – schnell realisieren lässt. Für performance-relevante Anwendungen sollte jedoch aus obligatorischen Gründen stets einem echten Interface der Vorzug gegeben werden, um kein Bottleneck zu erzeugen. Weiter im Text: Die SSL[CA]Certificate*-Direktiven kümmern sich in bekannter Weise um die Einbindung der applikationsspezifischen Zertifikate, im Directory-Tag werden – vereinfacht ausgedrückt – bestimmte Optionen und Direktiven für den Zugriff auf den physikalischen Ordner /etc (unser DocumentRoot in diesem Fall) gesetzt. Die Direktiven innerhalb des -Containers sorgen im Detail dafür, dass wir die im Verzeichnis vorhandenen Dateien vernünftig angezeigt bekommen (Options Indexes), nachdem uns das Modul authz_hosts per Allow-Direktive den hostbasierten Zugriff auf das Verzeichnis gewährt hat. Der Kernpunkt dabei ist jedoch die Direktive AllowOverride. Sie sorgt dafür, dass unterhalb vom DocumentRoot, also /etc, überhaupt erst nach einer Datei .htaccess gesucht wird, deren Direktiven in unserem Fall vollständig (All) beim Zugriff auf dieses Verzeichnis interpretiert werden. Die .htaccess kommt jedoch erst später ins Spiel, zunächst müssen wir uns darum kümmern, dass unser SSL-verschlüsselter vhost sauber startet.
488
1198.book Seite 489 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Fire it up! Nun können wir unseren Indianer dank der neuen SSL-spezifischen Settings auf die verschlüsselte Pirsch schicken. Nach dem (Neu-)Start von Apache sollte uns nmap in jedem Fall den avisierten Port 443 zeigen. Falls nicht, zunächst etwaige Fehlermeldungen beim Start des Apache genau prüfen, alle Konfigurationsdateien auf Typos prüfen und in jedem Fall einen Blick in Errorlogs werfen. SSLspezifische Fehlermeldungen werden in unserem Beispiel in die Log-Datei unter /var/log/apache2/ssl-error_log geschrieben. Wichtig in der oben beschriebenen Konfiguration sind vor allem die korrekten Verweise auf die Zertifikate: die CA (cacert.pem), das Serverzertifikat (newcert.pem) sowie das Keyfile (ldapkey.pem) und natürlich die korrekt erstellten Zertifikate selbst. Bisher haben wir also »nur« dafür gesorgt, dass der Apache seinen SSL-Modus anbietet. Das heißt, er nimmt nun HTTP-Requests auf Port 443 (https) entgegen. Steht der Port laut nmap korrekt zur Verfügung, sollte beim Aufruf des Apache per https (z.B. https://) zunächst die Zertifikatsmeldung im Browser erscheinen, die in neueren Firefox-Versionen (3.x) etwas deutlicher ausfällt, was selbstsignierte Zertifikate angeht. In Anbetracht des Debian-Zertifikats-Desasters vor einigen Monaten mit Sicherheit nicht das schlechteste:
Abbildung 4.17 Zertifikatswarnung im Firefox 3.x beim Aufbau der SSL-verschlüsselten Verbindung zu unserem Apache
Nachdem wir eine temporäre Ausnahme für unser selbstsigniertes Zertifikat hinzugefügt haben, sollte uns der Apache-vhost das Systemverzeichnis /etc präsentieren, und in der unteren rechten Ecke des Browsers sollte das typische SchlossSymbol für SSL-Verbindungen zu finden sein.
489
4.6
1198.book Seite 490 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Dadurch haben wir in jedem Fall schon einmal erreicht, dass der User-Name und das zugehörige Passwort, das wir später im Zuge der Authentifizierung vom Browser an den Server schicken, durch den SSL-Tunnel geschützt werden. Darum, dass Apache bei der Kommunikation mit unserem OpenLDAP auch nicht mehr belauscht werden kann, kümmern wir uns gleich per TLS. Im nächsten Schritt geht es darum, den Apache-Türsteher zu aktivieren, um selektiven Zugriff auf die Inhalte zu erlangen. Die virtuelle Steroid-Bombe, die sich vor dem Eingang des SSL-vhosts mächtig breit macht und nur darauf wartet, ungebetene Gäste wieder rauszukicken, hört auf den Namen .htaccess. Ihr Boss, AllowOverride, hat ihr schließlich per All alle Vollmachten für den Job gegeben, also lassen wir unseren Türsteher vor dem Wigwam von der Leine. Sämtliche nachfolgenden Konfigurationsdirektiven können natürlich auch direkt in der jeweiligen *.conf-Datei des Servers oder vhosts verankert werden. Allerdings wäre bei dieser Konfiguration nach jeder Änderung an den Direktiven ein Restart bzw. Reload des Apache nötig. Für Web-Portale mit wenig Änderungen an den (authentifizierungsspezifischen) Einstellungen und vielen Authentifizierungszugriffen wäre dieses Setup performancetechnisch in jedem Fall vorzuziehen, da sonst bei jedem Zugriff auf den Ordner die .htaccess geparst wird. Für unsere Testzwecke und kleine Sites mit wenig Zugriffen eignet sich die .htaccess jedoch hervorragend. Ein weiterer Kompromiss könnte darin bestehen, nur alle authentifizierungsrelevanten Settings einer .htaccess zu parsen; das könnten wir im Directory-Container des vhosts per AllowOverride AuthConfig einstellen. Restricted Area Betrachten wir zunächst die grundsätzliche Funktionsweise: In unserem einfachen Beispiel legen wir eine .htaccess-Datei unterhalb von /etc mit folgendem Inhalt an, die uns Zugriff auf die Inhalte von /etc nach erfolgreicher Authentifizierung gegen unseren LDAP ermöglicht. (Die Nummerierung dient nur der Erläuterung und ist nicht Bestandteil des Dateiinhalts.) # /etc/.htaccess 1: AuthType Basic 2: AuthzLDAPAuthoritative off 3: AuthBasicProvider ldap 4: AuthName "Zugriff auf Systemordner /etc" 5: AuthLDAPURL ldap://ldapmaster.local.site/dc=local,dc=site 6: require valid-user
490
1198.book Seite 491 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Zu den Direktiven 1. AuthType gibt das zu verwendende Client-Authentifizierungsverfahren an. Hier wird als Apache-Standard in Verbindung mit OpenLDAP der Typ Basic ausgewählt, bei dem das Base64-codierte Passwort im Klartext über das Netz geht. Wer schon einmal ein Base64 »gecryptetes« Passwort per tcpdump mitgesnifft und anschließend mit einem einfachen perl-Befehl per decode_Base64 in Klartext umgewandelt hat, weiß, dass Base64 so einfach zu knacken ist wie die Handschellen in jedem US-Spielfilm. Die andere, sicherere Variante wäre Digest, weil Username und Passwort pro Session mit einer Art One-Time-Key verschlüsselt werden (den MD5-Hash dazu liefert der Server einmalig pro Session). Auf der Serverseite muss dazu mod_auth_digest aktiviert werden, das eine separate Passwortdatenbank benutzt (siehe hierzu auch htdigest2(8)). Leider funktioniert der Authentifizierungstyp Digest definitiv nicht in Verbindung mit LDAP. Der Grund dafür – stark vereinfacht und abstrahiert: Unser LDAP-Server kann nur auf eine Anfrage der Form »Ist das übermittelte Passwort ‚linux‘ für User ckent korrekt?« antworten, wird aber niemals das Passwort von ckent selbst herausgeben. Da Digest wiederum kein Passwort zum Server sendet, hat Apache (in Verbindung mit Digest) kein Passwort, das es mit dem im LDAP gespeicherten vergleichen kann. Also bleibt unter dem Strich nur Basic übrig. Beide in RFC2617 spezifizierten Varianten (Basic und Digest) sind anfällig für Man-in-the-Middle-Attacken, daher sollte die Passwort-Übermittlung immer über eine SSL-gesicherte Verbindung erfolgen. 2. AuthzLDAPAuthoritative off ist eine Direktive des neuen Moduls authnz_ ldap und regelt, ob andere Authentifikationsmodule im Falle eines Fehlschlags der Authentifizierung versuchen sollen, den User zu authentifizieren. Sollte in Verbindung mit require user|group unbedingt auf OFF stehen, bei allen LDAP-relevanten require-Direktiven (ldap-user | ldap-group | ldap-*... siehe unten) auf ON. 3. Die Direktive AuthBasicProvider ldap des Moduls auth_basic legt fest, welcher »Provider« für die Authentifikation verwendet werden soll, in unserem Fall natürlich ldap. Die File-basierte und dezentrale Alternative würde bei Verwendung einer per htpasswd2 generierten Passwort-Datei dementsprechend file lauten. 4. AuthName gibt den String an, der bei der Authentifizierungsabfrage (Username/Passwort) im Browserfenster erscheint. 5. AuthLDAPURL erwartet genau das, was die Direktive aussagt, und zwar eine RFC 2255-konforme (»The LDAP URL Format«) LDAP-URL. Über die URL wird zunächst der LDAP-Server angegeben; optional ist die Angabe des Ports. Bei
491
4.6
1198.book Seite 492 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
SSL kann wie gewohnt ldaps://... oder :636 (Port) angegeben werden. Danach folgt die BaseDN bzw. Searchbase, ab der die Suche ausgeführt wird, in unserem Fall dc=local,dc=site. Dazu können noch einige Parameter angegeben werden wie Attribute, Scope und Searchfilter, die wir in den nächsten Beispielen erläutern. Ohne Angabe eines Scopes wird sub als Default angenommen, also in unserem Fall also der komplette DIT. 6. Der require-Parameter bietet zahlreiche Einstellungsmöglichkeiten, von denen wir einige im Folgenden noch erläutern werden. Im einfachsten Fall (in Verbindung mit valid-user und der unter Punkt 5 verwendeten LDAP-URL) erlaubt er zunächst jedem User aus dem DIT, der sich authentifizieren kann, den Zugriff. Ebenfalls möglich wäre die explizite Angabe von User-Namen, per Leerzeichen separiert, z.B.: require user ckent skiu Weitere ldap-spezifische Varianten wären require in Verbindung mit ldap-dn , ldap-group , ldap-attribute oder auch ldap-filter . Hierbei ist darauf zu achten, dass die Direktive AuthzLDAPAuthoritative auf ON gestellt sein sollte.
Betrachten wir im Folgenden kurz noch ein paar Beispiele für require in Verbindung mit ldap-* spezifischen Direktiven: require ldap-user ckent
Bezieht sich auf das zurückgegebene Attribut der LDAP-URL, Default also uid. require ldap-dn uid=ckent,ou=verkauf,dc=local,dc=site
Hier wird der komplette DN angegeben, um Fehler bei identischen uid’s im DIT zu vermeiden; in der Anmeldebox wird jedoch nur das zurückgegebene Attribut der LDAP-URL benötigt (Default : uid). require ldap-attribute title=admin
Wertet den Inhalt einzelner Attribute (hier: title) auf Übereinstimmung aus. require ldap-filter &(title=admin)(uidNumber=911)
Wertet in einer UND-bezogenen Filter-Verknüpfung (hier: title UND uidNumber) den Inhalt mehrerer Attribute auf Übereinstimmung aus. In den Logs unseres slapd läßt sich hervorragend erkennen, wie Letzterer den Suchfilter auswertet: slapd[19557]: conn=58 op=8 SRCH base="dc=local,dc=site" scope=2 deref=3 filter="(&(&(title=admin)(uidNumber=911))(uid=rdeckard))"
Wir sehen also: Uns stehen in Verbindung mit LDAP-URL und den require-Filtern jede Menge Varianten zur Verfügung, um den Zugriff auf bestimmte Bereiche entsprechend unserer Bedürfnisse anzupassen. Ein paar Beispiele hierzu, ins-
492
1198.book Seite 493 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
besondere was die Auswertung von Gruppen angeht, schauen wir uns im Folgenden noch an. Optional können auch noch die Direktiven AuthLDAPBindDN und AuthLDAPBindPassword angegeben werden, falls keine anonyme Bindung gewünscht oder gefordert ist. Nach Erstellung der Datei kann der Zugriff direkt getestet werden, da die .htaccess-Datei ja bei jedem Zugriff geparst wird. Es sollte das folgende Authentifizierungsfenster (hier im Firefox) erscheinen:
Abbildung 4.18
Benutzerauthentifizierung mit Apache und LDAP
Nach geglückter Authentifizierung sollten wir den Inhalt von /etc sehen, andernfalls auf jeden Fall einen Blick in /var/log/apache2/ssl-error_log und gegebenenfalls die Log-Ausgabe unseres LDAP werfen. Allerdings bieten nicht nur die require-Direktiven die Möglichkeit einer Restriktion auf bestimmte User oder Gruppen. Wir können auch schon mit unserer LDAP-URL relativ einfach prä-selektieren. Die folgende Beispiel-URL (wir beschreiben im Folgenden immer nur den Teil hinter AuthLDAPURL ldap://ldapmaster.local.site/ ) ou=forschung,dc=local,dc=site?cn?one?(objectClass=inetOrgPerson)
würde z.B. von vornherein nur den User-Accounts aus der Unit forschung (und nicht denen aus der darunter liegenden Sub-Unit »xeno«) Zugriff gewähren, die zur Objektklasse inetOrgPerson gehören. Achtung: In dem oben genannten Beispiel würde cn als Attribut zur Authentifizierung ausgewertet und müsste daher auch als Benutzer-/Login-Name angegeben werden. Wird in der URL kein Attribut (hier: cn) angegeben, wird automatisch uid verwendet.
Um den Zugriff schon vorab auf eine oder mehrere bestimmte uid einzuschränken, steht uns ebenfalls eine bereits bekannte Möglichkeit zur Verfügung: per URL-Filter (Zeile ist umbrochen).
493
4.6
1198.book Seite 494 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
ou=forschung,dc=local,dc=site?cn?sub?(&(objectClass= inetOrgPerson)(uid=eripley))
In dem Zusammenhang noch ein praktisches Fehlerbeispiel: In einer sehr ähnlichen Konfiguration (uid statt cn): ou=forschung,dc=local,dc=site?uid?sub?(&(objectClass= inetOrgPerson)(uid=eripley))
würde es unweigerlich zu einem Fehler kommen, egal, ob wir require ldapuser oder valid-user verwenden. Warum? Ganz einfach. Die uid (der RDN und damit Accountname) dieses User-Objekts existiert ja gemäß den bisher verwendeten Beispielen mehrfach: In verschiedenen Ebenen des DIT (wenn auch mit unterschiedlichen Attributen), und in diesem Subtree (forschung) sogar zwei Mal. Ergo ist unsere fulminante Ellen Ripley damit – zumindest vom Attribut uid her – nicht eindeutig, wenn der Scope sub ist. Die Fehlermeldung im entsprechenden Log des Apache könnte dann so aussehen: auth_ldap authenticate: user eripley authentication failed; URI / [User is not unique (search found two or more matches)]
Das lässt sich zwar durch Auswertung anderer Attribute kompensieren (cn, description, mail, title) oder durch die Verwendung der require ldap-dn Direktive ausschließen – ist aber, wie wir bereits aus dem Abschnitt 2.3, »Fingerübungen«, wissen, nicht »die feine englische Art«. Eleganter ist es immer, das UserObjekt einer Gruppe zuzuweisen (oder dynamisch per dynlist zuweisen zu lassen), die mit bestimmten Berechtigungen verknüpft ist. Dazu gleich mehr. Wie wir uns vorstellen können, sind über LDAP-URLs und require-Direktiven nahezu alle denkbaren Kombinationen möglich. Wir verweisen daher noch einmal auf die RFC 2255 und die vorbildliche Online-Dokumentation des Apache (httpd.apache.org/docs/2.2/), die auch Bestandteil des Paketes ist. Bei SUSE und Debian muss sie allerdings als separates Paket nachinstalliert werden (siehe Paketlisting, Anhang A, Sektion Apache/Squid). Im vorletzten Beispiel dieses Abschnitts werden wir uns noch eine interessante Konfigurationsmöglichkeit anschauen. Es wird also mal wieder Zeit für eine … Stammes-Gruppentherapie Natürlich geht es uns darum, wie wir auf möglichst elegante Weise User in bestimmten Gruppen bündeln und diese dann mit bestimmten Zugriffsrechten für die geschützten Bereiche unseres Webservers ausstatten. Für eine schnelle Gruppentherapie mit Apache und LDAP benötigen wir die folgenden Direktiven in der .htaccess, die wir an die bereits vorhandenen anfügen:
494
1198.book Seite 495 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
AuthLDAPGroupAttribute member AuthLDAPGroupAttributeIsDN On require ldap-user ckent rdeckard jmcclane skiu require ldap-group cn=superuser,dc=local,dc=site
Die AuthLDAPGroupAttribute-Direktive definiert das Attribut, über welches das Gruppenmitglied ausgewertet werden soll, in diesem Fall also das member-Attribut der Objektklasse groupOfNames. Alternativ wäre auch die Verwendung einer posixGroup möglich; hierzu müsste das AuthLDAPGroupAttribute auf memberUID gesetzt werden. Mit AuthLDAPGroupAttributeIsDN wird per Schalter definiert, ob nur das Attribut oder der ganze DN ausgewertet werden soll – für posixGroups definitiv auf Off zu setzen. In unserem Fall setzen wir es auf On, da ja das member-Attribut unserer Gruppe cn=superuser (Objektklasse groupOfNames) als kompletter DN angegeben ist. Die -Container definieren den Dateityp (Endung .conf), auf den die in der require ldap-group-Direktive angegebene Gruppe Zugriff erhalten soll. Die Gruppe selbst wird mit dem kompletten DN angegeben. Et voilà: Auf diese Art und Weise erhalten wir einen hierarchischen, selektiven Zugriff. Die User, die nicht zur Gruppe superuser (jmcclane, rdeckard) gehören, sehen nun keine .conf-Dateien mehr. ... und was ist eigentlich mit dynamischen Gruppen? Wer sich an dieser Stelle fragen sollte, wie es denn mit dynamisch generierten Gruppen à la dynlist aussieht, der sollte zunächst für ausreichende Sauerstoffzufuhr sorgen, anschließend kurz und scharf nachdenken, einen langen, bedeutungsvollen Blick auf die bereits ausführlich vorgestellte Direktive require ldapfilter werfen und sich dann wieder entspannt zurücklehnen. Dynamische Gruppen? Schöne Geschichte, kann Apaches mod_authnz_ldap aber selbst; dank umfangreicher Filterkriterien. Ein supersimples Beispiel: Optionale Prä-Selektion per LDAP-URL, anschließend Erzeugung der dynamischen Apache-Gruppe über die Auswertung eines oder mehrerer spezieller Attributwerte und/oder Objektklassen, z.B.: require ldap-filter &(title=webuser)(objectClass=inetOrgPerson) \ (|(description=*Forschung*)(description=*Verkauf*))
Im Klartext: Erlaube alle User, die im Attribut title den Wert webuser haben UND die Objektklasse inetOrgPerson besitzen UND im description-Attribut entweder den Teilstring Forschung ODER Verkauf haben.
495
4.6
1198.book Seite 496 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Natürlich können wir auch einen entsprechenden LDAP-Filter direkt in der AuthLDAPURL-Direktive angeben, und per require valid-user die bereits gefilterte Teilmenge einfach durchschleusen. Wir sehen, Möglichkeiten en masse ... Verschlüsselte Rauchzeichen Nun zum letzten Schliff – der verschlüsselten Kommunikation zwischen Apache und unserem guten, alten OpenLDAP. Unterstützte Apache in Version 2.0.x nur SSL-Verbindungen zu unserem LDAP-Server, so werden uns in der aktuellen Version 2.2 beide Verbindungsarten (SSL und TLS) von mod_ldap.so zur Verfügung gestellt. Die SSL-Anbindung ist denkbar trivial; ein entsprechendes ldaps:// -Statement in der AuthLDAPURL-Direktive sorgt bei sauber konfiguriertem SSL auf Seiten unseres slapd für entsprechende Verschlüsselung: AuthLDAPURL ldap://:636/dc=local,dc=site ...
oder AuthLDAPURL ldaps:///dc=local,dc=site ...
Das TLS-Setup erfordert nur unwesentlich mehr Vorarbeit; um genau zu sein, müssen wir der zentralen Apache-Konfigurationsdatei lediglich einige Zeilen hinzufügen und der AuthLDAPURL-Direktive noch ein kleines, aber effektives »TLS« am Ende der URL spendieren. Im Detail: Am Ende der httpd.conf platzieren wir die folgenden, selbsterklärenden Direktiven, die uns von mod_ldap zur Verfügung gestellt werden: LDAPTrustedGlobalCert CA_BASE64 /etc/apache2/certs/cacert.pem LDAPTrustedClientCert CERT_BASE64 /etc/apache2/certs/newcert.pem LDAPTrustedClientCert KEY_BASE64 /etc/apache2/certs/ldapkey.pem LDAPTrustedMode TLS LDAPVerifyServerCert On
Und ergänzen die LDAP-URL in unserer Datei /etc/.htaccess: AuthLDAPURL ldap:/// ...
TLS
Starten wir nun ein Login für den geschützten Bereich mit der uid von ckent, sollten wir in den Logs unseres slapd in etwa Folgendes sehen: slapd[21329]: conn=2 op=0 STARTTLS slapd[21329]: conn=2 fd=15 TLS established tls_ssf=256 ssf=256 slapd[21329]: conn=2 op=1 BIND dn="" method=128 slapd[21329]: conn=2 op=2 SRCH base="dc=local,dc=site" scope=2 deref=3 filter="(&(objectClass=*)(uid=ckent))"
496
1198.book Seite 497 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Um ganz sicherzugehen, können wir auch noch per tcpdump in der altbekannten Weise die Kommunikation zwischen LDAP und Apache überwachen. #> tcpdump -xX -s 10000 -i lo dst port 389
Bis auf den Zertifikats-DN und sonstiges »Rauschen« sollte beim Login nichts zu erkennen sein. Vor dem Test gegebenenfalls beide Dienste neu starten, so ist sichergestellt, dass die TLS-Verbindung in jedem Fall hergestellt (bzw. der Versuch initiiert) wird. Debugging Sollte irgendetwas nicht geklappt haben, folgende Punkte checken: 왘 Alle Dateien auf Typos geprüft? 왘 Logs und etwaige Fehlermeldungen des Apache und slapd ausgewertet? 왘 Zertifikate korrekt generiert und eingebunden? 왘 In der LDAP-URL den FQHN statt einer IP verwendet und »TLS« ergänzt? Denkbar sind natürlich auch Anwendungen im DAV-Bereich, bei denen sich Apache – optional mit SVN und LDAP als Authentifizierungsbackend – hervorragend als webbasierter Fileserver aufsetzen lässt. So viel an dieser Stelle zu unserer tapferen Rothaut, die hoffentlich niemals gegen uns auf den Kriegspfad zieht. Nun aber weg von der Steppe und ab ins Wasser. Denn da wartet ein vielseitiger Tintenfisch.
4.6.2
Squid – Zugriffe auf den Proxy über OpenLDAP kontrollieren
Gestatten ... Doctor Octopus. Squid als HTTP-Proxy hat sich von seinem ursprünglichen Zweck als reine »Caching-Maschine« fortentwickelt zu einem wichtigen Sicherheitstool in modernen Firmennetzwerken. Der konsequente Einsatz von Firewalls in Verbindung mit Proxies kann Zugriffe auf das Internet erheblich sicherer gestalten. Da Squid auf der obersten TCP/IP-Schicht, dem Application Layer, arbeitet, ist er zwar von innen (fast) unsichtbar, aber für Angriffe aus der Wildnis ein kaum zu überwindendes Hindernis. Jeder Versuch, mit Synflooding, verstümmelten TCP-Headern oder anderen Standardangriffen Informationen zu erlangen, scheitert zwangsläufig. Der Proxy packt jedes angeforderte Datagramm vollständig aus, um es auf der Empfängerseite eigenhändig mit neuen TCP- und IP-Headern zu versehen. Da läuft der nordkoreanische Geheimdienst leider ins Leere. Und CIA & NSA ebenso.
497
4.6
1198.book Seite 498 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Ursprünglich ging es bei HTTP-Proxies um etwas völlig anderes, nämlich um die Verbesserung der Zugriffsmöglichkeiten. Wir erinnern uns an die frühen 90er – keine Bandbreite. Damals lag die Aufgabe von Proxy-Diensten primär darin, einen ausreichend aktuellen Cache anzulegen, das heißt, jede Seite, die irgendjemand geholt hatte, lag im Rahmen ihrer Gültigkeitsdauer in einem Zwischenspeicher, dem so genannten Cache. Von dort konnte sie, wenn eine weitere Anforderung kam, ohne lange Nachfrage mit LAN-Geschwindigkeit gezeigt werden. Das war ein klarer Performance-Vorteil. Auch heute macht ein guter Proxy Webzugriffe schneller: Mit dem so genannten DNS-Caching wird die Auflösung der Namen häufig besuchter Seiten zwischengespeichert, es entfällt ein kompletter Request und damit meist eine ganze Sekunde bis zum Zugriff auf den entfernten Dienst. Damit ein moderner Proxy die in ihn gesetzten Erwartungen in punkto Sicherheit erfüllen kann, bringt er eine Flut von Filter- und Kontrollmöglichkeiten mit sich. An dieser Stelle seien z.B. SquidGard als URL-Filter oder DansGuardian (für privaten Einsatz kostenfrei) als echter Content-Filter genannt. In Verbindung mit Tor und Privoxy kann man ihn sogar als Anonymizer dazu verwenden, die Datensammelwut unserer Staatsdiener hinsichtlich IP-Speicherung herrlich ins Nirwana laufen zu lassen. Kurzum – das ist alles sehr schön, aber nicht unser Thema. Wir wollen hier Squid-Benutzer via LDAP authentifizieren. Dafür bringt Squid von Haus ein paar Zusatztools (so genannte Helper) mit, als da wären squid_ldap_auth, squid_group_auth und – nicht zu vergessen – digest_ ldap_auth. Die Sourcen für squid_ldap_auth befinden sich im Tarball unterhalb des Ordners helpers/basic_auth/ldap/, für squid_group_auth unter helpers/external_acl/ squid_ldap_group. Die Kompilationsoptionen zu Squid finden sich im Anhang. Bei Debian finden wir die Helper z.B. unter /usr/lib/squid/. Setup Wir verwenden für unser Setup Squid in der aktuellen Version 3.0 Stable. Jeder, der schon einmal mit Squid in Berührung gekommen ist, weiß, dass unser vielseitiger Tintenfisch ein wahres Konfigurationsmonster ist und daher weder – mal eben – (da war es wieder ...) abzuhandeln noch umfassend aufzusetzen. Aber das ist an dieser Stelle auch nicht unsere Aufgabe, denn wir kümmern uns primär um ein einfaches, funktionierendes Basic-Setup, bevor wir die Zugriffe auf unseren Proxy gegen unseren slapd authentifizieren. Wer bereits einen Squid oder anderen Proxy im Netz hat, kann einfach über die cache_peer-Direktive auf den entfernten Squid als parent cache zeigen; auf diese Art und Weise wird die Kommunikation des Test-Squids zum »normalen« Squid weitergeleitet:
498
1198.book Seite 499 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
cache_peer parent 3128 3130 no-query
Bevor wir die Squid-Konfiguration starten, testen wir die Funktionalität der Helper, indem wir manuell per Kommandozeile mit dem jeweiligen Tool auf unseren LDAP zugreifen, zunächst mit squid_ldap_auth: #> /usr/sbin/squid_ldap_auth -b ou=security,dc=local,dc=site \ -f uid=%s -h ldapmaster.local.site -p 389 -v 3
Anschließend wird eine Eingabe in der Klartext-Form userpasswort<ENTER>
erwartet. Als Antwort sollten wir bei Verwendung der Kombination rdeckard linux, also einem gültigen User aus der Unit security, in jedem
Fall folgende Ausgabe bekommen, die durch den Parameter -d (debug) etwas geschwätziger ist: user filter 'uid=rdeckard, searchbase 'ou=security,dc=local,dc=site' attempting to authenticate user 'uid=rdeckard,ou=security,dc=local,dc=site' OK
Falls ein »ERR« erscheint, sollte ein Blick in die Log-Datei unseres LDAP relativ schnell Klärung bringen. Ist bis zu dieser Stelle alles in Ordnung, können wir die weitere Modifikation der squid.conf auf jeden Fall beruhigt angehen, die Kommunikation mit unserem LDAP wird kein Problem sein. Die Bedeutung der einzelnen Parameter schauen wir uns gleich an. Wir binden nun das Tool squid_ldap_auth mit einigen Einträgen in der Konfigurationsdatei des Squid (üblicherweise /etc/squid/squid.conf) ein. Die erste Zeile (auth_param_basic) ist im Listing umbrochen, in der squid.conf sollte sie in einer Zeile ausgeschrieben werden, wobei der Pfad zur Binary gegebenenfalls anzupassen ist (der Kommentar ist nicht Bestandteil der Zeile): auth_param basic program /usr/sbin/squid_ldap_auth -b ou=security,dc=local,dc=site –f uid=%s -h ldapmaster.local.site -p 389 -v 3 #(-Z)f.TLS ergaenzen auth_param basic children 5 auth_param basic credentialsttl 2 hours auth_param basic realm Proxy-Authentifizierung per LDAP
In der ersten Zeile teilen wir Squid über den absoluten Pfad mit, wo sich der Helper (zum Vergleich der übergebenen Authentifizierungsdaten mit unserem LDAP) befindet. Über den Parameter -b wird die Searchbase angegeben, unterhalb derer (ou=security,dc=local,dc=site) sich die zulässigen Benutzer befinden. Der Parameter -f spezifiziert das Attribut (uid=%s), das zur Auswertung des Benutzernamens bei der Authentifizierung verwendet wird. Der Parameter -v 3 sorgt dafür, dass Squid unseren LDAP mit Hilfe der aktuellen Protokollversion 3
499
4.6
1198.book Seite 500 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
befragt und somit auch TLS-Konnektivität ermöglicht. Der Port-Parameter ist optional und wird nur benötigt, wenn unser slapd auf einem anderen Port als dem Default-Port 389 arbeiten sollte, oder falls SSL-Konnektivität gewünscht ist. Wenn Squid mit den OpenLDAP-Libraries kompiliert wurde, kann alternativ auch –(statt der Parameter -h und –b) der Parameter -H verwendet werden, über den sich eine LDAP-URL in bekannter Form spezifizieren lässt. So lässt sich auch recht einfach eine SSL-verschlüsselte Abfrage (ldaps://) unseres LDAP realisieren. Alternativ kann SSL natürlich auch konventionell über die Port-Direktive aktiviert werden (siehe oben, -p 636). Die aktuellere und bessere Variante mit TLS zur Verschlüsselung der Kommunikation zwischen Squid und OpenLDAP lässt sich einfach per Schalter -Z aktivieren. Es folgen noch die Zahl der maximal zu forkenden Kindprozesse (children 5) und die maximale Gültigkeitsdauer der Session (credentialsttl: 2 hours). Der letzte Teil enthält einfach nur den Anmeldetext der Messagebox des Browsers beim Login. Nun brauchen wir noch die entsprechenden ACLs, um den Zugriff zu steuern (die Nummerierung gehört nicht zu den Direktiven): # ACL-Sektion der squid.conf 1: acl proxyuser proxy_auth REQUIRED ... 2: http_access allow proxyuser 3: http_access deny all
1. Definiert den frei wählbaren Namen der ACL (proxyuser). Der Parameter proxy_auth legt fest, dass der Zugriff nur authentifiziert gestattet wird. Anstelle von REQUIRED, das – ähnlich wie valid-user bei Apache – alle User, auf die die LDAP-URL zutrifft, als gültig definiert, können auch selektiv einzelne Benutzernamen verwendet werden. 2. Aktiviert die ACL proxyuser und gestattet den entsprechenden authentifizierten Benutzern Zugriff auf den Proxy. Die Direktive sollte in unserem Testszenario oberhalb aller anderen http_access-Rules platziert werden, damit sie immer als Erste abgearbeitet wird. 3. Als letzte ACL muss im Squid immer deny all gesetzt sein. Das Popup-Fenster des Browsers sollte dann beim Zugriff auf eine Internet-Seite in etwa so aussehen:
500
1198.book Seite 501 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Abbildung 4.19 Squid-Proxy
Benutzerauthentifizierung im Firefox-Browser per LDAP beim Zugriff auf den
Im Log des LDAP sollten dann beim Login des authentifizierten Users rdeckard und aktiviertem TLS folgende Zeilen auftauchen: conn=168 op=0 STARTTLS slapd[22015]: conn=168 fd=18 TLS established tls_ssf=256 ssf=256 slapd[22015]: conn=168 op=1 SRCH base="ou=security,dc=local,dc=site" scope=2 deref=0 filter="(uid=rdeckard)"
Filterkonstrukte (»dynamische« Gruppen) Dynamische Gruppen? Das kennen wir – abgesehen von Overlay dynlist – doch schon aus unserem Exkurs ins Land der Indianer. Und genau so funktioniert auch hier, bei den Squid-Helferlein, das Zusammenstellen von Gruppen anhand bestimmter Filterkriterien. Hierfür schauen wir uns nur ein kurzes Beispiel an, denn das Verfahren an sich sollte uns mittlerweile so vertraut sein wie Kaffeekochen. Okay, immer vorausgesetzt, wir sind nüchtern. Zum Testen eignen sich natürlich auch hier die Trockentests mit squid_ldap_auth auf der Kommandozeile. Schauen wir uns dazu folgendes, einfaches Beispiel an, wobei wir nur die Filter-relevanten Kriterien des Befehls erläutern: #> /usr/sbin/squid_ldap_auth -b ou=verkauf,dc=local,dc=site \ -f "(&(uid=%s)(title=proxyuser)(objectClass=posixAccount))" \ -h ldapmaster.local.site -p 389 -v 3 -d ckent linux user filter '(&(uid=ckent)(title=proxyuser)(objectClass=posixAccount))', searchbase 'dc=local,dc=site' attempting to authenticate user 'uid=ckent,ou=verkauf,dc=local,dc=site' OK
Kurze Analyse: -b präselektiert von vornherein die Suchbasis auf die ou verkauf, -f gibt uns die Filterkriterien für den verbliebenen Subtree vor, als da wären: Die uid wird als Login-Name ausgewertet, das Objekt muss die Objektklasse posixAccount besitzen und natürlich im title-Attribut den Wert proxyuser vorweisen können, sonst gibt’s keinen Einlass.
501
4.6
1198.book Seite 502 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Denkbar sind hier alle möglichen Filter-Konstrukte und Variationen; was der Admin letztlich einsetzt, hängt natürlich von den Gegebenheiten seines Netzes und wie immer von den Vorlieben des üblicherweise etwas IT-fremden Weisungsbefugten ab. Da das Attribut title Multi-Valuable ist, kann ein User z.B. durchaus mehrere title-Attribute besitzen, mit denen er sich für Web- und Proxy- Services berechtigen kann. Debugging Sollte bis hierher etwas nicht geklappt haben, folgende Punkte prüfen: 왘 Reihenfolge der ACLs in Ordnung? 왘 Filterkriterien korrekt gesetzt? 왘 Alle entsprechenden Attribute in den Userobjekten vorhanden? 왘 Funktioniert die Helper-Anweisung (squid_ldap_auth) auf der Kommandozeile? 왘 Was sagen die Logs? 왘 Stimmt die Zeile auth_param_basic in der squid.conf? (Pfad zur Binary etc.) Ein guter Ansatzpunkt ist immer der direkte Aufruf der squid-Binary mit deaktiviertem DNS-Lookup (-D) und im Debug-Mode, z.B. -d 1. Hier sollten sich Hinweise auf mögliche Fehlkonfigurationen schnell aufspüren lassen. Gruppentherapie, zum Letzten Natürlich bringt unser Squiddie auch ein Helferlein mit, das die Auswertung »statischer« Gruppenobjekte im ldap ermöglicht. Das dafür vorgesehene HelperModul squid_group_ldap gestattet es, die member(UID)-Attribute von LDAPGruppen auszuwerten. Allerdings dürfte die statische Variante in Anbetracht der umfangreichen Filtermöglichkeiten (und somit quasi-dynamischen Teilmengen von berechtigten Usern) eher obsolet sein. Daher werden wir uns nur kurz mit dem Setup befassen und auf die wichtigsten Details eingehen. Der Einfachheit halber verwenden wir hierfür die bereits existierende Gruppe cn=superuser,dc=local,dc=site vom Typ groupOfNames und testen an ihr die Auswertung einer gruppenbasierten, externen ACL für Squid. Zum Trocken-Test könnten wir folgendes Statement anwenden (hier ohne Pfad zum Helper):
502
1198.book Seite 503 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
#> squid_ldap_group -b "cn=superuser,dc=local,dc=site" \ -f "(&(cn=%g)(member=%u)(objectClass=groupOfNames))" \ -B "dc=local,dc=site" -F "(uid=%s)" -h ldapmaster -d 1 -v 3
Der Schalter -d aktiviert wie bereits bekannt den Debug-Mode; -b gibt den DN an, unter der die Gruppe zu finden ist. Der Filter (-f) gibt die Filterdirektiven für die auszuwertende Gruppe an, -B und -F definieren die Searchbase und den zusätzlichen Suchfilter für die Userobjekte. Nach der Eingabe von ckent<SPACE>superuser<ENTER>
sollten wir folgende Ausgabe erhalten, die eine detaillierte Info über die interne Abarbeitung des Suchfilters liefert: Connected OK user filter '(uid=ckent)', searchbase 'dc=local,dc=site' group filter '(&(cn=superuser)(member=uid=ckent,ou=verkauf,dc=local,dc=site) (objectClass=groupOfNames))', searchbase 'dc=local,dc=site' OK
Damit wäre der grundlegende Funktionstest bestanden. Alternativ lässt sich natürlich auch eine Gruppe vom Typ posixGroup verwenden; in diesem Fall muss das member-Attribut in der Helper-Direktive natürlich auf memberUid umgestellt werden. Die Verschlüsselung per TLS lässt sich auch hier durch den Schalter -Z aktivieren. Um nun die »externe« ACL in die squid.conf zu integrieren, benötigen wir folgende Schritte: Der Block, in dem die squid_ldap_auth-Direktiven gesetzt wurden, bleibt erhalten, wir modifizieren nur die Searchbase auf dc=local,dc=site. Die User-Authentifizierung soll ja nach wie vor erfolgen, danach erst wird selektiert, ob der User über seine Gruppenzuordnung berechtigt ist oder nicht. (Die folgenden Zeilen dürfen in der squid.conf nicht umbrochen sein.) # squid_ldap_auth auth_param basic program /usr/sbin/squid_ldap_auth \ –b dc=local,dc=site -f uid=%s -h ldapmaster -p 389 -v 3 auth_param ...
Nun kommt der entscheidende Punkt: die Definition der »externen« ACL per squid_ldap_group. Sie erfolgt über die nachstehende Direktive. (Die folgenden Zeilen dürfen in der squid.conf nicht umbrochen sein, die Nummerierung dient nur der Erläuterung.) # squid_ldap_group – external_acl 1) external_acl_type ldap_group %LOGIN \ /usr/sbin/squid_ldap_group -b dc=local,dc=site \
503
4.6
1198.book Seite 504 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
-f "(&(cn=%g)(member=%u)(objectClass=groupOfNames))" \ -d -h ldapmaster.local.site -v 3 2) acl ldapacl external ldap_group superuser 3) http_access allow ldapacl
Zeile 1: Der Parameter ldap_group definiert den frei gewählten Bezeichner dieser ACL. %LOGIN übergibt den authentifizierten Login-Namen des Users an squid_ ldap_group. Der Parameter –b definiert hier ebenfalls die Searchbase. Etwas komplexer wird’s beim Filter (-f): Über cn=%g wird der in Zeile 2 festgelegte Gruppenname (cn=)superuser vom Filter ausgewertet. Zeile 2 definiert die eigentliche ACL unter dem Namen ldapacl, Typ external. ACL-Definition ist ldap_group (siehe Zeile 1), superuser ist der Name der groupOfNames in unserem DIT, die über die ACL ausgewertet werden soll. Zeile 3 schaltet die zuvor definierte ACL mit dem Bezeichner ldapacl scharf. Nicht vergessen, dass als letzte ACL-Direktive der squid.conf wie üblich http_ access deny all stehen muss. In den Logs können wir gut die Auswertung der gesetzten externen ACL erkennen: slapd[2834]: conn=156 op=0 SRCH base="dc=local,dc=site" scope=2 deref=0 filter="(&(cn=superuser)(?member=pparker)(objectClass=groupOfNames))"
Natürlich dürfen wir bei allen bisherigen Betrachtungen nicht vergessen, dass der erste Teil der Kommunikation zwischen Browser und Squid nach wie vor unverschlüsselt abläuft – und so ohne weiteres mitgesnifft und »dank« Base64 mit einem Perl-Einzeiler in Klartext umgesetzt werden kann. Squid bietet von sich aus leider keine praktikable Lösung, um die Kommunikation Browser ↔ Proxy zu verschlüsseln; insofern bleibt dem sicherheitsbewussten Admin in Verbindung mit auth_param_basic oft nur der Griff zu separaten Produkten wie ssltunnel, die sich als tcp-Wrapper um die verschlüsselte Kommunikation zwischen Client und Applikation kümmern. Aber: Das ebenfalls mitgelieferte Helper-Programm digest_ldap_auth bringt uns auf dem – zugegebenermaßen ab hier etwas verschlungenen – Crypto-Weg zwischen Browser und Squid ein gutes Stück weiter. Easy to digest – leicht verdauliche Kost für die Krake im Baum Basic Auth ohne SSL oder TLS? Nicht mit uns. Wir sorgen dafür, dass wir trotz unverschlüsselter Kommunikation ein sicheres Login per Browser gegen unseren ge-ldap-ten Squid hinbekommen. Hierfür schnappen wir uns das freundliche Helper-Tool digest_ldap_auth und schauen mal, wer zum Essen kommt.
504
1198.book Seite 505 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
Zunächst noch einmal ein paar wirklich kurze und stark vereinfachte Basics zum Thema. Bei der Verwendung einer Digest-basierten Authentifizierung kann das »normale« LDAP-Passwort unserer User nicht verwendet werden – wir erinnern uns. Daher benötigen wir ein zweites Digest-»Passwort«, das wir als zusätzliches Attribut in den relevanten User-Objekten speichern und das vom squid-DigestHelper abgefragt wird. Zusätzliches Attribut? Für uns als mittlerweile semi-professionelle Schema-Designer kein Problem mehr. Wir können hierfür z.B. einfach unser bestehendes localsite.schema um ein entsprechendes Attribut (z.B. userDigest), das einen beliebigen String speichern kann, wie z.B. das Attribut name, erweitern. Oder: Wir greifen einfach auf ein bestehendes, aber von uns bisher nicht benutztes Attribut zurück. Hierzu eignet sich logischerweise jedes Attribut, das eine 1.3.6.1.4.1.1466.115.121.1.15-konforme UTF-8-Syntax hat, also z.B. das nach außen unscheinbare givenName. Wir nehmen hier der Einfachheit halber givenName und starten als Erstes mit der Erweiterung unseres Users ckent um das neue Attribut, das sein Digest-Passwort in der Form username:realm:password enthält. Hierzu erzeugen wir zunächst den notwendigen Passwort-Hash: #> echo -n "ckent:local.site:linux" | md5sum | cut -f1 -d' ' 5843065ad8319dfebb4c027e180d3a60
Anschließend erzeugen wir ein passendes LDIF, um das Attribut einzupflegen: dn: uid=ckent,ou=verkauf,dc=local,dc=site changetype: modify add: givenName givenName: local.site:5843065ad8319dfebb4c027e180d3a60
Nach dem ldapmodify von ckent führen wir unseren ersten Trockentest mit digest_ldap_auth in der bereits vom squid_ldap_auth Helper bekannten Form durch. Logischerweise benötigen wir hier einige andere Parameter (Zeile ist umbrochen): #> echo '"ckent":"local.site"' | digest_ldap_auth \ -b "ou=verkauf,dc=local,dc=site" -u "uid" -A "givenName" \ -D "cn=ldapadmin,dc=local,dc=site" -w "linux" -e -v 3 \ -h ldapmaster.local.site -d Connected OK searchbase 'uid=ckent, ou=verkauf,dc=local,dc=site' password: 5843065ad8319dfebb4c027e180d3a60 5843065ad8319dfebb4c027e180d3a60
Hier nur kurz die Erläuterung der wichtigsten Parameter, die übrigen sollten hinlänglich bekannt bzw. selbsterklärend sein: -A übergibt das für den Hash auszu-
505
4.6
1198.book Seite 506 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
wertende Attribut; -e (encryption) erzwingt die Verwendung verschlüsselter Passwörter und -d startet wie üblich das Debugging. Nun benötigt unser ldap noch etwas Feintuning, um die ganze Digest-Mimik perfekt verarbeiten zu können. Hierfür legen wir zunächst ein Userobjekt an, das im späteren Arbeitsbetrieb die Anmeldung und das Readonly-Auslesen der HashAttributwerte übernimmt: dn: uid=digestreader,dc=local,dc=site objectClass: top objectClass: account objectClass: simpleSecurityObject uid: digestreader userPassword: {SSHA}aPXzfR6lc1np3Ws44rZRZc9k87SL4TZJ
Anschließend setzen wir noch die entsprechende ACL in unserer slapd.conf, damit digestreader die entsprechenden Leserechte erhält: access to attrs=givenName by dn="uid=digestreader,dc=local,dc=site" read by anonymous auth by self write by * break
Im nächsten Schritt hinterlegen wir das Passwort (»linux«) des digestreaderObjekts in der Datei /etc/digestreader_cred, die vom Squid-Helper ausgelesen werden kann und somit nur die minimal erforderlichen Leserechte (400) für den User (bei SUSE z.B. squid), mit dessen Identität der digest_ldap_auth-Helper läuft, besitzen darf. Anschließend führen wir unseren Trockentest erneut aus, diesmal jedoch mit den Credentials des digestreaders: #> echo '"ckent":"local.site"' | digest_ldap_auth \ –b "ou=verkauf,dc=local,dc=site" -u "uid" -A "givenName" \ -D "uid=digestreader,dc=local,dc=site" \ –W "/etc/digestreader_cred" -e -v 3 -h ldapmaster.local.site -d Connected OK searchbase 'uid=ckent, ou=verkauf,dc=local,dc=site' password: 5843065ad8319dfebb4c027e180d3a60 5843065ad8319dfebb4c027e180d3a60
Die Parameter kennen wir schon; nur haben wir statt des Klartextkennwortes (-w »passwort«) per -W die Passwortdatei für unseren digestreader-Account übergeben. Hat alles funktioniert, sind wir bereit, unser neues Helferlein in Doc Ock zu implantieren. Hierfür verwenden wir die folgende Sektion der squid.conf (auth_param digest) und passen sie unseren Bedürfnissen entsprechend an (Zeile 1 umbrochen, muss als Einzeiler geschrieben werden, der Pfad zur Binary ist anzupassen):
506
1198.book Seite 507 Donnerstag, 5. Februar 2009 3:02 15
Indianer und Kraken im Baum – Apache und Squid mit OpenLDAP
auth_param digest program /usr/sbin/digest_ldap_auth -b "ou=verkauf,dc=local,dc=site" -u "uid" -A "givenName" -D "uid=digestreader,dc=local,dc=site" -W "/etc/digestreader_cred" -e -v 3 -h ldapmaster.local.site auth_param digest children 5 auth_param digest realm local.site auth_param digest nonce_garbage_interval 5 minutes auth_param digest nonce_max_duration 30 minutes auth_param digest nonce_max_count 50
Nachdem wir Squid neu gestartet haben, kommen wir zum finalen Test, dem Login des Users. Beim Aufruf des Browsers (hier ausnahmsweise mal IE, damit niemand sagen kann, wir würden nicht auf Randgruppen eingehen) sollte uns das Login-Fenster des Digest-Realms entgegenprangen:
Abbildung 4.20 Squid-Authentifizierung per digest-Realm im IE
Sieht spitze aus, aber wissen wir, ob wirklich nichts Verwertbares über den Draht gegangen ist? Also tcpdump mal wieder ausgepackt, und ans Werk: #> tcpdump -xX -s 10000 -i eth0 dst port 3128
Beim Mitsniffen des Login-Vorgangs sollten wir in etwa das folgende Listing zu sehen bekommen. Die Digest-spezifischen cnonce und response (stark vereinfacht: Austausch und Vergleich der Hash-Werte) lassen sich hier gut erkennen:
507
4.6
1198.book Seite 508 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
0x0130: 0x0140: 0x0150: 0x0160: 0x0170: 0x0180: 0x0190: 0x01a0: 0x01b0: 0x01c0: 0x01d0: 0x01e0: 0x01f0: 0x0200: 0x0210:
416c 686f 7374 6e74 6c2e 7468 4d44 6f6e 6950 3030 3430 6162 2072 3364 3535
6976 7269 2075 222c 7369 222c 3522 6365 6261 3031 3438 6432 6573 6633 3263
650d 7a61 7365 2072 7465 2061 2c20 3d22 3150 2c20 3462 3038 706f 3762 6566
0a50 7469 726e 6561 222c 6c67 7572 3552 222c 636e 3433 6163 6e73 6631 6333
726f 6f6e 616d 6c6d 2071 6f72 693d 3477 206e 6f6e 6230 6434 653d 3166 6132
7879 3a20 653d 3d22 6f70 6974 222f 5359 633d 6365 3130 3437 2231 3032 3822
2d41 4469 2263 6c6f 3d22 686d 222c 7a49 3030 3d22 3163 3161 3534 3564 0d0a
7574 6765 6b65 6361 6175 3d22 206e 4e62 3030 3138 3765 222c 6335 3237 0d0a
Alive..Proxy-Aut horization:.Dige st.username="cke nt",.realm="loca l.site",.qop="au th",.algorithm=" MD5",.uri="/",.n once="5R4wSYzINb iPba1P",.nc=0000 0001,.cnonce="18 40484b43b0101c7e abd208acd4471a", .response="154c5 3df37bf11f025d27 552cefc3a28"....
Hat irgendetwas nicht hingehauen, geht’s – na was wohl? – ans Debugging: 왘 Typos? 왘 Funktioniert der squid-Helper standalone? 왘 Aller erforderlichen Objekte im DIT angelegt/ergänzt? 왘 Rechte der /etc/digestreader_cred ok? 왘 ACLs in der slapd.conf entsprechend gesetzt? Damit ist unser Setup sicherheitstechnisch auf der gesamten Strecke (Browser ↔ squid ↔ ldap) so wasserdicht, wie es sich für eine professionelle Krake gehört. Für Produktivumfelder empfiehlt sich natürlich eine semi-automatisierte, skriptbasierte Variante, um die User mit den entsprechenden Digest-Attributen aufzumotzen. Eine sehr einfache Variante (add_digest.sh), die aber mit Sicherheit als Grundstock dienen kann, haben wir zu den Beispieldateien (http://www.galileocomputing.de/1801) dieses Abschnitts gepackt. Weitere Informationen zum Thema Squid mit digest_ldap_auth bietet auch: http://wiki.squid-cache.org/KnowledgeBase/LdapBackedDigestAuthentication Auf der oben genannten Seite findet sich auch ein entsprechendes Verfahren, um mit Hilfe von Samba und den smbldap-Skripten die Passwort-Synchro automatisch bei der Änderung des Samba-Passworts mit zu synchronisieren. Weitere Informationen zu Squid allgemein liefern die sehr gut kommentierte squid.conf sowie die Manpages zu Squid und den Helpern. Das war’s mit den Indianern und den Tintenfischen, nun geht’s auf zum finalen Abschnitt über grafische Frontends. Aber seien wir mal ehrlich: Wir haben doch schon längst einen Blick reingeworfen, oder? Ja ne, is klar ...
508
1198.book Seite 509 Donnerstag, 5. Februar 2009 3:02 15
Auf den Schirm! – Grafische Frontends zur OpenLDAP-Administration
4.7
Auf den Schirm! – Grafische Frontends zur OpenLDAP-Administration
Grafische Oberflächen ersparen unerfahrenen Anwendern in der Regel ein tieferes Verständnis der dahinter liegenden Technik. Weil sie dann aber in der Regel nicht wirklich wissen, was sie tun, und sich die eine oder andere Sache verbiegen, müssen sie früher oder später ohnehin auf die Kommandozeile zurück, um die Dinge wieder zu richten ... Okay – manche Dinge lassen sich einfach besser verstehen, wenn man sie als Ganzes erfassen kann. Vor allem für einen LDAP-Neuling ist die Struktur eines Baumes auf der Kommandozeile oft kaum zu erfassen, und selbst etwas erfahrenere »LDAP-er« können – je nach Komplexität des Baumes – in dem Fall auch einen bis zwei Augenblicke benötigen, um die Struktur zu erkennen. Ein grafisches Frontend bringt hier oft das richtungsweisende Aha-Erlebnis. Und auch das »mal eben einen Attributwert ändern ...« geht so natürlich schneller von der Hand, als erst ein LDIF zu erstellen und es dann per ldapmodify einzulesen. Aber genau hier liegt auch der dicke Bock begraben. Grafische Frontends können eine schöne Sache sein, um den Tree als Ganzes zu betrachten, die Schemas zu erkunden oder mal eben fix ein Attribut zu ändern. Nur – wenn wir mit den entsprechenden Rechten unterwegs sind und ein- bis zweimal zu schnell klicken, ist ein Objekt weg, ein Subtree verschoben oder gar ganz gelöscht. Also, bei allem netten Klicki-Bunti: immer schön das Risiko im Auge haben, und darauf achten, als wer man unterwegs ist ... gell?
4.7.1
Kein kalter Kaffee – JXplorer
Der JXplorer ist ein Java-basierter (Open)LDAP-Browser und damit plattformunabhängig. Er ist frei verfügbar und kann über www.jxplorer.org oder sourceforge heruntergeladen werden. Voraussetzung ist natürlich eine Java-RuntimeUmgebung, wie sie Sun Microsystems ebenfalls frei erhältlich für fast alle OSPlattformen zur Verfügung stellt (www.java.com). SUSE und Debian z.B. bieten die entsprechenden Java-Pakete über ihre Internet-Repositories an. Das Setup des JXplorers geht relativ problemlos vonstatten. Zunächst wird (falls erforderlich) das JRE (Java Runtime Environment) nachinstalliert, anschließend entpacken wir einfach das Archiv oder Zip-File in einen Ordner und rufen je nach OS entweder das .bat oder .sh-File zum Start des Tools auf.
509
4.7
1198.book Seite 510 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Im gestarteten JXplorer rufen wir den Menüpunkt Datei 폷 Verbinden bzw. den Connect-Button auf. So öffnet sich ein Fenster, in dem wir unsere Verbindungsdaten eingeben können. Für unseren DIT stellt sich das etwa so dar:
Abbildung 4.21
Verbindungs-Setup im JXplorer
Über den Button »Speichern« kann man verschiedene Anwendungsprofile ablegen. Als Sicherheitsgrad wählen wir zunächst Benutzer + Passwort. Dabei ist darauf zu achten, dass sowohl BaseDN als auch der DN des Users, mit dem der Bind erfolgen soll, vollständig angegeben wird. Nach Eingabe des dem entsprechenden User-Objekt zugehörigen Passworts kann es dann auch schon losgehen: Auf der linken Seite finden wir die Struktur unseres DIT. Die Objekte lassen sich per Klick auf die Knoten [+] erweitern. Nahezu jedes Objekt lässt sich per Drag & Drop oder (Kontext-)Menü kopieren, verschieben oder löschen. Dabei sollte man natürlich immer die entsprechende Vorsicht walten lassen, vor allem, wenn man mit rootdn-Rechten unterwegs ist. Hat man ein Objekt markiert, kann man rechts davon die Details – zu dem jeweils markierten Objekt einsehen und natürlich auch modifizieren, sofern die entsprechenden Berechtigungen vorliegen. Dabei kann zwischen HTML und der (unserer Meinung nach) etwas übersichtlicheren tabellarischen Darstellung geswitcht werden. Ausgefüllte MUST-Attribute werden immer als Erstes in fett markierter Schrift angezeigt, MAY-Attribute finden sich weiter unten. Ändert man Attributwerte, so muss der Button »Abschicken« explizit betätigt werden, damit die Änderungen in den DIT geschrieben werden.
510
1198.book Seite 511 Donnerstag, 5. Februar 2009 3:02 15
Auf den Schirm! – Grafische Frontends zur OpenLDAP-Administration
Abbildung 4.22
DIT-Übersicht im JXplorer
Der Karteireiter »Schema« in der linken Spalte bietet die Möglichkeit, per (LDAP V3) Schema-Discovery einen Blick auf die eingebundenen Objektklassen und Attribute sowie die zur Verfügung stehenden LDAP-Syntaxen und MatchingRules zu werfen. Über die Suchzeile (Schnellsuche) kann nach einzelnen Attributwerten gesucht werden. Suchfilter können über den Menüpunkt Suchen 폷 Suchdialog erstellt werden. Dabei können die Einzelfilter zu komplexeren Suchfiltern ausgebaut und sogar miteinander verknüpft werden. Über den Menüpunkt LDIF besteht die Möglichkeit, Daten im LDIF-Format zu im- oder exportieren. Ein neues Objekt lässt sich über den Menüpunkt Bearbeiten 폷 Neu erzeugen. Alternativ kann man es auch im Kontextmenü erstellen. Dabei muss der jeweilige Knoten markiert werden, der als übergeordnetes Objekt für das neu zu erstellende Objekt dienen soll. Danach einfach »Neu« wählen. Der JXplorer bietet dabei die Möglichkeit, dem neuen Objekt automatisch Objektklassen zuzuordnen. Zusätzlich können über die linke Spalte aus allen eingebundenen Objektklassen die entsprechenden ausgewählt werden. Im folgenden Beispiel legen wir ein User-Objekt unterhalb der ou forschung an (siehe Abbildung 4.23). Über den Button »Eigenschaften« können die operational Attributes des gewählten Objekts angezeigt werden. Der Button »Klasse ändern« bietet die Möglichkeit, ein vorhandenes Objekt um neue Objektklassen zu erweitern.
511
4.7
1198.book Seite 512 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Abbildung 4.23 Objekt im JXplorer anlegen
Verschlüsselte Verbindung Die gute Nachricht: Verschlüsselte Verbindungen sind möglich. Die schlechte: per Default nach wie vor nur auf Port 636 (SSL). Leider ist – gerade in Bezug auf SASLMech EXTERNAL und TLS – wie so oft eine stillschweigende Ignoranz der Frontend-Entwickler festzustellen. Anders ist es nicht zu erklären, warum das eigentlich schon seit einer halben Ewigkeit etablierte TLS so wenig Unterstützung in dieser Sparte findet. Des Setup zur Authentifizierung per SSL + SASL + Keystore-Passwort ist so unhandlich, dass selbst in der Dokumentation von der Verwendung abgeraten wird. Das Setup für die Verbindung per SSL ist relativ schnell erläutert: Über den Menüpunkt Sicherheit 폷 Vertrauenswürdige Server … können CA’s und Serverzertifikate in verschiedenen Formaten (u.a. auch das von uns bisher verwendete PEM-Format) eingebunden werden. Zur Abspeicherung der Zertifikate verlangt der JXplorer ein Passwort, das den Defaultwert »changeit« hat. Der lässt sich wiederum über den Button »Passwort setzen« modifizieren. Über den Menüpunkt »Client Certificates« können entsprechend für den Client erstellte Zertifikate eingebunden werden. Das Default-Passwort zur Abspeiche-
512
1198.book Seite 513 Donnerstag, 5. Februar 2009 3:02 15
Auf den Schirm! – Grafische Frontends zur OpenLDAP-Administration
rung ist »passphrase« und kann ebenfalls über den Button »Passwort setzen« modifiziert werden. Eine weitere Alternative ist die Authentifizierung per GSSAPI: Hierbei erfolgt der Authentifikationsvorgang ohne User-Namen und Passwort. Voraussetzung ist natürlich ein gültiges Kerberos-Ticket.
4.7.2
Indianerland – Apache Directory Studio
Die Apache Foundation betreibt seit einiger Zeit ihr eigenes LDAP-Projekt unter dem Namen Apache DS (Directory Server). Dieses Projekt wird komplett in Java(!) realisiert und liegt mit einer stabilen 1.0-Version seit April 2007 auf dem Tisch. Aktuell ist der Server bei Hauptversion 1.5 angelangt und soll komplett LDAPv3-konform sein. Über die Notwendigkeit, einen Verzeichnisdienst-Server komplett in Java auf die Füße zu stellen, schweigen wir uns lieber aus – denn bei allen netten grafischen Gimmicks, die ein derartiger DS mitbringt: Die Performance kann und wird auch mit dem niedlichsten Eyecandy nie auch nur ansatzweise in die Nähe eines professionellen DS wie OpenLDAP kommen. Erste Tests haben das bereits vernichtend unter Beweis gestellt. Dies soll aber nicht unser Thema sein. Was uns in diesem Zusammenhang viel mehr interessiert: Zum Apache-Directory-Server-Projekt existiert ein sehr potentes, Eclipse-basiertes Verwaltungswerkzeug, das mit ziemlich jedem LDAP sprechen soll – laut Apache. Mit unserem OpenLDAP kommuniziert das Apache Directory Studio jedenfalls einfach und problemlos. Das Tool ist sehr umfangreich, so dass wir an dieser Stelle natürlich nur einen sehr eingeschränkten Einblick bieten können. Die zum Zeitpunkt der Erstellung des Buches aktuelle Version 1.3 finden wir unter http://directory.apache.org/studio/. Apache Directory Studio ist verfügbar für die Plattformen Linux, MacOS und Windows. Apache Studio benötigt – ebenso wie der JXplorer – ein JAVA Runtime Environment (JRE). Die Installation unter Windows ist trivial: Wenn wir Apache Studio auf einer Linux-Plattform installieren wollen, laden wir das Archiv, entpacken es nach Wahl und können das Programm anschließend direkt starten. #>/Pfad/zu/ApacheDS/ApacheDirectoryStudio
Nach dem ersten Start bietet uns Apache DS einen Startbildschirm an, von dem aus wir über den Button unten rechts direkt zur Workbench, der eigentlichen Arbeitsoberfläche, gelangen können. Dort angekommen, muss zunächst wie üblich eine Verbindung zum DIT bzw. LDAP-Server hergestellt werden, damit wir auf unseren DIT zugreifen können.
513
4.7
1198.book Seite 514 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
Das erledigen wir entweder über das Fenster unten rechts (»Connections«) via Kontextmenü oder über das Hauptmenü »LDAP -> New Connection«. Der Connection Wizard ist selbsterklärend und führt uns ohne große Umschweife zur gewünschten Verbindung. Wir haben zusätzlich die Möglichkeit, bei jeder einzelnen Seite des Wizards unsere getroffen Einstellungen gegen den ausgewählten LDAP zu prüfen – ein gutes Feature, denn so lassen sich Fehlkonfigurationen vermeiden bzw. schnell aufspüren. Haben wir alle drei Seiten (»Network Parameter«/»Authentication«/»Browser Options«) erfolgreich editiert, wird die neue Verbindung automatisch aktiviert, und wir können auf unseren DIT zugreifen:
Abbildung 4.24 Verbindung-Herstellung im Apache DS
(Serverseitige) TLS-Connections funktionieren out of the box, SSL wird natürlich ebenfalls per ldaps:// unterstützt. Noch ein Vorteil: Wenn mehrere Connections vorhanden sind, kann einfach zwischen ihnen umgeschaltet werden, ein An- und Abmelden wie beim JXplorer ist nicht nötig. Allerdings sollte in dem Fall sicherheitshalber ein Refresh (F5) des jeweils aktiven DIT oder Objekts ausgeführt werden. Betrachten wir nun die einzelnen Teile der Workbench, die sich insgesamt so darstellt:
514
1198.book Seite 515 Donnerstag, 5. Februar 2009 3:02 15
Auf den Schirm! – Grafische Frontends zur OpenLDAP-Administration
Abbildung 4.25 Apache DS Workbench
LDAP-Browser Das Übliche: Wir können unseren Verzeichnisdienst durchsuchen, und – die entsprechenden Rechte vorausgesetzt – Objekte anlegen, löschen verschieben modifizieren usw. Ein überaus hilfreiches Feature dabei: Zu jeder Operation wird (ebenfalls in der Box »Modification Logs«; unten Mitte) ein entsprechender LDIFOutput generiert, der sich per Copy & Paste hervorragend auf der Kommandozeile oder im internen LDIF-Editor weiterverwenden lässt. Eine vollständige Beschreibung des Apache DS LDAP-Browsers findet sich unter http://directory.apache.org/studio/users-guide.html. Diese Seite verlinkt auch zu den Dokumentationen von Schema- und LDIF-Editor. Entry-Editor Hier können die Attribute/Objektklassen der einzelnen Objekte wie im JXplorer bearbeitet werden – entsprechende Rechte natürlich vorausgesetzt. Wenn ein Objekt im LDAP-Browser markiert ist, werden seine Objektklassen und Attribute (je nach Zugriffsrechten) ebenfalls in tabellarischer Form dargestellt. Zur Bestätigung einer Modifikation reicht hier im Unterschied zum JXplorer die Eingabe von [Enter] oder [Tabulator] aus, um die Änderungen abzuschicken. Wollen wir neue Objekte erstellen, haben wir die Wahl, vorhandene als Template zu ver-
515
4.7
1198.book Seite 516 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
wenden, oder sie direkt from the Scratch zu erstellen. Kleiner Tipp: Über die Einstellungen Window 폷 Preferences 폷 LDAP 폷 Entry Editor können wir die operational Attributes zu allen Objekten einblenden. LDIF Editor Ein kleiner Editor (Menü LDAP 폷 New LDIF File) für unsere LDIF-Dateien. Die Einträge aus den Modification- oder Searchlogs können praktischerweise per Copy&Paste direkt übernommen werden. Der Editor soll uns in zukünftigen Versionen eine korrekte Überprüfung der LDIF-Syntax anbieten. Die Entwicklergemeinde rät derzeit allerdings noch zur Vorsicht: The LDIF editor is still in development. The handling of big LDIF files is a problem because the complete file is loaded into memory which may cause an OutOfMemoryException. The syntax check doesn't work correctly. The error annotations and displayed messages are not very helpful at the moment. Currently there is no URL support. Schema Editor Ein kleiner Editor (File 폷 New 폷 Schema-Editor) zur Erstellung von SchemaDateien, Attribut-Typen und Objektklassen. Und sonst Über den Menüpunkt File 폷 Export lassen sich wahlweise gefilterte Objekte oder ganze Schemas als LDIF-, Excel-, DSML- oder CVS-Dateien bzw. alternativ auch in Schema-Projekten speichern, die dann über den Schema-Editor weiterbearbeitet werden können. Gleiches gilt in umgekehrter Weise für File 폷 Import; hier werden die Formate DSML (und natürlich LDIF) unterstützt.
4.7.3
… und noch ein paar LDAP-Browser/-Tools
Neben den Tools JXplorer und Apache DS existieren natürlich noch etliche andere LDAP-Browser bzw. -Tools, die ebenfalls für die Ansicht und/oder die Verwaltung eines LDAP-Trees (und auch mehr) geeignet sind. Jedes Einzelne von ihnen besitzt bestimmte Vorzüge und eignet sich für bestimmte Szenarien besonders gut, daher schauen wir uns einige von ihnen ebenfalls noch kurz an. Noch eine kleine Anmerkung: Die Reihenfolge und auch die Ausführlichkeit der Darstellung aller in diesem Abschnitt vorgestellten, grafischen LDAP-Browser/Admin-Tools stellt dabei unsererseits keine (Be-)Wertung dar, und die Wahl des Lieblings-LDAP-Browsers und -Editors unterliegt dabei – abgesehen von faktischen Schwächen oder Vorzügen der jeweiligen Applikation – natürlich der persönlichen Präferenz des Admins. Freedom of choice ...
516
1198.book Seite 517 Donnerstag, 5. Februar 2009 3:02 15
Auf den Schirm! – Grafische Frontends zur OpenLDAP-Administration
Webmin Webmin ist ein echter Allrounder. Das Paket steht – in der zum Zeitpunkt der Bucherstellung aktuellen Version 1.441 frei verfügbar unter www.webmin.com in etlichen Paketierungsformen zum Download. Webmin installiert seinen eigenen Webserver auf Port 10000 und ermöglicht die (Remote-)Administration eines Systems via Browser und https. Webmin ist dabei kein spezielles LDAPTool, es bringt »lediglich« LDAP-Module mit, über das man die LDAP-User und Gruppen grafisch relativ einfach administrieren kann. Webmins gesamte Funktionalität deckt mittlerweile nahezu die komplette System- und Netzwerkadministration unter Linux ab (113 Module), zudem existieren noch etliche 3rd-PartyModule, die das Funktionsspektrum erweitern. Insofern ist es eher als komplettes, grafisches System- und Netzwerk-Administrationstool unter Linux zu sehen – mit allen Vor- und Nachteilen. Web2ldap Das LDAP-Administrationstool web2ldap (www.web2ldap.de, aktuell ist die stabile Version 1.0.5 verfügbar) basiert auf Python und bringt wie Webmin seinen eigenen http-Server mit; die Adminstration erfolgt ebenfalls Browser-basiert (via Port 1760), bei Bedarf natürlich auch verschlüsselt, z.B. per TLS. Alternativ kann es auch in bestehende Webserver-Installationen, wie z.B. Apache eingebunden werden. Es läuft auf Unix-basierten OS- und Win32-Plattformen, wird seit fast 10 Jahren kontinuierlich weiterentwickelt, und ist aufgrund dessen sehr ausgereift, umfangreich konfigurierbar und vielseitig. Es erlaubt u.a. dank vorhandener und selbst erstellbarer Templates eine effiziente Erleichterung des tagtäglichen Jobs im Umfeld eines jeden LDAP-Admins. web2ldap benötigt zusätzlich das Paket python-ldap. phpldapadmin ist ebenfalls ein webbasierter LDAP-Administrations-Client, bringt jedoch keinen eigenen Webserver mit. Eine Installation out of the box ist somit nicht möglich; phpldapadmin muss daher explizit in einen vorhandenen Webserver (z.B. Apache) integriert werden. Der Webserver selbst muss dabei mit PHP(5) Unterstützung konfiguriert sein, ebenso mit GETTEXT, LDAP und XML-Support. Unterstützt werden neben den üblichen administrativen Kapabilitäten auch Templates. Infos rund um das Projekt finden sich unter: http://phpldapadmin.sourceforge.net/wiki/index.php/Main_Page.
517
4.7
1198.book Seite 518 Donnerstag, 5. Februar 2009 3:02 15
4
OpenLDAP und Applikationen
4.8
Ein kurzes Wort zu LDAP in eigenen Applikationen
Die meisten Programmiersprachen stellen mittlerweile sehr ausgereifte API’s und Funktionsbibliotheken zur Verfügung, um auf Verzeichnisdienste zuzugreifen; als Beispiele seien hier vor allem php, perl und python genannt. Der jeweilige Einsatzzweck gibt dabei üblicherweise die zu verwendende Sprache vor. Soll z.B. eine Webapplikation mit LDAP-Kapabilitäten ausgestattet werden, liegt die Verwendung von php nahe. Auf Betriebssystemebene wäre perl sicher eine mögliche Alternative. Neben diesen Kriterien sollten natürlich weitere Aspekte mit einbezogen werden; wichtig sind dabei natürlich der Funktionsumfang der Bibliotheken insgesamt, um größtmögliche administrative Flexibilität zu bieten, und für den Praxiseinsatz sollte natürlich vor allem auch die Unterstützung von verschlüsselungstechnischen Funktionalitäten ein wichtiges Auswahlkriterium sein. Natürlich bieten die oben genannten Sprachen so viel Stoff, dass sie selbst komplette Bücher füllen, deren Studium im Fall einer eigenen Applikationsentwicklung im LDAP-Bereich auch dringend angeraten ist. Was die LDAP-Kapabilitäten der jeweiligen Sprache angeht, so kann sich der interessierte Leser u.a. über die nachfolgend gelisteten Quellen vorab einen Einblick über den Funktionsumfang verschaffen: 왘 http://www.perl.org/docs.html und http://ldap.perl.org/ 왘 http://de.php.net/manual/de/ und http://de.php.net/manual/de/book.ldap.php 왘 http://docs.python.org/ und http://python-ldap.sourceforge.net/docs.shtml Zum guten Schluss ... Damit sind wir mit unserem Buch über OpenLDAP schon wieder am Ende angelangt. Wir hoffen, wir konnten auch dieses Mal einen guten Einstieg in die Materie liefern, und ebenso die passenden Lösungsansätze für speziellere Konfigurationen in der Praxis. Letztlich wird es immer schwierig sein, wirklich jeden Wunsch zu erfüllen, genauso, wie es nahezu unmöglich ist, jede nur erdenkliche Konfiguration zu berücksichtigen. Wir hoffen, dass Ihnen unser Buch neues Know-how verschafft hat und dass die Lektüre nicht allzu trocken war. In jedem Fall bedanken wir uns bei Ihnen, dem Leser. Ohne Sie ist der Autor nur ein Motor – ohne Treibstoff.
518
1198.book Seite 519 Donnerstag, 5. Februar 2009 3:02 15
Anhang A
Paketlisten .............................................................. 521
B
Kompilationsoptionen ............................................ 529
C
RFCs, Drafts und LDAPv3-Core-Spezifikationen .... 533
D
Manpages nach Sektionen und Glossar .................. 545
519
1198.book Seite 520 Donnerstag, 5. Februar 2009 3:02 15
1198.book Seite 521 Donnerstag, 5. Februar 2009 3:02 15
A
Paketlisten
Nachstehend sind die von uns verwendeten Pakete der jeweiligen Distributionen sowie die Quellpakete mit den zugehörigen Versionsständen aufgelistet, die wir im Rahmen unserer Setups verwendet haben. Dabei muss natürlich immer berücksichtigt werden, dass je nach Distribution und/oder tatsächlich verwendeter Paket-Version spezifische Problematiken auftreten können, die wir unmöglich berücksichtigen können. Noch eine kurze Anmerkung zum nachfolgenden Listing: Pakete, die in einer Sektion bereits gelistet wurden, werden in nachfolgenden Sektionen in der Regel nicht mehr explizit gelistet. Achtung: Natürlich sollte auch immer ein Blick auf die OpenLDAP-seitig minimal geforderten Software-Versionen für das aktuelle OpenLDAP-Release geworfen werden. Aktuelles hierzu findet sich üblicherweise unter: http://www.openldap.org/software/release/readme.html und http://www.openldap.org/doc/admin24/appendix-recommended-versions.html
Kapitel 2: Basic-Setup/Fingerübungen Distributionsspezifisch Debian
SUSE
slapd 2.4.11-1
libldap-2_4-2-2.4.12-51.1
ldap-utils 2.4.11-1
nss_ldap-260-22.1
libldap-2.4-2 2.4.11-1
openldap2-2.4.12-50.1
libnss-ldap 261-2
openldap2-client-2.4.12-51.1
libpam-ldap 184-4.1
openldap2-devel-2.4.12-66.1
ldapvi 1.7-4+b1
pam_ldap-184-108.1
make 3.81-5
make-3.81-103.1
gcc 4:4.3.2-2
gcc43-4.3.1_20080507-6.1
gcc-4.3 4.3.2-1
libgcc43-4.3.1_20080507-6.1
gcc-4.3-base 4.3.2-1
gcc-4.3-39.1
libgcc1 1:4.3.2-1
521
1198.book Seite 522 Donnerstag, 5. Februar 2009 3:02 15
A
Paketlisten
Sources Software
Quelle
OpenLDAP
www.openldap.org
nss_ldap / pam_ldap
www.padl.com
ldapvi
www.lichteblau.com/
Kapitel 3: Replikation Distributionsspezifisch Debian
SUSE
ntp 1:4.2.4p4+dfsg-7
ntp-4.2.4p4-44.1
ntp-doc 1:4.2.4p4+dfsg-7
ntp-doc-4.2.4p4-44.1
heartbeat 2.1.3-6
heartbeat-2.1.4-2.1
heartbeat-2 2.1.3-6
heartbeat-stonith-2.1.4-2.1
heartbeat-2-gui 2.1.3-6
heartbeat-pils-2.1.4-2.1
heartbeat-gui 2.1.3-6
Sources: Software
Quelle
ntp
http://support.ntp.org/
Heartbeat
www.linux-ha.org
Pacemaker
www.clusterlabs.org/
Kapitel 3: SSL/ TLS Distributionsspezifisch Debian
SUSE
libssl0.9.8 0.9.8g-13
libopenssl0_9_8-0.9.8g-47.1
openssl 0.9.8g-13
openssl-0.9.8g-47.1
libssl-dev 0.9.8g-14
libopenssl-devel-0.9.8g-47.1
libsasl2-2 2.1.22.dfsg1-23
cyrus-sasl-2.1.22-140.1
libsasl2-dev 2.1.22.dfsg1-23
cyrus-sasl-saslauthd-2.1.22-148.1
libsasl2-modules 2.1.22.dfsg1-23
cyrus-sasl-plain-2.1.22-140.1
libsasl2-modules-gssapi-mit 2.1.22.dfsg1-23
cyrus-sasl-gssapi-2.1.22-140.1
sasl2-bin 2.1.22.dfsg1-23
tcpdump-3.9.8-31.1
tcpdump 3.9.8-4
522
cyrus-sasl-devel-2.1.22-140.1
1198.book Seite 523 Donnerstag, 5. Februar 2009 3:02 15
Paketlisten
Sources Software
Quelle
openssl
www.openssl.org
cyrus-sasl
http://asg.web.cmu.edu/sasl/sasl-library.html
Kapitel 3: PAM Distributionsspezifisch Debian
SUSE
libpam-krb5 3.11-3
pam_ldap-184-108.1
libpam-ldap 184-4.2
pam-1.0.1-8.1
libpam-modules 1.0.1-4
pam-devel-1.0.1-8.1
libpam-runtime 1.0.1-4
pam-config-0.53-3.1
libpam0g 1.0.1-4
pam_krb5-2.2.22-35.2
libpam0g-dev 1.0.1-4
pam-modules-11.0-35.1
libnss-ldap 261-2.1
nss_ldap-260-22.1
libnss3-1d 3.12.0-5 libnss3-dev 3.12.0-5
Sources Software
Quelle
pam
www.kernel.org/pub/linux/libs/pam/
nss_ldap/pam_ldap
www.padl.com
Kapitel 3: BDB Distributionsspezifisch Debian
SUSE
libdb4.5 4.5.20-13
db-utils-4.5.20-67.1
libdb4.5-dev 4.5.20-13
libdb-4_5-devel-4.5.20-67.1
db4.5-util 4.5.20-13
libdb-4_5-4.5.20-67.1
Sources Software
Quelle
bdb
http://www.oracle.com/technology/software/products/berkeley-db/index.html
slamd
www.slamd.com
523
A
1198.book Seite 524 Donnerstag, 5. Februar 2009 3:02 15
A
Paketlisten
Kapitel 4: Samba 3 Distributionsspezifisch Debian
SUSE
samba 2:3.2.3-3
samba-winbind-3.2.3-0.1
samba-common 2:3.2.3-3
samba-client-3.2.3-0.1
samba-doc 2:3.2.3-3
samba-3.2.3-0.1
libsmbclient 2:3.2.3-3
samba-doc-3.2.3-0.1
smbclient 2:3.2.3-3
libsmbios-libs-0.13.12-5.1
perl 5.10.0-16
libsmbclient0-3.2.3-0.1
perl-base 5.10.0-16
perl-5.10.0-37.4
perl-doc 5.10.0-16
perl-Net_SSLeay-1.32-20.1
perl-modules 5.10.0-16
perl-Crypt-SSLeay-0.57-14.1
libperl5.10 5.10.0-16
perl-IO-Socket-SSL-1.13-28.1
libcrypt-smbhash-perl 0.12-2
perl-ldap-ssl-0.34-20.1
libio-socket-ssl-perl 1.16-1
perl-Crypt-SmbHash-0.12-109.1
libnet-ldap-perl 1:0.36-1
perl-ldap-0.34-20.1
libnet-ssleay-perl 1.35-1
Sources: Software
Quelle
samba
www.samba.org
smbldaptools
http://download.gna.org/smbldap-tools/
perl
www.perl.org
srvtools.exe
www.microsoft.com
Kapitel 4: Samba 4 Distributionsspezifisch Debian
SUSE
autoconf 2.61-8 make 3.81-5 gcc 4:4.3.2-2 gcc-4.3 4.3.2-1 gcc-4.3-base 4.3.2-1 libgcc1 1:4.3.2-1 libblkid1 1.41.3-1 libncurses5 5.6+20080830-2 libgnutls26 2.4.2-3
autoconf-2.61-85.1 make-3.81-103.1 gcc43-4.3.1_20080507-6.1 libgcc43-4.3.1_20080507-6.1 gcc-4.3-39.1 python-2.5.2-26.2 python-devel-2.5.2-26.2 libgnutls-extra-devel-2.2.2-17.1 gnutls-2.2.2-17.1
524
1198.book Seite 525 Donnerstag, 5. Februar 2009 3:02 15
Paketlisten
Debian
SUSE
bind9-host 1:9.5.0.dfsg.P2-4 dnsutils 1:9.5.0.dfsg.P2-4 libbind9-40 1:9.5.0.dfsg.P2-4 libisccfg40 1:9.5.0.dfsg.P2-4 libisccc40 1:9.5.0.dfsg.P2-4 libdns43 1:9.5.0.dfsg.P2-4 libisc44 1:9.5.0.dfsg.P2-4 liblwres40 1:9.5.0.dfsg.P2-4 python2.5 2.5.2-14 python2.5-minimal 2.5.2-14 python 2.5.2-3 python-minimal 2.5.2-3 bind9utils 1:9.5.0.dfsg.P2-4 bind9 1:9.5.0.dfsg.P2-4 bison 1:2.3.dfsg-5 libgpg-error-dev 1.4-2 libgcrypt11-dev 1.4.1-1 libtasn1-3-dev 1.4-1 libgnutls-dev 2.4.2-3 libncurses5-dev 5.6+20080830-2 libpopt-dev 1.14-4 libreadline5-dev 5.2-3 libsqlite3-dev 3.5.9-5 libtdb1 1.1.2~git20080615-1 python2.5-dev 2.5.2-14 python-dev 2.5.2-3 swig 1.3.36-1 swig1.3 1.3.36-1
libgnutls-devel-2.2.2-17.1 libgnutls26-2.2.2-17.1 libgnutls-extra26-2.2.2-17.1 libacl-devel-2.2.47-6.1 libacl-2.2.47-6.1 acl-2.2.47-6.1 libattr-2.4.39-40.1 attr-2.4.39-40.1 libattr-devel-2.4.39-40.1 libreadline5-5.2-71.1 readline-devel-5.2-112.1 libblkid-devel-1.40.8-20.1 libblkid1-1.40.8-20.1 cyrus-sasl-devel-2.1.22-140.1 bind-chrootenv-9.4.2-39.2 bind-libs-9.4.2-39.2 bind-utils-9.4.2-39.2 bind-9.4.2-39.2 popt-1.7-427.1 popt-devel-1.7-427.1 sqlite3-3.5.7-17.1 sqlite3-devel-3.5.7-17.1 pkg-config-0.23-21.1 libaio-devel-0.3.104-113.1 libaio-0.3.104-113.1 swig-1.3.35-15.1 bison-2.3-101.1 libtdb1-3.2.3-0.1 libtdb-devel-3.2.3-0.1
Kapitel 4: Kerberos Distributionsspezifisch Debian
SUSE
krb5-admin-server 1.6.dfsg.4~beta1-4
krb5-apps-servers-1.6.3-50.1
krb5-config 1.21
krb5-1.6.3-50.1
krb5-doc 1.6.dfsg.4~beta1-4
krb5-apps-clients-1.6.3-50.1
krb5-kdc 1.6.dfsg.4~beta1-4
krb5-plugin-kdb-ldap-1.6.3-8.1
krb5-kdc-ldap 1.6.dfsg.4~beta1-4
krb5-doc-1.6.3-82.1
krb5-pkinit 1.6.dfsg.4~beta1-4
pam_krb5-2.2.22-35.2
krb5-user 1.6.dfsg.4~beta1-4
krb5-client-1.6.3-50.1
525
A
1198.book Seite 526 Donnerstag, 5. Februar 2009 3:02 15
A
Paketlisten
Debian
SUSE
libkrb5-25-heimdal 1.2.dfsg.1-2.1
krb5-devel-1.6.3-50.1
libkrb5-dev 1.6.dfsg.4~beta1-4
krb5-server-1.6.3-50.1
libkrb53 1.6.dfsg.4~beta1-4
cyrus-sasl-gssapi-2.1.22-140.1
libpam-krb5 3.11-3
Sources: Software
Quelle
MIT-Kerberos
http://web.mit.edu/kerberos/www/
Heimdal-Kerberos
www.h5l.org
Kapitel 4: Mail Distributionsspezifisch Debian
SUSE
postfix 2.5.5-1.1
postfix-2.5.1-28.5
postfix-ldap 2.5.5-1.1
postfix-devel-2.5.1-28.5
postfix-pcre 2.5.5-1.1
pcre-7.6-22.2
libpcre3 7.6-2.1
cyrus-imapd-2.3.11-31.1
qpopper 4.0.9.dfsg-1
perl-Cyrus-IMAP-2.3.11-31.1
cyrus-imapd-2.2 2.2.13-14+b3
cyrus-imapd-devel-2.3.11-31.1
cyrus-admin-2.2 2.2.13-14
cyrus-sasl-ldap-auxprop-2.1.22-148.1
cyrus-clients-2.2 2.2.13-14+b3
qpopper-4.0.9-16.1
cyrus-common-2.2 2.2.13-14+b3
MozillaThunderbird-translations-2.0.0.18-1.1
cyrus-dev-2.2 2.2.13-14+b3
MozillaThunderbird-2.0.0.18-1.1
cyrus-imapd-2.2 2.2.13-14+b3
evolution-2.22.1.1-15.1
cyrus-pop3d-2.2 2.2.13-14+b3 icedove 2.0.0.17-1 evolution 2.22.3.1-1 evolution-common 2.22.3.1-1
Sources Software
Quelle
cyrus-imapd
http://asg.web.cmu.edu/cyrus/imapd/
postfix
www.postfix.org/
Thunderbird
www.mozilla-europe.org
Evolution
http://projects.gnome.org/evolution/
526
1198.book Seite 527 Donnerstag, 5. Februar 2009 3:02 15
Paketlisten
Kapitel 4: Apache/Squid Distributionsspezifisch Debian
SUSE
apache2 2.2.9-10
apache2-prefork-2.2.8-28.1
apache2-doc 2.2.9-10
apache2-example-pages-2.2.8-28.1
apache2-mpm-prefork 2.2.9-10
apache2-utils-2.2.8-28.1
apache2-utils 2.2.9-10
apache2-2.2.8-28.1
apache2.2-common 2.2.9-10
apache2-mod_php5-5.2.6-0.4
libapache2-mod-perl2 2.0.4-3
apache2-doc-2.2.8-28.1
libapache2-mod-php5 5.2.6-5
apache2-mod_perl-2.0.3.99-46.1
libapache2-mod-python 3.3.1-5
apache2-mod_php5-5.2.6-0.6
libapr1 1.2.12-5
apache2-devel-2.2.8-28.4
libaprutil1 1.2.12+dfsg-8
libapr1-devel-1.2.12-27.1
php5-common 5.2.6-5
libapr1-1.2.12-27.1
squid 2.7.STABLE3-1
libapr-util1-1.2.12-43.1
squid-common 2.7.STABLE3-1
libapr-util1-devel-1.2.12-43.1 php5-5.2.6-0.4 squid3-3.0.STABLE5-11.1
Sources Software
Quelle
Apache
www.apache.org
Squid
www.squid-cache.org
php
www.php.net
Kapitel 4: Grafische Frontends Installationspakete/Sources Software
Quelle
Apache Directory Studio
http://directory.apache.org/studio/
Java Runtime (JRE)
www.java.com
JXplorer
http://sourceforge.net/projects/jxplorer/
phpLDAPAdmin
http://phpldapadmin.sourceforge.net/
Web2ldap
www.web2ldap.de
Webmin
www.webmin.com
527
A
1198.book Seite 528 Donnerstag, 5. Februar 2009 3:02 15
1198.book Seite 529 Donnerstag, 5. Februar 2009 3:02 15
B
Kompilationsoptionen
Nachfolgend sind die Kompilationsoptionen zu einigen wichtigen Paketen gelistet, die der jeweils von uns verwendeten Konfiguration und Version entsprechen. Die Pfadeinstellungen beziehen sich beispielhaft auf SUSE und müssen gegebenenfalls der jeweils verwendeten Distribution angepasst werden. Zur Übersicht der tatsächlich zur Verfügung stehenden Optionen sollte auf jeden Fall immer vorab ein Blick in die Optionen des configure-Skripts geworfen werden: ./configure --help | less
Ebenso kann der Inhalt der Datei config.log hilfreich sein, um etwaigen Fehlern bei der Kompilation auf die Schliche zu kommen. Vor einer erneuten Rekompilation mit geänderten Parametern sollte stets make clean | distclean bzw. der entsprechende make-Befehl ausgeführt werden, um alte Einstellungen und Dateien komplett zu entfernen. OpenLDAP 2.4.12 #>./configure --prefix=/usr --sysconfdir=/etc \ --libexecdir=/usr/lib/openldap --mandir=/usr/share/man \ --with-tls --with-cyrus-sasl --enable-overlays=yes #> make depend && make && make test && make install
(make test ist optional) Heartbeat 2.1.4 Zusätzlich benötigte Pakete: autoconf, automake, glib2-devel, swig, libnetapi-devel, openwbem-devel, cimple-devel, libxml(2,++)-devel, libzip-devel, libbz2-devel, flex, ncurses-devel, python(-gtk)-devel (für gui) #> ./ConfigureMe install --enable-fatal-warnings=no
Cyrus-SASL 2.1.22 #> export CPPFLAGS=-I/usr/include/gssapi #>./configure --prefix=/usr --libdir=/usr/lib \ --with-plugindir=/usr/lib/sasl2 --sysconfigdir=/etc \ --mandir=/usr/share/man --with-saslauthd=/var/run/sasl2 \ --with-pam=/usr/include/security --with-dblib=berkeley \ --with-bdb-libdir=/usr/lib --enable-login --enable-gssapi \ --enable-plain --enable-digest=no --enable-cram=no \ --without-des #> make && make install
529
1198.book Seite 530 Donnerstag, 5. Februar 2009 3:02 15
B
Kompilationsoptionen
pam_ldap / nss_ldap #>./configure #> make && make install
Postfix 2.5.1 #> export CCARGS="-DHAS_LDAP -DHAS_PCRE -DUSE_SASL_AUTH \ -I/usr/include/sasl -DMAX_DYNAMIC_MAPS -DUSE_TLS \ -Wno-comments" #> export AUXLIBS="-lldap -llber -lpcre -lsasl2 -lssl -lcrypto" #> export PIE=-pie #> make makefiles #> make #> sh postfix-install -non-interactive \ install_root=/ \ config_directory=/etc/postfix \ daemon_directory=/usr/lib/postfix \ command_directory=/usr/sbin \ queue_directory=/var/spool/postfix \ sendmail_path=/usr/sbin/sendmail \ newaliases_path=/usr/bin/newaliases \ mailq_path=/usr/bin/mailq \ manpage_directory=/usr/share/man \ setgid_group=mail \ readme_directory=/usr/share/doc/packages/postfix
Cyrus-Imapd 2.3.11 Gegebenenfalls zuvor das Tool makedepend-Buildfiles – zu finden im Unterordner makedepend/ – per ./configure, make und ./install-sh erzeugen und einbinden. #> export CFLAGS=" –fno-strict-aliasing \ -I/usr/include/krb5 –I/usr/lib/sasl2" #>./configure --prefix=/usr --mandir=/usr/share/man \ --with-cyrus-user=cyrus --with-cyrus-group=mail \ --with-cyrus-prefix=/usr/lib/cyrus \ --localstatedir=/var/lib --without-notify \ --with-sasl=/usr/lib --with-auth=unix \ --with-openssl=/usr/include/openssl \ --with-auth=unix --with-dbdir=/usr/lib \ --with-lock=fcntl \ --libdir=/usr/lib \ --with-perl=/usr/bin/perl \ --with-libwrap=/usr \ --with-gss_impl=auto --with-syslogfacility=DAEMON \ --enable-idled #> make depend && make && make install
530
1198.book Seite 531 Donnerstag, 5. Februar 2009 3:02 15
Kompilationsoptionen
Samba 3.2.3 Zusätzlich benötigte Pakete: cups-devel #> ./configure --prefix=/usr --sysconfdir=/etc/samba \ --infodir=/usr/share/info --mandir=/usr/share/man \ --with-piddir=/var/run --with-ldap --with-ads \ --with-krb5=base-dir --with-smbmount \ --with-libsmbclient --with-configdir=/etc/samba \ --with-logfilebase=/var/log/samba \ --with-lockdir=/var/lib/samba #> make && make install
Samba 4 pre-Alpha 6 Siehe Abschnitt 4.1.7, »Setup eines Standalone Samba 4 DC mit OpenLDAP-Backend« und 4.1.8, »Staffelflug« MIT-Kerberos 1.6.3 Zusätzlich benötigte Pakete: ncurses-devel/libncurses-dev, bison/yacc #> CFLAGS="-I/usr/include -fno-strict-aliasing" #> ./configure --prefix=/usr/lib/mit --sysconfdir=/etc \ --localstatedir=/var/lib/kerberos --infodir=/usr/share/info \ --mandir=/usr/share/man --libexecdir=/usr/lib/mit/sbin \ --includedir=/usr/include --enable-kdc-replay-cache \ --enable-dns-for-realm #> make && make install
pam_krb5 #> ./configure --libdir=/lib/security --mandir=/usr/share/man #> make && make check && make install
--prefix=/usr
\
Apache 2.2.8 #> ./configure --prefix=/usr --sysconfdir=/etc/apache2 \ --mandir=/usr/share/man \ --enable-so --with-mpm=prefork --libdir=/usr/lib/apache2 \ --includedir=/usr/include/apache2 \ --with-ssl=/usr/include/openssl --enable-mods-shared=all \ --enable-maintainer-mode --enable-ssl --disable-isapi \ --enable-echo --enable-ext-filter --enable-charset-lite \ --enable-file-cache --enable-logio --enable-dumpio \ --enable-case_filter --with-ldap \ --enable-ldap --enable-authnz-ldap --enable-cache \ --enable-disk-cache --enable-mem-cache --enable-suexec #> make && make install
531
B
1198.book Seite 532 Donnerstag, 5. Februar 2009 3:02 15
B
Kompilationsoptionen
Squid 3.0 export CFLAGS="-fPIE" export LDFLAGS="-pie" ./configure --prefix=/usr --sysconfdir=/etc/squid \ --bindir=/usr/sbin --sbindir=/usr/sbin \ --localstatedir=/var --libexecdir=/usr/sbin \ --datadir=/usr/share/squid --with-dl \ --enable-useragent-log --enable-auth="basic digest ntlm" \ --enable-basic-auth-helpers="LDAP MSNT NCSA PAM SMB YP \ getpwnam multi-domain-NTLM" \ --enable-ntlm-auth-helpers="SMB no_check" \ --enable-digest-auth-helpers="password" \ --enable-external-acl-helpers="ip_user ldap_group \ unix_group wbinfo_group" \ --enable-ntlm-fail-open --enable-referer-log \ --enable-arp-acl \ --enable-stacktraces --enable-delay-pools \ --enable-ssl --enable-cache-digests \ --enable-storeio="aufs,ufs,diskd,null" \ --enable-removal-policies="heap,lru" \ --enable-x-accelerator-vary make DEFAULT_SWAP_DIR=/var/cache/squid \ DEFAULT_LOG_PREFIX=/var/log/squid \ DEFAULT_PID_FILE=/var/run/squid.pid make install
532
1198.book Seite 533 Donnerstag, 5. Februar 2009 3:02 15
C
RFCs, Drafts und LDAPv3-Core-Spezifikationen
Alle nachstehend gelisteten RFCs und Drafts finden sich in den Beispieldaten zu diesem Buch, Download über http://www.galileocomputing.de/1801. Für die aktuellsten Versionen können die am Ende des Abschnitts genannten Quellen konsultiert werden.
C.1
RFCs
C.1.1
LDAP
Nummer
Autor/Editor
Datum
Status
RFC5020 LDAP 'entryDN' operational attribute
Bezeichnung
K. Zeilenga
August 2007
PROPOSED STANDARD
RFC4533 The Lightweight Directory Access Protocol (LDAP) Content Synchronization Operation
K. Zeilenga
June 2006
EXPERIMENTAL
RFC4532 Lightweight Directory Access Protocol (LDAP) "Who am I?" Operation
K. Zeilenga
June 2006
PROPOSED STANDARD
RFC4531 Lightweight Directory Access Pro- K. Zeilenga tocol (LDAP) Turn Operation
June 2006
EXPERIMENTAL
RFC4530 Lightweight Directory Access Protocol (LDAP) entryUUID Operational Attribute
K. Zeilenga
June 2006
PROPOSED STANDARD
RFC4529 Requesting Attributes by Object K. Zeilenga Class in the Lightweight Directory Access Protocol (LDAP)
June 2006
RFC4528 Lightweight Directory Access K. Zeilenga Protocol (LDAP) Assertion Control
June 2006
PROPOSED STANDARD
RFC4527 Lightweight Directory Access Protocol (LDAP) Read Entry Controls
K. Zeilenga
June 2006
PROPOSED STANDARD
RFC4526 Lightweight Directory Access Protocol (LDAP) Absolute True and False Filters
K. Zeilenga
June 2006
PROPOSED STANDARD
533
1198.book Seite 534 Donnerstag, 5. Februar 2009 3:02 15
C
RFCs, Drafts und LDAPv3-Core-Spezifikationen
Nummer
Autor/Editor
Datum
Status
RFC4525 Lightweight Directory Access Protocol (LDAP) Modify-Increment Extension
K. Zeilenga
June 2006
INFORMATIONAL
RFC4524 COSINE LDAP/X.500 Schema
K. Zeilenga
June 2006
PROPOSED STANDARD
RFC4523 Lightweight Directory Access K. Zeilenga Protocol (LDAP) Schema Definitions for X.509 Certificates
June 2006
PROPOSED STANDARD
RFC4522 Lightweight Directory Access Protocol (LDAP): The Binary Encoding Option
S. Legg
June 2006
PROPOSED STANDARD
RFC4521 Considerations for Lightweight Directory Access Protocol (LDAP) Extensions
K. Zeilenga
June 2006
BEST CURRENT PRACTICE
RFC4520 Internet Assigned Numbers Authority (IANA) Considerations for the Lightweight Directory Access Protocol (LDAP)
K. Zeilenga
June 2006
BEST CURRENT PRACTICE
RFC4519 Lightweight Directory Access Protocol (LDAP): Schema for User Applications
A. Sciberras
June 2006
PROPOSED STANDARD
RFC4518 Lightweight Directory Access K. Zeilenga Protocol (LDAP): Internationalized String Preparation
June 2006
PROPOSED STANDARD
RFC4517 Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules
S. Legg
June 2006
PROPOSED STANDARD
RFC4516 Lightweight Directory Access Protocol (LDAP): Uniform Resource Locator
M. Smith, T. Howes
June 2006
PROPOSED STANDARD
RRC4515 Lightweight Directory Access Protocol (LDAP): String Representation of Search Filters
M. Smith, T. Howes
June 2006
PROPOSED STANDARD
RFC4514 Lightweight Directory Access Pro- K. Zeilenga tocol (LDAP): String Representation of Distinguished Names
June 2006
PROPOSED STANDARD
RFC4513 Lightweight Directory Access Protocol (LDAP): Authentication Methods and Security Mechanisms
June 2006
PROPOSED STANDARD
534
Bezeichnung
R. Harrison
1198.book Seite 535 Donnerstag, 5. Februar 2009 3:02 15
RFCs
Nummer
Autor/Editor
Datum
Status
RFC4512 Lightweight Directory Access Protocol (LDAP): Directory Information Models
Bezeichnung
K. Zeilenga
June 2006
PROPOSED STANDARD
RFC4511 Lightweight Directory Access Protocol (LDAP): The Protocol
J. Sermersheim
June 2006
PROPOSED STANDARD
RFC4510 Lightweight Directory Access K. Zeilenga Protocol (LDAP): Technical Specification Road Map
June 2006
PROPOSED STANDARD
RFC4403 Lightweight Directory Access Protocol (LDAP): Schema for Universal Description, Discovery, and Integration version 3 (UDDIv3)
B. Bergeson, K. Boogert, V. Nanjundaswamy
February 2006
INFORMATIONAL
RFC4373 Lightweight Directory Access Protocol (LDAP) Bulk Update/ Replication Protocol (LBURP)
R. Harrison, J. Sermersheim
January 2006
INFORMATIONAL
RFC4370 Lightweight Directory Access R. Weltman Protocol (LDAP) Proxied Authorization Control
February 2006
PROPOSED STANDARD
RFC4013 SASLprep: Stringprep Profile for K. Zeilenga User Names and Passwords
February 2005
PROPOSED STANDARD
RFC3928 Lightweight Directory Access Protocol (LDAP) Client Update Protocol (LCUP)
October 2004
PROPOSED STANDARD
RFC3909 Lightweight Directory Access K. Zeilenga Protocol (LDAP) Cancel Operation
October 2004
PROPOSED STANDARD
RFC3876 Returning Matched Values with D. Chadwick, the Lightweight Directory S. Mullan Access Protocol version 3 (LDAPv3)
September 2004
PROPOSED STANDARD
R. Megginson, Ed., M. Smith, O. Natkovich, J. Parham
RFC3866 Language Tags and Ranges in the Lightweight Directory Access Protocol (LDAP)
K. Zeilenga, Ed. July 2004 PROPOSED STANDARD
RFC3829 Lightweight Directory Access Protocol (LDAP) Authorization Identity Request and Response Controls
R. Weltman, M. Smith, M. Wahl
July 2004 INFORMATIONAL
RFC3727 ASN.1 Module Definition for the LDAP and X.500 Component Matching Rules
S. Legg
February 2004
PROPOSED STANDARD
535
C.1
1198.book Seite 536 Donnerstag, 5. Februar 2009 3:02 15
C
RFCs, Drafts und LDAPv3-Core-Spezifikationen
Nummer
Autor/Editor
Datum
Status
RFC3712 Lightweight Directory Access Protocol (LDAP): Schema for Printer Services
P. Fleming, I. McDonald
February 2004
INFORMATIONAL
RFC3703 Policy Core Lightweight Directory Access Protocol (LDAP) Schema
J. Strassner, B. Moore, R. Moats, E. Ellesson
February 2004
PROPOSED STANDARD
RFC3698 Lightweight Directory Access Protocol (LDAP): Additional Matching Rules
K. Zeilenga, Ed. February 2004
PROPOSED STANDARD
RFC3687 Lightweight Directory Access Protocol (LDAP) and X.500 Component Matching Rules
S. Legg
February 2004
PROPOSED STANDARD
RFC3673 Lightweight Directory Access Protocol version 3 (LDAPv3): All Operational Attributes
K. Zeilenga
December 2003
PROPOSED STANDARD
RFC3672 Subentries in the Lightweight Directory Access Protocol (LDAP)
K. Zeilenga, S. Legg
December 2003
PROPOSED STANDARD
RFC3671 Collective Attributes in the Lightweight Directory Access Protocol (LDAP)
K. Zeilenga
December 2003
PROPOSED STANDARD
RFC3663 Domain Administrative Data in A. Newton Lightweight Directory Access Protocol (LDAP)
December 2003
EXPERIMENTAL
RFC3296 Named Subordinate References K. Zeilenga in Lightweight Directory Access Protocol (LDAP) Directories
July 2002 PROPOSED STANDARD
RFC3112 LDAP Authentication Password K. Zeilenga Schema
May 2001 INFORMATIONAL
RFC3088 OpenLDAP Root Service An ex- K. Zeilenga perimental LDAP referral service
April 2001
EXPERIMENTAL
RFC3062 LDAP Password Modify Extended Operation
K. Zeilenga
February 2001
PROPOSED STANDARD
RFC3045 Storing Vendor Information in the LDAP root DSE
M. Meredith
January 2001
INFORMATIONAL
RFC2926 Conversion of LDAP Schemas to J. Kempf, and from SLP Templates R. Moats, P. St. Pierre
September 2000
INFORMATIONAL
RFC2891 LDAP Control Extension for Ser- T. Howes, ver Side Sorting of Search M. Wahl, Results A. Anantha
August 2000
PROPOSED STANDARD
536
Bezeichnung
1198.book Seite 537 Donnerstag, 5. Februar 2009 3:02 15
RFCs
Nummer
Bezeichnung
Autor/Editor
Datum
Status
RFC2849 The LDAP Data Interchange G. Good Format (LDIF) – Technical Specification
June 2000 PROPOSED STANDARD
RFC2798 Definition of the inetOrgPerson M. Smith LDAP Object Class
April 2000
INFORMATIONAL
RFC2714 Schema for Representing V. Ryan, R. Lee, October CORBA Object References in an S. Seligman 1999 LDAP Directory
INFORMATIONAL
RFC2713 Schema for Representing Java(tm) Objects in an LDAP Directory
V. Ryan, S. Seligman, R. Lee
October 1999
INFORMATIONAL
RFC2696 LDAP Control Extension for Simple Paged Results Manipulation
C. Weider, A. Herron, A. Anantha, T. Howes
September 1999
INFORMATIONAL
RFC2649 An LDAP Control and Schema B. Greenblatt, for Holding Operation Signatu- P. Richard res
August 99 EXPERIMENTAL
RFC2589 Lightweight Directory Access Protocol (v3): Extensions for Dynamic Directory Services
May 1999 PROPOSED STANDARD
Y. Yaacovi, M. Wahl, T. Genovese
RFC2377 Naming Plan for Internet Direc- A. Grimstad, tory-Enabled Applications R. Huber, S. Sataluri, M. Wahl
September 1998
INFORMATIONAL
RFC2307 An Approach for Using LDAP as L. Howard a Network Information Service
March 1998
EXPERIMENTAL
RFC2294 Representing the O/R Address S. Kille hierarchy in the X.500 Directory Information Tree
March 1998
PROPOSED STANDARD
RFC2293 Representing Tables and Subtrees in the X.500 Directory
March 1998
PROPOSED STANDARD
RFC2247 Using Domains in LDAP/X.500 S. Kille, Distinguished Names M. Wahl, A. Grimstad, R. Huber, S. Sataluri
January 1998
PROPOSED STANDARD
RFC2079 Definition of an X.500 Attribute M. Smith Type and an Object Class to Hold Uniform Resource Identifiers (URIs)
January 1997
PROPOSED STANDARD
S. Kille
537
C.1
1198.book Seite 538 Donnerstag, 5. Februar 2009 3:02 15
C
RFCs, Drafts und LDAPv3-Core-Spezifikationen
C.1.2
SASL
Nummer
Bezeichnung
Autor/Editor
Datum
Status
RFC4422
Simple Authentication and Security Layer (SASL)
A. Melnikov, K.Zeilenga
June 2006
PROPOSED STANDARD
RFC4013
SASLprep: Stringprep Profile K. Zeilenga for User Names and Passwords
February 2005
PROPOSED STANDARD
RFC3163
ISO/IEC 9798-3 Authentication SASL Mechanism
August 01 EXPERIMENTAL
RFC2831
Using Digest Authentication as P. Leach, a SASL Mechanism C. Newman
May 2000 PROPOSED STANDARD
RFC2808
The SecurID(r) SASL Mechanism
M. Nystrom
April 00
INFORMATIONAL
RFC2554
SMTP Service Extension for Authentication
J. Myers
March 1999
PROPOSED STANDARD
RFC2444
The One-Time-Password SASL C. Newman Mechanism
October 1998
PROPOSED STANDARD
RFC2245
Anonymous SASL Mechanism
C. Newman
November 97
PROPOSED STANDARD
Autor/Editor
Datum
Status
RFC5246 The TLS Protocol, V 1.2
T.Dierks, E.Rescorla
August 2008
PROPOSED STANDARD
RFC5216 PPP EAP TLS Authentication Protocol
B. Aboba, D. Simon, R.Hurst
March 2008
PROPOSED STANDARD
C.1.3
R. Zuccherato, M. Nystrom
TLS
Nummer
Bezeichnung
RFC4934 Extensible Provisioning Proto- S. Hollenbeck col (EPP) Transport Over TCP
May 2007 PROPOSED STANDARD
RFC4681 TLS User Mapping Extension
S.Santesson, A. Medvinsky, J.Ball
October 2006
PRPOSED STANDARD
RFC4680 TLS Handshake Message for Supplemental Data
S.Santesson
September 2006
PRPOSED STANDARD
RFC4366 Transport Layer Security (TLS) S. Blake-Wilson, April Extensions M. Nystrom, 2006 D. Hopwood, J. Mikkelsen, T. Wright
538
PROPOSED STANDARD
1198.book Seite 539 Donnerstag, 5. Februar 2009 3:02 15
RFCs
Nummer
Autor/Editor
Datum
Status
RFC4346 The TLS Protocol, V 1.1
Bezeichnung
T.Dierks, E.Rescorla
April 2006
OBSOLETE by RFC5246
RFC4279 Pre-Shared Key Ciphersuites for Transport Layer Security (TLS)
P. Eronen, Ed., H. Tschofenig, Ed.
December 2005
PROPOSED STANDARD
RFC4261 Common Open Policy Service J. Walker, A. (COPS) Over Transport Layer Kulkarni, Ed. Security (TLS)
December 2005
PROPOSED STANDARD
RFC4217 Securing FTP with TLS
October 2005
PROPOSED STANDARD
RFC4169 Hypertext Transfer Protocol V. Torvinen, (HTTP) Digest Authentication J. Arkko, Using Authentication and Key M. Naslund Agreement (AKA) Version-2
November 2005
INFORMATIONAL
RFC4162 Addition of SEED Cipher Sui- H.J. Lee, J. tes to Transport Layer Security H. Yoon, (TLS) J.I. Lee
August 2005
PROPOSED STANDARD
RFC4132 Addition of Camellia Cipher S. Moriai, Suites to Transport Layer Secu- A. Kato, rity (TLS) M. Kanda
July 2005 PROPOSED STANDARD
RFC3943 Transport Layer Security (TLS) R. Friend Protocol Compression Using Lempel-Ziv-Stac (LZS)
November 2004
RFC3749 Transport Layer Security Protocol Compression Methods
S. Hollenbeck
May 2004 PROPOSED STANDARD
RFC3436 Transport Layer Security over Stream Control Transmission Protocol
A. Jungmaier, E. Rescorla, M. Tuexen
December 2002
PROPOSED STANDARD
RFC3207 SMTP Service Extension for Secure SMTP over Transport Layer Security
P. Hoffman
February 2002
PROPOSED STANDARD
RFC2818 HTTP Over TLS
E. Rescorla
May 2000 INFORMATIONAL
RFC2817 Upgrading to TLS Within HTTP/1.1
R. Khare, S. Lawrence
May 2000 PROPOSED STANDARD
P. FordHutchinson
INFORMATIONAL
RFC2712 Addition of Kerberos Cipher A. Medvinsky, Suites to Transport Layer Secu- M. Hur rity (TLS)
October 1999
PROPOSED STANDARD
RFC2595 Using TLS with IMAP, POP3 and ACAP
June 1999
PROPOSED STANDARD
C. Newman
539
C.1
1198.book Seite 540 Donnerstag, 5. Februar 2009 3:02 15
C
RFCs, Drafts und LDAPv3-Core-Spezifikationen
C.1.4
KERBEROS
Nummer
Bezeichnung
Autor/Editor
Datum
RFC5021
Extended Kerberos Version 5 KeyDistribution Center (KDC) Exchanges over TCP
S.Josefsson
August 2007 PROPOSED STANDARD
RFC4537
Kerberos Cryptosystem Nego- L. Zhu, P.Leach June 2006 tiation Extension K. Jaganathan
PROPOSED STANDARD
RFC4121
The Kerberos Version 5 Gene- L. Zhu, July 2005 ric Security Service ApplicaK. Jaganathan, tion Program Interface (GSS- S. Hartman API) Mechanism: Version 2
PROPOSED STANDARD
RFC4120
The Kerberos Network Authentication Service (V5)
July 2005
PROPOSED STANDARD
RFC3962
Advanced Encryption K. Raeburn Standard (AES) Encryption for Kerberos 5
February 2005
PROPOSED STANDARD
RFC3961
Encryption and Checksum Specifications for Kerberos 5
K. Raeburn
February 2005
PROPOSED STANDARD
RFC3244
Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols
M. Swift, J. Trostle, J. Brezak
February 2002
INFORMATIONAL
RFC2942
Telnet Authentication: Kerbe- T. Ts'o ros Version 5
September 00
PROPOSED STANDARD
RFC2712
Addition of Kerberos Cipher Suites to Transport Layer Security (TLS)
October 1999
PROPOSED STANDARD
RFC2623
NFS Version 2 and Version 3 M. Eisler Security Issues and the NFS Protocol's Use of RPCSEC_GSS and Kerberos V5
June 1999
PROPOSED STANDARD
RFC1964
The Kerberos Version 5 GSSAPI Mechanism
June 1996
PROPOSED STANDARD
RFC1411
Telnet Authentication: Kerbe- D. Borman, Ed. January 1993 EXPERIMENros Version 4 TAL
540
C. Neuman, T. Yu, S. Hartman, K. Raeburn
A. Medvinsky, M. Hur
J. Linn
Status
1198.book Seite 541 Donnerstag, 5. Februar 2009 3:02 15
LDAP-Drafts (Auszüge)
C.2
LDAP-Drafts (Auszüge)
LDAP Transactions
LDAP: Dynamic Groups for LDAPv3
LDAP Session Tracking Control
The LDAP Don't Use Copy Control
The LDAP No-Op Control
The LDAP Relax Rules Control
The LDAP Change Sequence Number
Distributed Procedures for LDAP Operations Password Policy for LDAP Directories
A Configuration Schema for LDAP Based Directory User Agents
Change Sequence Numbers for LDAP
LDAP: Access Control Administration
LDAP: Basic and Simplified Access Control LDAP: Directory Administrative Model
LDAP: Transfer Encoding Options
Subordinate Subtree Search Scope for LDAP LDAP Control to Specify Chaining Behavior The C LDAP Application Program Interface LDAP Control for a Duplicate Entry Repre- sentation of Search Results Discovering LDAP Services with DNS
LDAP Extensions for Scrolling View Brow- sing of Search Results LDAP Schema for Intranet Mail Routing
Access Control Model for LDAPv3
LDAP: Multi Master Replication Considered (draft-zeilenga-ldup-harmful-02.txt) harmful
541
C.2
1198.book Seite 542 Donnerstag, 5. Februar 2009 3:02 15
C
RFCs, Drafts und LDAPv3-Core-Spezifikationen
C.3
LDAPv3 Core – Specifications
왘 RFC 4510 – LDAP: Technical Specification Road Map Technische Spezifikationen der LDAPv3-Protokolldefinition. Dieser RFC definiert LDAPv3 als Protokoll, das Zugriff auf X.500-Verzeichnisse ohne die Verwendung von DAP (Directory Access Protocol) ermöglicht. Über das Protokoll sollen Browser- und Management-Applikationen lesenden und schreibenden Zugriff auf Verzeichnisse erhalten. Bei Interaktion von LDAPv3 mit einem Directory-Service, der das X.500-Protokoll »spricht«, soll LDAPv3 als Ergänzung zu dem X.500 DAP zu verstehen sein. Alle Protokollelemente von LDAPv2 werden unterstützt. Nahezu alle Protokoll-Datenelemente sollen als String encodiert werden können. Ergänzende Informationen hierzu sind in den folgenden RFC’s hinterlegt: 왘 LDAP: The Protocol [RFC4511] 왘 LDAP: Directory Information Models [RFC4512] 왘 LDAP: Authentication Methods and Security Mechanisms [RFC4513] 왘 LDAP: String Representation of Distinguished Names [RFC4514] 왘 LDAP: String Representation of Search Filters [RFC4515] 왘 LDAP: Uniform Resource Locator [RFC4516] 왘 LDAP: Syntaxes and Matching Rules [RFC4517] 왘 LDAP: Internationalized String Preparation [RFC4518] 왘 LDAP: Schema for User Applications [RFC4519] Dieses RFC-Paket ersetzt etliche der »Core«-Definitions, die ursprünglich in den RFC 2251-2256, 2829-2831 definiert waren (siehe unten): 왘 RFC 2252 – LDAPv3 Attribute Syntax Definitions Kurzinfo: LDAPv3 verlangt, dass die Felder der Attributwerte in den Protokollelementen als Oktett-Strings vorliegen. Dieser RFC definiert ein Set von Attributsyntaxen für LDAPv3, ebenso wie die Matching Rules, mit deren Hilfe Vergleichsoperationen durchgeführt werden können. 왘 RFC 2253 – UTF-8 String Representation of Distinguished Names Kurzinfo: X.500-Verzeichnisdienste verwenden DNs (Distinguished Names) als primäre Schlüssel, um Einträge in dem Verzeichnis zu verwalten. Diese DNs werden in X.500-Verzeichnissen per ASN.1 encodiert. Dieser RFC definiert, wie LDAPv3 diese DNs als Strings im UTF-8-Format encodiert.
542
1198.book Seite 543 Donnerstag, 5. Februar 2009 3:02 15
LDAPv3 Core – Specifications
왘 RFC 2254 – The String Representation of LDAP Search Filters Kurzinfo: In diesem RFC wird definiert, wie LDAP-Suchfilter, die an einen LDAP-Server geschickt werden, in menschenlesbarer Form abgebildet werden können. Dadurch können sie direkt in der Form von LDAP-URLs Verwendung finden, ebenso wie sie innerhalb von Applikationen eingesetzt werden können. 왘 RFC 2255 – The LDAP URL Format Kurzinfo: Dieser RFC beschreibt das »LDAP Uniform Resource Locator«-Format. Es definiert, wie Suchanfragen an den LDAP-Server in entsprechender Form als LDAP-URLs darzustellen sind und beschreibt ebenfalls eine Erweiterungsmöglichkeit für LDAP-URLs, so dass zukünftige Erweiterungen im LDAPv3-Protokoll mit einfließen können. 왘 RFC 2256 – A Summary of the X.500(96) User Schema for use with LDAPv3 Kurzinfo: Dieser RFC liefert eine Auflistung von Attribut-Typen und Objektklassen, die ursprünglich von der ISO und ITU-T für das X.500-Protokoll definiert wurden. Dabei bezieht es sich speziell auf die Attributtypen und Objektklassen, die in Verbindung mit Directory-Clients benötigt werden. Vereinfacht ausgedrückt werden Attribute und Objektklassen definiert, die in Verbindung mit LDAPv3 verwendet werden sollen. Sonstige Quellen zu diesem Anhang 왘 http://www.ietf.org/internet-drafts/ 왘 http://tools.ietf.org/html/ 왘 http://www.rfc-editor.org/
543
C.3
1198.book Seite 544 Donnerstag, 5. Februar 2009 3:02 15
1198.book Seite 545 Donnerstag, 5. Februar 2009 3:02 15
D
Manpages nach Sektionen und Glossar
Nachstehend sind die wichtigsten Manpages aufgelistet, unterteilt nach Sektionen bzw. Applikationen. Es sollten auch immer die Querverweise am Ende der jeweiligen Manpage berücksichtigt werden (Abschnitt: »SEE ALSO«), die auf korrespondierende Manpages verweisen. Die Namen der Tools können von Distribution zu Distribution gegebenenfalls etwas variieren. Ein zusätzliches Hilfsmittel kann in dem Fall der apropos Befehl sein.
D.1
OpenLDAP
Server-Konfiguration und LDIF
slapd (8)
stand alone LDAP Daemon
slapd.conf (5)
configuration file for slapd
slapd-config (5)
configuration backend to slapd
slapd.access (5)
access configuration for slapd
slapd.plugin (5)
plugin configuration for slapd
LDIF (5)
LDAP Data Interchange Format
Client-Konfiguration
ldap.conf (5)
ldap configuration file
.ldaprc (5) [ldap.conf]
ldap configuration file
Backends slapd-relay (5)
relay backend to slapd
slapd-tcl (5)
Tcl backend to slapd
slapd-bdb (5)
Berkeley DB backends to slapd
slapd-null (5)
Null backend to slapd
slapd-meta (5)
metadirectory backend
slapd-dnssrv (5)
DNS SRV referral backend to slapd
slapd-ldif (5)
LDIF backend to slapd
slapd-passwd (5)
/etc/passwd backend to slapd
slapd-monitor (5)
Monitor backend to slapd
slapd-perl (5)
Perl backend to slapd
slapd-ldap (5)
LDAP backend to slapd
slapd-hdb (5)
Berkeley DB backends to slapd
545
1198.book Seite 546 Donnerstag, 5. Februar 2009 3:02 15
D
Manpages nach Sektionen und Glossar
Backends slapd-sql (5)
SQL backend to slapd
slapd-shell (5)
Shell backend to slapd
Overlays slapo-accesslog (5)
Access Logging overlay to slapd
slapo-auditlog (5)
Audit Logging overlay to slapd
slapo-chain (5)
chain overlay to slapd
slapo-collect (5)
Collective attributes overlay to slapd
slapo-constraint (5)
Attribute Constraint Overlay to slapd
slapo-dds (5)
Dynamic Directory Services overlay to slapd
slapo-dyngroup (5)
Dynamic Group overlay to slapd
slapo-dynlist (5)
Dynamic List overlay to slapd
slapo-memberof (5)
Reverse Group Membership overlay to slapd
slapo-pcache (5)
proxycache overlay to slapd
slapo-ppolicy (5)
Password Policy overlay to slapd
slapo-refint (5)
Referential Integrity overlay to slapd
slapo-retcode (5)
return code overlay to slapd
slapo-rwm (5)
rewrite/remap overlay to slapd
slapo-syncprov (5)
Sync Provider overlay to slapd
slapo-translucent (5)
Translucent Proxy overlay to slapd
slapo-unique (5)
Attribute Uniqueness overlay to slapd
slapo-valsort (5)
Value Sorting overlay to slapd
ldap*-tools ldapadd (1)
LDAP modify entry and LDAP add entry tools
ldapcompare (1)
LDAP compare tool
ldapdelete (1)
LDAP delete entry tool
ldapmodify (1)
LDAP modify entry and LDAP add entry tools
ldapmodrdn (1)
LDAP rename entry tool
ldappasswd (1)
change the password of an LDAP entry
ldapsearch (1)
LDAP search tool
ldapwhoami (1)
LDAP who am i? tool
slap*-tools slapacl (8)
Check access to a list of attributes
slapadd (8)
Add entries to a SLAPD database
546
1198.book Seite 547 Donnerstag, 5. Februar 2009 3:02 15
PAM/NSS
slap*-tools slapauth (8)
Check a list of string-represented IDs for LDAP authc/authz
slapcat (8)
SLAPD database to LDIF utility
slapdn (8)
Check a list of string-represented LDAP DNs based on schema Syntax
slapindex (8)
Reindex entries in a SLAPD database
slappasswd (8)
OpenLDAP password utility
slaptest (8)
Check the suitability of the OpenLDAP slapd.conf file
D.2
PAM/NSS
pam_ldap (5)
LDAP pluggable authentication module
nss_ldap/libnss-ldap.conf (5) Configuration file for LDAP NSS library nsswitch.conf (5)
Name Service Switch configuration file
pam_unix2 (8)
Standard PAM module for traditional password authentication
pam_krb5 (8)
Kerberos 5 authentication
pam (7/8)
Pluggable Authentication Modules for Linux
pam_access (8)
PAM module for logdaemon style login access control
pam_cracklib (8)
PAM module to check passwords against dictionary words
pam_debug (8)
PAM module to debug the PAM stack
pam_deny (8)
The locking-out PAM module
pam_echo (8)
PAM module for printing text messages
pam_env (8)
PAM module to set/unset environment variables
pam_exec (8)
PAM module which calls an external command
pam_filter (8)
PAM filter module
pam_ftp (8)
PAM module for anonymous access module
pam_group (8)
PAM module for group access
pam_issue (8)
PAM module to add issue file to user prompt
pam_keyinit (8)
Kernel session keyring initialiser module
pam_lastlog (8)
PAM module to display date of last login
pam_limits (8)
PAM module to limit resources
pam_make (8)
PAM module which calls make
pam_mkhomedir (8)
PAM module to create users home directory
pam_namespace (8)
PAM module for configuring namespace for a session
pam_permit (8)
the promiscuous module
pam_pwcheck (8)
PAM module for password strength checking
547
D.2
1198.book Seite 548 Donnerstag, 5. Februar 2009 3:02 15
D
Manpages nach Sektionen und Glossar
pam_resmgr (8)
PAM module for resource manager
pam_rhosts (8)
the rhosts PAM module
pam_rpasswd (8)
PAM module to change remote password
pam_shells (8)
PAM module to check for valid login shell
pam_tally (8)
the login counter (tallying) module
pam_time (8)
PAM module for time control access
pam_umask (8)
PAM module to set the file mode creation mask
pam_unix (8)
Module for traditional password authentication
pam_unix2 (8)
Standard PAM module for traditional password authentic
pam_userdb (8)
PAM module to authenticate against a db database
pam_warn (8)
PAM module which logs all PAM items if called
pam_xauth (8)
PAM module to forward xauth keys between users
D.3
OpenSSL
openssl (1ssl)
OpenSSL command line tool
s_server (1ssl)
SSL/TLS server program
s_client (1ssl)
SSL/TLS client program
crypto (3ssl)
OpenSSL cryptographic library
config (5ssl)
OpenSSL CONF library configuration files
version (1ssl)
print OpenSSL version information
ssl (3ssl)
OpenSSL SSL/TLS library
CA.pl (1ssl)
friendlier interface for OpenSSL certificate programs
ciphers (1ssl)
SSL cipher display and cipher list tool
config (5ssl)
OpenSSL CONF library configuration files
D.4
SASL
sasl (3)
SASL authentication library
saslauthd (8)
sasl authentication server
testsaslauthd (8)
a test tool for saslauthd
(sasl)pluginviewer (8)
list loadable SASL plugins and their properties
548
1198.book Seite 549 Donnerstag, 5. Februar 2009 3:02 15
Samba
D.5
Samba
smbd (8)
server to provide SMB/CIFS services to clients
nmbd (8)
NetBIOS name server
testparm (1)
check an smb.conf configuration file for internal correctness
smb.conf (5)
the configuration file for the Samba suite
idmap_ad (8)
Samba's idmap_ad Backend for Winbind
idmap_ldap (8)
Samba's idmap_ldap Backend for Winbind
idmap_nss (8)
Samba's idmap_nss Backend for Winbind
idmap_rid (8)
Samba's idmap_rid Backend for Winbind
idmap_tdb (8)
Samba's idmap_tdb Backend for Winbind
lmhosts (5)
the Samba NetBIOS hosts file
net (8)
Tool for administration of Samba and remote CIFS servers
pdbedit (8)
manage the SAM database (Database of Samba Users)
samba (7)
A Windows SMB/CIFS fileserver for UNIX
smbpasswd (5)
the Samba encrypted password file
smbpasswd (8)
change a user's SMB password
smbstatus (1)
report on current Samba connections
nmbstatus (1)
lists NMB node status of a UDP network
swat (8)
Samba Web Administration Tool
tdbbackup (8)
backup and validation-tool for samba .tdb files
libsmbclient (7)
an extension library for browsers that can be used as a generic browsing API
smbcacls (1)
Set or get ACLs on an NT file or directory names
smbclient (1)
ftp-like client to access SMB/CIFS resources on servers
smbcontrol (1)
send messages to smbd, nmbd or winbindd processes
smbcquotas (1)
Set or get QUOTAs of NTFS 5 shares
smbget (1)
wget-like utility for download files over SMB
smbgetrc (5)
configuration file for smbget
smbspool (8)
send a print file to an SMB printer
smbtar (1)
shell script for backup SMB/CIFS shares to UNIX tape drives
smbtree (1)
A text based smb network browser
nmblookup (1)
NetBIOS over TCP/IP client
cupsaddsmb (8)
export printers to samba for windows clients
eventlogadm (8)
push records into the Samba event log store
549
D.5
1198.book Seite 550 Donnerstag, 5. Februar 2009 3:02 15
D
Manpages nach Sektionen und Glossar
VFS-Objects vfs_audit (8)
record selected Samba VFS operations in the system log
vfs_extd_audit (8)
record selected Samba VFS operations
vfs_full_audit (8)
record Samba VFS operations in the system log
vfs_gpfs (8)
gpfs specific samba extensions like acls and prealloc
vfs_readonly (8)
make a Samba share read only for a specified time period
vfs_recycle (8)
Samba VFS recycle bin
vfs_shadow_copy (8)
make a Samba share RO for a specified time period
D.6
Heartbeat
apphbd (8)
Application Heartbeat Monitor for High-Availability Linux
cibadmin (8)
read, modify, or administer heartbeat Cluster Information Base
cl_status (1)
Check Status of the High-Availability Linux Subsystem
heartbeat (8)
Heartbeat subsystem for High-Availability Linux
crm_resource (8)
Interact with the Cluster Resource Manager
stonith (8)
extensible interface for remotely power down a cluster node
hb_addnode (1)
sends a message to the cluster to add new nodes
hb_delnode (1)
sends a message to the cluster to delete nodes
hb_standby (1)
issues a failover from one node to another, if available
hb_takeover (1)
issues a command to takeover resources from another node, if available
D.7
MIT-Kerberos
.k5login (5)
Kerberos V5 acl file for host access
kadmin (8)
Kerberos V5 database administration program
kadmin.local (8)
Kerberos V5 database administration program
kdb5_ldap_util (8)
Kerberos Configuration Utility
kdb5_util (8)
Kerberos database maintenance utility
kdc.conf (5)
Kerberos V5 KDC configuration file
kdestroy (1)
destroy Kerberos tickets
kerberos (1)
introduction to the Kerberos system
kinit (1)
obtain and cache Kerberos ticket-granting ticket
klist (1)
list cached Kerberos tickets
kpasswd (1)
change a user's Kerberos password
kprop (8)
propagate a Kerberos V5 principal database to a slave server
550
1198.book Seite 551 Donnerstag, 5. Februar 2009 3:02 15
Postfix
kpropd (8)
Kerberos V5 slave KDC update server
krb.equiv (5)
Kerberos equivalences
krb5-config (1)
tool for linking against MIT Kerberos libraries
krb5.conf (5)
Kerberos configuration file
krb524init (1)
Obtain Kerberos V4 tickets from Kerberos V5 tickets
krb5kdc (8)
Kerberos V5 KDC
ktutil (8)
Kerberos keytab file maintenance utility
kvno (1)
print key version numbers of Kerberos principals
login.krb5 (8)
kerberos enhanced login program
pam_krb5 (5)
Kerberos 5 authentication
pam_krb5 (8)
Kerberos 5 authentication
sclient (1)
sample Kerberos version 5 client
sserver (8)
sample Kerberos version 5 server
v4rcp (1)
back end for Kerberos V4 rcp
D.8
Postfix
access (5)
Postfix SMTP server access table
aliases (5)
Postfix local alias database format
anvil (8)
Postfix session count and request rate control
body_checks (5)
Postfix built-in content inspection
bounce (5)
Postfix bounce message template format
bounce (8)
Postfix delivery status reports
canonical (5)
Postfix canonical table format
cidr_table (5)
format of Postfix CIDR tables
cleanup (8)
canonicalize and enqueue Postfix message
defer (8)
Postfix delivery status reports
discard (8)
Postfix discard mail delivery agent
error (8)
Postfix error/retry mail delivery agent
flush (8)
Postfix fast flush server
forward (5)
Postfix local alias database format
generic (5)
Postfix generic table format
header_checks (5)
Postfix built-in content inspection
ldap_table (5)
Postfix LDAP client configuration
lmtp (8)
Postfix SMTP+LMTP client
local (8)
Postfix local mail delivery
mailq (1)
Postfix to Sendmail compatibility interface
master (5)
Postfix master process configuration file format
master (8)
Postfix master process
551
D.8
1198.book Seite 552 Donnerstag, 5. Februar 2009 3:02 15
D
Manpages nach Sektionen und Glossar
mysql_table (5)
Postfix MySQL client configuration
newaliases (1)
Postfix to Sendmail compatibility interface
nisplus_table (5)
Postfix NIS+ client
oqmgr (8)
old Postfix queue manager
pcre_table (5)
format of Postfix PCRE tables
pgsql_table (5)
Postfix PostgreSQL client configuration
pickup (8)
Postfix local mail pickup
pipe (8)
Postfix delivery to external command
postalias (1)
Postfix alias database maintenance
postcat (1)
show Postfix queue file contents
postconf (1)
Postfix configuration utility
postconf (5)
Postfix configuration parameters
postdrop (1)
Postfix mail posting utility
postfix (1)
Postfix control program
postkick (1)
kick a Postfix service
postlog (1)
Postfix-compatible logging utility
postmap (1)
Postfix lookup table management
postqueue (1)
Postfix queue control
postsuper (1)
Postfix superintendent
proxymap (8)
Postfix lookup table proxy server
qmgr (8)
Postfix queue manager
qmqpd (8)
Postfix QMQP server
regexp_table (5)
format of Postfix regular expression tables
relocated (5)
Postfix relocated table format
scache (8)
Postfix shared connection cache server
sendmail (1)
Postfix to Sendmail compatibility interface
showq (8)
list the Postfix mail queue
smtp (8)
Postfix SMTP+LMTP client
smtpd (8)
Postfix SMTP server
spawn (8)
Postfix external command spawner
tcp_table (5)
Postfix client/server table lookup protocol
tlsmgr (8)
Postfix TLS session cache and PRNG manager
trace (8)
Postfix delivery status reports
transport (5)
Postfix transport table format
trivial-rewrite (8)
Postfix address rewriting and resolving daemon
verify (8)
Postfix address verification server
virtual (5)
Postfix virtual alias table format
virtual (8)
Postfix virtual domain mail delivery agent
552
1198.book Seite 553 Donnerstag, 5. Februar 2009 3:02 15
Apache
D.9
Cyrus-Imap
imtest (1)
interactive IMAP test program
imapd (8)
IMAP server process
imapd.conf (5)
IMAP configuration file
cyradm (1)
Cyrus administration shell
cyrus.conf (5)
Cyrus configuration file
deliver (8)
deliver mail to an IMAP mailbox
ipurge (8)
delete mail from IMAP mailbox based on age or size
syncnews (8)
synchronize IMAP news mailboxes with active file
chk_cyrus (8)
perform a consistency check of the cyrus mailstore
ctl_cyrusdb (8)
perform operations common to all Cyrus databases
cvt_cyrusdb (8)
convert a database file between cyrus database formats
cyr_dbtool (8)
manage Cyrus databases
cyrus_fetchnews (8)
retrieve new articles from peer and feed to Cyrus
cyrus_idled (8)
provide near real-time updates for IMAP IDLE
cyrus_master (8)
master Cyrus process
mbexamine (8)
examine a cyrus-format mailbox
notifyd (8)
Cyrus notification server
sync_client (8)
client side of the synchronization (replication) engine
sync_server (8)
server side of the synchronization (replication) engine
D.10 Apache ab2 (8)
Apache HTTP server benchmarking tool
apachectl2 (8)
Apache HTTP Server Control Interface
apache2 / httpd2 (8)
Apache Hypertext Transfer Protocol Server
apxs2 (8)
APache eXtenSion tool
rotatelogs2 (8)
Piped logging program to rotate Apache logs
logresolve2 (8)
Resolve IP-addresses to hostnames in Apache log files
htpasswd2 (1)
manage user files for basic authentication
htdigest (1)
manage user files for digest authentication
553
D.10
1198.book Seite 554 Donnerstag, 5. Februar 2009 3:02 15
D
Manpages nach Sektionen und Glossar
D.11
Squid
squid (8)
proxy caching server
squid (8)
proxy caching server
squid_db_auth (8)
Database auth helper for Squid
squid_ldap_auth (8)
Squid LDAP authentication helper
squid_ldap_group (8)
Squid LDAP external acl group helper
squid_radius_auth (8)
Squid RADIUS authentication helper
squid_session (8)
Squid session tracking external acl group helper
squid_unix_group (8)
Squid UNIX Group external_acl helper
cachemgr.cgi (8)
squid HTTP proxy manager interface
ncsa_auth (8)
NCSA httpd-style password file authentication helper for Squid
D.12 Glossar ASN.1
ITU-T's »Abstract Syntax Notation One«
BaseDN
Wurzel des DIT oder Naming Context (NC)
CN
Abkürzung des Attributtyps »Common Name«
CSN
Change Sequence Number (Sequenznummer der letzten Änderung)
ContextCSN
CSN des Naming Context eines LDAP-Servers
DAP
Directory Access Protocol
Delta-Syncrepl
Spezielle Variante der LDAP Sync Replication
DES
Data Encryption Standard
DIT
Directory Information Tree (alternativ: Naming Context)
DN
Distinguished Name
DSA
Directory Service Agent
DSE
DSA spezifischer Entry
Entry
Knoten oder Blatt im DIT
EntryCSN
CSN eines einzelnen Entries im DIT eines LDAP-Servers
EXTERNAL
SASLMech zur Authentifizierung via TLS
GSSAPI
SASLMech zur Authentifizierung via Kerberos
IETF
Internet Engineering Task Force
ITU
International Telecommunication Union
IMAP
Internet Messaging Access Protocol
Kerberos
Ticketbasierte Authentifizierung
554
1198.book Seite 555 Donnerstag, 5. Februar 2009 3:02 15
Glossar
MD5
kryptographischer Hash-Algorithmus Message Digest Nummer 5
POP3
Post Office Protocol Version 3
LAN
Local Area Network
LDAP
Lightweight Directory Access Protocol
LDIF
LDAP Data Interchange Format
Matching Rule
Regel die festlegt, wie Attribute verglichen werden
MIT
Massachusetts Institute of Technology
NC
Naming Context
NDS
Netware Directory Service, Nachfolger ist eDirectory
NIS
Network Information Service
NSS
Name Service Switch
OID
Object IDentifier (eindeutiger Identifikator für eine Schemadefinition)
RDN
Relative Distinguished Name (Teil eines DNs)
Referral
Verweis in Form einer URL auf einen anderen LDAP-Server
RFC
Request for Comment, Dokumentensammlung der IETF zur Beschreibung allgemeingültiger Regeln
RootDSE
Wurzel eines DIT
RSA
Public-Key-Verfahren
SASL
Simple Authentication Security Layer (RFC 4422)
Schema
enthält Definitionen, üblicherweise in Form von Attributen und Objektklassen
Scope
Suchtiefe im DIT
simple bind
unsicheres Verfahren zur LDAP-Authentifikation
slapd
OpenLDAP Standalone Daemon
SSL
Secure Socket Layer (verschlüsselte Datenübertragung)
strong bind
sicheres (verschlüsseltes) Authentifizierungs-Verfahren
syncrepl
OpenLDAP Sync Replication
Suffix
Wurzel des DIT/NC
TLS
standardisierter Nachfolger von SSL
URI
Uniform Resource Identifier, Zeichenkette zur Auffindung von Ressourcen
URL
Uniform Resource Locator, Synonym für URI
555
D.12
1198.book Seite 556 Donnerstag, 5. Februar 2009 3:02 15
1198.book Seite 557 Donnerstag, 5. Februar 2009 3:02 15
Index .htaccess 483, 488, 494 .ldaprc 461 /etc/passwd 67 @ 302
A abandon 76 ABSTRACT 32, 42, 363 access 57, 296, 429, 433 Access Control List 57, 145, 291 Access Levels 299 accesslog 124, 127, 197 account 282 ACI 292 ACID 321 ACL 291 ACL-Reihenfolge 293 ACLs 57 ACL-Syntax 293 Active Directory 24 Active/Active 222 Active/Passive 222 ADAM 351 add 76, 82, 313 addprinc 420 Administrator-Account 388 ADS 24, 148, 351, 377 Alert 239 Alias 84, 357 Allow 488 AllowOverride 488 Andrew Bartlett 401 ANONYMOUS 244 anonymous 304 Apache 15, 481, 482 Apache Directory Studio 112 append 90 Application Layer 497 ApplicationData 239 approx 86 approximate 349 aptitude 51 Archie 21 argsfile 61
ARPA 18 ARPANET 19 ASCII 74 ASN1 357 Atomarität 324 Attribut 29, 31, 37, 40, 357 Attributsyntax 31, 358 Attributsyntaxe 356 Attributtypen 356, 357 attrs 299 attrval 299 AUTH 458 auth 281, 299, 313, 314 authcId 430, 461 Authenticator 413 Authentifizierung 76, 91, 245, 279, 413 Authentifizierungsserver 143, 413 AuthLDAPGroupAttribute 495 AuthLDAPGroupAttributeIsDN 495 AuthLDAPURL 491 AuthName 491 AuthType 491 authzFrom 462 authz-regexp 163, 427 authzTo 462 automatische Ticketgenerierung 431 Autorisierung 279 AUXILIARY 32, 42, 43, 363 auxprop 460
B Backdoor 234 Backend 24, 54, 57, 288, 294, 323 Backend-ACL 295 Backend-Provisioning 403 Backup 94, 96, 145, 185, 188, 246, 353, 421 Backup Domain Controller 379 BAF 375 Balanced-Tree 335 BASE 79 base 85 Base64 465, 491 BaseDN 26
557
1198.book Seite 558 Donnerstag, 5. Februar 2009 3:02 15
Index
bash-history 71 Basic 491 Baumstruktur 26 BDB 50 bdb 54, 116, 182, 294, 399 bdb-Backend 326 BDB-Versionen 327 BDC 379, 395 Benchmark 351 Berkeley Database 54, 58, 182, 322, 331 berkeley_db_svc 329 binary 364 bind 76 BINDDN 64 binddn 77 Binding 76 Blowfish 237, 257 boolean 41, 75, 90, 358, 363 break 316 Browsing-Election 148 Bruce Schneier 235, 268 BSD 20 B-Tree 325, 335 Buffer-Overheads 338
C CA 238 Cache 59 Cachegröße 333 Caesar-Chiffrierung 233 Carnegie Mellon University 244, 472 caseExactMatch 362 CA-Sektionen 264 Certificate 246 Certification Authority 246, 250 Chaining 157 Change Sequence-Number 146 ChangeCipherSpec 239 changetype 81, 92, 109, 110, 111 Charles Babbage 233 Checkpunkt 346 children 301 chkconfig 70 Chosen Plaintext Attack 235 chown 102 chroot – Jail 463 CIB 225
558
cibadmin 228 CIFS 376, 379, 444 Cipher Suites 242 Client-Server 24 Client-Zertifikate 270 Clone-Resource 225 Cluster Information Base 225 Cluster Resource Manager 222 Cluster-Node 223 Clusterschwenk 215 Cluster-Software 150 CMU 472 cn 28 cn=config 100 cn=Module 105 cn=Schema 105 cn=schema 104 cn=subschema 88 common-account 282 common-auth 281 commonName 28, 34 common-password 282 common-session 283 compare 76, 90, 313, 314 constraint violation 132 Constraints 222 Consumer 178, 430 contextCSN 179, 180 continue 315, 316 Control 93 control-Flag 296, 314 core 36, 43, 82, 451 core.schema 357 cosine 31, 36 country 28 countryString 360 cpan 388 CRAM-MD5 244 createTimestamp 84 creator 306 creatorsName 84 credential 414 credentials 413 CRM 222 crm_mon 226 cron 221, 335, 432 csync 479 cyradm 476, 477
1198.book Seite 559 Donnerstag, 5. Februar 2009 3:02 15
Index
Cyrus 15 Cyrus Murder 472 CYRUS_VERBOSE 475 Cyrus-Administrator 475 Cyrus-Imap 244, 463, 466, 472, 474 Cyrus-Sasl 243, 244, 253, 262, 422, 447, 456, 472
D Daemon 51 DAP 22, 542 DARPA 19 Database 54 database 54, 125, 263, 294, 418 database config 99 database_module 436 Datagramm 497 Datenbank 29 Datenbank-Cache 334 Datenkonsistenz 147, 333, 347 Datex-P 19 Dauerhafigkeit 325 db_archive 329 db_checkpoint 329 db_codegen 329 DB_CONFIG 334, 336, 337, 340, 345 db_deadlock 329 db_dump 330 db_hotbackup 330 db_load 330 DB_LOG_AUTOREMOVE 344 db_printlog 330 db_recover 330, 340 db_stat 330, 333 DB_TXN_NOSYNC 344 db_upgrade 331 db_utils 328 db_verify 331 dbconfig 344, 345 dbmodules 436 dbnosync 344 DC 377 dc 28 dcObject 32 dds 308 Debian 49, 52, 60, 97, 166, 235, 248, 333, 386, 398, 422, 447, 456, 474, 475, 478, 485, 498
Debugging 254, 290, 466 Default Policy 292, 295 defaultsearchbase 85 delete 76, 313 delprinc 421 delta-syncrepl 145 deny all 500 DER 364 DES 237, 240, 257 dev/random 264 dev/urandom 264 Dictionary Attacks 416 Diffie/ Hellman 237 Diffie-Hellman-Algorithmus 236 Digest 491 digest_ldap_auth 504 DIGEST-MD5 244 Digest-Realms 507 Dir.X 25 Direct Hosted TCP 377 Directory Access Protocol 22, 24 Directory Information Tree 36, 41, 57, 59 directoryString 360 Disaster-Recovery 354 disclose 299, 313 diskreter Logarithmus 237 DISP 22 distinguished 28 Distinguished Name 35, 57, 59, 73, 297, 307 Distributed Coordinator 226 DIT 26, 54, 59 dn.regex 298 dn2id.bdb 335 dnattr 306 DNS 24 DNS-Caching 498 dnssrv 55 dnstyle 297, 304 DN-Syntax 129 DocumentRoot 488 domain 309 Domain Controller 377, 379 Domain Join 386, 393 domainComponent 28, 32, 125 Domain-Master-Browser 381 Domäne 396, 397 Domänenverwaltung 394 Domino Directory 25
559
1198.book Seite 560 Donnerstag, 5. Februar 2009 3:02 15
Index
Dr. Barry Alan Feigenbaum 376 Draft 533 DRBD 221 DRSUAPI 400 DS 24 DSP 22 Dynamic Directory Services 136 dynamicObject 136 dynamische Gruppen 119, 307 dyngroup.schema 120 dynlist 307, 366, 494 dynlist-attrset 121
E Eclipse 513 eDirectory 24 ehlo 464 EMP 17 Enigma 233, 234 Enterprise-OID 356 Entry 31 entry 301 entryCSN 84, 146, 181 entryExpireTimestamp 136 entryTtl 136 entryUUID 84, 189 eq 86 equal 349 EQUALITY 30, 359 Evolution 470 evolutionperson.schema 470 exact 307 Exim 446 expand 305, 307 extended hello 464 extended Operation 139, 308, 317 extended operations 93 extensible Search 89 extensibleObject 155 EXTERNAL 244, 245, 253, 256, 269, 396, 512 external_acl_type 503
F Failover 222 Fedora Directory Server 148 Filternegierung 87
560
Forkbombe 284 Frontend 79, 98, 108, 394, 395, 446, 481, 508, 512 FTP 19 Full Qualified HostName 167 Full Replica 145
G gcc 388 generalizedTime 361 GeoTrust 246 getent 287, 291 getprincs 420 GIT 402 givenName 505 glibc 286, 287 globale ACL 293 glue 151 GnuTLS 248 GOPHER 21 Gracetime 138 group 306 groupOfNames 123 groupOfURLs 120 groupstyle 306, 307 Gruppenzugehörigkeit 131 GSSAPI 244, 312, 416, 420, 425, 430, 513
H Hash 239, 382 Hashtabellen 325 hb_gui 223, 228 hdb 54 hdb-backend 326 Heartbeat 150, 215, 220 Heimdal 417, 419 Heimdal-Kerberos 417 Helper 498 hierarchische Abarbeitung 295 High Availability 214 History 71 HMAC 241 Hochverfügbarkeit 147, 220 homeDirectory 30 Hostprincipal 421 HTML 22, 482 HTTP 22
1198.book Seite 561 Donnerstag, 5. Februar 2009 3:02 15
Index
http 482 http_access 500 HTTP-Proxy 497, 498 https 489 Hybrid-Objekt 366
I IA5String 360 IANA 40, 356 iconv 74 id2entry.bdb 335 idlcachesize 347 idmap_ldap 391 IETF 238 IIS 482 IMAP 470 Imaps 475 IMP 18 imtest 475 Include 53, 57, 185, 281, 423, 484 include 57 Index 347, 348 index 343, 347 Indexcache 326 Indexeintrag 111 Indexfeld 111 Indexparameter 349, 350 inetOrgPerson 30, 33, 36, 42, 44, 362, 367, 447, 493 Infrastruktur 115 Initalbefüllung 99 Initial Content Load 178 insserv 70 Integer 31, 58, 62, 187, 346, 347, 360 integerMatch 362 Integritätsprüfung 129 Internal Pages 336 Internal-Pages 338 Internettelefonie 40 Interprozesskommunikation 401 Interrupt Timers 169 Interrupt-Controller 169 Intrusion 413 IPSec 245 IRC 21 ISO 20 ISO8859 74 Isolation 324 ITU 19
J J. C. Licklider 18 Java 509 JRE 509, 513 JXplorer 78, 509
K kadmin 419 kadmin.local 420 kadmind 422 kdb5_ldap_util 438 kdb5_util 419 KDC 413, 414, 416, 420, 430, 443 kdestroy 424 Kerberos 413 kerberos.schema 434 Kerberos-ACL 419 Key 246, 413 Keytab 421 keytab 421 KfW 444 Klassen 31 klist 422 Klonen 94 Kommandozeilentools 75 Kommentar 56 Konfigurationsdateien 15, 52 .bashrc 71 .ldaprc 64, 255 /etc/apache2/httpd.conf 484 /etc/apache2/sysconfig.d/loadmodule.conf 486 /etc/cyrus.conf 474 /etc/default/passwd 283 /etc/default/slapd 103 /etc/digestreader_cred 506 /etc/ha.d/ha.cf 224 /etc/hosts 79 /etc/imapd.conf 473 /etc/krb5.conf 418 /etc/ldap.conf 52, 65 /etc/ldap/ldap.conf 52, 63 /etc/ldap/slapd.conf 52 /etc/libnss-ldap.conf 52, 65 /etc/logins.defs 282 /etc/network/interfaces 224 /etc/nscd.conf 288
561
1198.book Seite 562 Donnerstag, 5. Februar 2009 3:02 15
Index
/etc/nsswitch.conf 66 /etc/ntp.conf 167 /etc/openldap/ldap.conf 52, 63 /etc/openldap/slapd.conf 52 /etc/pam.conf 279 /etc/pam.d/login 280 /etc/pam_ldap.conf 52, 65 /etc/postfix/main.cf 447 /etc/postfix/master.cf 456, 463 /etc/postfix/sasl/smtpd.conf 458 /etc/profile 63 /etc/samba/smb.conf 380 /etc/sasl2/smtpd.conf 461 /etc/saslauthd.conf 459 /etc/security/limits.conf 283 /etc/security/pam_env.conf 280, 281 /etc/services 479 /etc/smbldap-tools/smbldap.conf 386 /etc/smbldap-tools/smbldap_bind.conf 387 /etc/squid/squid.conf 499 /etc/ssl/openssl.cnf 246 /etc/sysconfig/apache2 485 /etc/sysconfig/ldap 52 /etc/sysconfig/network/ifcfg-eth 224 /etc/sysconfig/openldap 52, 102 /etc/syslog.conf 332 /etc/xinet.d/qpopper 467 /usr/lib/sasl2/slapd.conf 422 kdc.conf 418 Konsistenz 324 konvertieren 99 Konvertierung 372 krb5.keytab 421 krb5kdc 422 krbPrincipalAux 435 krbPrincipalName 441 krbTicketPolicyAux 435 ktadd 421 ktremove 421 ktutil 421
L labeledURI 120 labeledURIObject 120 LAN 19 Lastverteilung 151 Laufzeitkonfiguration 100
562
LDAP 23, 24 LDAP Sync 178 ldap_group 504 ldap_table 449 ldapadd 75, 76, 83, 93, 94 ldap-aliases.cf 448 ldap-attribute 492 ldapcompare 75, 90 LDAPCONF 63, 69 ldapdb 460 ldapdelete 75, 82, 156, 173 ldapexop 75, 317 ldap-filter 492, 495 ldapfilter 300 ldapi 400, 434, 448 ldapmodify 75, 79, 80, 91 ldapmodrdn 75, 91 ldappasswd 75, 90 LDAPRC 69 ldaps 243, 260, 275, 434, 448, 492 ldapsam 381 editposix 386, 388 trusted 389 ldapsearch 75, 78, 83, 85, 86, 88 ldapSyntaxes 361 LDAP-URI 66 LDAP-URL 404 ldap-user 492 ldapvi 97 ldapwhoami 75, 91 ldbm 55 LDIF 55, 57, 71, 92, 516 LDIF-Schema 39 Leaf-Objekte 27 Leaf-Pages 336, 338 Leerzeichen 56 Lenny 49 libldap 69 libnss_ldap.so 65 libnss-ldap 52, 69, 286 libpam 279 Lightweight Directory Access Protocol 24 Linux-Distributionen 49 Linux-HA 222 Listen 486 LLL 79 lmtpunix 474 Load Balancing 147
1198.book Seite 563 Donnerstag, 5. Februar 2009 3:02 15
Index
LoadModule 485 Local Master-Browser 381 locality 32 localsite.schema 362, 505 Locking 333 Locking-Mechanismus 148 Log-Facility 124 login 33 loginShell 30 loglevel 62 Logon-Server 397 LSB 227
M MAC 241 mail 30, 450 Mailadressen 446 Mailclient 157, 467, 470, 477, 478 Mail-Relay 455 Mailserver 244, 446, 454 main.cf 447 make 388 manage 139, 299, 313, 317 manageDIT 93 manageDSAit 93 manageDsaIT 156 mandb 117 Man-in-the-Middle 237, 416, 491 Manpages 51 Mapping 382 Maschinen-Account 382 Masterbrowser 381 Match 296 Matching Rules 31, 327, 359 matchingRuleUse 361 MAY 33, 37 mbox 472 MD5 237 member 306 memberUID 366 memberURL 120 Message-Exchange 76 meta 55 mgmtd 223 Mirror-Mode 215 Mirrormode 218 MIT 18, 421, 444
MIT-Kerberos 417 MMC 407 mod_auhtnz_ldap 483 mod_auth_digest 491 mod_auth_ldap 486 mod_ldap 486 mod_ssl 486 mode 161 modifiersName 84, 130 modify 76 modifyTimestamp 84, 105, 124 modrdn 91 Module 281, 284 monitor 55 Monitoring-Client 342 MTA 141, 446 Multi-Master-Replikation 147, 213, 403, 409 MUST 33, 37 Mutual Authentification 416
N nail 450 NAME 30 name 34 Name Service Caching Daemon 288 Name Service Switch 281 Naming Context 90, 111 NCSA 482 ndb 55 ndb-Backend 323 Nested Groups 310 net 391, 397 NetBIOS 377, 379, 384 NETLOGON 381 Netscape 481 Network Identity Manager 445 Netzwerk-SID 380, 397 -newca 249 -newcert 248 -newreq 251 NICHT 87 NIS 24 nis.schema 362 NIS-Schema 36 nmap 70, 383 nmbd 379
563
1198.book Seite 564 Donnerstag, 5. Februar 2009 3:02 15
Index
Node 222 Nodes 338 nolang 350 none 313, 314 nosubtypes 350 NO-USER-MODIFICATION 139 NSA 235 nscd 288, 459 NSS 286 NTP 147, 165 NTPD 165 nullok 283 numericString 360
O Object Identifier 40 objectClass 78 objectIdentifier 368 Objekt 29, 31, 37, 42, 364 Objekte 31 Objektklasse 29, 31, 32, 40, 362, 363 Objektklassendefinition 363 Objektklassenhierarchie 361, 368 OCF 222 octetString 361 ODER 87 OID 30, 31, 40, 41, 83, 307, 355, 451 OID-Makros 368 olc 104, 202 olcAccess 291 olcAttributeTypes 370 olcBackend 106 olcBackendConfig 108 olcConfigFile 103 olcDatabase 106 olcDbConfig 345 olcFrontendConfig 207 olcGlobal 207 olcLastMod 213 olcOverlay 106 olcOverlayConfig 206 olcReadOnly 110 olcRootDN 101 olcSecurity 257 olcServerID 220 olcSizeLimit 109 one 85 One-Time-Pad 235, 236
564
Online-Administration 108 Online-Format 100 Online-Konfiguration 98 OpenLDAP 24 openldap.schema 120 OpenLDAP-Foundation 149 openLDAPou 120 OpenSSL 66, 232, 240, 246 openssl.cnf 249 operational Attribute 84, 155, 306 operational Attributes 95, 189, 511 opportunistisches TLS 455 optional 284, 285 optional modifier 304 Oracle Berkeley Database 58 Oracle Berkeley DB 26 ORDERING 86, 350, 359 organization 27, 28 organizationalPerson 42, 44 organizationalRole 73, 439 organizationalUnit 27 OSI 20 OSI-Modell 22, 238 OS-Level 381 Outlook Express 466, 467 Overlay 185 overlay 56, 62, 430 Overlay accesslog 124, 125 Overlay chain 143, 159 Overlay constraint 141 Overlay dds 136 Overlay dynlist 119 Overlay glue 152 Overlay memberOf 130 Overlay refint 128 Overlay syncprov 143, 185 Overlay translucent 142 Overlay unique 141 Overlay valsort 142 Overlays 56, 116 Owner 104 owner 306
P Pacemaker 222 PADL 285 Page Caching 333 Pages 334
1198.book Seite 565 Donnerstag, 5. Februar 2009 3:02 15
Index
PAM 279 pam_ck_connector 284 pam_env 281 pam_krb5 423 pam_lastlog 284 pam_ldap 52, 65, 70, 281, 286, 423 pam_ldap.so 65 pam_limits 283 pam_listfile 282 pam_localuser 282 pam_loginuid 283 pam_mail 284 pam_mkhomedir 283, 284 pam_nologin 281 pam_pwcheck 282 pam_resmgr 284 pam_securetty 281 pam_umask 284 pam_unix 281 pam_unix2 281 parent 301 Partitionierung 25, 151, 153, 193 passdb backend 381, 397 password 282 PCT 238 pdbedit 384 PDC 379, 380 Peer-IP 430 peername 309 PEM 250, 364, 512 Performance 84, 147, 288, 299, 305, 382, 472, 474, 485 Perl 465 perl 518 perl-IO-Socket-SSL 398 persistent 179 person 43 php 518 phpldapadmin 517 PIM 470 Pluggable Authentication Modules 279 pluginviewer 244 Policy-Files 382 POP3 467 pop3s 475 Port 389 70 Port 636 398, 512 posixAccount 30, 33, 37, 367 posixGroup 123
postalAddress 361 postconf 447 Postfix 15, 446 postfix.schema 451 postfixMailGroup 453 postfixMailUser 452 postmap 449 Prefix 106 present 349 PRF 242 Principal 414 printableString 360 Privileges 314 Profil 385 Provider 178 Provisioning 391, 403 proxy_auth 500 Proxy-Autorisierung 162, 163, 276 Proxy-Cache 118 ps 70 Pseudoattribute 301 putty 424 python 518
Q qpopper 467 Query 48 query_filter 448 Queue 325
R RAID 146 Rand Corporation 17 RANDFILE 264 randkey 421 Random Number Generator 234 RDBMS 25 RDBMs 322 RDN 27, 28, 34, 129, 298 read 313 Read-only-Replikation 145 real 306 Realm 414 Rechte 299 Reconnect 187 Record Number 325 Redundanz 115, 144, 153, 221, 397
565
1198.book Seite 566 Donnerstag, 5. Februar 2009 3:02 15
Index
referentielle Integrität 128, 133 Referral 64, 153 refint 128 refint_attributes 130 refresh 136 refreshAndPersist 178 refreshOnly 178 Registry 394 Reguläre Ausdrücke 297 Relative Distinguished Name 27, 91 Relay 454 relay 55 relay_clientcerts 455 Replay-Attacke 416 Replica-ID 193 Replikation 25, 57, 143, 354, 369 Replikationsstatus 179 Request 76 require 492 required 281, 284 requisite 281, 285 ResourceAgents 222 Response 76 Restore 95, 353 result_attribute 448 reverse group membership 131 rewMailAddress 451 rid 187, 193 RNG 234 rolling replication 479 rootdn 60, 73, 77, 100, 292 rootDSE 26 Root-Page 338 rootpw 61 root-Zertifikat 264 ROT13 233 RPC 329, 377 RPM 50 rpm 51 RSA 236, 265 rsync 221, 402 Run-Levels 68
S Samba 35, 36, 145, 289, 348, 375, 379 Samba 4 400, 409 samba.schema 383 sambaDomainName 389
566
sambaLMPassword 382 sambaSAMAccount 35 SASL 243 sasl_ssf 311 saslauthd 454, 456, 473 SASLMech 244, 253, 269, 312, 416, 420, 425 SASLMechs 243, 244 saslpluginviewer 244 sasl-realm 428 Schema 30, 36 Schema-Discovery 39, 88, 511 Schema-Replikation 371 Scope 295 scope 85 Scopes 305 search 76, 313, 314 search_base 448 Searchbase 64, 86, 448, 468 searchstack 347 secrets.tdb 397 security 257 Security IDentifier 379 Security Strength Factor 257, 311 seed-Datei 212 Selbstzertifizierung 263 self 304, 312 selfdelete 313 selfwrite 313 sender_canonical 450 sender_canonical_maps 452 Server role 397 ServerID 218 Service-IP 227 Service-Principal 421 Session 76 session 283 Session-Cookies 146 SessionKey 414, 416 sessionlog 183 set 310 set_cachesize 337 set_lg_dir 344 set_lg_max 343 Sets 309 shadowAccount 35 Shadow-Copy 178 Shadow-Kontext 140 Shared Secrets 244
1198.book Seite 567 Donnerstag, 5. Februar 2009 3:02 15
Index
shares 27 Shell 51 sign 251 signcert 248 simple bind 83, 241 Single Point of Failure 150, 417 Single Sign On 379 Single-Process-Mode 406 SINGLE-VALUE 30 sizelimit 63, 80 Skalierbarkeit 147, 333, 472 Skytale 233 slamd 341 slamd-Clients 342 slapacl 96, 310, 320 slapadd 93, 184, 340 slapauth 97 slapcat 93, 184 slapd 51, 54, 61, 62, 68, 324 slapd.conf 38, 53 slapd.d/ 99, 205 slapd-config 112 slapd-ldap 160 slapdn 97 slapindex 96 slappasswd 61 slaptest 63, 97 slurpd 68, 173 SMB 379 smb.conf 403 smbclient 383, 444 smbd 379 smbldap-populate 387 smbldap-tools 385 smbldap-useradd 388 SMTP 447 snaplen 260 SNMP 357 SNTP 166 Socket 448 sockname 309 sockurl 309 special_result_attribute 454 Sperrlisten 263 Spiegelung 146 Split-Brain 215, 223 SPoA 417 SPoF 417 Spry Mosaic 481
sql 55 Squid 15, 497 squid_group_ldap 502 squid_ldap_auth 499 squirrelmail 481 SRI 18 srvmgr.exe 394 srvtools 386 srvtools.exe 394 SSF 257 ssf 311, 428 SSH 23, 79 SSL 238, 241 SSL Record Protocol 239 SSL-Handshake-Protokoll 239 SSL-Protokoll 238 SSL-Tunnel 490 SSO 416 Stack 347 Standard-Mailbox-Format 472 Standby-Master 145, 215, 220 start_tls 289, 398 STARTTLS 464 StartTLS 245, 257 starttls 272 StartTLS-Request 242 stash 419 Stonith 229 stop 316 storage engine 322 stratum 167 Strings 356 strong bind 241 STRUCTURAL 32, 42, 44, 363 sub 85, 350 subany 350 Subdomains 446 subfinal 350 Sub-Kontext 48 Subkontext 109 subordinate 151 subordinate Referrals 153 Subordinates 83 SUBSTRINGS 359 Subtree 48, 153 Subtree-Master 158 Subtree-Renaming 58 Suchfilter 85 Suchzeile 511
567
1198.book Seite 568 Donnerstag, 5. Februar 2009 3:02 15
Index
sufficient 285 Suffix 59 Superior 84 superior Referrals 153 SUPerior-Attribut 362 SuSE 49, 65, 70, 97, 166, 248, 299, 398, 424, 458, 476, 478, 485 swappen 335 SWAT 395 Sync Replication 176 sync_client 479 sync_server 479 Synchronisations-Cookie 179 syncprov 185 Sync-Provider 143, 178 syncrepl 145 Sync-Request 178 Synflooding 497 SYNTAX 30 Syntaxdefinitionen 361 syslog 332 syslogd 62 syslog-Facility 62 syslog-ng 332
T TCP 20 TCP/IP 20, 23, 165, 379, 413, 497 tcpdump 232, 259, 268, 271, 398, 497 Teilbaum 48 Teilstring-Vergleichsregel 358 telephoneNumber 30, 361 Telnet 19 telnet 464 testparm 379, 380, 384 testsaslauthd 459, 463 TGS 414 TGT 414 Thawte 246 Thread 176 Thunderbird 456, 466, 467, 468 Ticket 413, 414 Ticket Granting Server 414 Ticket Granting-Ticket 414 Ticket-Cache-File 432 Ticket-Lifetime 432 Timeserver 166 Timestamps 99
568
TLD 26, 59 TLS 68, 238, 240, 241 tls_ssf 311 tlsmgr 455, 456 Tomcat 342 top 32, 42 Top Level Domain 59 Transaction 339 Transaction Control 333 Transaktionskontrolle 59 Transaktionslog 60, 343 Transaktionslogs 231 transport_ssf 311 Treedesign 48 Triple DES 240 Trusted Third Party 413 TTL 123 txn_checkpoint 346
U ubjectAltName 278 ucast 225 udev 224 uid 27, 30 uidNumber 30, 37 umask 284 Unbind 76 UND 87, 319 Unicode::MapUTF8 388 Unit 47 Unix-Domain-Socket 400 Unix-Socket 458, 463, 474 update-rc.d 70 URI 64, 79 URL 64 URL-Expansion 123 use_authok 283 users 304 usrmgr.exe 394 UTF-8 74
V val.style 299 Vererbung 84 Vergleichregeln 356 Vergleichsregel 358 Verisign 246
1198.book Seite 569 Donnerstag, 5. Februar 2009 3:02 15
Index
Verschlüsselungsalgorithmus 90 Verzeichnisdienst 22, 24 vi(m) 57, 74 Vignère 233 virtual_alias_maps 453 Virtualbox 59 VMware 59, 171 VMware-Tools 170
W W2K3 381 W3C 22 Web2ldap 517 Webmin 517 Webserver 481, 482 Weiterleitung 158 Wildcard 188, 297, 304, 351, 359 Winbind 378 winbind 389 winbindd 379 Windows-Client 396, 398, 443, 444 WINS 377 wireshark 232 Workbench 513 Workgroup 377 workgroup 380 write 313 Wurzelzertifikat 266
X X.25 19 X.400 23 X.500 20, 22, 23 X.500-Standard 148 X.509-Zertifikate 245, 248 Xen 59 xinetd 467 XML 223
Y YaST 50, 484
Z Zeitsynchronisation 148 Zeitsynchronisationsdienst 165 Zertifikats-DN 246 Zertifikats-Request 250, 267 Zonendatei 405 zypper 51 ZZ 256
569