Mongo Only Pawn in Game of Life

August 25, 2024

TLDR;

Connecting to your MongoDB Atlas Cluster from a Container

I spent the weekend tinkering with my boilerplate go API, and wanted to wire up a version which used the go Mongo driver as I’ve never used it before. In doing so, I came upon an issue which others may bump into from time to time, and thought it would be a useful blog post.

MongoDB is a document database, and one of the most popular NoSQL solutions available. It makes it easy and quick to parse things like JSON objects or documents, store and query them in a non-relational manner. One cloud hosted provider for MongoDB is MongoDB Atlas, which I will be referencing for this blog post, although the topic is relevant to any platform.

Two aspects to consider when querying a database remotely are securing the data at rest, and securing the data in transit. At rest, we secure our data via at-rest encryption, authentication and authorization. By using systems like RBAC we can determine who may access what data, whether to reject a request etc.

In transit, we encrypt data using TLS traditionally. This involves a set of encryption keys, a private key used by the sender, and a public key that is sent to the receiver to allow them to decrypt the data. Signed certificates are stored and allow a client to “trust” a source; that is, validate that the public key is coming from who they claim to be.

Creating a Mongo client to connect to our database is quite simple. First, we fetch our Mongo driver module using go get http://go.mongodb.org/mongo-driver/mongo. The code to initalize our client is:

client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))

where uri is the connection string to our database.

Suppose we now try to find a doc in our database via a command like:


              coll := client.Database("my_database").Collection("stuff")
              filter := bson.D{{"name", "samuel l jackson"}}
              // Retrieves the first matching document
              var result Actor
              err = coll.FindOne(context.TODO(), filter).Decode(&result)
            

We are suddenly met with an error!


              Could not connect to mongodb_s1.dev:27017 x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "XYZ")
            

tls handshake diagram with no cert

What is this gibberish you speak?

This is because our container does not have a valid signed certificate with the proper authorization to access our database. We can obtain this certificate from our MongoDB Atlas dashboard by selecting our project, then on the left side **Security → Database Access and selecting the user whom you want to grant access**. Click “Edit” beside this user, then “Certificate”. This will permit you to download an `x509` certificate which we will load into the Docker container.

Once the user is edit/created and the certificate is downloaded (do not check this in to github, store it somewhere secure!), we need to ensure this is loaded into our container on build and our certificate store is updated. This will allow our applications http server to trust our database connection URI origin and complete the client setup:


              COPY path/to/mongoCert.pem /etc/ssl/certs/ca.pem
              RUN apt-get update && apt-get install -y ca-certificates
              RUN cp /etc/ssl/certs/ca.pem /usr/local/share/ca-certificates/ca.crt
              RUN update-ca-certificates
            

COPY path/to/mongoCert.pem /etc/ssl/certs/ca.pem

This command copies the certificate file onto our containers file system.

RUN apt-get update && apt-get install -y ca-certificates

This command updates our package manager and installs the ca-certificates utility.

RUN cp /etc/ssl/certs/ca.pem /usr/local/share/ca-certificates/ca.crt

This command copies our certificate to the trusted certificate folder.

RUN update-ca-certificates

Removes revoked or expired certificates, writes out a new file containing updated/combined certificates.

Now when we rebuild our container, we can successfully query our database cluster!

tls handshake diagram with cert

You are now free to communicate!