sql >> Base de Datos >  >> NoSQL >> MongoDB

Conexión de MongoDB a Ruby con certificados autofirmados para SSL

Dada la popularidad de nuestra publicación sobre la conexión de MongoDB SSL con certificados autofirmados en Node.js, decidimos escribir un tutorial sobre la conexión de MongoDB con Ruby. En este blog, le mostraremos cómo conectarse a un servidor MongoDB configurado con certificados autofirmados para SSL mediante el controlador Ruby MongoDB y el popular mongoide Object-Document-Mapper (ODM).

ScaleGrid actualmente usa certificados autofirmados para SSL al crear nodos para un nuevo clúster. Además, también le brindamos la opción de comprar sus propios certificados SSL y configurarlos en el servidor MongoDB, y puede enviar un correo electrónico a [email protected] para obtener más información sobre esta oferta.

Conexión a un conjunto de réplicas mediante el controlador Ruby MongoDB

Usaremos la última versión estable del controlador Ruby MongoDB versión 2.8 para este ejemplo. Las versiones 2.5.x del controlador tienen un error conocido que les impide trabajar con implementaciones de ScaleGrid. La versión de Ruby utilizada en los dos ejemplos a continuación es 2.6.3.

Las opciones de conexión disponibles para el controlador están documentadas aquí, y las opciones que necesitaremos son:

  • :ssl
  • :ssl_verificar
  • :ssl_ca_cert .

Primero, busque y copie su cadena de conexión de MongoDB desde la página de detalles del clúster en la consola de ScaleGrid:

El archivo del certificado de CA también está disponible para su descarga desde la página de detalles del clúster. Descargue y almacene el archivo de certificado en una ubicación que esté disponible para la aplicación:
Aquí hay un fragmento que muestra cómo conectarse a un conjunto de réplicas de MongoDB desde Ruby:

requiere 'mongo'Mongo::Logger.logger.level =::Logger::DEBUGMONGODB_CA_CERT ="/path/to/ca_cert.pem"MONGODB_CONN_URL ="mongodb://testuser:@SG-example- 17026.servers.mongodirector.com:27017,SG-example-17027.servers.mongodirector.com:27017,SG-example-17028.servers.mongodirector.com:27017/test?replicaSet=RS-example-0&ssl=true" options ={ ssl:true, ssl_verify:true, :ssl_ca_cert => MONGODB_CA_CERT }client =Mongo::Client.new(MONGODB_CONN_URL, options)db =client.databasecollections =db.collection_namesputs "db #{db.name} tiene colecciones # {colecciones}"cliente.cerrar

Para simplificar el ejemplo, hemos especificado la cadena de conexión y la ruta del archivo de certificado directamente en el fragmento de código; por lo general, los colocaría en un archivo yaml o los especificaría como Variables de entorno. Además, el ejemplo establece el nivel de registro en DEBUG para que cualquier problema de conectividad pueda ser depurado. Debe cambiarse a un nivel menos detallado una vez que se hayan solucionado los problemas de conectividad.

Cómo conectar MongoDB a una aplicación Ruby con SSLClick To Tweet

Conexión usando Mongoid

La versión mongoide que usaremos en nuestro ejemplo es la última versión estable:7.0.2. Usaremos un archivo yaml para proporcionar la configuración a mongoid, y los detalles de dicho archivo de configuración se documentan aquí. Las opciones de configuración específicas de SSL que necesitaremos para conectarnos a nuestro conjunto de réplicas son:

  • ssl
  • ssl_verificar
  • ssl_ca_cert

Nuestro archivo yml:

desarrollo:# Configurar clientes de bases de datos disponibles. (obligatorio) clientes:# Defina el cliente predeterminado. (obligatorio) predeterminado:# Se puede definir un uri para un cliente:# uri:'mongodb://usuario:contraseñ[email protected]:27017/mi_bd' # Consulte la documentación del controlador para obtener más detalles. Como alternativa, puede definir lo siguiente:# # Defina el nombre de la base de datos predeterminada a la que se puede conectar Mongoid. # (requerido). base de datos:prueba # Proporcione los hosts a los que se puede conectar el cliente predeterminado. Debe ser una matriz # de host:pares de puertos. (obligatorio) hosts:- SG-example-17026.servers.mongodirector.com:27017 - SG-example-17027.servers.mongodirector.com:27017 - SG-example-17028.servers.mongodirector.com:47100  opciones:# El nombre del usuario para la autenticación. usuario:'usuariodeprueba' # La contraseña del usuario para la autenticación. contraseña:'pwd' # Los roles de la base de datos del usuario. roles:- 'readWrite' # Cambiar el mecanismo de autenticación por defecto. Las opciones válidas son::scram, # :mongodb_cr, :mongodb_x509 y :plain. (el valor predeterminado en 3.0 es :scram, el número predeterminado en 2.4 y 2.6 es :plain) auth_mech::scram # La base de datos o la fuente para autenticar al usuario. (predeterminado:administrador) auth_source:prueba # Forzar al controlador a conectarse de una manera específica en lugar de auto- # descubrimiento. Puede ser uno de::direct, :replica_set, :sharded. Establézcalo en :direct # cuando se conecte a miembros ocultos de un conjunto de réplicas. connect::replica_set ... ... # El nombre del conjunto de réplicas al que conectarse. Se ignorarán los servidores proporcionados como semillas que # no pertenecen a este conjunto de réplicas. conjunto_de_réplicas:RS-ejemplo-0 # Si conectarse a los servidores a través de ssl. (predeterminado:falso) ssl:verdadero # Si hacer o no la validación de la certificación por pares. (predeterminado:verdadero) ssl_verify:verdadero # El archivo que contiene un conjunto de certificaciones de autoridades de certificación concatenadas # utilizado para validar los certificados pasados ​​desde el otro extremo de la conexión. ssl_ca_cert:/ruta/a/ca_cert.pem # Configure las opciones específicas de Mongoid. (opcional) opciones:# Establecer los niveles de registro del controlador Mongoid y Ruby. (predeterminado::info) log_level::debug

Ejemplo de conexión:

gem 'mongoid', '7.0.2'require 'mongoid'Mongoid.load!("/ruta/a/mongoid.yml", :desarrollo)# Sin usar ninguna de las características ODM - solo busque el mongo subyacente cliente e intente conectarclient =Mongoid::Clients.defaultdb =client.databasecollections =db.collection_namesputs "db #{db.name} tiene colecciones #{colecciones}" Mongoid::Clients.disconnect

Nuevamente, en las aplicaciones Ruby on Rails de producción, la ruta del archivo yaml se obtendría de las variables de entorno.

Comportamiento de prueba de conmutación por error

Al igual que otros controladores MongoDB, el controlador Ruby MongoDB también está diseñado para reconocer internamente los cambios en la topología debido a eventos como la conmutación por error. Sin embargo, es bueno probar y validar el comportamiento del controlador durante las conmutaciones por error para evitar sorpresas en la producción.

Al igual que mi publicación anterior sobre MongoDB PyMongo, podemos escribir un programa de prueba de escritor perpetuo para observar el comportamiento de conmutación por error del controlador.

La forma más sencilla de inducir la conmutación por error es ejecutar el comando rs.stepDown():

RS-example-0:PRIMARY> rs.stepDown()2019-04-18T19:44:42.257+0530 E QUERY [thread1] Error:error al realizar la consulta:error:error de red al intentar ejecutar el comando 'replSetStepDown' en el host 'SG-example-1.servers.mongodirector.com:27017' :DB.prototype.runCommand@src/mongo/shell/db.js:168:1DB.prototype.adminCommand@src/mongo/shell/db. js:185:1rs.stepDown@src/mongo/shell/utils.js:1305:12@(shell):1:12019-04-18T19:44:42.261+0530 I NETWORK [thread1] intentando volver a conectarme a SG-example -1.servers.mongodirector.com:27017 (X.X.X.X) falló2019-04-18T19:44:43.267+0530 I NETWORK [thread1] reconnect SG-example-1.servers.mongodirector.com:27017 (X.X.X.X) okRS-example- 0:SECUNDARIO>

Estas son las partes relevantes de nuestro código de prueba:

requerir 'mongo'...logger =Logger.new(STDOUT)logger.level =Logger::INFOMONGODB_CA_CERT ="/path/to/ca_cert.pem"MONGODB_CONN_URL ="mongodb://testuser:@ SG-example-17026.servers.mongodirector.com:27017,SG-example-17027.servers.mongodirector.com:27017,SG-example-17028.servers.mongodirector.com:27017/test?replicaSet=RS-example- 0&ssl=true"options ={ ssl:true, ssl_verify:true, :ssl_ca_cert => MONGODB_CA_CERT }begin logger.info("Intentando conectarse...") client =Mongo::Client.new(MONGODB_CONN_URL, options) i =0 loop do db =client.database collection =db[:test] begin doc ={"idx":i, "date":DateTime.now, "text":SecureRandom.base64(3) } result =collection.insert_one( doc) logger.info("Registro insertado - id:#{result.inserted_id}") i +=1 sleep(3) rescate Mongo::Error => e logger.error("Mong Error visto:#{e.message }") registrador.error(e.backtrace) registrador.i nfo("Reintentando...") end end logger.info("Listo")rescue => err logger.error("Excepción vista:#{err.mensaje}") logger.error(err.backtrace)asegurar cliente. cerrar a menos que client.nil?end

Esto escribe continuamente entradas como estas en la colección de prueba en la base de datos de prueba:

RS-test-0:PRIMARY> db.test.find(){ "_id" :ObjectId("5cf50ff1896cd172a4f7c6ee"), "idx" :0, "fecha" :ISODate("2019-06-03T12:17 :53.008Z"), "texto" :"HTvd" }{ "_id" :ObjectId("5cf50ff6896cd172a4f7c6ef"), "idx" :1, "fecha" :ISODate("2019-06-03T12:17:58.697Z" ), "texto" :"/e5Z" }{ "_id" :ObjectId("5cf50ff9896cd172a4f7c6f0"), "idx" :2, "fecha" :ISODate("2019-06-03T12:18:01.940Z"), " texto" :"quuw" }{ "_id" :ObjectId("5cf50ffd896cd172a4f7c6f1"), "idx" :3, "fecha" :ISODate("2019-06-03T12:18:05.194Z"), "texto" :" gTyY" }{ "_id" :ObjectId("5cf51000896cd172a4f7c6f2"), "idx" :4, "fecha" :ISODate("2019-06-03T12:18:08.442Z"), "texto" :"VDXX" }{ "_id" :ObjectId("5cf51003896cd172a4f7c6f3"), "idx" :5, "fecha" :ISODate("2019-06-03T12:18:11.691Z"), "texto" :"UY87" }...

Veamos el comportamiento durante una conmutación por error:

I, [2019-06-03T17:53:25.079829 #9464] INFO -- :Intentando conectar...I, [2019-06-03T17:53:30.577099 #9464] INFO -- :Registro insertado - id:5cf5113f896cd124f8f31062I, [2019-06-03T17:53:33.816528 #9464] INFO --:Registro insertado - id:5cf51145896cd124f8f31063I, [2019-06-03T17:53:37.047043] - INFO id:insertado 5CF51148896CD124F8F31064I, [2019-06-03T17:53:40.281537 #9464] INFO-:REGISTRADO-ID:5CF5114C896CD124F8F31065I, [2019-06-03T17:53:43.520010 [2019-06-03T17:53:46.747080 #9464] INFO -- :Registro insertado - id:5cf51152896cd124f8f31067I, [2019-06-03T17:53:49.978077 #9464] INFO -- :Registro insertado - id:5cf511548886 <<3f12cd1 Conmutación por error iniciada aquíE, [2019-06-03T17:53:52.980434 #9464] ERROR --:Mong Error visto:EOFError:se alcanzó el final del archivo (para x.x.x.x:27017 (sg-example-17026.servers.mongodirector.com:27017 , TLS))E, [2019-06-03T17:53:52.980533 #9464] ERROR -- :["C:/Rubí 26-x64/lib/ruby/gems/2.6.0/gems/mongo-2.8.0/lib/mongo/socket.rb:300:in `rescatar en handle_errors'", "C:/Ruby26-x64/lib/ ruby/gems/2.6.0/gems/mongo-2.8.0/lib/mongo/socket.rb:294:in `handle_errors'", "C:/Ruby26-x64/lib/ruby/gems/2.6.0/ gems/mongo-2.8.0/lib/mongo/socket.rb:126:in `leer'", "C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/mongo-2.8.0/ lib/mongo/protocol/message.rb:139:in `deserialize'",......I, [2019-06-03T17:53:52.980688 #9464] INFO -- :Reintentando...W, [ 2019-06-03T17:53:52.981575 #9464] WARN -- :Reintentando ismaster en sg-example-17026.servers.mongodirector.com:27017 debido a:Mongo::Error::SocketError EOFError:se alcanzó el final del archivo (para x.x.x.x:27017 (sg-example-17026.servers.mongodirector.com:27017, TLS))I, [2019-06-03T17:54:06.293100 #9464] INFO -- :Registro insertado - id:5cf51163896cd124f8f3106aI, [2019- 06-03T17:54:09.547716 #9464] INFO -- :Registro insertado - id:5cf51169896cd124f8f3106bI, [2019-06-03T17:54:12.806636 #9464] INFO -- :Registro insertado - id:5cf5116c896cd1106c8f 

Es evidente que si se detectan los errores correctos y se vuelve a intentar la lectura/escritura, el controlador detectará automáticamente el cambio de topología y se volverá a conectar al nuevo maestro. Para escrituras, la opción :retry_writes asegúrese de que el controlador vuelva a intentarlo una vez por su cuenta antes de notificar a la aplicación de un error.

También hay varios tiempos de espera del controlador que se pueden ajustar en función del comportamiento exacto y la latencia que ve en su configuración. Estos están documentados aquí.

Resolución de problemas

Si tiene problemas para conectarse a su implementación de MongoDB compatible con SSL, aquí hay algunos consejos para la depuración:

  • Primero, verifique que realmente pueda conectarse al servidor MongoDB desde el servidor donde se ejecuta su aplicación. La forma más sencilla de hacer esto es instalar mongo shell en la máquina cliente. En Linux, no necesitaría instalar todo el servidor MongoDB; puede optar por instalar el shell por separado. Una vez que el shell esté disponible, intente usar la "Sintaxis de la línea de comandos" que proporcionamos para intentar conectarse al servidor.
  • Si no puede conectarse a través del shell mongo, significa que la máquina cliente no puede llegar al puerto 27017 de los servidores MongoDB. Examine la configuración del cortafuegos de su grupo de seguridad, VPC y ScaleGrid para asegurarse de que haya conectividad entre las máquinas cliente y servidor.
  • Si la conectividad de la red es correcta, lo siguiente que debe verificar es que esté usando versiones de Ruby, mongoid y mongo gem que sean compatibles con la versión de su servidor MongoDB.
  • Si ha confirmado que las versiones del controlador son correctas, intente ejecutar una secuencia de comandos Ruby de muestra, similar al ejemplo que proporcionamos anteriormente, en el IRB. Una ejecución paso a paso podría señalar dónde está el problema.
  • Si la secuencia de comandos de prueba funciona bien, pero aún no puede conectarse con mongoid, intente ejecutar una secuencia de comandos de prueba simple, como el ejemplo que proporcionamos anteriormente .
  • Si aún tiene problemas para conectarse a su instancia, escríbanos a [email protected] con los resultados detallados de los pasos de solución de problemas anteriores y con las versiones exactas de Ruby, mongoid y mongo driver que está utilizando. Gemfile.lock le proporcionará las versiones exactas.

Si eres nuevo en ScaleGrid y quieres probar este tutorial, regístrate para una prueba gratuita de 30 días para explorar la plataforma y probar conectando MongoDB a su aplicación Ruby.