Connect to MongoDB 3.2 on Compose from Golang

With our latest MongoDB deployments, you should choose to keep SSL enabled. Connections are safer once made, even if it is a little harder to get started. We will show two variations of how to connect from Go with the community driver of choice mgo (pronounced mango). Officially, it doesn't support 3.2 but we'll look past that since it seems to work just fine. (Caveat: you should test before you go to production.) We'll start the review of the two ways to connect with the easier first.

Easier: SSL Enabled, No Certificate Authority

To get started we have to configure tls. Specifically, we have to configure not using a Certificate Authority. While this does open up some attack vectors, it is vastly superior to no SSL. Here are the comments directly from the source code of the tls.Config struct for the particular boolean we need to set:

        // InsecureSkipVerify controls whether a client verifies the
        // server's certificate chain and host name.
        // If InsecureSkipVerify is true, TLS accepts any certificate
        // presented by the server and any host name in that certificate.
        // In this mode, TLS is susceptible to man-in-the-middle attacks.
        // This should be used only for testing.
        InsecureSkipVerify bool

While a man in the middle attack is a concern, stopping packet sniffing by not sending things in the clear by using tls like this still seems like a good idea. Here are the imports needed to connect:

import (  
  "crypto/tls"
  "net"
  "gopkg.in/mgo.v2"
)

The following is the code needed to connect. It sets the 'InsecureSkipVerify' that was mentioned above, parses the url which you can get from the Compose dashboard, and then calls the 'mgo.DialWithInfo()' which is the main difference from the normal 'mgo.Dial()' call which is used without SSL.

  tlsConfig := &tls.Config{}
  tlsConfig.InsecureSkipVerify = true

  //connect URL:
  // "mongodb://<username>:<password>@<hostname>:<port>,<hostname>:<port>/<db-name>
  dialInfo, err := mgo.ParseURL("mongodb://helgi:secret_stag@aws-us-east-1-portal.2.dblayer.com:11097, aws-us-east-1-portal.3.dblayer.com:11049/valhalla")
  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)

While the above is pretty safe and can certainly be used in development and testing scenarios, we do suggest that at some point you consider the next option too even if it is a little harder.

A Little Harder: SSL Enabled, Local Certificate

The most secure way to connect is to manually copy the public certificate to your application. You will need to get the public key from your Compose deployment's overview page by selecting "Show SSL Public Key" and then pasting the entire certificate into a file available to your code. We've named the file for the example here as "myPEM". The example follows:

Overview

Be sure to select the entire contents of the key and then place into a file.

SSL Public Key

Here are the imports needed:

import(  
  "crypto/tls"
  "crypto/x509"
  "io/ioutil"
  "net"
  "gopkg.in/mgo.v2"
)

Then the code itself:

  roots := x509.NewCertPool()

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

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

  //connect URL:
  // "mongodb://<username>:<password>@<hostname>:<port>,<hostname>:<port>/<db-name>
  dialInfo, err := mgo.ParseURL("mongodb://helgi:secret_stag@aws-us-east-1-portal.2.dblayer.com:11097,aws-us-east-1-portal.3.dblayer.com:11049/valhalla")
  dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
    conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
    return conn, err
  }
  //Here is the session you are looking for. Up to you from here ;)
  session, err := mgo.DialWithInfo(dialInfo)

We aren't doing anything here much more different than the easier version above. First, we load the certificate file which was manually downloaded. Then we add this certificate, as one would a Certificate Authority certificate, to our RootCAs. This allows our code to verify the certificate from our server. Do note that when this code is executed it should be from the same directory as the myPEM file. You could structure this other ways, but we will leave that to you.

Either Way

Both of these examples are pretty simple and either way you should definitely keep ssl enabled. Cheers.