Api REST/Mongo WireListener (Parte I - Configuración)
He estado configurando el WireListener de Informix en dos de sus modalidades, Mongo y REST. Luego de varios meses buscando información, NO encontré un solo lugar donde se hallen todos los pasos juntos, con todo lo necesario, partiendo desde los pre requisitos, hasta las pruebas pasando por las configuraciones, y recomendaciones.
Arranquemos con algunas generalidades, que luego iré describiendo en detalle. El WireListener requiere de un usuario propio, el cual debe ser definido en Informix, y algo importante, NO requiere estar definido a nivel de SO, lo autenticará Informix. Es un unmapped user. En mi caso lo llamé simplemente “mongo”. Es decir que tanto REST como Mongo tendrán cada uno su WireListener, cada cual con su archivo de propiedades o configuraciones. Para el resto de los usuarios que utilicen el WireListener requieren de la autenticación PAM (Pluggable Authentication Method). Si bien cada servicio utilizará un PORT diferente (Mongo usando el que MongoDB utiliza por defecto 27017, y REST 27018), pueden compartir el mismo usuario “mongo”. En versiones anteriores, eran dos aplicaciones separadas, ahora la api REST utiliza la misma configuración que la api Mongo, y su diferencia está básicamente en el archivo de propiedades (listener.type=mongo o rest, el puerto donde escuche cada uno, y security.sql.passthrough=true o false (ver explicación de ésta última variable en la sección: Preparar los archivos de Propiedades)).
Pre requisitos.
Java debe estar instalado y actualizado en el server. Tiene que ser un JRE 1.7 o superior. La versión que utilicé yo es la siguiente:
java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build pap3280sr4fp6-20170518_02(SR4 FP6))
IBM J9 VM (build 2.8, JRE 1.8.0 AIX ppc-32 20170516_348050 (JIT enabled, AOT enabled)
J9VM - R28_20170516_1905_B348050
JIT - tr.r14.java_20170516_348050
GC - R28_20170516_1905_B348050
J9CL - 20170516_348050)
JCL - 20170516_01 based on Oracle jdk8u131-b11
Dos últimos requisitos, que si bien no son necesarios para el funcionamiento de los WireListeners, para probar sus funcionamientos, sí son necsarios. Para probar la api REST, instalar la herramienta curl en el servidor. Para probar la api MONGO, instalar el cliente mongo Robo 3T en Windows (versión free -- www.robomongo.org). No probar con el cliente mongo propio de MongoDB (Compass) porque no funciona aún, seguramente en versiones futuras será compatible.
Seteo de variables de entorno
Agregar en el .profile:
export IFMXMONGOAUTH=1
Esto le indica al motor de Informix que utilizará PAM para la autenticación de los usuarios que utilizan el WireListener.
Estas otras dos variables de entorno, pueden no ser necesarias, pero es recomendable tenerlas seteados:
export IBM_JAVA_OPTIONS=-Dcom.ibm.tools.attach.enable=no
Este parámetro evita que (otras) aplicaciones puedan "hackear" la máquina virtual Java del WireListener. (Sin este parámetro, una aplicación puede conectarse a la JVM y luego cargar su propio código de programa en la JVM para su ejecución).
export CLASSPATH=${INFORMIXDIR}/lib/ifxjdbc.jar:${CLASSPATH}
Dado que la comunicación entre el server de Informix y el WireListener es vía JDBC, es importante que si el driver de JDBC no está ubicado en su lugar por defecto, se especifique en éste lugar.
Configuración PAM
Dependerá de la versión del SO de como configurar PAM. Típicamente el archivo de configuración con los parámetros se encuentra en /etc/pam.conf.
En Linux, es diferente, hay un archivo para cada servicio PAM dentro de /etc/pam.d, y el archivo a crear es el /etc/pam.d/pam_mongo.
En mi caso con AIX, agregué estas dos líneas de configuración , cada cual en su sección correspondiente:
# Authentication
pam_mongo auth required /opt/Informix_Software_Bundle/lib/pam_mongo.so file=mongohash
# Account Management
pam_mongo account required /opt/Informix_Software_Bundle/lib/pam_mongo.so
No utilizar el PATH relativo, sino el absoluto para indicar donde se ecuentre la librería pam_mongo.so. Es decir no utilizar $INFROMIXDIR/lib/pam_mongo.so
En Linux como no es un archivo único para todos los servicios, se deben agregar estas mismas líneas pero sin pam_mongo adelante de todo en la línea (ver resaltado arriba):
# Authentication
auth required /opt/Informix_Software_Bundle/lib/pam_mongo.so file=mongohash
# Account Management
account required /opt/Informix_Software_Bundle/lib/pam_mongo.so
Crear Link
En el caso de utilizar AIX únicamente (como es mi caso), crear un link simbólico llamado 64 que apunta al lib de Informix
cd $INFORMIXDIR/lib
ln -s . 64
Configuración INFORMIXSQLHOSTS
Agregar el servicio para mongo en el INFORMIXSQLHOSTS, donde su nivel de autenticación será a través de PAM. Quinta columna columna s=<server security setting>
myempresa_mongo onsoctcp myhost 30000 s=4,pam_serv=pam_mongo,pamauth=password
Ojo con el Host, en algunas documentaciones encontré que utilizaron localhost, en vez de indicar el nombre del host. A mi no me anduvo con localhost en AIX, a pesar que tenía el loopback localhost seteado en /etc/hosts
Configuración ONCONFIG
Habilitar las conexiones de usuarios mapeados en el ONCONFIG a BASIC o ADMIN.
USERMAPPING=BASIC
Por defecto el USERMAPPING está en OFF. es decir que los usuarios autentican a través del SO. Seteándolo como BASIC es suficiente para permitir que usuarios no mapeados (que no tengan cuenta a nivel del SO) puedan conectarse. Lo necesita para el usuario "mongo" que se utiliza en el WireListener.
El motor debe ser reiniciado para que tome el mapeo, o también a través de:
onmode -wf USERMAPPING=BASIC
También agregar el nuevo servicio myempresa_mongo a DBSERVERALIAS.
Configuración del usuario sustituto
Setear el mapeo a un usuario de SO que no tenga privilegios, es decir que no exista, como comentaba antes. Esto conjuntamente con el seteo del paso anterior, nos habilitará a crear el usuario “mongo” para que autentique contra Informix únicamente. Se pueden (el directorio /etc/Informix y el archivo allowed.surrogates) crear como root:informix y permisos 644 (para que Informix lo pueda modificar)
echo “users:nobody” >> /etc/informix/allowed.surrogates
El motor debe ser reinicado para que tome al user nobody, o también a través de: onmode -cache surrogates
Preparar los archivos de propiedades
Setear los siguientes valores en cada uno de los archivos de propiedades REST y Mongo. Lo que hay que hacer es tomar el archivo modelo que viene con la distribución ($INFORMIXDIR/etc/jsonListener-example.properties), hacer una copia, y modificarlo para cada uno los siguientes valores. Recomiendo segurizar los archivos de propiedades con permisos de r/w para Informix solamente 600:
Properties file (REST):
authentication.enable=true
database.connection.strategy=informix-mongodb-cr → Es el mecanismo de autenticación que utiliza MongoDB.
database.locale.default=en_US.819
db.authentication=informix-mongodb-cr
listener.authentication.timeout=60000
listener.hostName=* → Es necesario para que se permitan conexiones fuera del host local. Es decir que una vez levantado el WireListener, podemos comprobar el puerto 27018 con netstat -a y comprobar que en vez de localhost figurará *. De esa manera podemos restringir el acceso según el requerimiento.
listener.port=27018
listener.type=rest
mongo.api.version=2.6 → Es posible también usar compatibilidad con MongoDB 3.2, si bien la versión actual de MongoDB es 3.6, 3.2 está muy cerca.
url=jdbc:informix-sqli://myhost.empresa.com.ar:30000/sysmaster:INFORMIXSERVER=myempresa_mongo;USER=mongo;PASSWORD=mipassword;NONCE=0123456789abcdef
Properties file (MONGO):
authentication.enable=true
database.connection.strategy=informix-mongodb-cr
database.locale.default=en_US.819
db.authentication=informix-mongodb-cr
listener.authentication.timeout=60000
listener.hostName=*
listener.port=27017
listener.type=mongo
mongo.api.version=2.6
security.sql.passthrough=true → Es necesario habilitar éste parámetro en los WireListeners para poder enviar/ejecutar sentencias SQL y Stored Procedures. Fue introducido en 12.10.xFC7.
url=jdbc:informix-sqli://myhost.empresa.com.ar:30000/sysmaster:INFORMIXSERVER=myempresa_mongo;USER=mongo;PASSWORD=mipassword;NONCE=0123456789abcdef
Como dije al principio, las diferencias entre los archivos de configuraciones de Api REST y Mongo, son mínimas ya que utilizan la misma aplicaicón.
Reiniciar el motor de Informix
Si bien algunos cambios se pueden hacer on-line, como el del cambio en el ONCONFIG, hay otros como el del SQLHOSTS, que requiren que el motor se reinicie, para que levante los seteos y configuraciones.
En realidad si se hicieron los cambios en el ONCONFIG dinámicamente con onmode, por lo único que se requeriría reiniciar sería por los nuevos nombres de servicios agregados al SQLHOSTS file.
Crear el usuario 'mongo' en Informix.
El usuario necesita permiso de conexión a sysmaster. Notar que se crea con la propiedad de "nobody", es decir que el usuario "mongo" no será mapeado. La password que utilicemos acá, será la que el WireListener de REST y Mongo utilizarán para autenticar.
DATABASE sysmaster;
CREATE USER 'mongo' WITH PASSWORD 'mipassword'
PROPERTIES USER 'nobody';
GRANT CONNECT TO 'mongo';
IMPORTANTE: No crear el usuario sin antes haber bounceado el motor, después de haber seteado las variables de entorno. Si el motor no fue bounceado con la variable de entorno IFMXMONGOAUTH en 1, no se creará el usuario 'mongo' correctamente en la tabla sysmongousers. Para comprobar que el usuario se haya creado correctamente chequear lo siguiente:
echo "SELECT * FROM sysmongousers" | dbaccess sysuser
Database selected.
username mongo hashed_password 0f23c91e12ceb4d01e044b3a135196fa
1 row(s) retrieved.
Database closed.
Iniciar los WireListeners
Para iniciar los listeners, cree dos scripts, cada cual para arrancar los listeners correspondientes, utilizando el siguiente contenido:
cat start_wire_listenerREST.sh
java -cp $INFORMIXDIR/bin/jsonListener.jar \
com.ibm.nosql.server.ListenerCLI \
-config $INFORMIXDIR/etc/jsonListenerREST-myempresa.properties \
-logfile $INFORMIXDIR/tmp/jsonListenerREST-myempresa.log \
-loglevel info -start &
#-loglevel debug -start &
#-loglevel trace -start &
Los niveles de logging del WireListener, se pueden manejar desde acá. Al momento de levantar el listener, yendo de menor a mayor nivel de logging, partiendo de info a trace, pasando por debug.
Una vez levantados los procesos, podemos verlos corriendo:
ps -fu informix | grep Listener
informix 25034932 1 1 Apr 11 - 4:37 java -cp /opt/Informix_Software_Bundle/bin/jsonListener.jar com.ibm.nosql.server.ListenerCLI -config /opt/Informix_Software_Bundle/etc/jsonListenerMONGO-myempresa.properties -logfile /opt/Informix_Software_Bundle/tmp/jsonListenerMONGO-myempresa.log -loglevel debug -start
informix 31522870 1 1 08:43:13 pts/0 0:02 java -cp /opt/Informix_Software_Bundle/bin/jsonListener.jar com.ibm.nosql.server.ListenerCLI -config /opt/Informix_Software_Bundle/etc/jsonListenerREST-myempresa.properties -logfile /opt/Informix_Software_Bundle/tmp/jsonListenerREST-myempresa.log -loglevel info -start
Para bajar los listeners se pueden simplemente matar los procesos con un kill.
Podemos revisar los logs jsonListenerMONGO-myempresa.log y jsonListenerREST-myempresa.log para comprobar que no hayan errores. Notar que para el WireListener de Mongo el nivel de logging es debug, conviene al principio mantener ese nivel de logging, hasta que veamos que está todo sin errores, después ya pasarlo a nivel info es suficiente.
Referencias