Can a Mongo-Express container connect to MongoDB with TLS?

2.2k views Asked by At

I have a mongo container, started with the requireTLS TLS mode, and a mongo-express container. Mongo-express does not seem to manage to connect to mongo using TLS.

My docker-compose.yml:

version: '3.1'
services:
  mongodb1:
    image          : "mongo:4.2"
    container_name : "mongodb-001"
    ports:
      - '27017:27017'
    environment:
      MONGO_INITDB_ROOT_USERNAME : "admin"
      MONGO_INITDB_ROOT_PASSWORD : "adminpasswd"
    volumes:
      - "./mongo-data:/data/db"
      - "./etc_mongod.conf:/etc/mongod.conf"
      - "./certificates:/etc/certificates:ro"
    command:
      - "--tlsMode"
      - "preferTLS"
      - "--tlsDisabledProtocols"
      - "none"
      - "--tlsCertificateKeyFile"
      - "/etc/certificates/certificateKey.pem"
      - "--tlsCAFile"
      - "/etc/certificates/CA.crt"
      - "--tlsAllowConnectionsWithoutCertificates"

  mongo-express:
    image          : "mongo-express:latest"
    container_name : "mongo-express-001"
    ports:
      - '8081:8081'
    depends_on:
      - mongodb1
    volumes:
      - "./certificates/CA.crt:/etc/certificates/CA.crt:ro"
    environment:
      ME_CONFIG_MONGODB_SERVER: "mongodb-001"
      ME_CONFIG_MONGODB_PORT: "27017"
      ME_CONFIG_MONGODB_ENABLE_ADMIN: "false"
      ME_CONFIG_MONGODB_AUTH_DATABASE: "admin"
      ME_CONFIG_MONGODB_AUTH_USERNAME: "admin"
      ME_CONFIG_MONGODB_AUTH_PASSWORD: "adminpasswd"
      ME_CONFIG_MONGODB_ADMINUSERNAME: "admin"
      ME_CONFIG_MONGODB_ADMINPASSWORD: "adminpasswd"
      ME_CONFIG_SITE_SSL_ENABLED: "true"
      ME_CONFIG_MONGODB_CA_FILE: "/etc/certificates/CA.crt"

...and the error message I get:

mongodb-001      | 2020-10-09T14:16:13.299+0000 I  NETWORK  [listener] connection accepted from 172.31.0.3:44774 #2 (1 connection now open)
mongodb-001      | 2020-10-09T14:16:13.305+0000 I  NETWORK  [conn2] Error receiving request from client: SSLHandshakeFailed: The server is configured to only allow SSL connections. Ending connection from 172.31.0.3:44774 (connection id: 2)
mongodb-001      | 2020-10-09T14:16:13.305+0000 I  NETWORK  [conn2] end connection 172.31.0.3:44774 (0 connections now open)
mongo-express-001 | 
mongo-express-001 | /node_modules/mongodb/lib/server.js:265
mongo-express-001 |         process.nextTick(function() { throw err; })
mongo-express-001 |                                       ^
mongo-express-001 | Error [MongoError]: connection 0 to mongodb-001:27017 closed
mongo-express-001 |     at Function.MongoError.create (/node_modules/mongodb-core/lib/error.js:29:11)
mongo-express-001 |     at Socket.<anonymous> (/node_modules/mongodb-core/lib/connection/connection.js:200:22)
mongo-express-001 |     at Object.onceWrapper (events.js:422:26)
mongo-express-001 |     at Socket.emit (events.js:315:20)
mongo-express-001 |     at TCP.<anonymous> (net.js:674:12)
mongo-express-001 exited with code 1

Note that:

  • I can connect to MongoDB using a mongo shell with the same parameters I pass to mongo-express:
mongo "mongodb://admin:adminpasswd@mongodb-001:27017/admin?authSource=admin" --tls --tlsCAFile certificates/CA.crt
  • If I start MongoDB in preferTLS mode, the mongo-express connection works
2

There are 2 answers

0
private_567 On

Connection from mongo-express starts to work better when both are in the same docker network, like

docker network create netw1
docker network connect netw1 mongo
docker network connect netw1 mongo-exprs

And network can be defined with suitable arguments

docker network create --attachable --internal netw1
0
Hubbard.ZLee On

tl;dr

Create a new config.js file with the following code

module.exports = {
  mongodb: {
    connectionOptions: {
      ssl: true,
    }
  }
};

and mount that file in your docker compose file at /node_modules/mongo-express/config.js

Explanation

It appears to be an issue with their config.default.js file. In it, they have this

module.exports = {                                                                                                     
  mongodb: {                                                                                                           
    // if a connection string options such as server/port/etc are ignored
    connectionString: mongo.connectionString || getConnectionStringFromEnvVariables(),
                                                                                                                   
    connectionOptions: {                              
    // ssl: connect to the server using secure SSL
    ssl: process.env.ME_CONFIG_MONGODB_SSL || mongo.ssl,
                                                                                                                   
    // sslValidate: validate mongod server certificate against CA
    sslValidate: process.env.ME_CONFIG_MONGODB_SSLVALIDATE || true,
                                                                                                                   
    // sslCA: array of valid CA certificates                                                                         
    sslCA: sslCAFromEnv ? [sslCAFromEnv] : [],

    // autoReconnect: automatically reconnect if connection is lost                                 
    autoReconnect: true,                                                                                             
                                                                                                                   
    // poolSize: size of connection pool (number of connections to use)
    poolSize: 4,                                   
  }
}

You'll notice the existence of an env var that's not listed (with reason) in their documentation. ME_CONFIG_MONGODB_SSL

This is required to enable tls support. Setting the env var yourself however does nothing but throw an error and break express due to it not being cast to a Boolean. So it just reads as a string 'true' or 'false'.

This code is fixed in their npm package code, but they haven't updated their docker image since late 2021. So the only "fix" I've found for this is to create a new config.js file with the following code

module.exports = {
  mongodb: {
    connectionOptions: {
      ssl: true,
      sslValidate: true,
    }
  }
};

Then mount this file at /node_modules/mongo-express/config.js in your docker-compose file. It'll read these and overwrite the defaults.

Note: I added the sslValidate key:value pair as well due to the fact that it suffers from the same lack of type casting. So if you omit the ME_CONFIG_MONGODB_SSLVALIDATE env var entirely, it'll be set as true, but if you include the env var as either true or false, it'll just simply break (undefined behaviour).