Tradicionalmente, la aplicación típica consta de los siguientes componentes:
En este caso sencillo, bastaría con una configuración básica:
- la aplicación utiliza un mecanismo de autenticación local simple para sus usuarios
- la aplicación utiliza un grupo de conexiones simple
- hay un único usuario definido para el acceso a la base de datos
Sin embargo, a medida que la organización evoluciona y crece, se agregan más componentes:
- más aplicaciones de inquilinos o instancias de la aplicación que acceden a la base de datos
- más servicios y sistemas accediendo a la base de datos
- autenticación/autorización central (AA) para todos (o la mayoría) de los servicios
- separación de componentes para escalar más fácilmente en el futuro
En el esquema anterior, todas las preocupaciones se separan en componentes individuales, cada componente tiene un propósito especializado. Sin embargo, el conjunto de conexiones aún utiliza un solo usuario de base de datos dedicado como en la configuración anterior más simple que vimos arriba.
Además de los nuevos componentes, también llegan nuevos requisitos:
- mejor control detallado de lo que los usuarios pueden hacer en el nivel de la base de datos
- auditoría
- mejor registro del sistema más útil
Siempre podemos implementar los tres con más código de aplicación o más capas en la aplicación, pero esto es engorroso y difícil de mantener.
Además, PostgreSQL ofrece un conjunto tan rico de soluciones en las áreas antes mencionadas (seguridad, seguridad de nivel de fila, auditoría, etc.) que tiene perfecto sentido mover todos esos servicios a la capa de la base de datos. Para tomar esos servicios directamente de la base de datos, debemos olvidarnos del usuario único en la base de datos y usar usuarios individuales reales en su lugar.
Esto nos lleva a un esquema como el siguiente:
En nuestro caso de uso, describiremos una configuración empresarial típica que consiste en el esquema anterior donde usamos:
- Servidor de aplicaciones Wildfly (se muestran ejemplos para la versión 10)
- Servicio de autenticación/autorización LDAP
- agrupador de conexiones pgbouncer
- PostgreSQL 10
Parece una configuración típica, ya que jboss/wildfly ha sido compatible con la autenticación y autorización LDAP durante muchos años, PostgreSQL ha sido compatible con LDAP durante muchos años.
Sin embargo, pgbouncer solo comenzó a admitir LDAP (y esto a través de PAM) desde la versión 1.8 a fines de 2017, lo que significa que alguien hasta ese momento no podía usar el agrupador de conexiones PostgreSQL más popular en una configuración empresarial de este tipo (que no sonaba prometedor desde cualquier ángulo que elijamos mirarlo)!
En este blog, describiremos la configuración necesaria en cada capa.
Configuración de Wildfly 10
La configuración de la fuente de datos tendrá que verse así, estoy mostrando las cosas más importantes:
<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>
He puesto en negrita los parámetros y valores importantes. Recuerde definir la dirección IP (o nombre de host), el nombre de la base de datos y el puerto de acuerdo con la configuración de su servidor pgbouncer.
Además, en lugar del típico nombre de usuario/contraseña, deberá tener definido un dominio de seguridad, que debe especificarse en la sección de fuente de datos como se muestra arriba. Su definición se verá así:
<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 esta forma, wildfly delegará el contexto de seguridad a pgbouncer.
Los usuarios de wildfly deben autenticarse en su servidor LDAP de la siguiente manera:
<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>
Los archivos de configuración anteriores se aplican a wildfly 10.0, se recomienda en cualquier caso consultar la documentación oficial de su entorno.
Configuración de PostgreSQL
Para decirle a PostgreSQL que se autentique (NOTA: ¡no autorice!) contra su servidor LDAP, debe realizar los cambios apropiados en postgresql.conf y pg_hba.conf. Las entradas de interés son las siguientes:
En postgresql.conf:
listen_addresses = '*'
y en 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"
Asegúrese de que la configuración de LDAP definida aquí coincida exactamente con la que definió en la configuración del servidor de su aplicación. Hay dos modos de operación en los que se puede indicar a PostgreSQL que se ponga en contacto con el servidor LDAP:
- enlace simple
- buscar y vincular
El modo de enlace simple requiere solo una conexión al servidor LDAP, por lo tanto, es más rápido pero requiere una organización de diccionario LDAP algo más estricta que el segundo modo. El modo de búsqueda y vinculación permite una mayor flexibilidad. Sin embargo, para el directorio LDAP promedio, el primer modo (enlace simple) funcionará bien. Debemos subrayar ciertos puntos sobre la autenticación LDAP de PostgreSQL:
- Esto tiene que ver con autenticación solamente (verificación de contraseñas).
- La membresía de roles todavía se realiza en PostgreSQL, como de costumbre.
- Los usuarios deben crearse en PostgreSQL (a través de CREAR usuario/rol) como de costumbre.
Existen algunas soluciones para ayudar con la sincronización entre los usuarios de LDAP y PostgreSQL (p. ej., ldap2pg) o simplemente puede escribir su propio contenedor que manejará tanto LDAP como PostgreSQL para agregar o eliminar usuarios.
Descargue el documento técnico hoy Gestión y automatización de PostgreSQL con ClusterControl Obtenga información sobre lo que necesita saber para implementar, monitorear, administrar y escalar PostgreSQLDescargar el documento técnicoConfiguración de PgBouncer
Esta es la parte más difícil de nuestra configuración, debido al hecho de que pgbouncer aún no cuenta con soporte LDAP nativo, y la única opción es autenticarse a través de PAM, lo que significa que esto depende de la configuración local correcta de PAM de UNIX/Linux para LDAP.
Entonces, el procedimiento se divide en dos pasos.
El primer paso es configurar y probar que pgbouncer funciona con PAM, y el segundo paso es configurar PAM para que funcione con LDAP.
pgbouncer
pgbouncer debe compilarse con soporte PAM. Para hacerlo tendrás que:
- instalar libpam0g-dev
- ./configure --with-pam
- recompilar e instalar pgbouncer
Su pgbouncer.ini (o el nombre de su archivo de configuración de pgbouncer) debe estar configurado para pam. Además, debe contener los parámetros correctos para su base de datos y su aplicación de acuerdo con los parámetros descritos en las secciones anteriores. Cosas que tendrás que definir o cambiar:
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
Por supuesto, tendrá que leer los documentos de pgbouncer y ajustar su pgbouncer según sus necesidades. Para probar la configuración anterior, todo lo que tiene que hacer es crear un nuevo usuario local de UNIX e intentar autenticarse en pgbouncer:
# adduser testuser
<answer to all question, including password>
Para que pgbouncer funcione con PAM al leer archivos passwd locales, el ejecutable de pgbouncer debe ser propiedad de root y con 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
Nota:La necesidad de propiedad raíz y setuid (que es cierto para todos los sistemas debian/ubuntu que he probado) no está documentada en ninguna parte, ni en los documentos oficiales de pgbouncer ni en ninguna parte de la red.
Luego iniciamos sesión (como superusuario de pgsql) en el host de postgresql (o psql -h your.pgsql.server) y creamos el nuevo usuario:
CREATE USER testuser PASSWORD 'same as the UNIX passwd you gave above';
luego desde el servidor pgbouncer:
psql -h localhost -p 6432 yourdbname -U testuser
Debería poder obtener un aviso y ver las tablas como si estuviera conectado directamente a su servidor de base de datos. Recuerde eliminar a este usuario del sistema y también eliminarlo de la base de datos cuando haya terminado con todas sus pruebas.
PAM
Para que PAM interactúe con el servidor LDAP, se necesita un paquete adicional:libpam-ldap. Su secuencia de comandos posterior a la instalación ejecutará un cuadro de diálogo en modo texto al que deberá responder con los parámetros correctos para su servidor LDAP. Este paquete hará las actualizaciones necesarias en los archivos /etc/pam.d y también creará un archivo llamado:/etc/pam_ldap.conf. En caso de que algo cambie en el futuro, siempre puede volver atrás y editar este archivo. Las líneas más importantes de este archivo son:
base cn=users,cn=accounts,dc=yourorgname,dc=com
uri ldap://your.ldap.server/
ldap_version 3
pam_password crypt
El nombre/dirección de su servidor LDAP y la base de búsqueda deben ser exactamente los mismos que los especificados en los archivos pg_hba.conf de PostgreSQL y Wildfly standalone.xml conf explicados anteriormente. pam_login_attribute por defecto es uid. Le recomendamos que eche un vistazo a los archivos /etc/pam.d/common-* y vea qué cambió después de la instalación de libpam-ldap. Siguiendo los documentos, puede crear un nuevo archivo llamado /etc/pam.d/pgbouncer y definir todas las opciones de PAM allí, pero los archivos common-* predeterminados serán suficientes. Echemos un vistazo en /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
La contraseña de Unix se verificará primero, y si esto falla, se verificará LDAP, así que tenga en cuenta que deberá borrar las contraseñas locales para aquellos usuarios que estén definidos tanto en el linux/unix /etc/passwd local como en LDAP. . Ahora es el momento de hacer la prueba final. Elija un usuario que esté definido en su servidor LDAP y también creado en PostgreSQL, e intente autenticarse desde la base de datos (a través de pgsql -h your.pgsql.server), luego desde pgbouncer (también a través de pgbouncer -h your.pgbouncer.server) y finalmente a través de su aplicación. ¡Acabas de hacer realidad tener un único sistema de seguridad para la aplicación, el agrupador de conexiones y PostgreSQL!