Traditionell besteht die typische Anwendung aus den folgenden Komponenten:
In diesem einfachen Fall würde eine Grundeinstellung ausreichen:
- Die Anwendung verwendet einen einfachen lokalen Authentifizierungsmechanismus für ihre Benutzer
- die Anwendung verwendet einen einfachen Verbindungspool
- es gibt einen einzelnen Benutzer, der für den Datenbankzugriff definiert ist
Wenn sich die Organisation jedoch weiterentwickelt und größer wird, werden weitere Komponenten hinzugefügt:
- weitere Mandanten-Apps oder Instanzen der App, die auf die Datenbank zugreifen
- weitere Dienste und Systeme, die auf die Datenbank zugreifen
- Zentrale Authentifizierung/Autorisierung (AA) für alle (oder die meisten) Dienste
- Trennung von Komponenten für eine einfachere zukünftige Skalierung
Im obigen Schema sind alle Anliegen in einzelne Komponenten aufgeteilt, jede Komponente dient einem speziellen Zweck. Der Verbindungspool verwendet jedoch immer noch einen einzigen dedizierten Datenbankbenutzer, wie in der vorherigen einfacheren Einrichtung, die wir oben gesehen haben.
Neben den neuen Komponenten treffen auch neue Anforderungen ein:
- bessere feinkörnige Kontrolle darüber, was Benutzer auf Datenbankebene tun können
- Prüfung
- bessere nützlichere Systemprotokollierung
Wir können immer alle drei mit mehr Anwendungscode oder mehr Ebenen in der Anwendung implementieren, aber das ist nur umständlich und schwer zu warten.
Darüber hinaus bietet PostgreSQL eine so große Auswahl an Lösungen für die oben genannten Bereiche (Sicherheit, Sicherheit auf Zeilenebene, Auditing usw.), dass es absolut sinnvoll ist, alle diese Dienste auf die Datenbankebene zu verschieben. Um diese Dienste direkt aus der Datenbank zu nehmen, müssen wir einzelne Benutzer in der Datenbank vergessen und stattdessen echte individuelle Benutzer verwenden.
Dies bringt uns zu einem Schema wie dem folgenden:
In unserem Anwendungsfall beschreiben wir ein typisches Unternehmens-Setup, das aus dem obigen Schema besteht, wobei wir Folgendes verwenden:
- Wildfly-App-Server (Beispiele für Version 10 gezeigt)
- LDAP-Authentifizierungs-/Autorisierungsdienst
- pgbouncer-Verbindungspooler
- PostgreSQL 10
Es scheint ein typisches Setup zu sein, da jboss/wildfly seit vielen Jahren LDAP-Authentifizierung und -Autorisierung unterstützt, PostgreSQL unterstützt seit vielen Jahren LDAP.
Allerdings hat pgbouncer erst Ende 2017 mit der Unterstützung für LDAP (und das über PAM) seit Version 1.8 begonnen, was bedeutet, dass jemand bis dahin den heißesten PostgreSQL-Verbindungspooler in einem solchen Enterprise-Setup nicht verwenden konnte (was aus keinem von uns gewählten Blickwinkel vielversprechend klang). um es anzusehen)!
In diesem Blog beschreiben wir die Einrichtung, die in jeder Ebene benötigt wird.
Wildfly 10-Konfiguration
Die Datenquellenkonfiguration muss so aussehen, ich zeige das Wichtigste:
<xa-datasource jndi-name="java:/pgsql" pool-name="pgsqlDS" enabled="true" mcp="org.jboss.jca.core.connectionmanager.pool.mcp.LeakDumperManagedConnectionPool">
<xa-datasource-property name="DatabaseName">
yourdbname
</xa-datasource-property>
<xa-datasource-property name="PortNumber">
6432
</xa-datasource-property>
<xa-datasource-property name="ServerName">
your.pgbouncer.server
</xa-datasource-property>
<xa-datasource-property name="PrepareThreshold">
0
</xa-datasource-property>
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
<driver>postgresql-9.4.1212.jar</driver>
<new-connection-sql>
SET application_name to 'myapp';
</new-connection-sql>
<xa-pool>
<max-pool-size>400</max-pool-size>
<allow-multiple-users>true</allow-multiple-users>
</xa-pool>
<security>
<security-domain>postgresqluser</security-domain>
</security>
</xa-datasource>
Ich habe die wichtigen Parameter und Werte fett gedruckt. Denken Sie daran, die IP-Adresse (oder den Hostnamen), den Datenbanknamen und den Port entsprechend der Einrichtung Ihres pgbouncer-Servers zu definieren.
Außerdem muss anstelle des typischen Benutzernamens/Passworts eine Sicherheitsdomäne definiert werden, die wie oben gezeigt im Datenquellenabschnitt angegeben werden muss. Seine Definition sieht folgendermaßen aus:
<security-domain name="postgresqluser">
<authentication>
<login-module code="org.picketbox.datasource.security.CallerIdentityLoginModule" flag="required">
<module-option name="managedConnectionFactoryName" value="name=pgsql,jboss.jca:service=XATxCM"/>
</login-module>
</authentication>
</security-domain>
Auf diese Weise wird Wildfly den Sicherheitskontext an pgbouncer delegieren.
HINWEIS: In diesem Blog behandeln wir die Grundlagen, d. h. wir verwenden oder erwähnen TLS nicht, es wird Ihnen jedoch dringend empfohlen, es in Ihrer Installation zu verwenden.
Die wildfly-Benutzer müssen sich wie folgt bei Ihrem LDAP-Server authentifizieren:
<login-module code="<your login module class>" flag="sufficient">
<module-option name="java.naming.provider.url" value="ldap://your.ldap.server/"/>
<module-option name="java.naming.security.authentication" value="simple"/>
<module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
<module-option name="principalDNPrefix" value="uid="/>
<module-option name="uidAttributeID" value="memberOf"/>
<module-option name="roleNameAttributeID" value="cn"/>
<module-option name="roleAttributeID" value="memberOf"/>
<module-option name="principalDNSuffix"
value=",cn=users,cn=accounts,dc=yourorgname,dc=com"/>
<module-option name="userSrchBase" value="dc=yourorgname,dc=com"/>
<module-option name="rolesCtxDN"
value="cn=groups,cn=accounts,dc=yourorgname,dc=com"/>
<module-option name="matchOnUserDN" value="true"/>
<module-option name="unauthendicatedIdentity" value="foousr"/>
<module-option name="com.sun.jndi.ldap.connect.timeout" value="5000"/>
</login-module>
Die obigen Konfigurationsdateien gelten für wildfly 10.0, es wird Ihnen auf jeden Fall empfohlen, die offizielle Dokumentation für Ihre Umgebung zu konsultieren.
PostgreSQL-Konfiguration
Um PostgreSQL anzuweisen, sich zu authentifizieren (HINWEIS: nicht autorisieren!) gegen Ihren LDAP-Server müssen Sie die entsprechenden Änderungen an postgresql.conf und pg_hba.conf vornehmen. Die Einträge von Interesse sind die folgenden:
In postgresql.conf:
listen_addresses = '*'
und in pg_hba.conf:
#TYPE DATABASE USER CIDR-ADDRESS METHOD
host all all ip.ofYourPgbouncer.server/32 ldap ldapserver=your.ldap.server ldapprefix="uid=" ldapsuffix=",cn=users,cn=accounts,dc=yourorgname,dc=com"
Stellen Sie sicher, dass die hier definierten LDAP-Einstellungen genau mit denen übereinstimmen, die Sie in Ihrer App-Server-Konfiguration definiert haben. Es gibt zwei Betriebsmodi, mit denen PostgreSQL angewiesen werden kann, den LDAP-Server zu kontaktieren:
- einfache Bindung
- suchen und dann binden
Der einfache Bindungsmodus erfordert nur eine Verbindung zum LDAP-Server, daher ist er schneller, erfordert aber eine etwas strengere Organisation des LDAP-Wörterbuchs als der zweite Modus. Der Such- und Bindungsmodus ermöglicht eine größere Flexibilität. Für das durchschnittliche LDAP-Verzeichnis funktioniert jedoch der erste Modus (einfaches Binden) einwandfrei. Wir müssen bestimmte Punkte zur PostgreSQL-LDAP-Authentifizierung hervorheben:
- Das hat nur mit Authentifizierung zu tun (Passwörter prüfen).
- Die Mitgliedschaft in Rollen erfolgt weiterhin wie gewohnt in PostgreSQL.
- Die Benutzer müssen wie gewohnt in PostgreSQL (über CREATE user/role) angelegt werden.
Es gibt einige Lösungen, die bei der Synchronisierung zwischen LDAP- und PostgreSQL-Benutzern helfen (z. B. ldap2pg), oder Sie können einfach Ihren eigenen Wrapper schreiben, der sowohl LDAP als auch PostgreSQL zum Hinzufügen oder Löschen von Benutzern handhabt.
Laden Sie noch heute das Whitepaper PostgreSQL-Verwaltung und -Automatisierung mit ClusterControl herunterErfahren Sie, was Sie wissen müssen, um PostgreSQL bereitzustellen, zu überwachen, zu verwalten und zu skalierenLaden Sie das Whitepaper herunterPgBouncer-Konfiguration
Dies ist der schwierigste Teil unserer Einrichtung, da pgbouncer immer noch keine native LDAP-Unterstützung bietet und die einzige Option die Authentifizierung über PAM ist, was bedeutet, dass dies von der korrekten lokalen UNIX/Linux-PAM-Einrichtung für LDAP abhängt.
Das Verfahren ist also in zwei Schritte unterteilt.
Der erste Schritt besteht darin, zu konfigurieren und zu testen, ob pgbouncer mit PAM funktioniert, und der zweite Schritt besteht darin, PAM für die Arbeit mit LDAP zu konfigurieren.
pgbouncer
pgbouncer muss mit PAM-Unterstützung kompiliert werden. Dazu müssen Sie:
- installiere libpam0g-dev
- ./configure --with-pam
- pgbouncer neu kompilieren und installieren
Ihre pgbouncer.ini (oder der Name Ihrer pgbouncer-Konfigurationsdatei) muss für pam konfiguriert sein. Außerdem muss es die korrekten Parameter für Ihre Datenbank und Ihre Anwendung gemäß den in den Abschnitten oben beschriebenen Parametern enthalten. Dinge, die Sie definieren oder ändern müssen:
yourdbname = host=your.pgsql.server dbname=yourdbname pool_size=5
listen_addr = *
auth_type = pam
# set pool_mode for max performance
pool_mode = transaction
# required for JDBC
ignore_startup_parameters = extra_float_digits
Natürlich müssen Sie die pgbouncer-Dokumentation lesen und Ihren pgbouncer an Ihre Bedürfnisse anpassen. Um das obige Setup zu testen, müssen Sie lediglich einen neuen lokalen UNIX-Benutzer erstellen und versuchen, sich bei pgbouncer zu authentifizieren:
# adduser testuser
<answer to all question, including password>
Damit pgbouncer beim Lesen aus den lokalen passwd-Dateien mit PAM arbeiten kann, muss die ausführbare pgbouncer-Datei root gehören und die setuid:
haben# chown root:staff ~pgbouncer/pgbouncer-1.9.0/pgbouncer
# chmod +s ~pgbouncer/pgbouncer-1.9.0/pgbouncer
# ls -l ~pgbouncer/pgbouncer-1.9.0/pgbouncer
-rwsrwsr-x 1 root staff 1672184 Dec 21 16:28 /home/pgbouncer/pgbouncer-1.9.0/pgbouncer
Hinweis:Die Notwendigkeit von root-Besitz und setuid (was für jedes Debian/Ubuntu-System gilt, das ich getestet habe) ist nirgendwo dokumentiert, weder in den offiziellen pgbouncer-Dokumenten noch irgendwo im Netz.
Dann melden wir uns (als pgsql-Superuser) beim postgresql-Host (oder psql -h your.pgsql.server) an und erstellen den neuen Benutzer:
CREATE USER testuser PASSWORD 'same as the UNIX passwd you gave above';
dann vom Pgbouncer-Host:
psql -h localhost -p 6432 yourdbname -U testuser
Sie sollten eine Eingabeaufforderung erhalten und die Tabellen so sehen können, als wären Sie direkt mit Ihrem Datenbankserver verbunden. Denken Sie daran, diesen Benutzer aus dem System zu löschen und auch aus der Datenbank zu löschen, wenn Sie mit all Ihren Tests fertig sind.
PAM
Damit PAM mit dem LDAP-Server kommunizieren kann, wird ein zusätzliches Paket benötigt:libpam-ldap . Sein Post-Install-Skript führt einen Dialog im Textmodus aus, den Sie mit den richtigen Parametern für Ihren LDAP-Server beantworten müssen. Dieses Paket nimmt die notwendigen Aktualisierungen in den Dateien /etc/pam.d vor und erstellt auch eine Datei mit dem Namen:/etc/pam_ldap.conf. Falls sich in Zukunft etwas ändert, können Sie jederzeit zurückgehen und diese Datei bearbeiten. Die wichtigsten Zeilen in dieser Datei sind:
base cn=users,cn=accounts,dc=yourorgname,dc=com
uri ldap://your.ldap.server/
ldap_version 3
pam_password crypt
Der Name/die Adresse Ihres LDAP-Servers und der Suchbasis müssen genau mit denen übereinstimmen, die in den oben erläuterten Konf-Dateien pg_hba.conf von PostgreSQL und Wildfly standalone.xml angegeben sind. pam_login_attribute ist standardmäßig uid. Wir empfehlen Ihnen, einen Blick auf die Dateien /etc/pam.d/common-* zu werfen und zu sehen, was sich nach der Installation von libpam-ldap geändert hat. Nach der Dokumentation könnten Sie eine neue Datei namens /etc/pam.d/pgbouncer erstellen und dort alle PAM-Optionen definieren, aber die standardmäßigen common-*-Dateien reichen aus. Werfen wir einen Blick in /etc/pam.d/common-auth:
auth [success=2 default=ignore] pam_unix.so nullok_secure
auth [success=1 default=ignore] pam_ldap.so use_first_pass
auth requisite pam_deny.so
auth required pam_permit.so
Unix passwd wird zuerst überprüft, und wenn dies fehlschlägt, wird LDAP überprüft, also denken Sie daran, dass Sie alle lokalen Passwörter für die Benutzer löschen müssen, die sowohl im lokalen linux/unix /etc/passwd als auch in LDAP definiert sind . Jetzt ist es an der Zeit, den letzten Test zu machen. Wählen Sie einen Benutzer, der in Ihrem LDAP-Server definiert und auch in PostgreSQL erstellt wurde, und versuchen Sie, sich von der DB (über pgsql -h your.pgsql.server ) und dann von pgbouncer (auch über psql -h your.pgbouncer.server) zu authentifizieren. , und schließlich über Ihre App. Sie haben gerade ein einziges Sicherheitssystem für App, Connection Pooler und PostgreSQL Wirklichkeit werden lassen!