Search code examples
mongodbsslgotls1.2compose-db

Connecting golang mgo to mongo via ssl


I'm trying to setup mongo locally to test the setup described in

https://www.compose.com/articles/connect-to-mongo-3-2-on-compose-from-golang/ "A Little Harder" section

Mongo

I have a working set of self signed credentials, and mongo setup. I've included keys, as those will only be used during dev to make sure mongo ssl code is working.

mongo ssl config

When using this, running via

mongod --config config/location

The config is

net:
  port: 27017
  ssl:
    mode: requireSSL
    CAFile: /data/mongo/ca.crt
    PEMKeyFile: /data/mongo/server.pem
    allowInvalidHostnames: true
    allowConnectionsWithoutCertificates: true

I can then connect to the db with

mongo --ssl --sslCAFile /data/mongo/ca.crt

Golang

func NewSession(url string, ca string) (m *mgo.Session, err error) {
    roots := x509.NewCertPool()
    roots.AppendCertsFromPEM([]byte(ca))

    tlsConfig := &tls.Config{}
    tlsConfig.RootCAs = roots

    url = strings.TrimSuffix(url, "?ssl=true")
    dialInfo, err := mgo.ParseURL(url)
    dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
        conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
        return conn, err
    }

    //Here it is the session. Up to you from here ;)
    session, err := mgo.DialWithInfo(dialInfo)
    if err != nil {
        return m, err
    }

    session.SetMode(mgo.Monotonic, true)

    return session, nil
}

Result

The golang stuff tries to connect and hits the 10s timeout. A fmt at the top of session shows the correct file is making it into the ca var.

Mongo logs show

utumongo_1         | 2017-07-27T08:09:14.964+0000 I NETWORK  [initandlisten] connection accepted from 172.19.0.4:57474 #30 (1 connection now open)
utumongo_1         | 2017-07-27T08:09:14.966+0000 E NETWORK  [conn30] SSL: error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate
utumongo_1         | 2017-07-27T08:09:14.967+0000 I NETWORK  [conn30] end connection 172.19.0.4:57474 (0 connections now open)

Edit Updated mongo config


Solution

  • What are you passing into NewSession as the ca parameter? This needs to be the PEM encoded CA certificate bytes, not the file name of the CA certificate. AppendCertsFromPEM will return true if it managed to add any certificates to the pool.

    The article already shows code to do this:

    if ca, err := ioutil.ReadFile("myPEM"); err == nil { 
        roots.AppendCertsFromPEM(ca)
    }
    

    The SSL error means that the client is rejecting the server certificate. I suspect it is because your self-signed certificate was not added to the pool correctly.

    EDIT

    I ran a copy of mongo locally with your config. Using docker, this was:

    docker run --rm -ti -v $(pwd):/data/mongo --net=host mongo -f /data/mongo/mongo.yaml
    

    When ran from where your configuration was extracted

    Using your NewSession func inside Go showed that the tls.Dial was returning an error due to the lack of any Subject Access Name (SAN) extensions as per my comment below.

    You will need to correct your server certificate to have the appropriate host name (or IP address) SAN entries required.

    You can debug this and any other TLS connection errors that occur with:

    dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
        conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
        if err != nil {
            fmt.Println(err)
        }
        return conn, err
    }