PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Un seul système de sécurité pour les applications, le regroupement de connexions et PostgreSQL - Le cas de LDAP

Traditionnellement, l'application typique se compose des composants suivants :

Dans ce cas simple, une configuration de base suffirait :

  • l'application utilise un mécanisme d'authentification local simple pour ses utilisateurs
  • l'application utilise un pool de connexion simple
  • il n'y a qu'un seul utilisateur défini pour l'accès à la base de données

Cependant, à mesure que l'organisation évolue et s'agrandit, d'autres composants sont ajoutés :

  • plus d'applications locataires ou d'instances de l'application accédant à la base de données
  • plus de services et de systèmes accédant à la base de données
  • Authentification/autorisation centrale (AA) pour tous (ou la plupart) des services
  • séparation des composants pour faciliter la mise à l'échelle future

Dans le schéma ci-dessus, toutes les préoccupations sont séparées en composants individuels, chaque composant ayant un objectif spécialisé. Cependant, le pool de connexions utilise toujours un seul utilisateur de base de données dédié, comme dans la configuration précédente plus simple que nous avons vue ci-dessus.

Outre les nouveaux composants, de nouvelles exigences arrivent :

  • meilleur contrôle précis de ce que les utilisateurs peuvent faire au niveau de la base de données
  • audit
  • meilleure journalisation système plus utile

Nous pouvons toujours implémenter les trois avec plus de code d'application ou plus de couches dans l'application, mais c'est juste encombrant et difficile à maintenir.

De plus, PostgreSQL offre un ensemble de solutions si riche dans les domaines susmentionnés (sécurité, sécurité au niveau des lignes, audit, etc.) qu'il est parfaitement logique de déplacer tous ces services vers la couche base de données. Afin de tirer ces services directement de la base de données, nous devons oublier l'utilisateur unique dans la base de données et utiliser de vrais utilisateurs individuels à la place.

Cela nous amène à un schéma comme ci-dessous :

Dans notre cas d'utilisation, nous décrirons une configuration d'entreprise typique consistant en le schéma ci-dessus où nous utilisons :

  • Serveur d'application Wildfly (exemples présentés pour la version 10)
  • Service d'authentification/d'autorisation LDAP
  • regroupement de connexions pgbouncer
  • PostgreSQL 10

Cela semble être une configuration typique, puisque jboss/wildfly prend en charge l'authentification et l'autorisation LDAP depuis de nombreuses années, PostgreSQL prend en charge LDAP depuis de nombreuses années.

Cependant, pgbouncer n'a commencé à prendre en charge LDAP (et cela via PAM) que depuis la version 1.8 fin 2017, ce qui signifie que quelqu'un jusque-là ne pouvait pas utiliser le pooler de connexions PostgreSQL le plus chaud dans une telle configuration d'entreprise (ce qui ne semblait pas prometteur sous tous les angles que nous choisissons pour le regarder) !

Dans ce blog, nous décrirons la configuration nécessaire dans chaque couche.

Configuration Wildfly 10

La configuration de la source de données devra ressembler à ceci, je montre les éléments les plus importants :

<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>

J'ai mis en gras les paramètres et valeurs importants. N'oubliez pas de définir l'adresse IP (ou le nom d'hôte), le nom de la base de données et le port en fonction de la configuration de votre serveur pgbouncer.

De plus, au lieu du nom d'utilisateur/mot de passe typique, vous devrez définir un domaine de sécurité, qui doit être spécifié dans la section de la source de données, comme indiqué ci-dessus. Sa définition ressemblera à :

<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>

De cette façon, wildfly déléguera le contexte de sécurité à pgbouncer.

REMARQUE : dans ce blog, nous couvrons les bases, c'est-à-dire que nous n'utilisons ni ne mentionnons TLS, mais vous êtes fortement encouragé à l'utiliser dans votre installation.

Les utilisateurs sauvages doivent s'authentifier auprès de votre serveur LDAP comme suit :

<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>

Les fichiers de configuration ci-dessus s'appliquent à wildfly 10.0, il vous est conseillé dans tous les cas de consulter la documentation officielle de votre environnement.

Configuration PostgreSQL

Afin de dire à PostgreSQL de s'authentifier (REMARQUE : pas autoriser !) sur votre serveur LDAP, vous devez apporter les modifications appropriées à postgresql.conf et pg_hba.conf. Les entrées intéressantes sont les suivantes :

Dans postgresql.conf :

listen_addresses = '*'

et dans 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"

Assurez-vous que les paramètres LDAP définis ici correspondent exactement à ceux que vous avez définis dans la configuration de votre serveur d'applications. Il existe deux modes de fonctionnement dans lesquels PostgreSQL peut être chargé de contacter le serveur LDAP :

  • liaison simple
  • rechercher puis lier

Le mode de liaison simple ne nécessite qu'une seule connexion au serveur LDAP, il est donc plus rapide mais nécessite une organisation de dictionnaire LDAP plus stricte que le second mode. Le mode de recherche et de liaison permet une plus grande flexibilité. Cependant, pour l'annuaire LDAP moyen, le premier mode (liaison simple) fonctionnera très bien. Nous devons souligner certains points concernant l'authentification LDAP PostgreSQL :

  • Cela concerne l'authentification uniquement (vérification des mots de passe).
  • L'appartenance aux rôles se fait toujours dans PostgreSQL, comme d'habitude.
  • Les utilisateurs doivent être créés dans PostgreSQL (via CREATE user/role) comme d'habitude.

Il existe des solutions pour faciliter la synchronisation entre les utilisateurs LDAP et PostgreSQL (par exemple, ldap2pg) ou vous pouvez simplement écrire votre propre wrapper qui gérera à la fois LDAP et PostgreSQL pour ajouter ou supprimer des utilisateurs.

Téléchargez le livre blanc aujourd'hui PostgreSQL Management &Automation with ClusterControlDécouvrez ce que vous devez savoir pour déployer, surveiller, gérer et faire évoluer PostgreSQLTélécharger le livre blanc

Configuration de PgBouncer

C'est la partie la plus difficile de notre configuration, car le support LDAP natif est toujours absent de pgbouncer, et la seule option est de s'authentifier via PAM, ce qui signifie que cela dépend de la configuration PAM UNIX/Linux locale correcte pour LDAP.

La procédure est donc divisée en deux étapes.

La première étape consiste à configurer et tester que pgbouncer fonctionne avec PAM, et la deuxième étape consiste à configurer PAM pour qu'il fonctionne avec LDAP.

pgbuncer

pgbouncer doit être compilé avec le support PAM. Pour ce faire, vous devrez :

  • installer libpam0g-dev
  • ./configure --with-pam
  • recompiler et installer pgbouncer

Votre pgbouncer.ini (ou le nom de votre fichier de configuration pgbouncer) doit être configuré pour pam. De plus, il doit contenir les paramètres corrects pour votre base de données et votre application conformément aux paramètres décrits dans les sections ci-dessus. Choses que vous devrez définir ou modifier :

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

Bien sûr, vous devrez lire la documentation de pgbouncer et ajuster votre pgbouncer en fonction de vos besoins. Afin de tester la configuration ci-dessus, tout ce que vous avez à faire est de créer un nouvel utilisateur UNIX local et d'essayer de vous authentifier auprès de pgbouncer :

# adduser testuser
<answer to all question, including password>

Pour que pgbouncer fonctionne avec PAM lors de la lecture des fichiers passwd locaux, l'exécutable pgbouncer doit appartenir à root et avec setuid :

# 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

Remarque :La nécessité d'être propriétaire root et de setuid (ce qui est vrai pour tous les systèmes debian/ubuntu que j'ai testés) n'est documentée nulle part, ni dans la documentation officielle de pgbouncer ni nulle part sur le net.

Ensuite, nous nous connectons (en tant que superutilisateur pgsql) à l'hôte postgresql (ou psql -h your.pgsql.server) et créons le nouvel utilisateur :

CREATE USER testuser PASSWORD 'same as the UNIX passwd you gave above';

puis depuis l'hôte pgbouncer :

psql -h localhost -p 6432 yourdbname -U testuser

Vous devriez pouvoir obtenir une invite et voir les tables comme si vous étiez connecté directement à votre serveur de base de données. N'oubliez pas de supprimer cet utilisateur du système et de le supprimer également de la base de données lorsque vous avez terminé tous vos tests.

PAM

Pour que PAM s'interface avec le serveur LDAP, un package supplémentaire est nécessaire :libpam-ldap . Son script de post-installation lancera une boîte de dialogue en mode texte à laquelle vous devrez répondre avec les paramètres corrects pour votre serveur LDAP. Ce paquet effectuera les mises à jour nécessaires dans les fichiers /etc/pam.d et créera également un fichier nommé :/etc/pam_ldap.conf. Au cas où quelque chose changerait à l'avenir, vous pouvez toujours revenir en arrière et modifier ce fichier. Les lignes les plus importantes de ce fichier sont :

base cn=users,cn=accounts,dc=yourorgname,dc=com
uri ldap://your.ldap.server/
ldap_version 3
pam_password crypt

Le nom/l'adresse de votre serveur LDAP et la base de recherche doivent être exactement les mêmes que ceux spécifiés dans les fichiers PostgreSQL pg_hba.conf et Wildfly standalone.xml conf expliqués ci-dessus. pam_login_attribute est par défaut uid. Nous vous encourageons à consulter les fichiers /etc/pam.d/common-* et à voir ce qui a changé après l'installation de libpam-ldap. En suivant la documentation, vous pouvez créer un nouveau fichier nommé /etc/pam.d/pgbouncer et y définir toutes les options PAM, mais les fichiers common-* par défaut suffiront. Jetons un coup d'œil dans /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 sera vérifié en premier, et si cela échoue, LDAP sera vérifié, alors gardez à l'esprit que vous devrez effacer tous les mots de passe locaux pour les utilisateurs qui sont définis à la fois sur le linux/unix /etc/passwd local et dans LDAP . Il est maintenant temps de faire le test final. Choisissez un utilisateur défini dans votre serveur LDAP et également créé dans PostgreSQL, et essayez de vous authentifier depuis la BD (via pgsql -h votre.pgsql.server ), puis depuis pgbouncer (également via psql -h your.pgbouncer.server) , et enfin via votre application. Vous venez de faire d'un système de sécurité unique pour les applications, le pool de connexions et PostgreSQL une réalité !